rp2040/example/boot2/main.c

250 lines
7.6 KiB
C
Raw Normal View History

2025-04-19 21:07:29 +08:00
#include "gpio.h"
#include "ssi_reg.h"
2025-05-18 22:09:57 +08:00
#include "system.h"
2025-04-19 21:07:29 +08:00
2025-04-13 21:33:56 +08:00
void __attribute__((section(".text.boot2_pre"))) boot2_copy_self(void)
{
2025-04-19 21:07:29 +08:00
#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;
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 */
2025-05-31 21:33:48 +08:00
ioqspi_hw->io[1].ctrl = GPIO_OVER_OUT_LOW;
2025-04-19 21:07:29 +08:00
/* 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 */
2025-05-31 21:33:48 +08:00
ioqspi_hw->io[1].ctrl = GPIO_OVER_OUT_HIGH;
2025-04-13 21:33:56 +08:00
}
2025-06-02 12:57:09 +08:00
#include "common.h"
2025-04-21 21:34:34 +08:00
#include "resets.h"
#include "clock.h"
#include "uart.h"
#include "flash.h"
2025-06-01 16:18:31 +08:00
#include "watchdog.h"
2025-04-21 21:34:34 +08:00
#include "timer.h"
2025-06-02 12:57:09 +08:00
#include "jump.h"
2025-04-21 21:34:34 +08:00
2025-06-02 17:27:26 +08:00
#define UART_ID uart0_hw
2025-06-02 12:57:09 +08:00
uint8_t tx_buffer[512] __attribute__((aligned(4)));
uint8_t rx_buffer[512] __attribute__((aligned(4)));
2025-04-21 21:34:34 +08:00
2025-05-04 21:16:41 +08:00
void process_return_ok(void)
{
2025-06-02 17:27:26 +08:00
uart_write_block(UART_ID, (uint8_t *)"OKAY", 4);
2025-05-04 21:16:41 +08:00
}
void process_return_fail(void)
{
2025-06-02 17:27:26 +08:00
uart_write_block(UART_ID, (uint8_t *)"FAIL", 4);
2025-05-04 21:16:41 +08:00
}
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);
2025-06-02 17:27:26 +08:00
uart_write_block(UART_ID, data, FLASH_READ_SIZE);
2025-05-04 21:16:41 +08:00
addr += FLASH_READ_SIZE;
length -= FLASH_READ_SIZE;
}
if (length > 0) {
flash_read(addr, data, length);
2025-06-02 17:27:26 +08:00
uart_write_block(UART_ID, data, length);
2025-05-04 21:16:41 +08:00
}
}
2025-05-04 17:53:04 +08:00
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;
2025-06-02 12:57:09 +08:00
p = rx_buffer + 8;
2025-05-04 17:53:04 +08:00
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;
}
}
2025-05-04 21:16:41 +08:00
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);
2025-05-04 17:53:04 +08:00
if (code == 0x0001) {
2025-05-04 21:16:41 +08:00
process_flash_erase(v1, v2);
process_return_ok();
2025-05-04 17:53:04 +08:00
} else if (code == 0x0002) {
2025-05-04 21:16:41 +08:00
process_flash_write(v1, p + 8, v2);
process_return_ok();
2025-05-04 17:53:04 +08:00
} else if (code == 0x0003) {
2025-05-04 21:16:41 +08:00
process_return_ok();
2025-06-02 12:57:09 +08:00
process_flash_read(v1, tx_buffer, v2);
2025-05-04 17:53:04 +08:00
}
}
2025-06-02 17:27:26 +08:00
void uart_state_machine(uart_hw_t *uart)
2025-05-04 17:53:04 +08:00
{
static uint64_t time_fifo_empty = 0;
static uint16_t uart_rx_length = 0;
uint16_t code, code_inv, length, length_inv;
2025-06-02 17:27:26 +08:00
if (uart_get_flags(uart) & UART_FLAG_RXFE) {
2025-05-05 21:42:38 +08:00
if (timer_count_read() - time_fifo_empty < 100) {
2025-05-04 17:53:04 +08:00
return;
}
time_fifo_empty = timer_count_read();
if (uart_rx_length < 8) {
uart_rx_length = 0;
return;
}
2025-06-02 12:57:09 +08:00
code = ((uint16_t)rx_buffer[0] << 8) | (uint16_t)rx_buffer[1];
code_inv = ((uint16_t)rx_buffer[2] << 8) | (uint16_t)rx_buffer[3];
length = ((uint16_t)rx_buffer[4] << 8) | (uint16_t)rx_buffer[5];
length_inv = ((uint16_t)rx_buffer[6] << 8) | (uint16_t)rx_buffer[7];
2025-05-04 17:53:04 +08:00
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 {
2025-06-02 12:57:09 +08:00
rx_buffer[uart_rx_length++] = uart0_hw->dr & 0xFF;
2025-05-04 17:53:04 +08:00
time_fifo_empty = timer_count_read();
2025-06-02 12:57:09 +08:00
if (uart_rx_length >= sizeof(rx_buffer)) {
2025-05-04 17:53:04 +08:00
uart_rx_length = 0;
return;
}
}
}
2025-04-13 17:29:34 +08:00
int main(void)
{
2025-05-05 21:42:38 +08:00
uint32_t boot_pin_low, boot_pin_high;
2025-06-02 12:57:09 +08:00
struct fw_header_s *header;
2025-05-05 21:42:38 +08:00
2025-06-02 12:57:09 +08:00
clock_ref_set(CLOCK_REF_SRC_XOSC_GLITCHLESS, 1);
clock_sys_set(CLOCK_SYS_SRC_REF_GLITCHLESS, 1);
clock_peri_set(ENABLE, CLOCK_PERI_SRC_XOSC);
2025-04-21 21:34:34 +08:00
reset_unreset_blocks_wait(RESETS_BLOCK_IO_BANK0 | RESETS_BLOCK_PADS_BANK0 | RESETS_BLOCK_UART0 | RESETS_BLOCK_TIMER);
2025-05-31 21:33:48 +08:00
gpio_init(0, GPIO_FUNC_UART | GPIO_PULL_UP | GPIO_DRIVE_4MA); /* UART_TX pin */
gpio_init(1, GPIO_FUNC_UART | GPIO_PULL_UP | GPIO_SCHMITT | GPIO_PAD_IE | GPIO_PAD_OD); /* UART_RX pin */
2025-06-02 17:27:26 +08:00
uart_init(uart0_hw, 750 * 1000, UART_DATABITS_8 | UART_PARITY_NONE | UART_STOPBITS_1);
2025-06-01 16:18:31 +08:00
watchdog_start_tick(12); /* 12MHz / 12 = 1MHz, as 1us */
2025-04-21 21:34:34 +08:00
timer_start();
2025-05-31 21:33:48 +08:00
gpio_init(2, GPIO_FUNC_NULL | GPIO_PULL_DOWN | GPIO_SCHMITT | GPIO_PAD_IE | GPIO_PAD_OD); /* boot pin */
2025-05-05 21:42:38 +08:00
boot_pin_low = 0;
boot_pin_high = 0;
2025-05-31 21:33:48 +08:00
for (uint32_t i = 0; i < 10; i++) {
2025-05-05 21:42:38 +08:00
if (gpio_read(2)) {
boot_pin_high++;
} else {
boot_pin_low++;
}
2025-05-04 17:53:04 +08:00
}
2025-05-05 21:42:38 +08:00
if (boot_pin_high > boot_pin_low) {
2025-06-02 12:57:09 +08:00
for (uint32_t i = 0; i < 4; i++) {
tx_buffer[i] = 0x55;
}
2025-06-02 17:27:26 +08:00
uart_write_block(UART_ID, tx_buffer, 4);
2025-05-05 21:42:38 +08:00
while (1) {
2025-06-02 17:27:26 +08:00
uart_state_machine(UART_ID);
2025-05-05 21:42:38 +08:00
}
} else {
2025-06-02 12:57:09 +08:00
flash_read(FW_ADDRESS, rx_buffer, FLASH_READ_SIZE);
header = (struct fw_header_s *)rx_buffer;
if (jump_check_is_failed(header)) {
flash_enter_quad_xip(6);
jump_to_address((uint32_t)(uintptr_t *)(FW_ADDRESS | XIP_BASE | 1));
} else {
jump_pre_config(header);
jump_to_address(((struct fw_header_s *)header)->jump_address | 1);
}
2025-05-05 21:42:38 +08:00
}
2025-04-13 17:29:34 +08:00
return 0;
}