Download firmware/boot/stage2.c from Snapkitty/phaser-ags: direct link, hf CLI and curl.
- Browser
- Download file 10.8 kB
-
https://huggingface.co/Snapkitty/phaser-ags/resolve/main/firmware/boot/stage2.c
- Command line
-
hf download hf://Snapkitty/phaser-ags/firmware/boot/stage2.c
-
curl -L -o stage2.c https://huggingface.co/Snapkitty/phaser-ags/resolve/main/firmware/boot/stage2.c
10.8 kB
| /* | |
| * ARM Cortex-A8 (OMAP3530) Stage 2 Bootloader | |
| * | |
| * Full firmware stack: MMU, Ethernet, SPI, MMC, shell | |
| * Integrates patterns from IMX6 Platinum and R8A7740: | |
| * - platinum_setup_enet(): PHY reset → pinmux → MDIO → link check | |
| * - platinum_setup_spi(): McSPI pinmux for FPGA config | |
| * - spl_dram_init(): MMU + cache enable after DRAM init | |
| * - do_go / do_reset: boot shell fallback | |
| */ | |
| /* ---- Console + peripherals ---- */ | |
| static uart_dev_t console; | |
| static timer_dev_t systimer; | |
| static gpio_dev_t gpio1; | |
| static eth_dev_t eth0; | |
| static mmc_dev_t mmc1; | |
| typedef struct { | |
| uint32_t magic; | |
| uint32_t size; | |
| uint32_t crc32; | |
| uint32_t entry_offset; | |
| } stage2_header_t; | |
| /* ---- MMU identity mapping (1MB sections, 4GB) ---- */ | |
| __attribute__((aligned(16384))) | |
| static uint32_t mmu_table[4096]; | |
| static void mmu_init(void) { | |
| for (int i = 0; i < 4096; i++) { | |
| uint32_t pa = (uint32_t)i << 20; | |
| if (pa >= 0x30000000UL && pa < 0x40000000UL) { | |
| mmu_table[i] = pa | 0x00001C0E; /* DRAM: WB, full access */ | |
| } else if (pa < 0x00020000UL) { | |
| mmu_table[i] = pa | 0x0000040E; /* SRAM: WT */ | |
| } else if ((pa >= 0x48000000UL && pa < 0x4A000000UL) || | |
| (pa >= 0x6C000000UL && pa < 0x70000000UL)) { | |
| mmu_table[i] = pa | 0x0000180E; /* Peripherals: device, XN */ | |
| } else { | |
| mmu_table[i] = pa | 0x0000000E; /* Strongly ordered */ | |
| } | |
| } | |
| __asm__ volatile( | |
| "mcr p15, 0, %0, c2, c0, 0\n" | |
| "mov r0, #0\n" | |
| "mcr p15, 0, r0, c2, c0, 2\n" | |
| "mov r0, #0\n" | |
| "mcr p15, 0, r0, c3, c0, 0\n" | |
| "mov r0, #0\n" | |
| "mcr p15, 0, r0, c8, c7, 0\n" | |
| "dsb\nisb\n" | |
| :: "r"(mmu_table) | |
| ); | |
| __asm__ volatile( | |
| "mrc p15, 0, r0, c1, c0, 0\n" | |
| "orr r0, r0, #(1 << 0)\n" | |
| "orr r0, r0, #(1 << 2)\n" | |
| "orr r0, r0, #(1 << 12)\n" | |
| "orr r0, r0, #(1 << 11)\n" | |
| "orr r0, r0, #(1 << 13)\n" | |
| "dsb\n" | |
| "mcr p15, 0, r0, c1, c0, 0\n" | |
| "isb\n" | |
| ); | |
| } | |
| /* ---- Ethernet setup — platinum_setup_enet() pattern ---- */ | |
| static int setup_ethernet(void) { | |
| uart_puts(&console, "Setting up Ethernet...\r\n"); | |
| if (eth_init(ð0, MDIO_BASE, EMAC_BASE, 0) != 0) { | |
| uart_puts(&console, "EMAC init failed\r\n"); | |
| return -1; | |
| } | |
| /* PHY reset via GPIO1[9] — mirrors IMX6 Platinum: | |
| 1. Assert PHY reset while pinmux is configured | |
| 2. Wait 10ms | |
| 3. Release reset | |
| 4. Wait 100µs for PHY startup */ | |
| eth_phy_reset(ð0, &gpio1, 9); | |
| if (eth_phy_config(ð0) != 0) { | |
| uart_puts(&console, "PHY config failed\r\n"); | |
| return -1; | |
| } | |
| /* Check link */ | |
| if (eth_link_check(ð0) > 0) { | |
| uart_puts(&console, "Ethernet: LINK UP at "); | |
| uart_put_hex(&console, eth0.link_speed); | |
| uart_puts(&console, "Mbps\r\n"); | |
| } else { | |
| uart_puts(&console, "Ethernet: no link\r\n"); | |
| } | |
| return 0; | |
| } | |
| /* ---- SPI setup — platinum_setup_spi() pattern ---- */ | |
| static spi_dev_t spi1; | |
| static int setup_spi(void) { | |
| uart_puts(&console, "Setting up McSPI1...\r\n"); | |
| /* Enable McSPI1 clock */ | |
| hw_reg32_t cm = (hw_reg32_t)CM_BASE; | |
| reg_set32(cm + CM_FCLKEN1_CORE, (1 << 18)); /* EN_MCSPI1 */ | |
| reg_set32(cm + CM_ICLKEN1_CORE, (1 << 18)); | |
| delay_cycles(500); | |
| if (spi_init(&spi1, MCSPI1_BASE, 0, REF_CLK_HZ, 1000000, SPI_MODE_0, 8) != 0) { | |
| uart_puts(&console, "McSPI1 init failed\r\n"); | |
| return -1; | |
| } | |
| uart_puts(&console, "McSPI1 ready (1MHz, mode 0)\r\n"); | |
| return 0; | |
| } | |
| /* ---- MMC setup — for SD card kernel boot ---- */ | |
| static int setup_mmc(void) { | |
| uart_puts(&console, "Setting up MMC1 (SD card)...\r\n"); | |
| /* Enable MMC1 clock */ | |
| hw_reg32_t cm = (hw_reg32_t)CM_BASE; | |
| reg_set32(cm + CM_FCLKEN1_CORE, (1 << 24)); /* EN_MMC1 */ | |
| reg_set32(cm + CM_ICLKEN1_CORE, (1 << 24)); | |
| delay_cycles(500); | |
| if (mmc_init(&mmc1, MMC1_BASE, REF_CLK_HZ) != 0) { | |
| uart_puts(&console, "MMC1 init failed\r\n"); | |
| return -1; | |
| } | |
| if (mmc_detect_card(&mmc1) != 0) { | |
| uart_puts(&console, "No SD card detected\r\n"); | |
| return -1; | |
| } | |
| uart_puts(&console, "SD card: RCA=0x"); | |
| uart_put_hex(&console, mmc1.rca); | |
| uart_puts(&console, " width="); | |
| uart_put_hex(&console, mmc1.bus_width); | |
| uart_puts(&console, " SDHC="); | |
| uart_puts(&console, mmc1.high_capacity ? "yes" : "no"); | |
| uart_puts(&console, "\r\n"); | |
| return 0; | |
| } | |
| /* ---- FPGA NCONFIG reset — IMX6 Platinum platinum_init_gpio() pattern ---- */ | |
| /* OMAP3530 version: 3 FPGAs on SPI bus, NCONFIG via GPIO */ | |
| static void fpga_init_gpio(void) { | |
| /* Configure NCONFIG pins as outputs — mirrors IMX6: | |
| gpio_direction_output(GPIO_IP_NCONFIG, 0) */ | |
| gpio_set_output(&gpio1, GPIO_FPGA1_NCONFIG); | |
| gpio_set_output(&gpio1, GPIO_FPGA2_NCONFIG); | |
| gpio_set_output(&gpio1, GPIO_FPGA3_NCONFIG); | |
| /* Assert NCONFIG low (reset all FPGAs) */ | |
| gpio_write(&gpio1, GPIO_FPGA1_NCONFIG, 0); | |
| gpio_write(&gpio1, GPIO_FPGA2_NCONFIG, 0); | |
| gpio_write(&gpio1, GPIO_FPGA3_NCONFIG, 0); | |
| /* Wait 3µs (IMX6 Platinum: udelay(3)) */ | |
| delay_cycles(CPU_CLK_HZ / 333333); /* ~3µs */ | |
| /* Release NCONFIG — FPGAs begin configuration from SPI */ | |
| gpio_write(&gpio1, GPIO_FPGA1_NCONFIG, 1); | |
| gpio_write(&gpio1, GPIO_FPGA2_NCONFIG, 1); | |
| gpio_write(&gpio1, GPIO_FPGA3_NCONFIG, 1); | |
| uart_puts(&console, "[FPGA] NCONFIG released — configuration via SPI\r\n"); | |
| } | |
| /* ---- Load kernel from MMC ---- */ | |
| typedef struct { | |
| uint32_t code[4]; | |
| uint32_t magic; | |
| uint32_t start; | |
| uint32_t end; | |
| } zimage_header_t; | |
| static int load_kernel_mmc(void) { | |
| /* Read MBR + kernel from SD card sectors to DRAM */ | |
| uint8_t *dst = (uint8_t *)DRAM_KERNEL_BASE; | |
| /* Kernel typically starts at sector 2048 (1MB offset, FAT boot partition) */ | |
| uart_puts(&console, "Loading kernel from MMC (sector 2048)...\r\n"); | |
| for (uint32_t sec = 0; sec < 8192; sec++) { | |
| if (mmc_read_block(&mmc1, 2048 + sec, dst + sec * MMC_BLOCK_SIZE) != 0) { | |
| uart_puts(&console, "MMC read error at sector "); | |
| uart_put_hex(&console, 2048 + sec); | |
| uart_puts(&console, "\r\n"); | |
| return -1; | |
| } | |
| } | |
| uart_puts(&console, "Loaded 4MB from MMC\r\n"); | |
| return 0; | |
| } | |
| /* ---- Load kernel from NAND ---- */ | |
| static int load_kernel_nand(void) { | |
| nand_dev_t nand; | |
| if (nand_init(&nand, 0) != 0) return -1; | |
| uint8_t page_buf[NAND_PAGE_SIZE]; | |
| uint8_t *dst = (uint8_t *)DRAM_KERNEL_BASE; | |
| uint32_t copied = 0; | |
| for (uint32_t block = 8; block < 64 && copied < DRAM_KERNEL_SIZE; block++) { | |
| if (nand_is_bad_block(&nand, block)) continue; | |
| for (uint32_t page = 0; page < nand.pages_per_block && copied < DRAM_KERNEL_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) return -1; | |
| for (uint32_t i = 0; i < nand.page_size && copied < DRAM_KERNEL_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 (copied > 0) ? 0 : -1; | |
| } | |
| /* ================================================================ */ | |
| void stage2_main(void) { | |
| /* 1. Console */ | |
| uart_init(&console, UART0_BASE, REF_CLK_HZ); | |
| uart_configure(&console, 115200, 8, 0, 1); | |
| uart_puts(&console, "\r\n=============================\r\n"); | |
| uart_puts(&console, " Phaser AGS Stage 2 Bootloader\r\n"); | |
| uart_puts(&console, "=============================\r\n"); | |
| /* 2. Timer */ | |
| timer_init(&systimer, GPTIMER2_BASE, REF_CLK_HZ); | |
| /* 3. MMU + caches (IMX6 SPL: spl_dram_init then enable caches) */ | |
| uart_puts(&console, "Enabling MMU and caches...\r\n"); | |
| mmu_init(); | |
| uart_puts(&console, "MMU + I$/D$ enabled\r\n"); | |
| /* 4. GPIO + status LED */ | |
| gpio_init(&gpio1, 1); | |
| gpio_set_output(&gpio1, 8); | |
| gpio_write(&gpio1, 8, 1); | |
| /* 5. Interrupt controller */ | |
| intc_init(); | |
| /* 6. SPI setup (platinum_setup_spi pattern) */ | |
| setup_spi(); | |
| /* 7. Ethernet setup (platinum_setup_enet pattern) */ | |
| setup_ethernet(); | |
| /* 8. MMC setup (for SD card boot) */ | |
| int mmc_ok = (setup_mmc() == 0); | |
| /* 9. FPGA init (platinum_init_gpio: NCONFIG reset) */ | |
| fpga_init_gpio(); | |
| /* 10. Load kernel */ | |
| volatile zimage_header_t *zimg = (volatile zimage_header_t *)DRAM_KERNEL_BASE; | |
| /* Try MMC first, then NAND */ | |
| int kernel_loaded = 0; | |
| if (mmc_ok && load_kernel_mmc() == 0) { | |
| kernel_loaded = 1; | |
| } else if (load_kernel_nand() == 0) { | |
| kernel_loaded = 1; | |
| } | |
| if (kernel_loaded && zimg->magic == ZIMAGE_MAGIC) { | |
| uint32_t ksize = zimg->end - zimg->start; | |
| uart_puts(&console, "Linux zImage: "); | |
| uart_put_hex(&console, ksize); | |
| uart_puts(&console, " bytes\r\n"); | |
| /* Blink LED 3× then boot */ | |
| for (int i = 0; i < 3; i++) { | |
| gpio_write(&gpio1, 8, 1); | |
| timer_delay_ms(&systimer, 50); | |
| gpio_write(&gpio1, 8, 0); | |
| timer_delay_ms(&systimer, 50); | |
| } | |
| uart_puts(&console, "Booting kernel at "); | |
| uart_put_hex(&console, DRAM_KERNEL_BASE); | |
| uart_puts(&console, "...\r\n"); | |
| uart_flush(&console); | |
| uint32_t machine_type = 0x862; | |
| uint32_t dtb_addr = 0x30000000; | |
| __asm__ volatile( | |
| "dsb\nisb\n" | |
| "mov r0, #0\n" | |
| "mov r1, %0\n" | |
| "mov r2, %1\n" | |
| "bx %2\n" | |
| : | |
| : "r"(machine_type), "r"(dtb_addr), "r"(DRAM_KERNEL_BASE) | |
| : "r0", "r1", "r2", "memory" | |
| ); | |
| } | |
| /* 11. No kernel found or boot failed — drop to shell (U-Boot do_go pattern) */ | |
| uart_puts(&console, "\r\nNo kernel loaded. Dropping to shell.\r\n"); | |
| uart_puts(&console, "Use 'go <addr>' to jump, or 'help' for commands.\r\n\r\n"); | |
| shell_run(&console); | |
| } | |