busk/main.c
2023-05-18 09:20:54 +00:00

126 lines
3.0 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hardware/vreg.h"
#include "hardware/clocks.h"
#include "pico/stdlib.h"
#include "hardware/watchdog.h"
#include "pins.h"
#include "firmware.h"
void pins_setup(void)
{
// avoid mosfet enable no matter what
gpio_pull_down(PIN_GLI_WS);
gpio_pull_down(PIN_GLI_XIAO);
gpio_pull_down(PIN_GLI_PICO);
gpio_pull_down(PIN_GLI_ITSY);
*(uint32_t*)(0x4001c000 + 4 + PIN_RST*4 + 0x2000) = 0x81;
}
// overclock setup
void oc_setup(void)
{
vreg_set_voltage(VREG_VOLTAGE_1_30);
set_sys_clock_khz(200000, true);
}
void zzz() {
*(uint32_t*)(0x4000803C + 0x3000) = 1; // go to 12 MHz
uint32_t * vreg = (uint32_t*)0x40064000;
vreg[1] &= ~1; // disable brownout
*(uint32_t*)0x40060000 = 0x00d1e000; // disable rosc
*(uint32_t*)0x40004018 = 0xFF; // disable SRAMs
vreg[0] = 1; // lowest possible power
*(uint32_t*)0x40024000 = 0x00d1e000; // disable xosc
while(1);
}
void halt() {
// disable all pins except glitch
for(int pin = 0; pin <= 29; pin += 1) {
uint32_t pad_reg = 0x4001c000 + 4 + pin*4;
// glitch pin pulldown, just in case
if (pin == PIN_GLI_PICO || pin == PIN_GLI_XIAO || pin == PIN_GLI_WS || pin == PIN_GLI_ITSY)
*(uint32_t*)pad_reg = 0x85; //pulldown
else
*(uint32_t*)pad_reg = 0x81;
}
zzz();
}
#define fw_slot_0 ((struct fw_header *) (XIP_BASE + 0x10000))
#define fw_slot_1 ((struct fw_header *) (XIP_BASE + 0x48000))
#define RAM ((uint8_t *) 0x20000000)
#define FUSE_OFF 0xF000
#define fuses ((const uint8_t *) (XIP_BASE + FUSE_OFF))
int count_fuses()
{
int weight = 0;
uint32_t * buf = (uint32_t*)fuses;
for (int i = 0; i < 64; i++) {
if(buf[i] == 0)
weight += 32;
else {
weight += __builtin_ctz(buf[i]);
break;
}
}
return weight;
}
void perform_reboot()
{
watchdog_enable(0, false);
while(1);
}
void startup_from_slot(int slot)
{
struct fw_header * fw = slot ? fw_slot_1 : fw_slot_0;
watchdog_enable(100, false);
// set the slot where we have started from
watchdog_hw->scratch[1] = slot;
// check the size
if (fw->size > 0x38000 || fw->size == 0) {
perform_reboot();
}
// copy data into the RAM
memcpy(RAM, fw->data, fw->size);
uint32_t real_crc = crc32(RAM, fw->size);
if (real_crc != fw->crc)
{
perform_reboot();
}
// jump to the unpacked firmware
((nopar*)0x20000001)();
}
int main(void)
{
pins_setup();
oc_setup();
int boot_slot = (count_fuses() & 1);
if (!watchdog_enable_caused_reboot() || !watchdog_caused_reboot()) // first boot attempt
{
watchdog_hw->scratch[0] = 0;
startup_from_slot(boot_slot & 1);
}
else if (watchdog_caused_reboot()) // next boot attempt
{
int boot_try = watchdog_hw->scratch[0];
if (boot_try == 3) // 1 -> update or failed boot, 2->rollback after update, 3- total fail
{
halt();
}
watchdog_hw->scratch[0] = boot_try + 1;
startup_from_slot((boot_slot ^ boot_try ^ 1) & 1);
}
return 0;
}