diff options
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 | } |