diff options
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/spl-x1000.c')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/spl-x1000.c | 141 |
1 files changed, 63 insertions, 78 deletions
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c index 6505cabbef..07453f6182 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c | |||
@@ -20,7 +20,6 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "spl-x1000.h" | 22 | #include "spl-x1000.h" |
23 | #include "spl-target.h" | ||
24 | #include "clk-x1000.h" | 23 | #include "clk-x1000.h" |
25 | #include "nand-x1000.h" | 24 | #include "nand-x1000.h" |
26 | #include "system.h" | 25 | #include "system.h" |
@@ -29,16 +28,15 @@ | |||
29 | #include "x1000/ddrc.h" | 28 | #include "x1000/ddrc.h" |
30 | #include "x1000/ddrc_apb.h" | 29 | #include "x1000/ddrc_apb.h" |
31 | #include "x1000/ddrphy.h" | 30 | #include "x1000/ddrphy.h" |
31 | #include "ucl_decompress.h" | ||
32 | 32 | ||
33 | struct x1000_spl_arguments* const spl_arguments = | 33 | #ifdef FIIO_M3K |
34 | (struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS; | 34 | # define SPL_DDR_MEMORYSIZE 64 |
35 | 35 | # define SPL_DDR_AUTOSR_EN 1 | |
36 | struct x1000_spl_status* const spl_status = | 36 | # define SPL_DDR_NEED_BYPASS 1 |
37 | (struct x1000_spl_status*)SPL_STATUS_ADDRESS; | 37 | #else |
38 | 38 | # error "please add SPL memory definitions" | |
39 | /* defined to be Linux compatible; Rockbox needs no arguments so there | 39 | #endif |
40 | * is no harm in passing them and we save a little code size */ | ||
41 | typedef void(*entry_fn)(int, char**, int, int); | ||
42 | 40 | ||
43 | /* Note: This is based purely on disassembly of the SPL from the FiiO M3K. | 41 | /* Note: This is based purely on disassembly of the SPL from the FiiO M3K. |
44 | * The code there is somewhat generic and corresponds roughly to Ingenic's | 42 | * The code there is somewhat generic and corresponds roughly to Ingenic's |
@@ -243,83 +241,70 @@ static int nandread(uint32_t addr, uint32_t size, void* buffer) | |||
243 | return rc; | 241 | return rc; |
244 | } | 242 | } |
245 | 243 | ||
246 | static int nandwrite(uint32_t addr, uint32_t size, const void* buffer) | 244 | /* Entry point function type, defined to be Linux compatible. */ |
247 | { | 245 | typedef void(*entry_fn)(int, char**, int, int); |
248 | int rc; | ||
249 | int mf_id, dev_id; | ||
250 | 246 | ||
251 | if((rc = nand_open())) | 247 | /* Kernel command line arguments */ |
252 | return rc; | 248 | static char* argv[2]; |
253 | if((rc = nand_identify(&mf_id, &dev_id))) { | ||
254 | nand_close(); | ||
255 | return rc; | ||
256 | } | ||
257 | 249 | ||
258 | if((rc = nand_enable_writes(true))) | 250 | /* This variable is defined by the maskrom. It's simply the level of the |
259 | goto _end; | 251 | * boot_sel[2:0] pins (GPIOs B28-30) at boot time. Meaning of the bits: |
252 | * | ||
253 | * boot_sel[2] boot_sel[1] boot_sel[0] Description | ||
254 | * ----------------------------------------------------------------- | ||
255 | * 1 X X EXCLK is 26 MHz | ||
256 | * 0 X X EXCLK is 24 MHz | ||
257 | * X 1 1 Boot from SFC0 | ||
258 | * X 0 1 Boot from MSC0 | ||
259 | * X 1 0 Boot from USB 2.0 device | ||
260 | * ----------------------------------------------------------------- | ||
261 | * Source: X1000 PM pg. 687, "XBurst Boot ROM Specification" | ||
262 | */ | ||
263 | extern const uint32_t boot_sel; | ||
260 | 264 | ||
261 | if((rc = nand_erase(addr, size))) | 265 | void spl_main(void) |
262 | goto _end1; | 266 | { |
267 | int opt_index; | ||
268 | uint8_t* load_addr; | ||
269 | const struct spl_boot_option* opt; | ||
263 | 270 | ||
264 | rc = nand_write(addr, size, (const uint8_t*)buffer); | 271 | /* Basic hardware init */ |
272 | init(); | ||
265 | 273 | ||
266 | _end1: | 274 | /* If doing a USB boot, host PC will upload 2nd stage itself, |
267 | /* an error here is very unlikely, so ignore it */ | 275 | * we should not load anything from flash or change clocks. */ |
268 | nand_enable_writes(false); | 276 | if((boot_sel & 3) == 2) |
277 | return; | ||
269 | 278 | ||
270 | _end: | 279 | /* Get the boot option */ |
271 | nand_close(); | 280 | opt_index = spl_get_boot_option(); |
272 | return rc; | 281 | opt = &spl_boot_options[opt_index]; |
273 | } | 282 | load_addr = (uint8_t*)opt->load_addr; |
274 | 283 | ||
275 | /* Kernel command line arguments */ | 284 | /* Set up hardware, load stuff from flash */ |
276 | static char* argv[2]; | 285 | spl_handle_pre_boot(opt_index); |
286 | if(nandread(opt->nand_addr, opt->nand_size, load_addr)) | ||
287 | spl_error(); | ||
277 | 288 | ||
278 | void main(void) | 289 | if(!opt->cmdline) { |
279 | { | 290 | /* No command line => we are booting Rockbox, decompress bootloader. |
280 | if(!(SPL_ARGUMENTS->flags & SPL_FLAG_SKIP_INIT)) | 291 | * In the case of Rockbox, load binary directly to exec address */ |
281 | init(); | 292 | uint32_t out_size = X1000_DRAM_END - opt->exec_addr; |
282 | 293 | int rc = ucl_unpack(load_addr, opt->nand_size, | |
283 | switch(SPL_ARGUMENTS->command) { | 294 | (uint8_t*)opt->exec_addr, &out_size); |
284 | case SPL_CMD_BOOT: { | 295 | if(rc != UCL_E_OK) |
285 | int option = SPL_ARGUMENTS->param1; | ||
286 | if(option == SPL_BOOTOPT_CHOOSE) | ||
287 | option = spl_get_boot_option(); | ||
288 | if(option == SPL_BOOTOPT_NONE) | ||
289 | return; | ||
290 | |||
291 | const struct spl_boot_option* opt = &spl_boot_options[option-1]; | ||
292 | if(nandread(opt->nand_addr, opt->nand_size, (void*)opt->load_addr)) | ||
293 | spl_error(); | 296 | spl_error(); |
294 | |||
295 | /* Let target handle necessary pre-boot setup */ | ||
296 | spl_handle_pre_boot(option); | ||
297 | |||
298 | /* Reading the Linux command line from the bootloader is handled by | ||
299 | * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. | ||
300 | * | ||
301 | * Rockbox doesn't use arguments, but passing them does not hurt and it | ||
302 | * saves an unnecessary branch. | ||
303 | */ | ||
304 | entry_fn entry = (entry_fn)opt->exec_addr; | ||
305 | argv[0] = 0; | ||
306 | argv[1] = (char*)opt->cmdline; | ||
307 | |||
308 | commit_discard_idcache(); | ||
309 | entry(2, argv, 0, 0); | ||
310 | __builtin_unreachable(); | ||
311 | } | 297 | } |
312 | 298 | ||
313 | case SPL_CMD_FLASH_READ: | 299 | /* Reading the Linux command line from the bootloader is handled by |
314 | SPL_STATUS->err_code = nandread(SPL_ARGUMENTS->param1, | 300 | * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. It's |
315 | SPL_ARGUMENTS->param2, | 301 | * simply an (int argc, char* argv[]) thing. |
316 | (void*)SPL_BUFFER_ADDRESS); | 302 | */ |
317 | return; | 303 | entry_fn entry = (entry_fn)opt->exec_addr; |
318 | 304 | argv[0] = 0; | |
319 | case SPL_CMD_FLASH_WRITE: | 305 | argv[1] = (char*)opt->cmdline; |
320 | SPL_STATUS->err_code = nandwrite(SPL_ARGUMENTS->param1, | 306 | |
321 | SPL_ARGUMENTS->param2, | 307 | commit_discard_idcache(); |
322 | (const void*)SPL_BUFFER_ADDRESS); | 308 | entry(2, argv, 0, 0); |
323 | return; | 309 | __builtin_unreachable(); |
324 | } | ||
325 | } | 310 | } |