phaser-ags / firmware /boot /stage1.c
SNAPKITTYWEST's picture
October 2026 main drop: mirror from GitHub
829b19c verified
Raw History Blame Contribute Delete
7.9 kB
/*
* ARM Cortex-A8 (OMAP3530) Stage 1 Bootloader — C Entry
*
* Called from start.S after assembly lowlevel_init completes:
* - DPLLs locked (600MHz CPU, 266MHz DDR)
* - SDRC initialized (JEDEC sequence complete)
* - GPMC configured (NOR CS0, NAND CS1)
* - Stack and BSS ready
*
* This file: console init, board init, Stage 2 load + validate + jump
*/
#include "../common/types.h"
#include "../common/platform.h"
#include "../hal/uart.h"
#include "../hal/gpio.h"
#include "../hal/timer.h"
#include "../hal/interrupt.h"
#include "../hal/clock.h"
#include "../hal/pinmux.h"
#include "../hal/i2c.h"
#include "../drivers/sdram.h"
#include "../drivers/nor_flash.h"
#include "../drivers/nand_flash.h"
#include "board.h"
/* ---- Console UART ---- */
static uart_dev_t console;
/* ---- CRC32 (Ethernet polynomial) ---- */
static uint32_t crc32_table[256];
static void crc32_init(void) {
for (uint32_t i = 0; i < 256; i++) {
uint32_t crc = i;
for (int j = 0; j < 8; j++) {
if (crc & 1)
crc = (crc >> 1) ^ 0xEDB88320UL;
else
crc >>= 1;
}
crc32_table[i] = crc;
}
}
static uint32_t crc32_compute(const uint8_t *data, uint32_t len) {
uint32_t crc = 0xFFFFFFFFUL;
for (uint32_t i = 0; i < len; i++) {
crc = (crc >> 8) ^ crc32_table[(crc ^ data[i]) & 0xFF];
}
return crc ^ 0xFFFFFFFFUL;
}
/* ---- Boot source detection via SYS_BOOT pins ---- */
static boot_source_t detect_boot_source(void) {
hw_reg32_t scm = (hw_reg32_t)SCM_BASE;
reg32_t sysboot = reg_read32(scm + 0x2F0) & 0x1F;
switch (sysboot) {
case 0x00: return BOOT_SOURCE_NAND;
case 0x01: return BOOT_SOURCE_NOR;
case 0x02: return BOOT_SOURCE_UART;
case 0x03: return BOOT_SOURCE_MMC;
default: return BOOT_SOURCE_UNKNOWN;
}
}
/* ---- Load Stage 2 from NOR Flash ---- */
static int load_stage2_nor(void) {
uart_puts(&console, "Loading Stage 2 from NOR Flash...\r\n");
if (nor_flash_init(0) != 0) {
uart_puts(&console, "NOR Flash init failed\r\n");
return -1;
}
uint16_t mfr, dev;
nor_flash_read_id(0, &mfr, &dev);
uart_puts(&console, "NOR Flash ID: mfr=");
uart_put_hex(&console, mfr);
uart_puts(&console, " dev=");
uart_put_hex(&console, dev);
uart_puts(&console, "\r\n");
volatile uint8_t *src = (volatile uint8_t *)(NOR_FLASH_BASE + 0x40000);
volatile uint8_t *dst = (volatile uint8_t *)DRAM_BOOT_BASE;
for (uint32_t i = 0; i < DRAM_BOOT_SIZE; i++) {
dst[i] = src[i];
}
return 0;
}
/* ---- Load Stage 2 from NAND Flash ---- */
static int load_stage2_nand(void) {
uart_puts(&console, "Loading Stage 2 from NAND Flash...\r\n");
nand_dev_t nand;
if (nand_init(&nand, 0) != 0) {
uart_puts(&console, "NAND Flash init failed\r\n");
return -1;
}
uart_puts(&console, "NAND ID: mfr=");
uart_put_hex_byte(&console, nand.manufacturer_id);
uart_puts(&console, " dev=");
uart_put_hex_byte(&console, nand.device_id);
uart_puts(&console, "\r\n");
uint32_t start_block = 1;
uint8_t page_buf[NAND_PAGE_SIZE];
uint8_t *dst = (uint8_t *)DRAM_BOOT_BASE;
uint32_t copied = 0;
for (uint32_t block = start_block; block < 8 && copied < DRAM_BOOT_SIZE; block++) {
if (nand_is_bad_block(&nand, block))
continue;
for (uint32_t page = 0; page < nand.pages_per_block && copied < DRAM_BOOT_SIZE; page++) {
uint32_t abs_page = block * nand.pages_per_block + page;
if (nand_read_page(&nand, abs_page, page_buf, (uint8_t *)0) != 0) {
uart_puts(&console, "NAND read error\r\n");
return -1;
}
for (uint32_t i = 0; i < nand.page_size && copied < DRAM_BOOT_SIZE; i++) {
dst[copied++] = page_buf[i];
}
}
}
uart_puts(&console, "Loaded ");
uart_put_hex(&console, copied);
uart_puts(&console, " bytes from NAND\r\n");
return 0;
}
/* ---- Stage 2 header ---- */
#define STAGE2_MAGIC 0x53544132UL
typedef struct {
uint32_t magic;
uint32_t size;
uint32_t crc32;
uint32_t entry_offset;
} stage2_header_t;
static int validate_stage2(void) {
volatile stage2_header_t *hdr = (volatile stage2_header_t *)DRAM_BOOT_BASE;
if (hdr->magic != STAGE2_MAGIC) {
uart_puts(&console, "Stage 2: bad magic (");
uart_put_hex(&console, hdr->magic);
uart_puts(&console, ")\r\n");
return -1;
}
if (hdr->size > DRAM_BOOT_SIZE) {
uart_puts(&console, "Stage 2: too large\r\n");
return -1;
}
crc32_init();
uint32_t computed = crc32_compute(
(const uint8_t *)(DRAM_BOOT_BASE + sizeof(stage2_header_t)),
hdr->size - sizeof(stage2_header_t)
);
if (computed != hdr->crc32) {
uart_puts(&console, "Stage 2: CRC mismatch\r\n");
return -1;
}
uart_puts(&console, "Stage 2 validated (");
uart_put_hex(&console, hdr->size);
uart_puts(&console, " bytes, CRC OK)\r\n");
return 0;
}
/* ================================================================ */
/* RESET HANDLER — C entry from start.S */
/* ================================================================ */
void reset_handler(void) {
/* 1. Board early init (pinmux, peripheral clocks) */
board_early_init_f();
/* 2. Console UART */
uart_init(&console, UART0_BASE, REF_CLK_HZ);
uart_configure(&console, 115200, 8, 0, 1);
uart_puts(&console, "\r\n");
uart_puts(&console, "=============================\r\n");
uart_puts(&console, " Phaser AGS Stage 1 Bootloader\r\n");
uart_puts(&console, " OMAP3530 Cortex-A8 @ 600MHz\r\n");
uart_puts(&console, "=============================\r\n");
/* 3. Board init (GPIO, I2C PMIC, SDRAM verify) */
if (board_init() != 0) {
uart_puts(&console, "Board init FAILED\r\n");
while(1);
}
/* 4. Detect boot source and load Stage 2 */
boot_source_t boot = detect_boot_source();
uart_puts(&console, "Boot source: ");
switch (boot) {
case BOOT_SOURCE_NAND: uart_puts(&console, "NAND\r\n"); break;
case BOOT_SOURCE_NOR: uart_puts(&console, "NOR\r\n"); break;
case BOOT_SOURCE_UART: uart_puts(&console, "UART\r\n"); break;
case BOOT_SOURCE_MMC: uart_puts(&console, "MMC\r\n"); break;
default: uart_puts(&console, "UNKNOWN\r\n"); break;
}
int load_result = -1;
switch (boot) {
case BOOT_SOURCE_NAND:
load_result = load_stage2_nand();
break;
case BOOT_SOURCE_NOR:
load_result = load_stage2_nor();
break;
default:
uart_puts(&console, "Unsupported boot source\r\n");
while(1);
}
if (load_result != 0) {
uart_puts(&console, "Stage 2 load FAILED\r\n");
while(1);
}
/* 5. Validate Stage 2 */
if (validate_stage2() != 0) {
uart_puts(&console, "Stage 2 validation FAILED\r\n");
while(1);
}
/* 6. Board late init */
board_late_init();
/* 7. Jump to Stage 2 */
volatile stage2_header_t *hdr = (volatile stage2_header_t *)DRAM_BOOT_BASE;
void (*stage2_entry)(void) = (void (*)(void))(DRAM_BOOT_BASE + hdr->entry_offset);
uart_puts(&console, "Jumping to Stage 2 at ");
uart_put_hex(&console, (uint32_t)stage2_entry);
uart_puts(&console, "\r\n\r\n");
uart_flush(&console);
__asm__ volatile(
"mov r0, #0\n"
"mcr p15, 0, r0, c7, c5, 0\n" /* Invalidate I-cache */
"mcr p15, 0, r0, c7, c6, 0\n" /* Invalidate D-cache */
"dsb\n"
"isb\n"
);
stage2_entry();
uart_puts(&console, "Stage 2 returned unexpectedly\r\n");
while(1);
}