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);
}
Beispiel #2
0
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;
	}
}