summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-04-07 22:11:01 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-04-17 20:22:49 +0000
commit1b8542490da3283dfa0ce0f3363f16eab0609815 (patch)
treed3775ef4ee2739e0f140dc70f70e422bc06059f3
parent85fbbd9c7f3e1ac84910a16095a297cbe13a8123 (diff)
downloadrockbox-1b8542490da3283dfa0ce0f3363f16eab0609815.tar.gz
rockbox-1b8542490da3283dfa0ce0f3363f16eab0609815.zip
x1000: Redesign SPL, and allow it to flash the bootloader
SPL is now designed so core X1000 code is in control of the boot, under the reasonable assumption that the device boots from flash. It should not be too hard to adapt to other X1000 ports. The biggest functional change is that the SPL can now read/write the flash, under the control of a host computer. The SPL relies on the boot ROM for USB communication, so the host has to execute the SPL multiple times following a protocol. Change-Id: I3ffaa00e4bf191e043c9df0e2e64d15193ff42c9
-rw-r--r--bootloader/SOURCES7
-rw-r--r--firmware/SOURCES6
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c (renamed from bootloader/fiiom3k-spl.c)112
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h29
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000-defs.h66
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.c (renamed from bootloader/x1000-spl.c)136
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.h49
7 files changed, 279 insertions, 126 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/firmware/SOURCES b/firmware/SOURCES
index 3a42381003..ce3d8d52e2 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1747,6 +1747,9 @@ target/mips/ingenic_x1000/msc-x1000.c
1747#if (CONFIG_STORAGE & STORAGE_SD) 1747#if (CONFIG_STORAGE & STORAGE_SD)
1748target/mips/ingenic_x1000/sd-x1000.c 1748target/mips/ingenic_x1000/sd-x1000.c
1749#endif 1749#endif
1750#ifdef BOOTLOADER_SPL
1751target/mips/ingenic_x1000/spl-x1000.c
1752#endif
1750#endif /* CONFIG_CPU == X1000 */ 1753#endif /* CONFIG_CPU == X1000 */
1751 1754
1752#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777) 1755#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
@@ -1780,6 +1783,9 @@ target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
1780target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c 1783target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
1781target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c 1784target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c
1782target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c 1785target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
1786#ifdef BOOTLOADER_SPL
1787target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
1788#endif
1783#endif /* FIIO_M3K */ 1789#endif /* FIIO_M3K */
1784 1790
1785#if defined(LYRE_PROTO1) 1791#if defined(LYRE_PROTO1)
diff --git a/bootloader/fiiom3k-spl.c b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
index 67b4b0a59c..0ebe11e24d 100644
--- a/bootloader/fiiom3k-spl.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
@@ -19,28 +19,16 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "config.h" 22#include "spl-x1000.h"
23#include "nand-x1000.h"
24#include "gpio-x1000.h" 23#include "gpio-x1000.h"
25#include "mmu-mips.h" 24#include "nand-x1000.h"
25#include "system.h"
26#include <string.h> 26#include <string.h>
27 27
28/* "fiio" in little endian */ 28/* Boot select button state must remain stable for this duration
29#define BOOTMAGIC 0x6f696966 29 * before the choice will be accepted. Currently 100ms.
30 30 */
31/* Argument structure needed by Linux */ 31#define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000))
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 32
45static const char normal_cmdline[] = "mem=64M@0x0\ 33static const char normal_cmdline[] = "mem=64M@0x0\
46 no_console_suspend\ 34 no_console_suspend\
@@ -55,18 +43,13 @@ static const char normal_cmdline[] = "mem=64M@0x0\
55 rw\ 43 rw\
56 loglevel=8"; 44 loglevel=8";
57 45
58#define BOOTOPTION_ROCKBOX 0 46static const char recovery_cmdline[] = "mem=64M@0x0\
59#define BOOTOPTION_FIIOLINUX 1 47 no_console_suspend\
60#define BOOTOPTION_RECOVERY 2 48 console=ttyS2,115200n8\
61#define NUM_BOOTOPTIONS 3 49 lpj=5009408\
62 50 ip=off";
63static const struct bootoption { 51
64 uint32_t nand_addr; 52const struct spl_boot_option spl_boot_options[] = {
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 { 53 {
71 /* Rockbox: the first unused NAND page is 26 KiB in, and the 54 /* 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. 55 * remainder of the block is unused, giving us 102 KiB to use.
@@ -95,10 +78,7 @@ static const struct bootoption {
95 }, 78 },
96}; 79};
97 80
98/* Simple diagnostic if something goes wrong -- a little nicer than wondering 81void spl_error(void)
99 * what's going on when the machine hangs
100 */
101void die(void)
102{ 82{
103 const int pin = (1 << 24); 83 const int pin = (1 << 24);
104 84
@@ -119,12 +99,7 @@ void die(void)
119 } 99 }
120} 100}
121 101
122/* Boot select button state must remain stable for this duration 102int spl_get_boot_option(void)
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{ 103{
129 const uint32_t pinmask = (1 << 17) | (1 << 19); 104 const uint32_t pinmask = (1 << 17) | (1 << 19);
130 105
@@ -146,61 +121,12 @@ int get_boot_option(void)
146 121
147 /* Play button boots original firmware */ 122 /* Play button boots original firmware */
148 if(pin == (1 << 17)) 123 if(pin == (1 << 17))
149 return BOOTOPTION_FIIOLINUX; 124 return SPL_BOOTOPT_ORIG_FW;
150 125
151 /* Volume up boots recovery */ 126 /* Volume up boots recovery */
152 if(pin == (1 << 19)) 127 if(pin == (1 << 19))
153 return BOOTOPTION_RECOVERY; 128 return SPL_BOOTOPT_RECOVERY;
154 129
155 /* Default is to boot Rockbox */ 130 /* Default is to boot Rockbox */
156 return BOOTOPTION_ROCKBOX; 131 return SPL_BOOTOPT_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} 132}
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h
new file mode 100644
index 0000000000..ac90508f44
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h
@@ -0,0 +1,29 @@
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#ifndef __SPL_TARGET_H__
23#define __SPL_TARGET_H__
24
25#define SPL_DDR_MEMORYSIZE 64
26#define SPL_DDR_AUTOSR_EN 1
27#define SPL_DDR_NEED_BYPASS 1
28
29#endif /* __SPL_TARGET_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h b/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h
new file mode 100644
index 0000000000..1d9f120ee2
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h
@@ -0,0 +1,66 @@
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#ifndef __SPL_X1000_DEFS_H__
23#define __SPL_X1000_DEFS_H__
24
25#include <stdint.h>
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30
31#define SPL_CMD_BOOT 0
32#define SPL_CMD_FLASH_READ 1
33#define SPL_CMD_FLASH_WRITE 2
34
35#define SPL_BOOTOPT_CHOOSE 0
36#define SPL_BOOTOPT_ROCKBOX 1
37#define SPL_BOOTOPT_ORIG_FW 2
38#define SPL_BOOTOPT_RECOVERY 3
39#define SPL_BOOTOPT_NONE 4
40
41#define SPL_FLAG_SKIP_INIT (1 << 0)
42
43#define SPL_MAX_SIZE (12 * 1024)
44#define SPL_LOAD_ADDRESS 0xf4001000
45#define SPL_EXEC_ADDRESS 0xf4001800
46#define SPL_ARGUMENTS_ADDRESS 0xf40011f0
47#define SPL_STATUS_ADDRESS 0xf40011e0
48#define SPL_BUFFER_ADDRESS 0xa0004000
49
50struct x1000_spl_arguments {
51 uint32_t command;
52 uint32_t param1;
53 uint32_t param2;
54 uint32_t flags;
55};
56
57struct x1000_spl_status {
58 int err_code;
59 int reserved;
60};
61
62#ifdef __cplusplus
63}
64#endif
65
66#endif /* __SPL_X1000_DEFS_H__ */
diff --git a/bootloader/x1000-spl.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c
index 1c780a9843..59e0fb687d 100644
--- a/bootloader/x1000-spl.c
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c
@@ -19,26 +19,26 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "system.h" 22#include "spl-x1000.h"
23#include "spl-target.h"
23#include "clk-x1000.h" 24#include "clk-x1000.h"
25#include "nand-x1000.h"
26#include "system.h"
24#include "x1000/cpm.h" 27#include "x1000/cpm.h"
25#include "x1000/ost.h" 28#include "x1000/ost.h"
26#include "x1000/ddrc.h" 29#include "x1000/ddrc.h"
27#include "x1000/ddrc_apb.h" 30#include "x1000/ddrc_apb.h"
28#include "x1000/ddrphy.h" 31#include "x1000/ddrphy.h"
29 32
30#ifdef FIIO_M3K 33struct x1000_spl_arguments* const spl_arguments =
31# define DDR_USE_AUTOSR 1 34 (struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS;
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 35
38#define hang() do { } while(1) 36struct x1000_spl_status* const spl_status =
37 (struct x1000_spl_status*)SPL_STATUS_ADDRESS;
39 38
40/* Target-specific routine to load & execute the Rockbox bootloader */ 39/* defined to be Linux compatible; Rockbox needs no arguments so there
41extern void spl_main(void); 40 * is no harm in passing them and we save a little code size */
41typedef void(*entry_fn)(int, char**, int, int);
42 42
43/* Note: This is based purely on disassembly of the SPL from the FiiO M3K. 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 44 * The code there is somewhat generic and corresponds roughly to Ingenic's
@@ -95,9 +95,9 @@ static void ddr_init(void)
95 while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f) 95 while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f)
96 i -= 1; 96 i -= 1;
97 if(i == 0) 97 if(i == 0)
98 hang(); 98 spl_error();
99 99
100#if DDR_NEED_BYPASS 100#if SPL_DDR_NEED_BYPASS
101 REG_DDRPHY_ACDLLCR = 0x80000000; 101 REG_DDRPHY_ACDLLCR = 0x80000000;
102 REG_DDRPHY_DSGCR &= ~0x10; 102 REG_DDRPHY_DSGCR &= ~0x10;
103 REG_DDRPHY_DLLGCR |= 0x800000; 103 REG_DDRPHY_DLLGCR |= 0x800000;
@@ -109,7 +109,7 @@ static void ddr_init(void)
109 while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f) 109 while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f)
110 i -= 1; 110 i -= 1;
111 if(i == 0) 111 if(i == 0)
112 hang(); 112 spl_error();
113 113
114 REG_DDRC_APB_PHYRST_CFG = 0x400000; 114 REG_DDRC_APB_PHYRST_CFG = 0x400000;
115 mdelay(3); 115 mdelay(3);
@@ -118,7 +118,7 @@ static void ddr_init(void)
118 118
119 REG_DDRC_CFG = 0xa468aec; 119 REG_DDRC_CFG = 0xa468aec;
120 REG_DDRC_CTRL = 2; 120 REG_DDRC_CTRL = 2;
121#if DDR_NEED_BYPASS 121#if SPL_DDR_NEED_BYPASS
122 REG_DDRPHY_PIR = 0x20020081; 122 REG_DDRPHY_PIR = 0x20020081;
123#else 123#else
124 REG_DDRPHY_PIR = 0x85; 124 REG_DDRPHY_PIR = 0x85;
@@ -132,10 +132,10 @@ static void ddr_init(void)
132 } 132 }
133 133
134 if(i == 0) 134 if(i == 0)
135 hang(); 135 spl_error();
136 136
137 if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0) 137 if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0)
138 hang(); 138 spl_error();
139 139
140 REG_DDRC_CTRL = 0; 140 REG_DDRC_CTRL = 0;
141 REG_DDRC_CTRL = 10; 141 REG_DDRC_CTRL = 10;
@@ -147,10 +147,10 @@ static void ddr_init(void)
147 REG_DDRC_TIMING4 = 0xb7a0251; 147 REG_DDRC_TIMING4 = 0xb7a0251;
148 REG_DDRC_TIMING5 = 0xff090200; 148 REG_DDRC_TIMING5 = 0xff090200;
149 REG_DDRC_TIMING6 = 0xa0a0202; 149 REG_DDRC_TIMING6 = 0xa0a0202;
150#if DDR_MEMORYSIZE == 64 150#if SPL_DDR_MEMORYSIZE == 64
151 REG_DDRC_MMAP0 = 0x20fc; 151 REG_DDRC_MMAP0 = 0x20fc;
152 REG_DDRC_MMAP1 = 0x2400; 152 REG_DDRC_MMAP1 = 0x2400;
153#elif DDR_MEMORYSIZE == 32 153#elif SPL_DDR_MEMORYSIZE == 32
154 REG_DDRC_MMAP0 = 0x20fe; 154 REG_DDRC_MMAP0 = 0x20fe;
155 REG_DDRC_MMAP1 = 0x2200; 155 REG_DDRC_MMAP1 = 0x2200;
156#else 156#else
@@ -160,13 +160,13 @@ static void ddr_init(void)
160 REG_DDRC_REFCNT = 0x2f0003; 160 REG_DDRC_REFCNT = 0x2f0003;
161 REG_DDRC_CTRL = 0xc91e; 161 REG_DDRC_CTRL = 0xc91e;
162 162
163#if DDR_MEMORYSIZE == 64 163#if SPL_DDR_MEMORYSIZE == 64
164 REG_DDRC_REMAP1 = 0x03020c0b; 164 REG_DDRC_REMAP1 = 0x03020c0b;
165 REG_DDRC_REMAP2 = 0x07060504; 165 REG_DDRC_REMAP2 = 0x07060504;
166 REG_DDRC_REMAP3 = 0x000a0908; 166 REG_DDRC_REMAP3 = 0x000a0908;
167 REG_DDRC_REMAP4 = 0x0f0e0d01; 167 REG_DDRC_REMAP4 = 0x0f0e0d01;
168 REG_DDRC_REMAP5 = 0x13121110; 168 REG_DDRC_REMAP5 = 0x13121110;
169#elif DDR_MEMORYSIZE == 32 169#elif SPL_DDR_MEMORYSIZE == 32
170 REG_DDRC_REMAP1 = 0x03020b0a; 170 REG_DDRC_REMAP1 = 0x03020b0a;
171 REG_DDRC_REMAP2 = 0x07060504; 171 REG_DDRC_REMAP2 = 0x07060504;
172 REG_DDRC_REMAP3 = 0x01000908; 172 REG_DDRC_REMAP3 = 0x01000908;
@@ -178,8 +178,8 @@ static void ddr_init(void)
178 178
179 REG_DDRC_STATUS &= ~0x40; 179 REG_DDRC_STATUS &= ~0x40;
180 180
181#if DDR_USE_AUTOSR 181#if SPL_DDR_AUTOSR_EN
182#if DDR_NEED_BYPASS 182#if SPL_DDR_NEED_BYPASS
183 jz_writef(CPM_DDRCDR, GATE_EN(1)); 183 jz_writef(CPM_DDRCDR, GATE_EN(1));
184 REG_DDRC_APB_CLKSTP_CFG = 0x9000000f; 184 REG_DDRC_APB_CLKSTP_CFG = 0x9000000f;
185#else 185#else
@@ -187,10 +187,10 @@ static void ddr_init(void)
187#endif 187#endif
188#endif 188#endif
189 189
190 REG_DDRC_AUTOSR_EN = DDR_USE_AUTOSR; 190 REG_DDRC_AUTOSR_EN = SPL_DDR_AUTOSR_EN;
191} 191}
192 192
193void main(void) 193static void init(void)
194{ 194{
195 /* from original firmware SPL */ 195 /* from original firmware SPL */
196 REG_CPM_PSWC0ST = 0x00; 196 REG_CPM_PSWC0ST = 0x00;
@@ -224,7 +224,89 @@ void main(void)
224 224
225 /* init DDR memory */ 225 /* init DDR memory */
226 ddr_init(); 226 ddr_init();
227}
228
229static int nandread(uint32_t addr, uint32_t size, void* buffer)
230{
231 int rc;
232
233 if((rc = nand_open()))
234 return rc;
235
236 rc = nand_read_bytes(addr, size, buffer);
237 nand_close();
238 return rc;
239}
240
241static int nandwrite(uint32_t addr, uint32_t size, void* buffer)
242{
243 int rc;
244
245 if((rc = nand_open()))
246 return rc;
247
248 if((rc = nand_enable_writes(true)))
249 goto _end;
250
251 if((rc = nand_erase_bytes(addr, size)))
252 goto _end1;
227 253
228 /* jump to the target's main routine */ 254 rc = nand_write_bytes(addr, size, buffer);
229 spl_main(); 255
256 _end1:
257 /* an error here is very unlikely, so ignore it */
258 nand_enable_writes(false);
259
260 _end:
261 nand_close();
262 return rc;
263}
264
265void main(void)
266{
267 if(!(SPL_ARGUMENTS->flags & SPL_FLAG_SKIP_INIT))
268 init();
269
270 switch(SPL_ARGUMENTS->command) {
271 case SPL_CMD_BOOT: {
272 int option = SPL_ARGUMENTS->param1;
273 if(option == SPL_BOOTOPT_CHOOSE)
274 option = spl_get_boot_option();
275 if(option == SPL_BOOTOPT_NONE)
276 return;
277
278 const struct spl_boot_option* opt = &spl_boot_options[option-1];
279 if(nandread(opt->nand_addr, opt->nand_size, (void*)opt->load_addr))
280 spl_error();
281
282 /* TODO: implement dual boot */
283
284 /* Reading the Linux command line from the bootloader is handled by
285 * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources.
286 *
287 * Rockbox doesn't use arguments, but passing them does not hurt and it
288 * saves an unnecessary branch.
289 */
290 entry_fn entry = (entry_fn)opt->exec_addr;
291 char** argv = (char**)0x80004000;
292 argv[0] = 0;
293 argv[1] = (char*)opt->cmdline;
294
295 commit_discard_idcache();
296 entry(2, argv, 0, 0);
297 __builtin_unreachable();
298 }
299
300 case SPL_CMD_FLASH_READ:
301 SPL_STATUS->err_code = nandread(SPL_ARGUMENTS->param1,
302 SPL_ARGUMENTS->param2,
303 (void*)SPL_BUFFER_ADDRESS);
304 return;
305
306 case SPL_CMD_FLASH_WRITE:
307 SPL_STATUS->err_code = nandwrite(SPL_ARGUMENTS->param1,
308 SPL_ARGUMENTS->param2,
309 (void*)SPL_BUFFER_ADDRESS);
310 return;
311 }
230} 312}
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.h b/firmware/target/mips/ingenic_x1000/spl-x1000.h
new file mode 100644
index 0000000000..44601438f3
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000.h
@@ -0,0 +1,49 @@
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#ifndef __SPL_X1000_H__
23#define __SPL_X1000_H__
24
25#include "spl-x1000-defs.h"
26
27#define SPL_ARGUMENTS ((struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS)
28#define SPL_STATUS ((struct x1000_spl_status*)SPL_STATUS_ADDRESS)
29
30struct spl_boot_option {
31 uint32_t nand_addr;
32 uint32_t nand_size;
33 uint32_t load_addr;
34 uint32_t exec_addr;
35 const char* cmdline; /* for Linux */
36};
37
38/* Defined by target, indices are 0 = ROCKBOX, 1 = ORIG_FW, etc... */
39extern const struct spl_boot_option spl_boot_options[];
40
41/* Called on a fatal error */
42void spl_error(void) __attribute__((noreturn));
43
44/* When SPL boots with SPL_BOOTOPTION_CHOOSE, this function is invoked
45 * to let the target figure out the boot option based on buttons the
46 * user is pressing */
47extern int spl_get_boot_option(void);
48
49#endif /* __SPL_X1000_H__ */