diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2021-07-06 21:02:37 +0100 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-07-08 16:01:38 +0000 |
commit | 0e1a90ea1da0c1737363e9412781f734f39048d4 (patch) | |
tree | bef444477385a5eb8e8766ec75391ba48d63c613 /firmware/target/mips/ingenic_x1000/spl-x1000.c | |
parent | 65aa9ce57067f810d6a8f9417ec7d0a5741b404a (diff) | |
download | rockbox-0e1a90ea1da0c1737363e9412781f734f39048d4.tar.gz rockbox-0e1a90ea1da0c1737363e9412781f734f39048d4.zip |
x1000: SPL refactoring
This streamlines the boot code a bit and reduces target specific
boilerplate. The clock init hack used by the bootloader has been
"standardized" and works for the main Rockbox binary now, so you
can boot rockbox.bin over USB without special hacks.
Change-Id: I7c1fac37df5a45873583ce6818eaedb9f71a782b
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/spl-x1000.c')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/spl-x1000.c | 360 |
1 files changed, 286 insertions, 74 deletions
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c index fd664e231d..284b963e97 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c | |||
@@ -19,41 +19,188 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "system.h" | ||
22 | #include "spl-x1000.h" | 23 | #include "spl-x1000.h" |
23 | #include "clk-x1000.h" | 24 | #include "clk-x1000.h" |
24 | #include "system.h" | 25 | #include "nand-x1000.h" |
26 | #include "gpio-x1000.h" | ||
27 | #include "boot-x1000.h" | ||
25 | #include "x1000/cpm.h" | 28 | #include "x1000/cpm.h" |
26 | #include "x1000/ost.h" | 29 | #include "x1000/ost.h" |
30 | #include "x1000/uart.h" | ||
27 | #include "x1000/ddrc.h" | 31 | #include "x1000/ddrc.h" |
28 | #include "x1000/ddrc_apb.h" | 32 | #include "x1000/ddrc_apb.h" |
29 | #include "x1000/ddrphy.h" | 33 | #include "x1000/ddrphy.h" |
34 | #include "ucl_decompress.h" | ||
35 | #include <string.h> | ||
30 | 36 | ||
31 | #ifdef FIIO_M3K | 37 | #ifdef FIIO_M3K |
32 | # define SPL_DDR_MEMORYSIZE 64 | 38 | # define SPL_DDR_MEMORYSIZE 64 |
33 | # define SPL_DDR_AUTOSR_EN 1 | 39 | # define SPL_DDR_AUTOSR_EN 1 |
34 | # define SPL_DDR_NEED_BYPASS 1 | 40 | # define SPL_DDR_NEED_BYPASS 1 |
35 | #else | 41 | #else |
36 | # error "please add SPL memory definitions" | 42 | # error "please define DRAM settings" |
37 | #endif | 43 | #endif |
38 | 44 | ||
39 | /* Note: This is based purely on disassembly of the SPL from the FiiO M3K. | 45 | static void* heap = (void*)(X1000_SDRAM_BASE + X1000_SDRAM_SIZE); |
40 | * The code there is somewhat generic and corresponds roughly to Ingenic's | 46 | static nand_drv* ndrv = NULL; |
41 | * U-Boot code, but isn't entirely the same. | 47 | |
48 | void* spl_alloc(size_t count) | ||
49 | { | ||
50 | heap -= CACHEALIGN_UP(count); | ||
51 | memset(heap, 0, CACHEALIGN_UP(count)); | ||
52 | return heap; | ||
53 | } | ||
54 | |||
55 | int spl_storage_open(void) | ||
56 | { | ||
57 | /* We need to assign the GPIOs manually */ | ||
58 | gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)); | ||
59 | |||
60 | /* Allocate NAND driver manually in DRAM */ | ||
61 | ndrv = spl_alloc(sizeof(nand_drv)); | ||
62 | ndrv->page_buf = spl_alloc(NAND_DRV_MAXPAGESIZE); | ||
63 | ndrv->scratch_buf = spl_alloc(NAND_DRV_SCRATCHSIZE); | ||
64 | ndrv->refcount = 0; | ||
65 | |||
66 | return nand_open(ndrv); | ||
67 | } | ||
68 | |||
69 | void spl_storage_close(void) | ||
70 | { | ||
71 | nand_close(ndrv); | ||
72 | } | ||
73 | |||
74 | int spl_storage_read(uint32_t addr, uint32_t length, void* buffer) | ||
75 | { | ||
76 | return nand_read_bytes(ndrv, addr, length, buffer); | ||
77 | } | ||
78 | |||
79 | /* Used by: | ||
80 | * - FiiO M3K | ||
81 | * - Shanling Q1 | ||
42 | * | 82 | * |
43 | * I converted all the runtime conditionals to compile-time ones in order to | 83 | * Amend it and add #ifdefs for other targets if needed. |
44 | * save code space, since they should be constant for any given target. | 84 | */ |
85 | void spl_dualboot_init_clocktree(void) | ||
86 | { | ||
87 | /* Make sure these are gated to match the OF behavior. */ | ||
88 | jz_writef(CPM_CLKGR, PCM(1), MAC(1), LCD(1), MSC0(1), MSC1(1), OTG(1), CIM(1)); | ||
89 | |||
90 | /* Set clock sources, and make sure every clock starts out stopped */ | ||
91 | jz_writef(CPM_I2SCDR, CS_V(EXCLK)); | ||
92 | jz_writef(CPM_PCMCDR, CS_V(EXCLK)); | ||
93 | |||
94 | jz_writef(CPM_MACCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
95 | while(jz_readf(CPM_MACCDR, BUSY)); | ||
96 | |||
97 | jz_writef(CPM_LPCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
98 | while(jz_readf(CPM_LPCDR, BUSY)); | ||
99 | |||
100 | jz_writef(CPM_MSC0CDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
101 | while(jz_readf(CPM_MSC0CDR, BUSY)); | ||
102 | |||
103 | jz_writef(CPM_MSC1CDR, CE(1), STOP(1), CLKDIV(0xfe)); | ||
104 | while(jz_readf(CPM_MSC1CDR, BUSY)); | ||
105 | |||
106 | jz_writef(CPM_CIMCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
107 | while(jz_readf(CPM_CIMCDR, BUSY)); | ||
108 | |||
109 | jz_writef(CPM_USBCDR, CLKSRC_V(EXCLK), CE(1), STOP(1)); | ||
110 | while(jz_readf(CPM_USBCDR, BUSY)); | ||
111 | } | ||
112 | |||
113 | void spl_dualboot_init_uart2(void) | ||
114 | { | ||
115 | /* Ungate the clock and select UART2 device function */ | ||
116 | jz_writef(CPM_CLKGR, UART2(0)); | ||
117 | gpioz_configure(GPIO_C, 3 << 30, GPIOF_DEVICE(1)); | ||
118 | |||
119 | /* Disable all interrupts */ | ||
120 | jz_write(UART_UIER(2), 0); | ||
121 | |||
122 | /* FIFO configuration */ | ||
123 | jz_overwritef(UART_UFCR(2), | ||
124 | RDTR(3), /* FIFO trigger level = 60? */ | ||
125 | UME(0), /* UART module disable */ | ||
126 | DME(1), /* DMA mode enable? */ | ||
127 | TFRT(1), /* transmit FIFO reset */ | ||
128 | RFRT(1), /* receive FIFO reset */ | ||
129 | FME(1)); /* FIFO mode enable */ | ||
130 | |||
131 | /* IR mode configuration */ | ||
132 | jz_overwritef(UART_ISR(2), | ||
133 | RDPL(1), /* Zero is negative pulse for receive */ | ||
134 | TDPL(1), /* ... and for transmit */ | ||
135 | XMODE(1), /* Pulse width 1.6us */ | ||
136 | RCVEIR(0), /* Disable IR for recieve */ | ||
137 | XMITIR(0)); /* ... and for transmit */ | ||
138 | |||
139 | /* Line configuration */ | ||
140 | jz_overwritef(UART_ULCR(2), DLAB(0), | ||
141 | WLS_V(8BITS), /* 8 bit words */ | ||
142 | SBLS_V(1_STOP_BIT), /* 1 stop bit */ | ||
143 | PARE(0), /* no parity */ | ||
144 | SBK(0)); /* don't set break */ | ||
145 | |||
146 | /* Set the baud rate... not too sure how this works. (Docs unclear!) */ | ||
147 | const unsigned divisor = 0x0004; | ||
148 | jz_writef(UART_ULCR(2), DLAB(1)); | ||
149 | jz_write(UART_UDLHR(2), (divisor >> 8) & 0xff); | ||
150 | jz_write(UART_UDLLR(2), divisor & 0xff); | ||
151 | jz_write(UART_UMR(2), 16); | ||
152 | jz_write(UART_UACR(2), 0); | ||
153 | jz_writef(UART_ULCR(2), DLAB(0)); | ||
154 | |||
155 | /* Enable UART */ | ||
156 | jz_overwritef(UART_UFCR(2), | ||
157 | RDTR(0), /* FIFO trigger level = 1 */ | ||
158 | DME(0), /* DMA mode disable */ | ||
159 | UME(1), /* UART module enable */ | ||
160 | TFRT(1), /* transmit FIFO reset */ | ||
161 | RFRT(1), /* receive FIFO reset */ | ||
162 | FME(1)); /* FIFO mode enable */ | ||
163 | } | ||
164 | |||
165 | static void init_ost(void) | ||
166 | { | ||
167 | /* NOTE: the prescaler needs to be the same as in system-x1000.c */ | ||
168 | jz_writef(CPM_CLKGR, OST(0)); | ||
169 | jz_writef(OST_CTRL, PRESCALE2_V(BY_4)); | ||
170 | jz_overwritef(OST_CLEAR, OST2(1)); | ||
171 | jz_write(OST_2CNTH, 0); | ||
172 | jz_write(OST_2CNTL, 0); | ||
173 | jz_setf(OST_ENABLE, OST2); | ||
174 | } | ||
175 | |||
176 | /* NOTE: This is originally based on disassembly of the FiiO M3K SPL, which | ||
177 | * is in fact the GPL'd Ingenic X-Loader SPL. Similar stuff can be found in | ||
178 | * Ingenic's U-boot code. | ||
179 | * | ||
180 | * The source code for the Ingenic X-Loader SPL can be found in these repos: | ||
181 | * - https://github.com/JaminCheung/x-loader | ||
182 | * - https://github.com/YuanhuanLiang/X1000 | ||
183 | * | ||
184 | * Runtime conditionals based on the SoC type, looked up by OTP bits in EFUSE, | ||
185 | * are converted to compile-time conditionals here, as they are constant for a | ||
186 | * given target and there is no point in wasting precious space on dead code. | ||
45 | * | 187 | * |
46 | * I haven't bothered to decode all the register fields. Some of the values | 188 | * I didn't decode the register fields; note that some values are documented as |
47 | * written are going to bits documented as "Reserved" by Ingenic, but their | 189 | * "reserved" in the X1000 PM. The X-Loader source might shed more light on it; |
48 | * documentation doesn't seem completely reliable, so either these are bits | 190 | * it's likely these bits have meaning only on other Ingenic SoCs. |
49 | * which _do_ have a purpose, or they're only defined on other Ingenic CPUs. | ||
50 | * | 191 | * |
51 | * The DDR PHY registers appear to be from Synopsys "PHY Utility Block Lite". | 192 | * The DDR PHY registers match Synopsys's "PHY Utility Block Lite." The names |
52 | * These aren't documented by Ingenic, but the addresses and names can be found | 193 | * of those registers & their fields can also be found in the X-Loader code, |
53 | * in their U-Boot code. | 194 | * but they're not documented by Ingenic. |
54 | */ | 195 | */ |
55 | static void ddr_init(void) | 196 | static int init_dram(void) |
56 | { | 197 | { |
198 | #if SPL_DDR_MEMORYSIZE != 64 && SPL_DDR_MEMORYSIZE != 32 | ||
199 | # error "bad memory size" | ||
200 | #endif | ||
201 | |||
202 | jz_writef(CPM_CLKGR, DDR(0)); | ||
203 | |||
57 | REG_CPM_DRCG = 0x73; | 204 | REG_CPM_DRCG = 0x73; |
58 | mdelay(3); | 205 | mdelay(3); |
59 | REG_CPM_DRCG = 0x71; | 206 | REG_CPM_DRCG = 0x71; |
@@ -67,7 +214,11 @@ static void ddr_init(void) | |||
67 | REG_DDRC_CTRL = 0; | 214 | REG_DDRC_CTRL = 0; |
68 | mdelay(3); | 215 | mdelay(3); |
69 | 216 | ||
217 | #if SPL_DDR_MEMORYSIZE == 64 | ||
70 | REG_DDRC_CFG = 0xa468a6c; | 218 | REG_DDRC_CFG = 0xa468a6c; |
219 | #elif SPL_DDR_MEMORYSIZE == 32 | ||
220 | REG_DDRC_CFG = 0xa46896c; | ||
221 | #endif | ||
71 | REG_DDRC_CTRL = 2; | 222 | REG_DDRC_CTRL = 2; |
72 | REG_DDRPHY_DTAR = 0x150000; | 223 | REG_DDRPHY_DTAR = 0x150000; |
73 | REG_DDRPHY_DCR = 0; | 224 | REG_DDRPHY_DCR = 0; |
@@ -91,7 +242,7 @@ static void ddr_init(void) | |||
91 | while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f) | 242 | while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f) |
92 | i -= 1; | 243 | i -= 1; |
93 | if(i == 0) | 244 | if(i == 0) |
94 | spl_error(); | 245 | return 1; |
95 | 246 | ||
96 | #if SPL_DDR_NEED_BYPASS | 247 | #if SPL_DDR_NEED_BYPASS |
97 | REG_DDRPHY_ACDLLCR = 0x80000000; | 248 | REG_DDRPHY_ACDLLCR = 0x80000000; |
@@ -105,14 +256,18 @@ static void ddr_init(void) | |||
105 | while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f) | 256 | while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f) |
106 | i -= 1; | 257 | i -= 1; |
107 | if(i == 0) | 258 | if(i == 0) |
108 | spl_error(); | 259 | return 2; |
109 | 260 | ||
110 | REG_DDRC_APB_PHYRST_CFG = 0x400000; | 261 | REG_DDRC_APB_PHYRST_CFG = 0x400000; |
111 | mdelay(3); | 262 | mdelay(3); |
112 | REG_DDRC_APB_PHYRST_CFG = 0; | 263 | REG_DDRC_APB_PHYRST_CFG = 0; |
113 | mdelay(3); | 264 | mdelay(3); |
114 | 265 | ||
266 | #if SPL_DDR_MEMORYSIZE == 64 | ||
115 | REG_DDRC_CFG = 0xa468aec; | 267 | REG_DDRC_CFG = 0xa468aec; |
268 | #elif SPL_DDR_MEMORYSIZE == 32 | ||
269 | REG_DDRC_CFG = 0xa4689ec; | ||
270 | #endif | ||
116 | REG_DDRC_CTRL = 2; | 271 | REG_DDRC_CTRL = 2; |
117 | #if SPL_DDR_NEED_BYPASS | 272 | #if SPL_DDR_NEED_BYPASS |
118 | REG_DDRPHY_PIR = 0x20020081; | 273 | REG_DDRPHY_PIR = 0x20020081; |
@@ -128,15 +283,19 @@ static void ddr_init(void) | |||
128 | } | 283 | } |
129 | 284 | ||
130 | if(i == 0) | 285 | if(i == 0) |
131 | spl_error(); | 286 | return 3; |
132 | 287 | ||
133 | if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0) | 288 | if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0) |
134 | spl_error(); | 289 | return 4; |
135 | 290 | ||
136 | REG_DDRC_CTRL = 0; | 291 | REG_DDRC_CTRL = 0; |
137 | REG_DDRC_CTRL = 10; | 292 | REG_DDRC_CTRL = 10; |
138 | REG_DDRC_CTRL = 0; | 293 | REG_DDRC_CTRL = 0; |
294 | #if SPL_DDR_MEMORYSIZE == 64 | ||
139 | REG_DDRC_CFG = 0xa468a6c; | 295 | REG_DDRC_CFG = 0xa468a6c; |
296 | #elif SPL_DDR_MEMORYSIZE == 32 | ||
297 | REG_DDRC_CFG = 0xa46896c; | ||
298 | #endif | ||
140 | REG_DDRC_TIMING1 = 0x2050501; | 299 | REG_DDRC_TIMING1 = 0x2050501; |
141 | REG_DDRC_TIMING2 = 0x4090404; | 300 | REG_DDRC_TIMING2 = 0x4090404; |
142 | REG_DDRC_TIMING3 = 0x2704030d; | 301 | REG_DDRC_TIMING3 = 0x2704030d; |
@@ -149,11 +308,9 @@ static void ddr_init(void) | |||
149 | #elif SPL_DDR_MEMORYSIZE == 32 | 308 | #elif SPL_DDR_MEMORYSIZE == 32 |
150 | REG_DDRC_MMAP0 = 0x20fe; | 309 | REG_DDRC_MMAP0 = 0x20fe; |
151 | REG_DDRC_MMAP1 = 0x2200; | 310 | REG_DDRC_MMAP1 = 0x2200; |
152 | #else | ||
153 | # error "Unsupported DDR_MEMORYSIZE" | ||
154 | #endif | 311 | #endif |
155 | REG_DDRC_CTRL = 10; | 312 | REG_DDRC_CTRL = 10; |
156 | REG_DDRC_REFCNT = 0x2f0003; | 313 | REG_DDRC_REFCNT = 0x2f0003; /* is this adjustable for 32M? */ |
157 | REG_DDRC_CTRL = 0xc91e; | 314 | REG_DDRC_CTRL = 0xc91e; |
158 | 315 | ||
159 | #if SPL_DDR_MEMORYSIZE == 64 | 316 | #if SPL_DDR_MEMORYSIZE == 64 |
@@ -168,8 +325,6 @@ static void ddr_init(void) | |||
168 | REG_DDRC_REMAP3 = 0x01000908; | 325 | REG_DDRC_REMAP3 = 0x01000908; |
169 | REG_DDRC_REMAP4 = 0x0f0e0d0c; | 326 | REG_DDRC_REMAP4 = 0x0f0e0d0c; |
170 | REG_DDRC_REMAP5 = 0x13121110; | 327 | REG_DDRC_REMAP5 = 0x13121110; |
171 | #else | ||
172 | # error "Unsupported DDR_MEMORYSIZE" | ||
173 | #endif | 328 | #endif |
174 | 329 | ||
175 | REG_DDRC_STATUS &= ~0x40; | 330 | REG_DDRC_STATUS &= ~0x40; |
@@ -184,69 +339,126 @@ static void ddr_init(void) | |||
184 | #endif | 339 | #endif |
185 | 340 | ||
186 | REG_DDRC_AUTOSR_EN = SPL_DDR_AUTOSR_EN; | 341 | REG_DDRC_AUTOSR_EN = SPL_DDR_AUTOSR_EN; |
342 | return 0; | ||
187 | } | 343 | } |
188 | 344 | ||
189 | static void init(void) | 345 | static void* get_load_buffer(const struct spl_boot_option* opt) |
190 | { | 346 | { |
191 | /* from original firmware SPL */ | 347 | /* read to a temporary location if we need to decompress, |
348 | * otherwise simply read directly to the load address. */ | ||
349 | if(opt->flags & BOOTFLAG_UCLPACK) | ||
350 | return spl_alloc(opt->storage_size); | ||
351 | else | ||
352 | return (void*)opt->load_addr; | ||
353 | } | ||
354 | |||
355 | /* Mapping of boot_sel[1:0] pins. | ||
356 | * See X1000 PM pg. 687, "XBurst Boot ROM Specification" */ | ||
357 | enum { | ||
358 | BSEL_MSC = 1, | ||
359 | BSEL_USB = 2, | ||
360 | BSEL_SFC = 3, | ||
361 | }; | ||
362 | |||
363 | static uint32_t get_boot_sel(void) | ||
364 | { | ||
365 | /* This variable holds the level of the boot_sel[2:0] pins at boot time, | ||
366 | * and is defined by the maskrom. | ||
367 | * | ||
368 | * We use it to detect when we're USB booting, but this isn't totally | ||
369 | * accurate because it only reflects the selected boot mode at reset and | ||
370 | * not the current mode -- if the original selection fails and we fall | ||
371 | * back to USB, this variable will only return the original selection. | ||
372 | */ | ||
373 | return (*(uint32_t*)0xf40001ec) & 3; | ||
374 | } | ||
375 | |||
376 | typedef void(*entry_fn)(int, char**, int, int) __attribute__((noreturn)); | ||
377 | |||
378 | void spl_main(void) | ||
379 | { | ||
380 | int rc, boot_option; | ||
381 | const struct spl_boot_option* opt; | ||
382 | void* load_buffer; | ||
383 | char** kargv = NULL; | ||
384 | int kargc = 0; | ||
385 | |||
386 | /* magic */ | ||
192 | REG_CPM_PSWC0ST = 0x00; | 387 | REG_CPM_PSWC0ST = 0x00; |
193 | REG_CPM_PSWC1ST = 0x10; | 388 | REG_CPM_PSWC1ST = 0x10; |
194 | REG_CPM_PSWC2ST = 0x18; | 389 | REG_CPM_PSWC2ST = 0x18; |
195 | REG_CPM_PSWC3ST = 0x08; | 390 | REG_CPM_PSWC3ST = 0x08; |
196 | 391 | ||
197 | /* enable MPLL */ | 392 | /* set up boot flags */ |
198 | #if X1000_EXCLK_FREQ == 24000000 | 393 | init_boot_flags(); |
199 | /* 24 * (24+1) = 600 MHz */ | 394 | set_boot_option(BOOT_OPTION_ROCKBOX); |
200 | jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(24), PLLOD(0)); | ||
201 | #elif X1000_EXCLK_FREQ == 26000000 | ||
202 | /* 26 * (22+1) = 598 MHz */ | ||
203 | jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(22), PLLOD(0)); | ||
204 | #else | ||
205 | # error "unknown EXCLK frequency" | ||
206 | #endif | ||
207 | while(jz_readf(CPM_MPCR, ON) == 0); | ||
208 | 395 | ||
209 | /* set DDR clock to MPLL/3 = 200 MHz */ | 396 | /* early clock and DRAM init */ |
210 | jz_writef(CPM_CLKGR, DDR(0)); | 397 | clk_init_early(); |
211 | clk_set_ddr(X1000_CLK_MPLL, 3); | 398 | init_ost(); |
399 | if(init_dram() != 0) | ||
400 | spl_error(); | ||
212 | 401 | ||
213 | /* start OST so we can use mdelay/udelay */ | 402 | /* USB boot stops here */ |
214 | jz_writef(CPM_CLKGR, OST(0)); | 403 | if(get_boot_sel() == BSEL_USB) { |
215 | jz_writef(OST_CTRL, PRESCALE2_V(BY_4)); | 404 | set_boot_flag(BOOT_FLAG_USB_BOOT); |
216 | jz_writef(OST_CLEAR, OST2(1)); | 405 | return; |
217 | jz_write(OST_2CNTH, 0); | 406 | } |
218 | jz_write(OST_2CNTL, 0); | ||
219 | jz_setf(OST_ENABLE, OST2); | ||
220 | 407 | ||
221 | /* init DDR memory */ | 408 | /* find out what we should boot */ |
222 | ddr_init(); | 409 | boot_option = spl_get_boot_option(); |
223 | } | 410 | opt = &spl_boot_options[boot_option]; |
411 | load_buffer = get_load_buffer(opt); | ||
224 | 412 | ||
225 | /* This variable is defined by the maskrom. It's simply the level of the | 413 | /* save the selection for later */ |
226 | * boot_sel[2:0] pins (GPIOs B28-30) at boot time. Meaning of the bits: | 414 | set_boot_option(boot_option); |
227 | * | ||
228 | * boot_sel[2] boot_sel[1] boot_sel[0] Description | ||
229 | * ----------------------------------------------------------------- | ||
230 | * 1 X X EXCLK is 26 MHz | ||
231 | * 0 X X EXCLK is 24 MHz | ||
232 | * X 1 1 Boot from SFC0 | ||
233 | * X 0 1 Boot from MSC0 | ||
234 | * X 1 0 Boot from USB 2.0 device | ||
235 | * ----------------------------------------------------------------- | ||
236 | * Source: X1000 PM pg. 687, "XBurst Boot ROM Specification" | ||
237 | */ | ||
238 | extern const uint32_t boot_sel; | ||
239 | 415 | ||
240 | void spl_main(void) | 416 | /* finish up clock init */ |
241 | { | 417 | clk_init(); |
242 | /* Basic hardware init */ | ||
243 | init(); | ||
244 | 418 | ||
245 | /* If doing a USB boot, host PC will upload 2nd stage itself, | 419 | /* load the image from storage */ |
246 | * we should not load anything from flash or change clocks. */ | 420 | rc = spl_storage_open(); |
247 | if((boot_sel & 3) == 2) | 421 | if(rc != 0) |
248 | return; | 422 | spl_error(); |
423 | |||
424 | rc = spl_storage_read(opt->storage_addr, opt->storage_size, load_buffer); | ||
425 | if(rc != 0) | ||
426 | spl_error(); | ||
427 | |||
428 | /* handle compression */ | ||
429 | switch(opt->flags & BOOTFLAG_COMPRESSED) { | ||
430 | case BOOTFLAG_UCLPACK: { | ||
431 | uint32_t out_size = X1000_DRAM_END - opt->load_addr; | ||
432 | rc = ucl_unpack((uint8_t*)load_buffer, opt->storage_size, | ||
433 | (uint8_t*)opt->load_addr, &out_size); | ||
434 | } break; | ||
435 | |||
436 | default: | ||
437 | break; | ||
438 | } | ||
439 | |||
440 | if(rc != 0) | ||
441 | spl_error(); | ||
442 | |||
443 | /* call the setup hook */ | ||
444 | if(opt->setup) { | ||
445 | rc = opt->setup(); | ||
446 | if(rc != 0) | ||
447 | spl_error(); | ||
448 | } | ||
449 | |||
450 | /* close off storage access */ | ||
451 | spl_storage_close(); | ||
452 | |||
453 | /* handle kernel command line, if specified */ | ||
454 | if(opt->cmdline) { | ||
455 | kargv = (char**)opt->cmdline_addr; | ||
456 | kargv[kargc++] = 0; | ||
457 | kargv[kargc++] = (char*)opt->cmdline; | ||
458 | } | ||
249 | 459 | ||
250 | /* Just pass control to the target... */ | 460 | /* jump to the entry point */ |
251 | spl_target_boot(); | 461 | entry_fn fn = (entry_fn)opt->exec_addr; |
462 | commit_discard_idcache(); | ||
463 | fn(kargc, kargv, 0, 0); | ||
252 | } | 464 | } |