panda/board/spi_flasher.h

476 lines
13 KiB
C

// flasher state variables
uint32_t *prog_ptr = NULL;
int unlocked = 0;
#ifdef uart_ring
void debug_ring_callback(uart_ring *ring) {}
#endif
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) {
int resp_len = 0;
// flasher machine
memset(resp, 0, 4);
memcpy(resp+4, "\xde\xad\xd0\x0d", 4);
resp[0] = 0xff;
resp[2] = setup->b.bRequest;
resp[3] = ~setup->b.bRequest;
*((uint32_t **)&resp[8]) = prog_ptr;
resp_len = 0xc;
int sec;
switch (setup->b.bRequest) {
// **** 0xb0: flasher echo
case 0xb0:
resp[1] = 0xff;
break;
// **** 0xb1: unlock flash
case 0xb1:
if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
resp[1] = 0xff;
}
current_board->set_led(LED_GREEN, 1);
unlocked = 1;
prog_ptr = (uint32_t *)0x8004000;
break;
// **** 0xb2: erase sector
case 0xb2:
sec = setup->b.wValue.w;
// don't erase the bootloader
if (sec != 0 && sec < 12 && unlocked) {
FLASH->CR = (sec << 3) | FLASH_CR_SER;
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
resp[1] = 0xff;
}
break;
// **** 0xd0: fetch serial number
case 0xd0:
#ifdef STM32F4
// addresses are OTP
if (setup->b.wValue.w == 1) {
memcpy(resp, (void *)0x1fff79c0, 0x10);
resp_len = 0x10;
} else {
get_provision_chunk(resp);
resp_len = PROVISION_CHUNK_LEN;
}
#endif
break;
// **** 0xd1: enter bootloader mode
case 0xd1:
// this allows reflashing of the bootstub
// so it's blocked over wifi
switch (setup->b.wValue.w) {
case 0:
// TODO: put this back when it's no longer a "devkit"
//#ifdef ALLOW_DEBUG
#if 1
if (hardwired) {
#else
// no more bootstub on UNO once OTP block is flashed
if (hardwired && ((hw_type != HW_TYPE_UNO) || (!is_provisioned()))) {
#endif
puts("-> entering bootloader\n");
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
}
break;
case 1:
puts("-> entering softloader\n");
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
NVIC_SystemReset();
break;
}
break;
// **** 0xd6: get version
case 0xd6:
COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN);
memcpy(resp, gitversion, sizeof(gitversion));
resp_len = sizeof(gitversion);
break;
// **** 0xd8: reset ST
case 0xd8:
NVIC_SystemReset();
break;
}
return resp_len;
}
int usb_cb_ep1_in(void *usbdata, int len, bool hardwired) {
UNUSED(usbdata);
UNUSED(len);
UNUSED(hardwired);
return 0;
}
void usb_cb_ep3_out(void *usbdata, int len, bool hardwired) {
UNUSED(usbdata);
UNUSED(len);
UNUSED(hardwired);
}
void usb_cb_ep3_out_complete(void) {}
int is_enumerated = 0;
void usb_cb_enumeration_complete(void) {
puts("USB enumeration complete\n");
is_enumerated = 1;
}
void usb_cb_ep2_out(void *usbdata, int len, bool hardwired) {
UNUSED(hardwired);
current_board->set_led(LED_RED, 0);
for (int i = 0; i < len/4; i++) {
// program byte 1
FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG;
*prog_ptr = *(uint32_t*)(usbdata+(i*4));
while (FLASH->SR & FLASH_SR_BSY);
//*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr;
prog_ptr++;
}
current_board->set_led(LED_RED, 1);
}
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
UNUSED(len);
int resp_len = 0;
switch (data[0]) {
case 0:
// control transfer
resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), data_out, 0);
break;
case 2:
// ep 2, flash!
usb_cb_ep2_out(data+4, data[2], 0);
break;
}
return resp_len;
}
#ifdef PEDAL
#include "drivers/llcan.h"
#define CAN CAN1
#define CAN_BL_INPUT 0x1
#define CAN_BL_OUTPUT 0x2
void CAN1_TX_IRQ_Handler(void) {
// clear interrupt
CAN->TSR |= CAN_TSR_RQCP0;
}
#define ISOTP_BUF_SIZE 0x110
uint8_t isotp_buf[ISOTP_BUF_SIZE];
uint8_t *isotp_buf_ptr = NULL;
int isotp_buf_remain = 0;
uint8_t isotp_buf_out[ISOTP_BUF_SIZE];
uint8_t *isotp_buf_out_ptr = NULL;
int isotp_buf_out_remain = 0;
int isotp_buf_out_idx = 0;
void bl_can_send(uint8_t *odat) {
// wait for send
while (!(CAN->TSR & CAN_TSR_TME0));
// send continue
CAN->sTxMailBox[0].TDLR = ((uint32_t*)odat)[0];
CAN->sTxMailBox[0].TDHR = ((uint32_t*)odat)[1];
CAN->sTxMailBox[0].TDTR = 8;
CAN->sTxMailBox[0].TIR = (CAN_BL_OUTPUT << 21) | 1;
}
void CAN1_RX0_IRQ_Handler(void) {
while (CAN->RF0R & CAN_RF0R_FMP0) {
if ((CAN->sFIFOMailBox[0].RIR>>21) == CAN_BL_INPUT) {
uint8_t dat[8];
for (int i = 0; i < 8; i++) {
dat[i] = GET_BYTE(&CAN->sFIFOMailBox[0], i);
}
uint8_t odat[8];
uint8_t type = dat[0] & 0xF0;
if (type == 0x30) {
// continue
while (isotp_buf_out_remain > 0) {
// wait for send
while (!(CAN->TSR & CAN_TSR_TME0));
odat[0] = 0x20 | isotp_buf_out_idx;
memcpy(odat+1, isotp_buf_out_ptr, 7);
isotp_buf_out_remain -= 7;
isotp_buf_out_ptr += 7;
isotp_buf_out_idx++;
bl_can_send(odat);
}
} else if (type == 0x20) {
if (isotp_buf_remain > 0) {
memcpy(isotp_buf_ptr, dat+1, 7);
isotp_buf_ptr += 7;
isotp_buf_remain -= 7;
}
if (isotp_buf_remain <= 0) {
int len = isotp_buf_ptr - isotp_buf + isotp_buf_remain;
// call the function
memset(isotp_buf_out, 0, ISOTP_BUF_SIZE);
isotp_buf_out_remain = spi_cb_rx(isotp_buf, len, isotp_buf_out);
isotp_buf_out_ptr = isotp_buf_out;
isotp_buf_out_idx = 0;
// send initial
if (isotp_buf_out_remain <= 7) {
odat[0] = isotp_buf_out_remain;
memcpy(odat+1, isotp_buf_out_ptr, isotp_buf_out_remain);
} else {
odat[0] = 0x10 | (isotp_buf_out_remain>>8);
odat[1] = isotp_buf_out_remain & 0xFF;
memcpy(odat+2, isotp_buf_out_ptr, 6);
isotp_buf_out_remain -= 6;
isotp_buf_out_ptr += 6;
isotp_buf_out_idx++;
}
bl_can_send(odat);
}
} else if (type == 0x10) {
int len = ((dat[0]&0xF)<<8) | dat[1];
// setup buffer
isotp_buf_ptr = isotp_buf;
memcpy(isotp_buf_ptr, dat+2, 6);
if (len < (ISOTP_BUF_SIZE-0x10)) {
isotp_buf_ptr += 6;
isotp_buf_remain = len-6;
}
memset(odat, 0, 8);
odat[0] = 0x30;
bl_can_send(odat);
}
}
// next
CAN->RF0R |= CAN_RF0R_RFOM0;
}
}
void CAN1_SCE_IRQ_Handler(void) {
llcan_clear_send(CAN);
}
#endif
#ifdef GATEWAY
#include "drivers/llcan.h"
#define CAN CAN1
#define CAN_BL_INPUT 0x1
#define CAN_BL_OUTPUT 0x2
void CAN1_TX_IRQ_Handler(void) {
// clear interrupt
CAN->TSR |= CAN_TSR_RQCP0;
}
#define ISOTP_BUF_SIZE 0x110
uint8_t isotp_buf[ISOTP_BUF_SIZE];
uint8_t *isotp_buf_ptr = NULL;
int isotp_buf_remain = 0;
uint8_t isotp_buf_out[ISOTP_BUF_SIZE];
uint8_t *isotp_buf_out_ptr = NULL;
int isotp_buf_out_remain = 0;
int isotp_buf_out_idx = 0;
void bl_can_send(uint8_t *odat) {
// wait for send
while (!(CAN->TSR & CAN_TSR_TME0));
// send continue
CAN->sTxMailBox[0].TDLR = ((uint32_t*)odat)[0];
CAN->sTxMailBox[0].TDHR = ((uint32_t*)odat)[1];
CAN->sTxMailBox[0].TDTR = 8;
CAN->sTxMailBox[0].TIR = (CAN_BL_OUTPUT << 21) | 1;
}
void CAN1_RX0_IRQ_Handler(void) {
while (CAN->RF0R & CAN_RF0R_FMP0) {
if ((CAN->sFIFOMailBox[0].RIR>>21) == CAN_BL_INPUT) {
uint8_t dat[8];
for (int i = 0; i < 8; i++) {
dat[i] = GET_BYTE(&CAN->sFIFOMailBox[0], i);
}
uint8_t odat[8];
uint8_t type = dat[0] & 0xF0;
if (type == 0x30) {
// continue
while (isotp_buf_out_remain > 0) {
// wait for send
while (!(CAN->TSR & CAN_TSR_TME0));
odat[0] = 0x20 | isotp_buf_out_idx;
memcpy(odat+1, isotp_buf_out_ptr, 7);
isotp_buf_out_remain -= 7;
isotp_buf_out_ptr += 7;
isotp_buf_out_idx++;
bl_can_send(odat);
}
} else if (type == 0x20) {
if (isotp_buf_remain > 0) {
memcpy(isotp_buf_ptr, dat+1, 7);
isotp_buf_ptr += 7;
isotp_buf_remain -= 7;
}
if (isotp_buf_remain <= 0) {
int len = isotp_buf_ptr - isotp_buf + isotp_buf_remain;
// call the function
memset(isotp_buf_out, 0, ISOTP_BUF_SIZE);
isotp_buf_out_remain = spi_cb_rx(isotp_buf, len, isotp_buf_out);
isotp_buf_out_ptr = isotp_buf_out;
isotp_buf_out_idx = 0;
// send initial
if (isotp_buf_out_remain <= 7) {
odat[0] = isotp_buf_out_remain;
memcpy(odat+1, isotp_buf_out_ptr, isotp_buf_out_remain);
} else {
odat[0] = 0x10 | (isotp_buf_out_remain>>8);
odat[1] = isotp_buf_out_remain & 0xFF;
memcpy(odat+2, isotp_buf_out_ptr, 6);
isotp_buf_out_remain -= 6;
isotp_buf_out_ptr += 6;
isotp_buf_out_idx++;
}
bl_can_send(odat);
}
} else if (type == 0x10) {
int len = ((dat[0]&0xF)<<8) | dat[1];
// setup buffer
isotp_buf_ptr = isotp_buf;
memcpy(isotp_buf_ptr, dat+2, 6);
if (len < (ISOTP_BUF_SIZE-0x10)) {
isotp_buf_ptr += 6;
isotp_buf_remain = len-6;
}
memset(odat, 0, 8);
odat[0] = 0x30;
bl_can_send(odat);
}
}
// next
CAN->RF0R |= CAN_RF0R_RFOM0;
}
}
void CAN1_SCE_IRQ_Handler(void) {
llcan_clear_send(CAN);
}
#endif
void soft_flasher_start(void) {
#ifdef PEDAL
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
#endif
#ifdef GATEWAY
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
#endif
puts("\n\n\n************************ FLASHER START ************************\n");
enter_bootloader_mode = 0;
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
// pedal has the canloader
#ifdef PEDAL
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
// B8,B9: CAN 1
set_gpio_alternate(GPIOB, 8, GPIO_AF9_CAN1);
set_gpio_alternate(GPIOB, 9, GPIO_AF9_CAN1);
current_board->enable_can_transceiver(1, true);
// init can
llcan_set_speed(CAN1, 5000, false, false);
llcan_init(CAN1);
#endif
#ifdef GATEWAY
//init can for bootloading
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
set_gpio_alternate(GPIOB, 8, GPIO_AF8_CAN1);
set_gpio_alternate(GPIOB, 9, GPIO_AF8_CAN1);
current_board->enable_can_transceiver(1, true);
// init can
llcan_set_speed(CAN1, 5000, false, false);
llcan_init(CAN1);
#endif
// A4,A5,A6,A7: setup SPI
set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1);
set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1);
set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1);
set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1);
// A2,A3: USART 2 for debugging
set_gpio_alternate(GPIOA, 2, GPIO_AF7_USART2);
set_gpio_alternate(GPIOA, 3, GPIO_AF7_USART2);
// A11,A12: USB
set_gpio_alternate(GPIOA, 11, GPIO_AF10_OTG_FS);
set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG_FS);
GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12;
// flasher
spi_init();
// enable USB
usb_init();
// green LED on for flashing
current_board->set_led(LED_GREEN, 1);
enable_interrupts();
uint64_t cnt = 0;
for (cnt=0;;cnt++) {
if (cnt == 35 && !is_enumerated && usb_power_mode == USB_POWER_CLIENT) {
// if you are connected through a hub to the phone
// you need power to be able to see the device
puts("USBP: didn't enumerate, switching to CDP mode\n");
current_board->set_usb_power_mode(USB_POWER_CDP);
current_board->set_led(LED_BLUE, 1);
}
// blink the green LED fast
current_board->set_led(LED_GREEN, 0);
delay(500000);
current_board->set_led(LED_GREEN, 1);
delay(500000);
}
}