void flash_func_erase_sector(unsigned sector) { if (sector >= BOARD_FLASH_SECTORS) return; /* get the base address of the sector */ uint32_t address = 0; for (unsigned i = 0; i < sector; i++) address += flash_func_sector_size(i); /* blank-check the sector */ unsigned size = flash_func_sector_size(sector); bool blank = true; for (unsigned i = 0; i < size; i += sizeof(uint32_t)) { if (flash_func_read_word(address + i) != 0xffffffff) { blank = false; break; } } /* erase the sector if it failed the blank check */ if (!blank) flash_erase_sector(flash_sectors[sector].erase_code, FLASH_PROGRAM_X32); }
void bootloader(unsigned timeout) { int c; int arg = 0; unsigned i; unsigned address = board_info.fw_size; /* force erase before upload will work */ uint32_t first_word = 0xffffffff; static union { uint8_t c[256]; uint32_t w[64]; } flash_buffer; /* (re)start the timer system */ systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB); systick_set_reload(board_info.systick_mhz * 1000); /* 1ms tick, magic number */ systick_interrupt_enable(); systick_counter_enable(); /* if we are working with a timeout, start it running */ if (timeout) timer[TIMER_BL_WAIT] = timeout; while (true) { // Wait for a command byte led_off(LED_ACTIVITY); do { /* if we have a timeout and the timer has expired, return now */ if (timeout && !timer[TIMER_BL_WAIT]) return; /* try to get a byte from the host */ c = cin_wait(0); } while (c < 0); led_on(LED_ACTIVITY); // common argument handling for commands switch (c) { case PROTO_GET_SYNC: case PROTO_CHIP_ERASE: case PROTO_CHIP_VERIFY: case PROTO_DEBUG: /* expect EOC */ if (cin_wait(1000) != PROTO_EOC) goto cmd_bad; break; case PROTO_PROG_MULTI: /* expect count */ arg = cin_wait(1000); if (arg < 0) goto cmd_bad; break; case PROTO_GET_DEVICE: case PROTO_READ_MULTI: /* expect arg/count then EOC */ arg = cin_wait(1000); if (arg < 0) goto cmd_bad; if (cin_wait(1000) != PROTO_EOC) goto cmd_bad; break; } // handle the command byte switch (c) { case PROTO_GET_SYNC: // sync break; case PROTO_GET_DEVICE: // report board info switch (arg) { case PROTO_DEVICE_BL_REV: cout((uint8_t *)&bl_proto_rev, sizeof(bl_proto_rev)); break; case PROTO_DEVICE_BOARD_ID: cout((uint8_t *)&board_info.board_type, sizeof(board_info.board_type)); break; case PROTO_DEVICE_BOARD_REV: cout((uint8_t *)&board_info.board_rev, sizeof(board_info.board_rev)); break; case PROTO_DEVICE_FW_SIZE: cout((uint8_t *)&board_info.fw_size, sizeof(board_info.fw_size)); break; default: goto cmd_bad; } break; case PROTO_CHIP_ERASE: // erase the program area + read for programming flash_unlock(); for (i = 0; flash_func_sector_size(i) != 0; i++) flash_func_erase_sector(i); address = 0; break; case PROTO_CHIP_VERIFY: // reset for verification of the program area address = 0; break; case PROTO_PROG_MULTI: // program bytes if (arg % 4) goto cmd_bad; if ((address + arg) > board_info.fw_size) goto cmd_bad; if (arg > sizeof(flash_buffer.c)) goto cmd_bad; for (i = 0; i < arg; i++) { c = cin_wait(1000); if (c < 0) goto cmd_bad; flash_buffer.c[i] = c; } if (cin_wait(1000) != PROTO_EOC) goto cmd_bad; if (address == 0) { // save the first word and don't program it until // everything else is done first_word = flash_buffer.w[0]; // replace first word with bits we can overwrite later flash_buffer.w[0] = 0xffffffff; } arg /= 4; for (i = 0; i < arg; i++) { flash_func_write_word(address, flash_buffer.w[i]); address += 4; } break; case PROTO_READ_MULTI: // readback bytes if (arg % 4) goto cmd_bad; if ((address + arg) > board_info.fw_size) goto cmd_bad; arg /= 4; /* handle readback of the not-yet-programmed first word */ if ((address == 0) && (first_word != 0xffffffff)) { cout((uint8_t *)&first_word, 4); address += 4; arg--; } while (arg-- > 0) { cout_word(flash_func_read_word(address)); address += 4; } break; case PROTO_BOOT: // program the deferred first word if (first_word != 0xffffffff) { flash_func_write_word(0, first_word); // revert in case the flash was bad... first_word = 0xffffffff; } // quiesce and jump to the app return; case PROTO_DEBUG: // XXX reserved for ad-hoc debugging as required break; default: continue; } // we got a command worth syncing, so kill the timeout because // we are probably talking to the uploader timeout = 0; // send the sync response for this command sync_response(); continue; cmd_bad: // Currently we do nothing & let the programming tool time out // if that's what it wants to do. // Let the initial delay keep counting down so that we ignore // random chatter from a device. while(true); continue; } }