257 lines
7.7 KiB
C
257 lines
7.7 KiB
C
#include "gpio.h"
|
|
#include "ssi_reg.h"
|
|
|
|
void __attribute__((section(".text.boot2_pre"))) boot2_copy_self(void)
|
|
{
|
|
#define BOOT2_FLASHCMD_READ_DATA (0x03)
|
|
#define BOOT2_FLASH_OFFSET (256)
|
|
extern uint32_t _boot2_copy_self_start_addr;
|
|
extern uint32_t _boot2_copy_self_end_addr;
|
|
|
|
io_rw_32 *reg;
|
|
uint32_t cmd;
|
|
uint32_t length, tx_count, rx_count, rx_skip;
|
|
uint8_t *copy_to_addr;
|
|
uint8_t rxbyte;
|
|
|
|
/* force QSPI_CS low level as selected */
|
|
reg = (io_rw_32 *)(IO_QSPI_BASE + GPIO_QSPI_CS_CTRL_OFFSET);
|
|
*reg = GPIO_OVER_OUT_FORCE_LOW << GPIO_OVER_OUT_POS;
|
|
|
|
/* send command and length */
|
|
cmd = (BOOT2_FLASHCMD_READ_DATA << 24) | BOOT2_FLASH_OFFSET;
|
|
for (int i = 0; i < 4; ++i) {
|
|
ssi_hw->dr0 = cmd >> 24;
|
|
cmd <<= 8;
|
|
}
|
|
/* init parameter */
|
|
length = (uint32_t)&_boot2_copy_self_end_addr - (uint32_t)&_boot2_copy_self_start_addr;
|
|
tx_count = length;
|
|
rx_count = length;
|
|
rx_skip = 4;
|
|
copy_to_addr = (uint8_t *)&_boot2_copy_self_start_addr;
|
|
/* copy data from flash to ram */
|
|
while (tx_count || rx_skip || rx_count) {
|
|
uint32_t tx_level = ssi_hw->txflr;
|
|
uint32_t rx_level = ssi_hw->rxflr;
|
|
if (tx_count && tx_level + rx_level < 14) {
|
|
ssi_hw->dr0 = 0;
|
|
tx_count--;
|
|
}
|
|
if (rx_level) {
|
|
rxbyte = ssi_hw->dr0;
|
|
if (rx_skip) {
|
|
rx_skip--;
|
|
} else {
|
|
*copy_to_addr++ = rxbyte;
|
|
rx_count--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* force QSPI_CS high level as disselected */
|
|
*reg = GPIO_OVER_OUT_FORCE_HIGH << GPIO_OVER_OUT_POS;
|
|
}
|
|
|
|
#include "resets.h"
|
|
#include "clock.h"
|
|
#include "uart.h"
|
|
#include "flash.h"
|
|
#include "timer.h"
|
|
#include "stdio.h"
|
|
|
|
uint8_t uart_tx_buffer[512];
|
|
uint8_t uart_rx_buffer[512];
|
|
|
|
struct uart_cfg_s uart_cfg = {
|
|
.baudrate = 2 * 1000 * 1000,
|
|
.mode = UART_MODE_TX_RX,
|
|
.data_bits = UART_DATABITS_8,
|
|
.parity = UART_PARITY_NONE,
|
|
.stop_bits = UART_STOPBITS_1,
|
|
.fifo_enable = ENABLE,
|
|
.tx_fifo_level = UART_FIFO_LEVEL_1_2,
|
|
.rx_fifo_level = UART_FIFO_LEVEL_1_2,
|
|
};
|
|
|
|
void process_return_ok(void)
|
|
{
|
|
uart_write_block(UART_ID_0, (uint8_t *)"OKAY", 4);
|
|
}
|
|
|
|
void process_return_fail(void)
|
|
{
|
|
uart_write_block(UART_ID_0, (uint8_t *)"FAIL", 4);
|
|
}
|
|
|
|
void process_flash_erase(uint32_t addr, uint32_t length)
|
|
{
|
|
addr = addr & (~(FLASH_ERASE_SIZE - 1));
|
|
length = (length + FLASH_ERASE_SIZE - 1) / FLASH_ERASE_SIZE;
|
|
for (int i = 0; i < length; i++) {
|
|
flash_erase(addr + i * FLASH_ERASE_SIZE);
|
|
}
|
|
}
|
|
|
|
void process_flash_write(uint32_t addr, uint8_t *data, uint32_t length)
|
|
{
|
|
uint32_t offset;
|
|
uint32_t chunk_size;
|
|
|
|
offset = addr & (FLASH_WRITE_SIZE - 1);
|
|
if (offset) {
|
|
chunk_size = FLASH_WRITE_SIZE - offset;
|
|
if (chunk_size > length) {
|
|
chunk_size = length;
|
|
}
|
|
flash_write(addr, data, chunk_size);
|
|
addr += chunk_size;
|
|
data += chunk_size;
|
|
length -= chunk_size;
|
|
}
|
|
while (length >= FLASH_WRITE_SIZE) {
|
|
flash_write(addr, data, FLASH_WRITE_SIZE);
|
|
addr += FLASH_WRITE_SIZE;
|
|
data += FLASH_WRITE_SIZE;
|
|
length -= FLASH_WRITE_SIZE;
|
|
}
|
|
if (length > 0) {
|
|
flash_write(addr, data, length);
|
|
}
|
|
}
|
|
|
|
void process_flash_read(uint32_t addr, uint8_t *data, uint32_t length)
|
|
{
|
|
while (length >= FLASH_READ_SIZE) {
|
|
flash_read(addr, data, FLASH_READ_SIZE);
|
|
uart_write_block(UART_ID_0, data, FLASH_READ_SIZE);
|
|
addr += FLASH_READ_SIZE;
|
|
length -= FLASH_READ_SIZE;
|
|
}
|
|
if (length > 0) {
|
|
flash_read(addr, data, length);
|
|
uart_write_block(UART_ID_0, data, length);
|
|
}
|
|
}
|
|
|
|
void uart_process(uint16_t code, uint16_t length)
|
|
{
|
|
uint8_t *p;
|
|
uint32_t checksum_read, checksum_calc;
|
|
uint16_t i;
|
|
uint32_t v1, v2;
|
|
|
|
p = uart_rx_buffer + 8;
|
|
if ((length > 0) && (length <= 4)) {
|
|
return;
|
|
}
|
|
if (length > 4) {
|
|
checksum_read = ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | ((uint32_t)p[3] << 0);
|
|
p += 4;
|
|
length -= 4;
|
|
checksum_calc = 0;
|
|
for (i = 0; i < length; i++) {
|
|
checksum_calc += p[i];
|
|
}
|
|
if (checksum_read != checksum_calc) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
v1 = ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | ((uint32_t)p[3] << 0);
|
|
v2 = ((uint32_t)p[4] << 24) | ((uint32_t)p[5] << 16) | ((uint32_t)p[6] << 8) | ((uint32_t)p[7] << 0);
|
|
if (code == 0x0001) {
|
|
process_flash_erase(v1, v2);
|
|
process_return_ok();
|
|
} else if (code == 0x0002) {
|
|
process_flash_write(v1, p + 8, v2);
|
|
process_return_ok();
|
|
} else if (code == 0x0003) {
|
|
process_return_ok();
|
|
process_flash_read(v1, uart_tx_buffer, v2);
|
|
}
|
|
}
|
|
|
|
void uart_state_machine(uint8_t id)
|
|
{
|
|
static uint64_t time_fifo_empty = 0;
|
|
static uint16_t uart_rx_length = 0;
|
|
uint16_t code, code_inv, length, length_inv;
|
|
|
|
if (uart_get_flags(id) & UART_FLAG_RXFE) {
|
|
if (timer_count_read() - time_fifo_empty < 100) {
|
|
return;
|
|
}
|
|
time_fifo_empty = timer_count_read();
|
|
if (uart_rx_length < 8) {
|
|
uart_rx_length = 0;
|
|
return;
|
|
}
|
|
code = ((uint16_t)uart_rx_buffer[0] << 8) | (uint16_t)uart_rx_buffer[1];
|
|
code_inv = ((uint16_t)uart_rx_buffer[2] << 8) | (uint16_t)uart_rx_buffer[3];
|
|
length = ((uint16_t)uart_rx_buffer[4] << 8) | (uint16_t)uart_rx_buffer[5];
|
|
length_inv = ((uint16_t)uart_rx_buffer[6] << 8) | (uint16_t)uart_rx_buffer[7];
|
|
if ((code != (uint16_t)~code_inv) || (length != (uint16_t)~length_inv)) {
|
|
uart_rx_length = 0;
|
|
return;
|
|
}
|
|
uart_process(code, length);
|
|
uart_rx_length = 0;
|
|
} else {
|
|
uart_rx_buffer[uart_rx_length++] = uart0_hw->dr & 0xFF;
|
|
time_fifo_empty = timer_count_read();
|
|
if (uart_rx_length >= sizeof(uart_rx_buffer)) {
|
|
uart_rx_length = 0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
__attribute__((naked)) void jump_to_address(uint32_t address) {
|
|
__asm volatile (
|
|
"bx %0\n"
|
|
:
|
|
: "r" (address)
|
|
);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
uint32_t boot_pin_low, boot_pin_high;
|
|
|
|
clock_ref_set_src(CLOCK_REF_SRC_XOSC_GLITCHLESS);
|
|
clock_sys_set_src(CLOCK_SYS_SRC_REF_GLITCHLESS);
|
|
/* refdiv >= 5MHz, VCO=[750:1600]MHz, fbdiv=[16:320], postdiv=[1:7] */
|
|
clock_pll_init(CLOCK_PLL_SYSPLL, 1, 100, 5, 2); /* 12MHz / 1 * 100 / 5 / 2 = 120MHz */
|
|
clock_sys_set_div(2 << 8); /* 120MHz / 2 = 60MHz */
|
|
clock_sys_set_src(CLOCK_SYS_SRC_SYSPLL);
|
|
clock_peri_set(ENABLE, CLOCK_PERI_SRC_SYSPLL);
|
|
|
|
reset_unreset_blocks_wait(RESETS_BLOCK_IO_BANK0 | RESETS_BLOCK_PADS_BANK0 | RESETS_BLOCK_UART0 | RESETS_BLOCK_TIMER);
|
|
gpio_init_simple(0, GPIO_FUNC_UART, DISABLE, ENABLE);
|
|
gpio_init_simple(1, GPIO_FUNC_UART, DISABLE, ENABLE);
|
|
uart_init(UART_ID_0, &uart_cfg);
|
|
*(volatile uint32_t *)(WATCHDOG_BASE + 0x2C) = ((1 << 9) | (12 << 0));
|
|
timer_start();
|
|
|
|
gpio_init_simple(2, GPIO_FUNC_SIO, ENABLE, DISABLE);
|
|
boot_pin_low = 0;
|
|
boot_pin_high = 0;
|
|
for (uint32_t i = 0; i < 1000; i++) {
|
|
if (gpio_read(2)) {
|
|
boot_pin_high++;
|
|
} else {
|
|
boot_pin_low++;
|
|
}
|
|
}
|
|
if (boot_pin_high > boot_pin_low) {
|
|
while (1) {
|
|
uart_state_machine(UART_ID_0);
|
|
}
|
|
} else {
|
|
jump_to_address(0x00100000);
|
|
}
|
|
|
|
return 0;
|
|
}
|