summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_x1000/fiiom3k
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/fiiom3k')
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c327
1 files changed, 59 insertions, 268 deletions
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
index 5680b1e548..cbbe8b1d5d 100644
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
@@ -20,306 +20,97 @@
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "system.h" 22#include "system.h"
23#include "ucl_decompress.h" 23#include "clk-x1000.h"
24#include "spl-x1000.h" 24#include "spl-x1000.h"
25#include "gpio-x1000.h" 25#include "gpio-x1000.h"
26#include "clk-x1000.h"
27#include "nand-x1000.h"
28#include "x1000/cpm.h"
29#include <string.h>
30#include <stdint.h>
31
32/* Available boot options */
33#define BOOTOPTION_ROCKBOX 0
34#define BOOTOPTION_ORIG_FW 1
35#define BOOTOPTION_RECOVERY 2
36
37/* Boot select button state must remain stable for this duration
38 * before the choice will be accepted. Currently 100ms.
39 */
40#define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000))
41 26
42static const char normal_cmdline[] = "mem=64M@0x0\ 27#define CMDLINE_COMMON \
43 no_console_suspend\ 28 "mem=64M@0x0 no_console_suspend console=ttyS2,115200n8 lpj=5009408 ip=off"
44 console=ttyS2,115200n8\ 29#define CMDLINE_NORMAL \
45 lpj=5009408\ 30 " init=/linuxrc ubi.mtd=3 root=ubi0:rootfs ubi.mtd=4 rootfstype=ubifs rw loglevel=8"
46 ip=off\
47 init=/linuxrc\
48 ubi.mtd=3\
49 root=ubi0:rootfs\
50 ubi.mtd=4\
51 rootfstype=ubifs\
52 rw\
53 loglevel=8";
54 31
55static const char recovery_cmdline[] = "mem=64M@0x0\ 32static int dualboot_setup(void)
56 no_console_suspend\ 33{
57 console=ttyS2,115200n8\ 34 spl_dualboot_init_clocktree();
58 lpj=5009408\ 35 spl_dualboot_init_uart2();
59 ip=off";
60
61/* Entry point function type, defined to be Linux compatible. */
62typedef void(*entry_fn)(int, char**, int, int);
63 36
64struct spl_boot_option { 37 /* load PDMA MCU firmware */
65 uint32_t nand_addr; 38 jz_writef(CPM_CLKGR, PDMA(0));
66 uint32_t nand_size; 39 return spl_storage_read(0x4000, 0x2000, (void*)0xb3422000);
67 uint32_t load_addr; 40}
68 uint32_t exec_addr;
69 const char* cmdline; /* for Linux */
70};
71 41
72const struct spl_boot_option spl_boot_options[] = { 42const struct spl_boot_option spl_boot_options[] = {
73 { 43 [BOOT_OPTION_ROCKBOX] = {
74 /* Rockbox: the first unused NAND page is 26 KiB in, and the 44 .storage_addr = 0x6800,
75 * remainder of the block is unused, giving us 102 KiB to use. 45 .storage_size = 102 * 1024,
76 */ 46 .load_addr = X1000_DRAM_BASE,
77 .nand_addr = 0x6800,
78 .nand_size = 0x19800,
79 .load_addr = X1000_DRAM_END - 0x19800,
80 .exec_addr = X1000_DRAM_BASE, 47 .exec_addr = X1000_DRAM_BASE,
81 .cmdline = NULL, 48 .flags = BOOTFLAG_UCLPACK,
82 }, 49 },
83 { 50 [BOOT_OPTION_OFW_PLAYER] = {
84 /* Original firmware */ 51 .storage_addr = 0x20000,
85 .nand_addr = 0x20000, 52 .storage_size = 4 * 1024 * 1024,
86 .nand_size = 0x400000,
87 .load_addr = 0x80efffc0, 53 .load_addr = 0x80efffc0,
88 .exec_addr = 0x80f00000, 54 .exec_addr = 0x80f00000,
89 .cmdline = normal_cmdline, 55 .cmdline = CMDLINE_COMMON CMDLINE_NORMAL,
56 .cmdline_addr = 0x80004000,
57 .setup = dualboot_setup,
90 }, 58 },
91 { 59 [BOOT_OPTION_OFW_RECOVERY] = {
92 /* Recovery image */ 60 .storage_addr = 0x420000,
93 .nand_addr = 0x420000, 61 .storage_size = 5 * 1024 * 1024,
94 .nand_size = 0x500000,
95 .load_addr = 0x80efffc0, 62 .load_addr = 0x80efffc0,
96 .exec_addr = 0x80f00000, 63 .exec_addr = 0x80f00000,
97 .cmdline = recovery_cmdline, 64 .cmdline = CMDLINE_COMMON,
65 .cmdline_addr = 0x80004000,
66 .setup = dualboot_setup,
98 }, 67 },
99}; 68};
100 69
101void spl_error(void)
102{
103 const uint32_t pin = (1 << 24);
104
105 /* Turn on button light */
106 jz_clr(GPIO_INT(GPIO_C), pin);
107 jz_set(GPIO_MSK(GPIO_C), pin);
108 jz_clr(GPIO_PAT1(GPIO_C), pin);
109 jz_set(GPIO_PAT0(GPIO_C), pin);
110
111 while(1) {
112 /* Turn it off */
113 mdelay(100);
114 jz_set(GPIO_PAT0(GPIO_C), pin);
115
116 /* Turn it on */
117 mdelay(100);
118 jz_clr(GPIO_PAT0(GPIO_C), pin);
119 }
120}
121
122nand_drv* alloc_nand_drv(uint32_t laddr, uint32_t lsize)
123{
124 size_t need_size = sizeof(nand_drv) +
125 NAND_DRV_SCRATCHSIZE +
126 NAND_DRV_MAXPAGESIZE;
127
128 /* find a hole to keep the buffers */
129 uintptr_t addr;
130 if(X1000_SDRAM_BASE + need_size <= laddr)
131 addr = X1000_SDRAM_BASE;
132 else
133 addr = CACHEALIGN_UP(X1000_SDRAM_BASE + laddr + lsize);
134
135 uint8_t* page_buf = (uint8_t*)addr;
136 uint8_t* scratch_buf = page_buf + NAND_DRV_MAXPAGESIZE;
137 nand_drv* drv = (nand_drv*)(scratch_buf + NAND_DRV_SCRATCHSIZE);
138
139 drv->page_buf = page_buf;
140 drv->scratch_buf = scratch_buf;
141 drv->refcount = 0;
142 return drv;
143}
144
145void spl_target_boot(void)
146{
147 int opt_index = spl_get_boot_option();
148 const struct spl_boot_option* opt = &spl_boot_options[opt_index];
149 uint8_t* load_addr = (uint8_t*)opt->load_addr;
150
151 /* Clock setup etc. */
152 spl_handle_pre_boot(opt_index);
153
154 /* Since the GPIO refactor, the SFC driver no longer assigns its own pins.
155 * We don't want to call gpio_init(), to keep code size down. Assign them
156 * here manually, we shouldn't need any other pins. */
157 gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1));
158
159 /* Open NAND chip */
160 nand_drv* ndrv = alloc_nand_drv(opt->load_addr, opt->nand_size);
161 int rc = nand_open(ndrv);
162 if(rc)
163 spl_error();
164
165 /* For OF only: load DMA coprocessor's firmware from flash */
166 if(opt_index != BOOTOPTION_ROCKBOX) {
167 rc = nand_read_bytes(ndrv, 0x4000, 0x2000, (uint8_t*)0xb3422000);
168 if(rc)
169 goto nand_err;
170 }
171
172 /* Read the firmware */
173 rc = nand_read_bytes(ndrv, opt->nand_addr, opt->nand_size, load_addr);
174 if(rc)
175 goto nand_err;
176
177 /* Rockbox doesn't need the NAND; for the OF, we should leave it open */
178 if(opt_index == BOOTOPTION_ROCKBOX)
179 nand_close(ndrv);
180
181 /* Kernel arguments pointer, for Linux only */
182 char** kargv = (char**)0x80004000;
183
184 if(!opt->cmdline) {
185 /* Uncompress the rockbox bootloader */
186 uint32_t out_size = X1000_DRAM_END - opt->exec_addr;
187 int rc = ucl_unpack(load_addr, opt->nand_size,
188 (uint8_t*)opt->exec_addr, &out_size);
189 if(rc != UCL_E_OK)
190 spl_error();
191 } else {
192 /* Set kernel args */
193 kargv[0] = 0;
194 kargv[1] = (char*)opt->cmdline;
195 }
196
197 entry_fn entry = (entry_fn)opt->exec_addr;
198 commit_discard_idcache();
199 entry(2, kargv, 0, 0);
200 __builtin_unreachable();
201
202 nand_err:
203 nand_close(ndrv);
204 spl_error();
205}
206
207int spl_get_boot_option(void) 70int spl_get_boot_option(void)
208{ 71{
209 const uint32_t pinmask = (1 << 17) | (1 << 19); 72 /* Button debounce time in OST clock cycles */
73 const uint32_t btn_stable_time = 100 * (X1000_EXCLK_FREQ / 4000);
210 74
211 uint32_t pin = 1, lastpin = 0; 75 /* Buttons to poll */
76 const unsigned port = GPIO_A;
77 const uint32_t recov_pin = (1 << 19); /* Volume Up */
78 const uint32_t orig_fw_pin = (1 << 17); /* Play */
79
80 uint32_t pin = -1, lastpin = 0;
212 uint32_t deadline = 0; 81 uint32_t deadline = 0;
213 /* Iteration count guards against unlikely case of broken buttons 82 int iter_count = 30; /* to avoid an infinite loop */
214 * which never stabilize; if this occurs, we always boot Rockbox. */
215 int iter_count = 0;
216 const int max_iter_count = 30;
217 83
218 /* Configure the button GPIOs as inputs */ 84 /* set GPIOs to input state */
219 gpioz_configure(GPIO_A, pinmask, GPIOF_INPUT); 85 gpioz_configure(port, recov_pin|orig_fw_pin, GPIOF_INPUT);
220 86
221 /* Poll the pins for a short duration to detect a keypress */ 87 /* Poll until we get a stable reading */
222 do { 88 do {
223 lastpin = pin; 89 lastpin = pin;
224 pin = ~REG_GPIO_PIN(GPIO_A) & pinmask; 90 pin = ~REG_GPIO_PIN(port) & (recov_pin|orig_fw_pin);
225 if(pin != lastpin) { 91 if(pin != lastpin) {
226 /* This will always be set on the first iteration */ 92 deadline = __ost_read32() + btn_stable_time;
227 deadline = __ost_read32() + BTN_STABLE_TIME; 93 iter_count -= 1;
228 iter_count += 1;
229 } 94 }
230 } while(iter_count < max_iter_count && __ost_read32() < deadline); 95 } while(iter_count > 0 && __ost_read32() < deadline);
231 96
232 if(iter_count < max_iter_count && (pin & (1 << 17))) { 97 if(iter_count >= 0 && (pin & orig_fw_pin)) {
233 if(pin & (1 << 19)) 98 if(pin & recov_pin)
234 return BOOTOPTION_RECOVERY; /* Play+Volume Up */ 99 return BOOT_OPTION_OFW_RECOVERY;
235 else 100 else
236 return BOOTOPTION_ORIG_FW; /* Play */ 101 return BOOT_OPTION_OFW_PLAYER;
237 } else {
238 return BOOTOPTION_ROCKBOX; /* Volume Up or no buttons */
239 } 102 }
103
104 return BOOT_OPTION_ROCKBOX;
240} 105}
241 106
242void spl_handle_pre_boot(int bootopt) 107void spl_error(void)
243{ 108{
244 /* Move system to EXCLK so we can manipulate the PLLs */ 109 /* Flash the buttonlight */
245 clk_set_ccr_mux(CLKMUX_SCLK_A(EXCLK) | CLKMUX_CPU(SCLK_A) | 110 int level = 0;
246 CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A)); 111 while(1) {
247 clk_set_ccr_div(1, 1, 1, 1, 1); 112 gpio_set_function(GPIO_PC(24), GPIOF_OUTPUT(level));
248 113 mdelay(100);
249 /* Enable APLL @ 1008 MHz (24 MHz EXCLK * 42 = 1008 MHz) */ 114 level = 1 - level;
250 jz_writef(CPM_APCR, BS(1), PLLM(41), PLLN(0), PLLOD(0), ENABLE(1));
251 while(jz_readf(CPM_APCR, ON) == 0);
252
253 /* System clock setup -- common to Rockbox and FiiO firmware
254 * ----
255 * CPU at 1 GHz, L2 cache at 500 MHz
256 * AHB0 and AHB2 at 200 MHz
257 * PCLK at 100 MHz
258 * DDR at 200 MHz
259 */
260
261 if(bootopt == BOOTOPTION_ROCKBOX) {
262 /* We don't use MPLL in Rockbox, so run everything from APLL. */
263 clk_set_ccr_div(1, 2, 5, 5, 10);
264 clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) |
265 CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A));
266 clk_set_ddr(X1000_CLK_SCLK_A, 5);
267
268 /* Turn off MPLL */
269 jz_writef(CPM_MPCR, ENABLE(0));
270 } else {
271 /* Typical ingenic setup -- 1008 MHz APLL, 600 MHz MPLL
272 * with APLL driving the CPU/L2 and MPLL driving busses. */
273 clk_set_ccr_div(1, 2, 3, 3, 6);
274 clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) |
275 CLKMUX_AHB0(MPLL) | CLKMUX_AHB2(MPLL));
276
277 /* Mimic OF's clock gating setup */
278 jz_writef(CPM_CLKGR, PDMA(0), PCM(1), MAC(1), LCD(1),
279 MSC0(1), MSC1(1), OTG(1), CIM(1));
280
281 /* We now need to define the clock tree by fiddling with
282 * various CPM registers. Although the kernel has code to
283 * set up the clock tree itself, it isn't used and relies
284 * on the SPL for this. */
285 jz_writef(CPM_I2SCDR, CS_V(EXCLK));
286 jz_writef(CPM_PCMCDR, CS_V(EXCLK));
287
288 jz_writef(CPM_MACCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe));
289 while(jz_readf(CPM_MACCDR, BUSY));
290
291 jz_writef(CPM_LPCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe));
292 while(jz_readf(CPM_LPCDR, BUSY));
293
294 jz_writef(CPM_MSC0CDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe));
295 while(jz_readf(CPM_MSC0CDR, BUSY));
296
297 jz_writef(CPM_MSC1CDR, CE(1), STOP(1), CLKDIV(0xfe));
298 while(jz_readf(CPM_MSC1CDR, BUSY));
299
300 jz_writef(CPM_CIMCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe));
301 while(jz_readf(CPM_CIMCDR, BUSY));
302
303 jz_writef(CPM_USBCDR, CLKSRC_V(EXCLK), CE(1), STOP(1));
304 while(jz_readf(CPM_USBCDR, BUSY));
305
306 /* Handle UART initialization */
307 gpioz_configure(GPIO_C, 3 << 30, GPIOF_DEVICE(1));
308 jz_writef(CPM_CLKGR, UART2(0));
309
310 /* TODO: Stop being lazy and make this human readable */
311 volatile uint8_t* ub = (volatile uint8_t*)0xb0032000;
312 ub[0x04] = 0;
313 ub[0x08] = 0xef;
314 ub[0x20] = 0xfc;
315 ub[0x0c] = 3;
316 uint8_t uv = ub[0x0c];
317 ub[0x0c] = uv | 0x80;
318 ub[0x04] = 0;
319 ub[0x00] = 0x0d;
320 ub[0x24] = 0x10;
321 ub[0x28] = 0;
322 ub[0x0c] = uv & 0x7f;
323 ub[0x08] = 0x17;
324 } 115 }
325} 116}