diff options
Diffstat (limited to 'firmware/target/mips')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c | 148 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/spl-x1000.c | 62 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/spl-x1000.h | 16 |
3 files changed, 148 insertions, 78 deletions
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c index 85ce4da8f6..7c56e4ac19 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c | |||
@@ -19,11 +19,15 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "system.h" | ||
23 | #include "ucl_decompress.h" | ||
22 | #include "spl-x1000.h" | 24 | #include "spl-x1000.h" |
23 | #include "gpio-x1000.h" | 25 | #include "gpio-x1000.h" |
24 | #include "clk-x1000.h" | 26 | #include "clk-x1000.h" |
25 | #include "system.h" | 27 | #include "nand-x1000.h" |
28 | #include "x1000/cpm.h" | ||
26 | #include <string.h> | 29 | #include <string.h> |
30 | #include <stdint.h> | ||
27 | 31 | ||
28 | /* Available boot options */ | 32 | /* Available boot options */ |
29 | #define BOOTOPTION_ROCKBOX 0 | 33 | #define BOOTOPTION_ROCKBOX 0 |
@@ -54,6 +58,17 @@ static const char recovery_cmdline[] = "mem=64M@0x0\ | |||
54 | lpj=5009408\ | 58 | lpj=5009408\ |
55 | ip=off"; | 59 | ip=off"; |
56 | 60 | ||
61 | /* Entry point function type, defined to be Linux compatible. */ | ||
62 | typedef void(*entry_fn)(int, char**, int, int); | ||
63 | |||
64 | struct spl_boot_option { | ||
65 | uint32_t nand_addr; | ||
66 | uint32_t nand_size; | ||
67 | uint32_t load_addr; | ||
68 | uint32_t exec_addr; | ||
69 | const char* cmdline; /* for Linux */ | ||
70 | }; | ||
71 | |||
57 | const struct spl_boot_option spl_boot_options[] = { | 72 | const struct spl_boot_option spl_boot_options[] = { |
58 | { | 73 | { |
59 | /* Rockbox: the first unused NAND page is 26 KiB in, and the | 74 | /* Rockbox: the first unused NAND page is 26 KiB in, and the |
@@ -104,6 +119,75 @@ void spl_error(void) | |||
104 | } | 119 | } |
105 | } | 120 | } |
106 | 121 | ||
122 | void spl_target_boot(void) | ||
123 | { | ||
124 | int opt_index = spl_get_boot_option(); | ||
125 | const struct spl_boot_option* opt = &spl_boot_options[opt_index]; | ||
126 | uint8_t* load_addr = (uint8_t*)opt->load_addr; | ||
127 | |||
128 | /* Clock setup etc. */ | ||
129 | spl_handle_pre_boot(opt_index); | ||
130 | |||
131 | /* Since the GPIO refactor, the SFC driver no longer assigns its own pins. | ||
132 | * We don't want to call gpio_init(), to keep code size down. Assign them | ||
133 | * here manually, we shouldn't need any other pins. */ | ||
134 | gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)); | ||
135 | |||
136 | /* Open NAND chip */ | ||
137 | int rc = nand_open(); | ||
138 | if(rc) | ||
139 | spl_error(); | ||
140 | |||
141 | int mf_id, dev_id; | ||
142 | rc = nand_identify(&mf_id, &dev_id); | ||
143 | if(rc) | ||
144 | goto nand_err; | ||
145 | |||
146 | /* For OF only: load DMA coprocessor's firmware from flash */ | ||
147 | if(opt_index != BOOTOPTION_ROCKBOX) { | ||
148 | rc = nand_read(0x4000, 0x2000, (uint8_t*)0xb3422000); | ||
149 | if(rc) | ||
150 | goto nand_err; | ||
151 | } | ||
152 | |||
153 | /* Read the firmware */ | ||
154 | rc = nand_read(opt->nand_addr, opt->nand_size, load_addr); | ||
155 | if(rc) | ||
156 | goto nand_err; | ||
157 | |||
158 | /* Rockbox doesn't need the NAND; for the OF, we should leave it open | ||
159 | * and also make sure to turn off the write protect bits. */ | ||
160 | if(opt_index == BOOTOPTION_ROCKBOX) | ||
161 | nand_close(); | ||
162 | else | ||
163 | nand_enable_writes(true); | ||
164 | |||
165 | /* Kernel arguments pointer, for Linux only */ | ||
166 | char** kargv = (char**)0x80004000; | ||
167 | |||
168 | if(!opt->cmdline) { | ||
169 | /* Uncompress the rockbox bootloader */ | ||
170 | uint32_t out_size = X1000_DRAM_END - opt->exec_addr; | ||
171 | int rc = ucl_unpack(load_addr, opt->nand_size, | ||
172 | (uint8_t*)opt->exec_addr, &out_size); | ||
173 | if(rc != UCL_E_OK) | ||
174 | spl_error(); | ||
175 | } else { | ||
176 | /* Set kernel args */ | ||
177 | kargv[0] = 0; | ||
178 | kargv[1] = (char*)opt->cmdline; | ||
179 | } | ||
180 | |||
181 | entry_fn entry = (entry_fn)opt->exec_addr; | ||
182 | commit_discard_idcache(); | ||
183 | entry(2, kargv, 0, 0); | ||
184 | __builtin_unreachable(); | ||
185 | |||
186 | nand_err: | ||
187 | nand_close(); | ||
188 | spl_error(); | ||
189 | } | ||
190 | |||
107 | int spl_get_boot_option(void) | 191 | int spl_get_boot_option(void) |
108 | { | 192 | { |
109 | const uint32_t pinmask = (1 << 17) | (1 << 19); | 193 | const uint32_t pinmask = (1 << 17) | (1 << 19); |
@@ -157,17 +241,69 @@ void spl_handle_pre_boot(int bootopt) | |||
157 | * PCLK at 100 MHz | 241 | * PCLK at 100 MHz |
158 | * DDR at 200 MHz | 242 | * DDR at 200 MHz |
159 | */ | 243 | */ |
160 | clk_set_ccr_div(1, 2, 5, 5, 10); | ||
161 | clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) | | ||
162 | CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A)); | ||
163 | 244 | ||
164 | if(bootopt == BOOTOPTION_ROCKBOX) { | 245 | if(bootopt == BOOTOPTION_ROCKBOX) { |
165 | /* We don't use MPLL in Rockbox, so switch DDR memory to APLL */ | 246 | /* We don't use MPLL in Rockbox, so run everything from APLL. */ |
247 | clk_set_ccr_div(1, 2, 5, 5, 10); | ||
248 | clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) | | ||
249 | CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A)); | ||
166 | clk_set_ddr(X1000_CLK_SCLK_A, 5); | 250 | clk_set_ddr(X1000_CLK_SCLK_A, 5); |
167 | 251 | ||
168 | /* Turn off MPLL */ | 252 | /* Turn off MPLL */ |
169 | jz_writef(CPM_MPCR, ENABLE(0)); | 253 | jz_writef(CPM_MPCR, ENABLE(0)); |
170 | } else { | 254 | } else { |
171 | /* TODO: Original firmware needs a lot of other clocks turned on */ | 255 | /* Typical ingenic setup -- 1008 MHz APLL, 600 MHz MPLL |
256 | * with APLL driving the CPU/L2 and MPLL driving busses. */ | ||
257 | clk_set_ccr_div(1, 2, 3, 3, 6); | ||
258 | clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) | | ||
259 | CLKMUX_AHB0(MPLL) | CLKMUX_AHB2(MPLL)); | ||
260 | |||
261 | /* Mimic OF's clock gating setup */ | ||
262 | jz_writef(CPM_CLKGR, PDMA(0), PCM(1), MAC(1), LCD(1), | ||
263 | MSC0(1), MSC1(1), OTG(1), CIM(1)); | ||
264 | |||
265 | /* We now need to define the clock tree by fiddling with | ||
266 | * various CPM registers. Although the kernel has code to | ||
267 | * set up the clock tree itself, it isn't used and relies | ||
268 | * on the SPL for this. */ | ||
269 | jz_writef(CPM_I2SCDR, CS_V(EXCLK)); | ||
270 | jz_writef(CPM_PCMCDR, CS_V(EXCLK)); | ||
271 | |||
272 | jz_writef(CPM_MACCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
273 | while(jz_readf(CPM_MACCDR, BUSY)); | ||
274 | |||
275 | jz_writef(CPM_LPCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
276 | while(jz_readf(CPM_LPCDR, BUSY)); | ||
277 | |||
278 | jz_writef(CPM_MSC0CDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
279 | while(jz_readf(CPM_MSC0CDR, BUSY)); | ||
280 | |||
281 | jz_writef(CPM_MSC1CDR, CE(1), STOP(1), CLKDIV(0xfe)); | ||
282 | while(jz_readf(CPM_MSC1CDR, BUSY)); | ||
283 | |||
284 | jz_writef(CPM_CIMCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); | ||
285 | while(jz_readf(CPM_CIMCDR, BUSY)); | ||
286 | |||
287 | jz_writef(CPM_USBCDR, CLKSRC_V(EXCLK), CE(1), STOP(1)); | ||
288 | while(jz_readf(CPM_USBCDR, BUSY)); | ||
289 | |||
290 | /* Handle UART initialization */ | ||
291 | gpioz_configure(GPIO_C, 3 << 30, GPIOF_DEVICE(1)); | ||
292 | jz_writef(CPM_CLKGR, UART2(0)); | ||
293 | |||
294 | /* TODO: Stop being lazy and make this human readable */ | ||
295 | volatile uint8_t* ub = (volatile uint8_t*)0xb0032000; | ||
296 | ub[0x04] = 0; | ||
297 | ub[0x08] = 0xef; | ||
298 | ub[0x20] = 0xfc; | ||
299 | ub[0x0c] = 3; | ||
300 | uint8_t uv = ub[0x0c]; | ||
301 | ub[0x0c] = uv | 0x80; | ||
302 | ub[0x04] = 0; | ||
303 | ub[0x00] = 0x0d; | ||
304 | ub[0x24] = 0x10; | ||
305 | ub[0x28] = 0; | ||
306 | ub[0x0c] = uv & 0x7f; | ||
307 | ub[0x08] = 0x17; | ||
172 | } | 308 | } |
173 | } | 309 | } |
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c index 07453f6182..fd664e231d 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c | |||
@@ -21,14 +21,12 @@ | |||
21 | 21 | ||
22 | #include "spl-x1000.h" | 22 | #include "spl-x1000.h" |
23 | #include "clk-x1000.h" | 23 | #include "clk-x1000.h" |
24 | #include "nand-x1000.h" | ||
25 | #include "system.h" | 24 | #include "system.h" |
26 | #include "x1000/cpm.h" | 25 | #include "x1000/cpm.h" |
27 | #include "x1000/ost.h" | 26 | #include "x1000/ost.h" |
28 | #include "x1000/ddrc.h" | 27 | #include "x1000/ddrc.h" |
29 | #include "x1000/ddrc_apb.h" | 28 | #include "x1000/ddrc_apb.h" |
30 | #include "x1000/ddrphy.h" | 29 | #include "x1000/ddrphy.h" |
31 | #include "ucl_decompress.h" | ||
32 | 30 | ||
33 | #ifdef FIIO_M3K | 31 | #ifdef FIIO_M3K |
34 | # define SPL_DDR_MEMORYSIZE 64 | 32 | # define SPL_DDR_MEMORYSIZE 64 |
@@ -224,29 +222,6 @@ static void init(void) | |||
224 | ddr_init(); | 222 | ddr_init(); |
225 | } | 223 | } |
226 | 224 | ||
227 | static int nandread(uint32_t addr, uint32_t size, void* buffer) | ||
228 | { | ||
229 | int rc; | ||
230 | int mf_id, dev_id; | ||
231 | |||
232 | if((rc = nand_open())) | ||
233 | return rc; | ||
234 | if((rc = nand_identify(&mf_id, &dev_id))) { | ||
235 | nand_close(); | ||
236 | return rc; | ||
237 | } | ||
238 | |||
239 | rc = nand_read(addr, size, (uint8_t*)buffer); | ||
240 | nand_close(); | ||
241 | return rc; | ||
242 | } | ||
243 | |||
244 | /* Entry point function type, defined to be Linux compatible. */ | ||
245 | typedef void(*entry_fn)(int, char**, int, int); | ||
246 | |||
247 | /* Kernel command line arguments */ | ||
248 | static char* argv[2]; | ||
249 | |||
250 | /* This variable is defined by the maskrom. It's simply the level of the | 225 | /* This variable is defined by the maskrom. It's simply the level of the |
251 | * boot_sel[2:0] pins (GPIOs B28-30) at boot time. Meaning of the bits: | 226 | * boot_sel[2:0] pins (GPIOs B28-30) at boot time. Meaning of the bits: |
252 | * | 227 | * |
@@ -264,10 +239,6 @@ extern const uint32_t boot_sel; | |||
264 | 239 | ||
265 | void spl_main(void) | 240 | void spl_main(void) |
266 | { | 241 | { |
267 | int opt_index; | ||
268 | uint8_t* load_addr; | ||
269 | const struct spl_boot_option* opt; | ||
270 | |||
271 | /* Basic hardware init */ | 242 | /* Basic hardware init */ |
272 | init(); | 243 | init(); |
273 | 244 | ||
@@ -276,35 +247,6 @@ void spl_main(void) | |||
276 | if((boot_sel & 3) == 2) | 247 | if((boot_sel & 3) == 2) |
277 | return; | 248 | return; |
278 | 249 | ||
279 | /* Get the boot option */ | 250 | /* Just pass control to the target... */ |
280 | opt_index = spl_get_boot_option(); | 251 | spl_target_boot(); |
281 | opt = &spl_boot_options[opt_index]; | ||
282 | load_addr = (uint8_t*)opt->load_addr; | ||
283 | |||
284 | /* Set up hardware, load stuff from flash */ | ||
285 | spl_handle_pre_boot(opt_index); | ||
286 | if(nandread(opt->nand_addr, opt->nand_size, load_addr)) | ||
287 | spl_error(); | ||
288 | |||
289 | if(!opt->cmdline) { | ||
290 | /* No command line => we are booting Rockbox, decompress bootloader. | ||
291 | * In the case of Rockbox, load binary directly to exec address */ | ||
292 | uint32_t out_size = X1000_DRAM_END - opt->exec_addr; | ||
293 | int rc = ucl_unpack(load_addr, opt->nand_size, | ||
294 | (uint8_t*)opt->exec_addr, &out_size); | ||
295 | if(rc != UCL_E_OK) | ||
296 | spl_error(); | ||
297 | } | ||
298 | |||
299 | /* Reading the Linux command line from the bootloader is handled by | ||
300 | * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. It's | ||
301 | * simply an (int argc, char* argv[]) thing. | ||
302 | */ | ||
303 | entry_fn entry = (entry_fn)opt->exec_addr; | ||
304 | argv[0] = 0; | ||
305 | argv[1] = (char*)opt->cmdline; | ||
306 | |||
307 | commit_discard_idcache(); | ||
308 | entry(2, argv, 0, 0); | ||
309 | __builtin_unreachable(); | ||
310 | } | 252 | } |
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.h b/firmware/target/mips/ingenic_x1000/spl-x1000.h index 062cb40f88..81714a3ed2 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.h +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.h | |||
@@ -22,22 +22,14 @@ | |||
22 | #ifndef __SPL_X1000_H__ | 22 | #ifndef __SPL_X1000_H__ |
23 | #define __SPL_X1000_H__ | 23 | #define __SPL_X1000_H__ |
24 | 24 | ||
25 | #include <stdint.h> | 25 | /* TODO: this needs some refactoring... */ |
26 | |||
27 | struct spl_boot_option { | ||
28 | uint32_t nand_addr; | ||
29 | uint32_t nand_size; | ||
30 | uint32_t load_addr; | ||
31 | uint32_t exec_addr; | ||
32 | const char* cmdline; /* for Linux */ | ||
33 | }; | ||
34 | |||
35 | /* Defined by target, order is not important */ | ||
36 | extern const struct spl_boot_option spl_boot_options[]; | ||
37 | 26 | ||
38 | /* Called on a fatal error */ | 27 | /* Called on a fatal error */ |
39 | extern void spl_error(void) __attribute__((noreturn)); | 28 | extern void spl_error(void) __attribute__((noreturn)); |
40 | 29 | ||
30 | /* Called by SPL to handle a main boot */ | ||
31 | extern void spl_target_boot(void); | ||
32 | |||
41 | /* Invoked by SPL main routine to determine the boot option */ | 33 | /* Invoked by SPL main routine to determine the boot option */ |
42 | extern int spl_get_boot_option(void); | 34 | extern int spl_get_boot_option(void); |
43 | 35 | ||