summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c148
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.c62
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.h16
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. */
62typedef void(*entry_fn)(int, char**, int, int);
63
64struct 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
57const struct spl_boot_option spl_boot_options[] = { 72const 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
122void 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
107int spl_get_boot_option(void) 191int 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
227static 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. */
245typedef void(*entry_fn)(int, char**, int, int);
246
247/* Kernel command line arguments */
248static 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
265void spl_main(void) 240void 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
27struct 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 */
36extern const struct spl_boot_option spl_boot_options[];
37 26
38/* Called on a fatal error */ 27/* Called on a fatal error */
39extern void spl_error(void) __attribute__((noreturn)); 28extern void spl_error(void) __attribute__((noreturn));
40 29
30/* Called by SPL to handle a main boot */
31extern 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 */
42extern int spl_get_boot_option(void); 34extern int spl_get_boot_option(void);
43 35