summaryrefslogtreecommitdiff
path: root/bootloader
diff options
context:
space:
mode:
Diffstat (limited to 'bootloader')
-rw-r--r--bootloader/SOURCES7
-rw-r--r--bootloader/fiiom3k-spl.c206
-rw-r--r--bootloader/x1000-spl.c230
3 files changed, 1 insertions, 442 deletions
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index db9e05644c..446bdac0e1 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -89,11 +89,6 @@ show_logo.c
89#elif defined(SANSA_CONNECT) 89#elif defined(SANSA_CONNECT)
90sansaconnect.c 90sansaconnect.c
91show_logo.c 91show_logo.c
92#elif defined(FIIO_M3K) 92#elif defined(FIIO_M3K) && !defined(BOOTLOADER_SPL)
93#ifdef BOOTLOADER_SPL
94x1000-spl.c
95fiiom3k-spl.c
96#else
97fiiom3k.c 93fiiom3k.c
98#endif 94#endif
99#endif
diff --git a/bootloader/fiiom3k-spl.c b/bootloader/fiiom3k-spl.c
deleted file mode 100644
index 67b4b0a59c..0000000000
--- a/bootloader/fiiom3k-spl.c
+++ /dev/null
@@ -1,206 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "nand-x1000.h"
24#include "gpio-x1000.h"
25#include "mmu-mips.h"
26#include <string.h>
27
28/* "fiio" in little endian */
29#define BOOTMAGIC 0x6f696966
30
31/* Argument structure needed by Linux */
32struct linux_kargs {
33 void* arg0;
34 void* arg1;
35};
36
37#define LINUX_KARGSADDR 0x80004000
38
39static const char recovery_cmdline[] = "mem=xxM@0x0\
40 no_console_suspend\
41 console=ttyS2,115200n8\
42 lpj=5009408\
43 ip=off";
44
45static const char normal_cmdline[] = "mem=64M@0x0\
46 no_console_suspend\
47 console=ttyS2,115200n8\
48 lpj=5009408\
49 ip=off\
50 init=/linuxrc\
51 ubi.mtd=3\
52 root=ubi0:rootfs\
53 ubi.mtd=4\
54 rootfstype=ubifs\
55 rw\
56 loglevel=8";
57
58#define BOOTOPTION_ROCKBOX 0
59#define BOOTOPTION_FIIOLINUX 1
60#define BOOTOPTION_RECOVERY 2
61#define NUM_BOOTOPTIONS 3
62
63static const struct bootoption {
64 uint32_t nand_addr;
65 uint32_t nand_size;
66 unsigned long load_addr;
67 unsigned long exec_addr;
68 const char* cmdline;
69} boot_options[NUM_BOOTOPTIONS] = {
70 {
71 /* Rockbox: the first unused NAND page is 26 KiB in, and the
72 * remainder of the block is unused, giving us 102 KiB to use.
73 */
74 .nand_addr = 0x6800,
75 .nand_size = 0x19800,
76 .load_addr = 0x80003ff8, /* first 8 bytes are bootloader ID */
77 .exec_addr = 0x80004000,
78 .cmdline = NULL,
79 },
80 {
81 /* Original firmware */
82 .nand_addr = 0x20000,
83 .nand_size = 0x400000,
84 .load_addr = 0x80efffc0,
85 .exec_addr = 0x80f00000,
86 .cmdline = normal_cmdline,
87 },
88 {
89 /* Recovery image */
90 .nand_addr = 0x420000,
91 .nand_size = 0x500000,
92 .load_addr = 0x80efffc0,
93 .exec_addr = 0x80f00000,
94 .cmdline = recovery_cmdline,
95 },
96};
97
98/* Simple diagnostic if something goes wrong -- a little nicer than wondering
99 * what's going on when the machine hangs
100 */
101void die(void)
102{
103 const int 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
122/* Boot select button state must remain stable for this duration
123 * before the choice will be accepted. Currently 100ms.
124 */
125#define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000))
126
127int get_boot_option(void)
128{
129 const uint32_t pinmask = (1 << 17) | (1 << 19);
130
131 uint32_t pin = 1, lastpin = 0;
132 uint32_t deadline = 0;
133
134 /* Configure the button GPIOs as inputs */
135 gpio_config(GPIO_A, pinmask, GPIO_INPUT);
136
137 /* Poll the pins for a short duration to detect a keypress */
138 do {
139 lastpin = pin;
140 pin = ~REG_GPIO_PIN(GPIO_A) & pinmask;
141 if(pin != lastpin) {
142 /* This will always be set on the first iteration */
143 deadline = __ost_read32() + BTN_STABLE_TIME;
144 }
145 } while(__ost_read32() < deadline);
146
147 /* Play button boots original firmware */
148 if(pin == (1 << 17))
149 return BOOTOPTION_FIIOLINUX;
150
151 /* Volume up boots recovery */
152 if(pin == (1 << 19))
153 return BOOTOPTION_RECOVERY;
154
155 /* Default is to boot Rockbox */
156 return BOOTOPTION_ROCKBOX;
157}
158
159void spl_main(void)
160{
161 /* Get user boot option */
162 int booti = get_boot_option();
163 const struct bootoption* opt = &boot_options[booti];
164
165 /* Load selected firmware from flash */
166 if(nand_open())
167 die();
168 if(nand_read_bytes(opt->nand_addr, opt->nand_size, (void*)opt->load_addr))
169 die();
170
171 if(booti == BOOTOPTION_ROCKBOX) {
172 /* If bootloader is not installed, return back to boot ROM.
173 * Also read in the first eraseblock of NAND flash so it can be
174 * dumped back over USB.
175 */
176 if(*(unsigned*)(opt->load_addr + 4) != BOOTMAGIC) {
177 nand_read_bytes(0, 128 * 1024, (void*)0x80000000);
178 commit_discard_idcache();
179 return;
180 }
181 } else {
182 /* TODO: Linux boot not implemented yet
183 *
184 * - Have to initialize UART2, as it's used for the serial console
185 * - Must initialize APLL and change clocks over
186 * - There are some other clocks which need to be initialized
187 * - We should turn off OST since the OF SPL does not turn it on
188 */
189 die();
190 }
191
192 if(boot_options[booti].cmdline) {
193 /* Handle Linux command line arguments */
194 struct linux_kargs* kargs = (struct linux_kargs*)LINUX_KARGSADDR;
195 kargs->arg0 = 0;
196 kargs->arg1 = (void*)boot_options[booti].cmdline;
197 }
198
199 /* Flush caches and jump to address */
200 void* execaddr = (void*)opt->exec_addr;
201 commit_discard_idcache();
202 __asm__ __volatile__ ("jr %0\n"
203 "nop\n"
204 :: "r"(execaddr));
205 __builtin_unreachable();
206}
diff --git a/bootloader/x1000-spl.c b/bootloader/x1000-spl.c
deleted file mode 100644
index 1c780a9843..0000000000
--- a/bootloader/x1000-spl.c
+++ /dev/null
@@ -1,230 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "system.h"
23#include "clk-x1000.h"
24#include "x1000/cpm.h"
25#include "x1000/ost.h"
26#include "x1000/ddrc.h"
27#include "x1000/ddrc_apb.h"
28#include "x1000/ddrphy.h"
29
30#ifdef FIIO_M3K
31# define DDR_USE_AUTOSR 1
32# define DDR_NEED_BYPASS 1
33# define DDR_MEMORYSIZE 64
34#else
35# error "Please add DDR definitions for new target!"
36#endif
37
38#define hang() do { } while(1)
39
40/* Target-specific routine to load & execute the Rockbox bootloader */
41extern void spl_main(void);
42
43/* 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
45 * U-Boot code, but isn't entirely the same.
46 *
47 * I converted all the runtime conditionals to compile-time ones in order to
48 * save code space, since they should be constant for any given target.
49 *
50 * I haven't bothered to decode all the register fields. Some of the values
51 * written are going to bits documented as "Reserved" by Ingenic, but their
52 * documentation doesn't seem completely reliable, so either these are bits
53 * which _do_ have a purpose, or they're only defined on other Ingenic CPUs.
54 *
55 * The DDR PHY registers appear to be from Synopsys "PHY Utility Block Lite".
56 * These aren't documented by Ingenic, but the addresses and names can be found
57 * in their U-Boot code.
58 */
59static void ddr_init(void)
60{
61 REG_CPM_DRCG = 0x73;
62 mdelay(3);
63 REG_CPM_DRCG = 0x71;
64 mdelay(3);
65 REG_DDRC_APB_PHYRST_CFG = 0x1a00001;
66 mdelay(3);
67 REG_DDRC_APB_PHYRST_CFG = 0;
68 mdelay(3);
69 REG_DDRC_CTRL = 0xf00000;
70 mdelay(3);
71 REG_DDRC_CTRL = 0;
72 mdelay(3);
73
74 REG_DDRC_CFG = 0xa468a6c;
75 REG_DDRC_CTRL = 2;
76 REG_DDRPHY_DTAR = 0x150000;
77 REG_DDRPHY_DCR = 0;
78 REG_DDRPHY_MR0 = 0x42;
79 REG_DDRPHY_MR2 = 0x98;
80 REG_DDRPHY_PTR0 = 0x21000a;
81 REG_DDRPHY_PTR1 = 0xa09c40;
82 REG_DDRPHY_PTR2 = 0x280014;
83 REG_DDRPHY_DTPR0 = 0x1a69444a;
84 REG_DDRPHY_DTPR1 = 0x180090;
85 REG_DDRPHY_DTPR2 = 0x1ff99428;
86 REG_DDRPHY_DXGCR(0) = 0x90881;
87 REG_DDRPHY_DXGCR(1) = 0x90881;
88 REG_DDRPHY_DXGCR(2) = 0x90e80;
89 REG_DDRPHY_DXGCR(3) = 0x90e80;
90 REG_DDRPHY_PGCR = 0x1042e03;
91 REG_DDRPHY_ACIOCR = 0x30c00813;
92 REG_DDRPHY_DXCCR = 0x4912;
93
94 int i = 10000;
95 while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f)
96 i -= 1;
97 if(i == 0)
98 hang();
99
100#if DDR_NEED_BYPASS
101 REG_DDRPHY_ACDLLCR = 0x80000000;
102 REG_DDRPHY_DSGCR &= ~0x10;
103 REG_DDRPHY_DLLGCR |= 0x800000;
104 REG_DDRPHY_PIR = 0x20020041;
105#else
106 REG_DDRPHY_PIR = 0x41;
107#endif
108
109 while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f)
110 i -= 1;
111 if(i == 0)
112 hang();
113
114 REG_DDRC_APB_PHYRST_CFG = 0x400000;
115 mdelay(3);
116 REG_DDRC_APB_PHYRST_CFG = 0;
117 mdelay(3);
118
119 REG_DDRC_CFG = 0xa468aec;
120 REG_DDRC_CTRL = 2;
121#if DDR_NEED_BYPASS
122 REG_DDRPHY_PIR = 0x20020081;
123#else
124 REG_DDRPHY_PIR = 0x85;
125#endif
126
127 i = 500000;
128 while(REG_DDRPHY_PGSR != 0x1f) {
129 if(REG_DDRPHY_PGSR & 0x70)
130 break;
131 i -= 1;
132 }
133
134 if(i == 0)
135 hang();
136
137 if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0)
138 hang();
139
140 REG_DDRC_CTRL = 0;
141 REG_DDRC_CTRL = 10;
142 REG_DDRC_CTRL = 0;
143 REG_DDRC_CFG = 0xa468a6c;
144 REG_DDRC_TIMING1 = 0x2050501;
145 REG_DDRC_TIMING2 = 0x4090404;
146 REG_DDRC_TIMING3 = 0x2704030d;
147 REG_DDRC_TIMING4 = 0xb7a0251;
148 REG_DDRC_TIMING5 = 0xff090200;
149 REG_DDRC_TIMING6 = 0xa0a0202;
150#if DDR_MEMORYSIZE == 64
151 REG_DDRC_MMAP0 = 0x20fc;
152 REG_DDRC_MMAP1 = 0x2400;
153#elif DDR_MEMORYSIZE == 32
154 REG_DDRC_MMAP0 = 0x20fe;
155 REG_DDRC_MMAP1 = 0x2200;
156#else
157# error "Unsupported DDR_MEMORYSIZE"
158#endif
159 REG_DDRC_CTRL = 10;
160 REG_DDRC_REFCNT = 0x2f0003;
161 REG_DDRC_CTRL = 0xc91e;
162
163#if DDR_MEMORYSIZE == 64
164 REG_DDRC_REMAP1 = 0x03020c0b;
165 REG_DDRC_REMAP2 = 0x07060504;
166 REG_DDRC_REMAP3 = 0x000a0908;
167 REG_DDRC_REMAP4 = 0x0f0e0d01;
168 REG_DDRC_REMAP5 = 0x13121110;
169#elif DDR_MEMORYSIZE == 32
170 REG_DDRC_REMAP1 = 0x03020b0a;
171 REG_DDRC_REMAP2 = 0x07060504;
172 REG_DDRC_REMAP3 = 0x01000908;
173 REG_DDRC_REMAP4 = 0x0f0e0d0c;
174 REG_DDRC_REMAP5 = 0x13121110;
175#else
176# error "Unsupported DDR_MEMORYSIZE"
177#endif
178
179 REG_DDRC_STATUS &= ~0x40;
180
181#if DDR_USE_AUTOSR
182#if DDR_NEED_BYPASS
183 jz_writef(CPM_DDRCDR, GATE_EN(1));
184 REG_DDRC_APB_CLKSTP_CFG = 0x9000000f;
185#else
186 REG_DDRC_DLP = 0;
187#endif
188#endif
189
190 REG_DDRC_AUTOSR_EN = DDR_USE_AUTOSR;
191}
192
193void main(void)
194{
195 /* from original firmware SPL */
196 REG_CPM_PSWC0ST = 0x00;
197 REG_CPM_PSWC1ST = 0x10;
198 REG_CPM_PSWC2ST = 0x18;
199 REG_CPM_PSWC3ST = 0x08;
200
201 /* enable MPLL */
202#if X1000_EXCLK_FREQ == 24000000
203 /* 24 * (24+1) = 600 MHz */
204 jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(24), PLLOD(0));
205#elif X1000_EXCLK_FREQ == 26000000
206 /* 26 * (22+1) = 598 MHz */
207 jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(22), PLLOD(0));
208#else
209# error "unknown EXCLK frequency"
210#endif
211 while(jz_readf(CPM_MPCR, ON) == 0);
212
213 /* set DDR clock to MPLL/3 = 200 MHz */
214 jz_writef(CPM_CLKGR, DDR(0));
215 clk_set_ddr(X1000_CLK_MPLL, 3);
216
217 /* start OST so we can use mdelay/udelay */
218 jz_writef(CPM_CLKGR, OST(0));
219 jz_writef(OST_CTRL, PRESCALE2_V(BY_4));
220 jz_writef(OST_CLEAR, OST2(1));
221 jz_write(OST_2CNTH, 0);
222 jz_write(OST_2CNTL, 0);
223 jz_setf(OST_ENABLE, OST2);
224
225 /* init DDR memory */
226 ddr_init();
227
228 /* jump to the target's main routine */
229 spl_main();
230}