summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-05-11 13:28:43 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-05-12 10:35:20 +0000
commit3f26fcf34001197ed267fa1ad549095aae49c88e (patch)
treec81ab3298a349d1156e905d467492b603236f74d
parentcc22df198d0ccb64dfdfe0c2f247f7d86b7fd750 (diff)
downloadrockbox-3f26fcf34001197ed267fa1ad549095aae49c88e.tar.gz
rockbox-3f26fcf34001197ed267fa1ad549095aae49c88e.zip
FiiO M3K: New bootloaderbootloader_fiiom3k_v1
SPL and UCL-compressed bootloader are now packed into one output, bootloader.m3k, eliminating the separate SPL build phase. The Rockbox bootloader now has a recovery menu, accessible by holding VOL+ when booting, that lets you back up, restore, and update the bootloader from the device. Change-Id: I642c6e5fb83587a013ab2fbfd1adab439561ced2
-rw-r--r--bootloader/SOURCES2
-rw-r--r--bootloader/fiiom3k.c264
-rw-r--r--firmware/SOURCES8
-rw-r--r--firmware/export/installer.h31
-rw-r--r--firmware/target/mips/ingenic_x1000/boot.lds6
-rw-r--r--firmware/target/mips/ingenic_x1000/crt0.S33
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/boot.make30
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c345
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h51
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c38
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h29
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000-err.h27
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.c7
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.h9
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-start.S97
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000-defs.h66
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.c141
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.h11
-rw-r--r--firmware/target/mips/ingenic_x1000/spl.lds9
-rw-r--r--firmware/target/mips/ingenic_x1000/x1000boot.make53
-rwxr-xr-xtools/configure21
-rw-r--r--tools/root.make2
22 files changed, 790 insertions, 490 deletions
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index ff37971a8d..57c23b115c 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -89,6 +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) && !defined(BOOTLOADER_SPL) 92#elif defined(FIIO_M3K)
93fiiom3k.c 93fiiom3k.c
94#endif 94#endif
diff --git a/bootloader/fiiom3k.c b/bootloader/fiiom3k.c
index 9f169755ae..3d42ba7314 100644
--- a/bootloader/fiiom3k.c
+++ b/bootloader/fiiom3k.c
@@ -20,6 +20,7 @@
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "system.h" 22#include "system.h"
23#include "core_alloc.h"
23#include "kernel/kernel-internal.h" 24#include "kernel/kernel-internal.h"
24#include "i2c.h" 25#include "i2c.h"
25#include "power.h" 26#include "power.h"
@@ -35,6 +36,9 @@
35#include "rb-loader.h" 36#include "rb-loader.h"
36#include "loader_strerror.h" 37#include "loader_strerror.h"
37#include "version.h" 38#include "version.h"
39#include "installer-fiiom3k.h"
40#include "spl-x1000.h"
41#include "x1000/cpm.h"
38 42
39/* Load address where the binary needs to be placed */ 43/* Load address where the binary needs to be placed */
40extern unsigned char loadaddress[]; 44extern unsigned char loadaddress[];
@@ -59,6 +63,7 @@ void exec(void* dst, const void* src, int bytes)
59 63
60static bool lcd_inited = false; 64static bool lcd_inited = false;
61static bool usb_inited = false; 65static bool usb_inited = false;
66static bool disk_inited = false;
62 67
63static void init_lcd(void) 68static void init_lcd(void)
64{ 69{
@@ -79,6 +84,12 @@ static void init_lcd(void)
79 lcd_inited = true; 84 lcd_inited = true;
80} 85}
81 86
87static void put_version(void)
88{
89 lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2,
90 (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion);
91}
92
82static void do_splash2(int delay, const char* msg, const char* msg2) 93static void do_splash2(int delay, const char* msg, const char* msg2)
83{ 94{
84 init_lcd(); 95 init_lcd();
@@ -90,8 +101,7 @@ static void do_splash2(int delay, const char* msg, const char* msg2)
90 (LCD_HEIGHT + 2*SYSFONT_HEIGHT) / 2, msg2); 101 (LCD_HEIGHT + 2*SYSFONT_HEIGHT) / 2, msg2);
91 } 102 }
92 103
93 lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2, 104 put_version();
94 (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion);
95 lcd_update(); 105 lcd_update();
96 sleep(delay); 106 sleep(delay);
97} 107}
@@ -109,20 +119,232 @@ static void do_usb(void)
109 usb_inited = true; 119 usb_inited = true;
110 } 120 }
111 121
112 do_splash(0, "Waiting for USB"); 122 do_splash2(0, "Waiting for USB", "Press POWER to go back");
113 123
114 while(button_get(true) != SYS_USB_CONNECTED); 124 int btn;
115 do_splash(0, "USB mode"); 125 while(1) {
126 btn = button_get(true);
127 if(btn == SYS_USB_CONNECTED)
128 break;
129 else if(btn == BUTTON_POWER)
130 return;
131 }
116 132
133 do_splash(0, "USB mode");
117 usb_acknowledge(SYS_USB_CONNECTED_ACK); 134 usb_acknowledge(SYS_USB_CONNECTED_ACK);
118 while(button_get(true) != SYS_USB_DISCONNECTED); 135 while(button_get(true) != SYS_USB_DISCONNECTED);
119 136
120 do_splash(3*HZ, "USB disconnected"); 137 do_splash(3*HZ, "USB disconnected");
121} 138}
122 139
140static int init_disk(void)
141{
142 if(disk_inited)
143 return 0;
144
145 while(!storage_present(0)) {
146 do_splash2(0, "Insert SD card", "Press POWER for recovery");
147 int btn = button_get_w_tmo(HZ);
148 if(btn == BUTTON_POWER)
149 return 1;
150 }
151
152 if(disk_mount_all() <= 0) {
153 do_splash(5*HZ, "Cannot mount filesystem");
154 return 1;
155 }
156
157 disk_inited = true;
158 return 0;
159}
160
161static void do_boot(void)
162{
163 if(init_disk() != 0)
164 return;
165
166 int loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE);
167 if(loadsize <= 0) {
168 do_splash2(5*HZ, "Error loading Rockbox",
169 loader_strerror(loadsize));
170 do_usb();
171 return;
172 }
173
174 if(lcd_inited)
175 backlight_hw_off();
176
177 disable_irq();
178 exec(loadaddress, loadbuffer, loadsize);
179}
180
181#define INSTALL 0
182#define BACKUP 1
183#define RESTORE 2
184
185static void do_install(int which)
186{
187 int rc = init_disk();
188 if(rc != 0) {
189 do_splash2(5*HZ, "Install aborted", "No SD card present");
190 return;
191 }
192
193 const char* msg;
194 if(rc == INSTALL)
195 msg = "Installing";
196 else if(rc == BACKUP)
197 msg = "Backing up";
198 else
199 msg = "Restoring backup";
200
201 do_splash(0, msg);
202
203 if(which == INSTALL)
204 rc = install_boot("/bootloader.m3k");
205 else if(which == BACKUP)
206 rc = backup_boot("/fiiom3k-boot.bin");
207 else
208 rc = restore_boot("/fiiom3k-boot.bin");
209
210 char buf[32];
211 snprintf(buf, sizeof(buf), "Failed! Error: %d", rc);
212 const char* msg1 = rc == 0 ? "Success" : buf;
213 const char* msg2 = "Press POWER to continue";
214 do_splash2(0, msg1, msg2);
215
216 button_clear_queue();
217 while(button_get(true) != BUTTON_POWER);
218}
219
220static void recovery_menu(void)
221{
222 static const char* items[] = {
223 "--- Rockbox recovery menu ---",
224 "[System]",
225 " Start Rockbox",
226 " USB mode",
227 " Shutdown",
228 " Reboot",
229 "[Bootloader]",
230 " Install or update",
231 " Backup",
232 " Restore",
233 "",
234 "",
235 "",
236 "",
237 "",
238 "VOL+/VOL- move cursor",
239 "PLAY select item",
240 "POWER power off",
241 };
242
243 static const int nitems = sizeof(items) / sizeof(char*);
244
245 init_lcd();
246
247 int selection = 2;
248 do {
249 /* Draw menu */
250 lcd_clear_display();
251
252 for(int i = 0; i < nitems; ++i)
253 lcd_puts(0, i, items[i]);
254
255 if(items[selection][0] == ' ')
256 lcd_puts(0, selection, "=>");
257
258 put_version();
259 lcd_update();
260
261 /* Clear queue to avoid accidental input */
262 button_clear_queue();
263
264 /* Get the button */
265 int btn = button_get(true);
266
267 /* Process user input */
268 if(btn == BUTTON_VOL_UP) {
269 for(int i = selection-1; i >= 0; --i) {
270 if(items[i][0] == ' ') {
271 selection = i;
272 break;
273 }
274 }
275
276 continue;
277 } else if(btn == BUTTON_VOL_DOWN) {
278 for(int i = selection+1; i < nitems; ++i) {
279 if(items[i][0] == ' ') {
280 selection = i;
281 break;
282 }
283 }
284
285 continue;
286 } else if(btn == BUTTON_POWER) {
287 selection = 4; /* Shutdown */
288 } else if(btn != BUTTON_PLAY) {
289 continue;
290 }
291
292 /* User pressed PLAY so decide what action to take */
293 switch(selection) {
294 case 2: /* Start rockbox */
295 do_boot();
296 break;
297
298 case 3: /* USB mode */
299 do_usb();
300 break;
301
302 case 4: /* Shutdown */
303 do_splash(HZ, "Shutting down");
304 power_off();
305 break;
306
307 case 5: /* Reboot */
308 do_splash(HZ, "Rebooting");
309 system_reboot();
310 break;
311
312 case 7: /* Install bootloader */
313 do_install(INSTALL);
314 break;
315
316 case 8: /* Backup bootloader */
317 do_install(BACKUP);
318 break;
319
320 case 9: /* Restore bootloader */
321 do_install(RESTORE);
322 break;
323
324 default:
325 break;
326 }
327 } while(1);
328}
329
123void main(void) 330void main(void)
124{ 331{
332 bool recovery_mode = false;
333
334 /* This hack is needed because when USB booting, we cannot initialize
335 * clocks in the SPL -- it may break the mask ROM's USB code. So if the
336 * SPL has not already initialized the clocks, we need to do that now.
337 *
338 * Also use this as a sign that we should enter the recovery menu since
339 * this is probably the expected result if the user is USB booting...
340 */
341 if(jz_readf(CPM_MPCR, ENABLE)) {
342 spl_handle_pre_boot(0);
343 recovery_mode = true;
344 }
345
125 system_init(); 346 system_init();
347 core_allocator_init();
126 kernel_init(); 348 kernel_init();
127 i2c_init(); 349 i2c_init();
128 power_init(); 350 power_init();
@@ -136,32 +358,12 @@ void main(void)
136 358
137 filesystem_init(); 359 filesystem_init();
138 360
139 int loadsize = 0; 361 if(button_read_device() & BUTTON_VOL_UP)
140 do { 362 recovery_mode = true;
141 if(!storage_present(0)) {
142 do_splash(HZ, "Insert SD card");
143 continue;
144 }
145
146 if(disk_mount_all() <= 0) {
147 do_splash(5*HZ, "Cannot mount filesystem");
148 do_usb();
149 continue;
150 }
151
152 loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE);
153 if(loadsize <= 0) {
154 do_splash2(5*HZ, "Error loading Rockbox",
155 loader_strerror(loadsize));
156 do_usb();
157 continue;
158 }
159 } while(loadsize <= 0);
160 363
161 if(lcd_inited) 364 if(!recovery_mode)
162 backlight_hw_off(); 365 do_boot();
163 366
164 disable_irq(); 367 /* If boot fails or user holds Vol+, go to recovery menu */
165 368 recovery_menu();
166 exec(loadaddress, loadbuffer, loadsize);
167} 369}
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 8995e6a5b4..052847a6a6 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1664,9 +1664,9 @@ target/mips/ingenic_x1000/msc-x1000.c
1664#if (CONFIG_STORAGE & STORAGE_SD) 1664#if (CONFIG_STORAGE & STORAGE_SD)
1665target/mips/ingenic_x1000/sd-x1000.c 1665target/mips/ingenic_x1000/sd-x1000.c
1666#endif 1666#endif
1667#ifdef BOOTLOADER_SPL 1667target/mips/ingenic_x1000/spl-start.S
1668target/mips/ingenic_x1000/spl-x1000.c 1668target/mips/ingenic_x1000/spl-x1000.c
1669#endif 1669common/ucl_decompress.c
1670#endif /* CONFIG_CPU == X1000 */ 1670#endif /* CONFIG_CPU == X1000 */
1671 1671
1672#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777) 1672#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
@@ -1696,11 +1696,11 @@ target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c
1696target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c 1696target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c
1697target/mips/ingenic_x1000/fiiom3k/backlight-fiiom3k.c 1697target/mips/ingenic_x1000/fiiom3k/backlight-fiiom3k.c
1698target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c 1698target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
1699target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
1700target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c 1699target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
1701target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c 1700target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
1702#ifdef BOOTLOADER_SPL
1703target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c 1701target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
1702#ifdef BOOTLOADER
1703target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
1704#endif 1704#endif
1705#endif /* FIIO_M3K */ 1705#endif /* FIIO_M3K */
1706 1706
diff --git a/firmware/export/installer.h b/firmware/export/installer.h
deleted file mode 100644
index 802798618d..0000000000
--- a/firmware/export/installer.h
+++ /dev/null
@@ -1,31 +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#ifndef _INSTALLER_H_
23#define _INSTALLER_H_
24
25/* Provisional interface for installing/dumping a bootloader */
26
27extern int install_bootloader(const char* path);
28extern int dump_bootloader(const char* path);
29extern const char* installer_strerror(int rc);
30
31#endif /* _INSTALLER_H_ */
diff --git a/firmware/target/mips/ingenic_x1000/boot.lds b/firmware/target/mips/ingenic_x1000/boot.lds
index 81468a95fc..c274d69aab 100644
--- a/firmware/target/mips/ingenic_x1000/boot.lds
+++ b/firmware/target/mips/ingenic_x1000/boot.lds
@@ -1,5 +1 @@
1#ifdef BOOTLOADER_SPL #include "app.lds"
2# include "spl.lds"
3#else
4# include "app.lds"
5#endif
diff --git a/firmware/target/mips/ingenic_x1000/crt0.S b/firmware/target/mips/ingenic_x1000/crt0.S
index b717f96692..b36500b462 100644
--- a/firmware/target/mips/ingenic_x1000/crt0.S
+++ b/firmware/target/mips/ingenic_x1000/crt0.S
@@ -34,33 +34,6 @@
34 .section .init.text 34 .section .init.text
35 35
36_start: 36_start:
37 /* Clear data watchpoint */
38 mtc0 zero, C0_WATCHLO
39 mtc0 zero, C0_WATCHHI
40
41 /* Set BEV, ERL, mask interrupts */
42 li v0, 0x40fc04
43 mtc0 v0, C0_Status
44
45 /* Set Cause_IV to 1 (use special interrupt vector) */
46 li v0, M_CauseIV
47 mtc0 v0, C0_Cause
48
49 /* Set CPU_MODE and BUS_MODE to 1 in CPM_OPCR (Ingenic does this) */
50 lui v0, 0xb000
51 lw v1, 0x24(v0)
52 ori v1, v1, 0x22
53 sw v1, 0x24(v0)
54
55 /* Enable kseg0 cacheability */
56 li v0, 3
57 mtc0 v0, C0_Config
58 nop
59
60 /* According to ingenic: "enable idx-store-data cache insn" */
61 li v0, 0x20000000
62 mtc0 v0, C0_ErrCtl
63
64 /* Cache init */ 37 /* Cache init */
65 li v0, 0x80000000 38 li v0, 0x80000000
66 ori v1, v0, 0x4000 39 ori v1, v0, 0x4000
@@ -80,7 +53,6 @@ _cache_loop:
80 mtc0 v0, C0_Config, 7 53 mtc0 v0, C0_Config, 7
81 nop 54 nop
82 55
83#ifndef BOOTLOADER_SPL
84 /* Copy IRAM from BSS to low memory. */ 56 /* Copy IRAM from BSS to low memory. */
85 la t0, _iramcopy 57 la t0, _iramcopy
86 la t1, _iramstart 58 la t1, _iramstart
@@ -91,7 +63,6 @@ _iram_loop:
91 addiu t0, 4 63 addiu t0, 4
92 bne t1, t2, _iram_loop 64 bne t1, t2, _iram_loop
93 sw t3, -4(t1) 65 sw t3, -4(t1)
94#endif
95 66
96 /* Clear the BSS segment (needed to zero-initialize C static values) */ 67 /* Clear the BSS segment (needed to zero-initialize C static values) */
97 la t0, _bssbegin 68 la t0, _bssbegin
@@ -103,7 +74,6 @@ _bss_loop:
103 sw zero, -4(t0) 74 sw zero, -4(t0)
104_bss_done: 75_bss_done:
105 76
106#ifndef BOOTLOADER_SPL
107 /* Set stack pointer and clear the stack */ 77 /* Set stack pointer and clear the stack */
108 la sp, stackend 78 la sp, stackend
109 la t0, stackbegin 79 la t0, stackbegin
@@ -120,13 +90,11 @@ _irqstack_loop:
120 addiu t0, 4 90 addiu t0, 4
121 bne t0, k0, _irqstack_loop 91 bne t0, k0, _irqstack_loop
122 sw t1, -4(t0) 92 sw t1, -4(t0)
123#endif
124 93
125 /* Jump to C code */ 94 /* Jump to C code */
126 j main 95 j main
127 nop 96 nop
128 97
129#ifndef BOOTLOADER_SPL
130 /* Exception entry points */ 98 /* Exception entry points */
131 .section .vectors.1, "ax", %progbits 99 .section .vectors.1, "ax", %progbits
132 j tlb_refill_handler 100 j tlb_refill_handler
@@ -260,6 +228,5 @@ _exception_return:
260 lw sp, 0x80(sp) 228 lw sp, 0x80(sp)
261 eret 229 eret
262 nop 230 nop
263#endif
264 231
265 .set pop 232 .set pop
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/boot.make b/firmware/target/mips/ingenic_x1000/fiiom3k/boot.make
new file mode 100644
index 0000000000..77b23167c2
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/boot.make
@@ -0,0 +1,30 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10include $(ROOTDIR)/lib/microtar/microtar.make
11
12.SECONDEXPANSION:
13
14$(BUILDDIR)/spl.m3k: $(BUILDDIR)/spl.bin
15 $(call PRINTS,MKSPL $(@F))$(TOOLSDIR)/mkspl-x1000 -type=nand -ppb=2 -bpp=2 $< $@
16
17$(BUILDDIR)/bootloader.ucl: $(BUILDDIR)/bootloader.bin
18 $(call PRINTS,UCLPACK $(@F))$(TOOLSDIR)/uclpack --nrv2e -9 $< $@ >/dev/null
19
20.PHONY: $(BUILDDIR)/bootloader-info.txt
21$(BUILDDIR)/bootloader-info.txt:
22 $(call PRINTS,GEN $(@F))echo $(SVNVERSION) > $@
23
24$(BUILDDIR)/$(BINARY): $(BUILDDIR)/spl.m3k \
25 $(BUILDDIR)/bootloader.ucl \
26 $(BUILDDIR)/bootloader-info.txt
27 $(call PRINTS,TAR $(@F))tar -C $(BUILDDIR) \
28 --numeric-owner --no-acls --no-xattrs --no-selinux \
29 --mode=0644 --owner=0 --group=0 \
30 -cf $@ $(call full_path_subst,$(BUILDDIR)/%,%,$^)
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
index 154785ee0b..10a58ace38 100644
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
@@ -19,192 +19,265 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "installer.h" 22#include "installer-fiiom3k.h"
23#include "nand-x1000.h" 23#include "nand-x1000.h"
24#include "system.h" 24#include "system.h"
25#include "core_alloc.h" 25#include "core_alloc.h"
26#include "file.h" 26#include "file.h"
27#include "microtar.h"
28#include <stdint.h>
29#include <string.h>
30#include <stdio.h>
27 31
28#define INSTALL_SUCCESS 0 32#define IMAGE_SIZE (128 * 1024)
29#define ERR_FLASH_OPEN_FAILED (-1) 33#define TAR_SIZE (256 * 1024)
30#define ERR_FLASH_ENABLE_WP_FAILED (-2) 34
31#define ERR_FLASH_DISABLE_WP_FAILED (-3) 35static int flash_prepare(void)
32#define ERR_FLASH_ERASE_FAILED (-4)
33#define ERR_FLASH_WRITE_FAILED (-5)
34#define ERR_FLASH_READ_FAILED (-6)
35#define ERR_OUT_OF_MEMORY (-7)
36#define ERR_CANNOT_READ_FILE (-8)
37#define ERR_CANNOT_WRITE_FILE (-9)
38#define ERR_WRONG_SIZE (-10)
39
40#define BOOT_IMAGE_SIZE (128 * 1024)
41
42static int install_from_buffer(const void* buf)
43{ 36{
44 int status = INSTALL_SUCCESS;
45 int mf_id, dev_id; 37 int mf_id, dev_id;
38 int rc;
39
40 rc = nand_open();
41 if(rc < 0)
42 return INSTALL_ERR_FLASH(NAND_OPEN, rc);
46 43
47 if(nand_open()) 44 rc = nand_identify(&mf_id, &dev_id);
48 return ERR_FLASH_OPEN_FAILED; 45 if(rc < 0) {
49 if(nand_identify(&mf_id, &dev_id)) { 46 nand_close();
50 status = ERR_FLASH_OPEN_FAILED; 47 return INSTALL_ERR_FLASH(NAND_IDENTIFY, rc);
51 goto _exit;
52 } 48 }
53 49
54 if(nand_enable_writes(true)) { 50 return INSTALL_SUCCESS;
55 status = ERR_FLASH_DISABLE_WP_FAILED; 51}
56 goto _exit; 52
53static void flash_finish(void)
54{
55 /* Ensure writes are always disabled when we finish.
56 * Errors are safe to ignore here, there's nothing we could do anyway. */
57 nand_enable_writes(false);
58 nand_close();
59}
60
61static int flash_img_read(uint8_t* buffer)
62{
63 int rc = flash_prepare();
64 if(rc < 0)
65 goto error;
66
67 rc = nand_read(0, IMAGE_SIZE, buffer);
68 if(rc < 0) {
69 rc = INSTALL_ERR_FLASH(NAND_READ, rc);
70 goto error;
57 } 71 }
58 72
59 if(nand_erase(0, BOOT_IMAGE_SIZE)) { 73 error:
60 status = ERR_FLASH_ERASE_FAILED; 74 flash_finish();
61 goto _exit; 75 return rc;
76}
77
78static int flash_img_write(const uint8_t* buffer)
79{
80 int rc = flash_prepare();
81 if(rc < 0)
82 goto error;
83
84 rc = nand_enable_writes(true);
85 if(rc < 0) {
86 rc = INSTALL_ERR_FLASH(NAND_ENABLE_WRITES, rc);
87 goto error;
62 } 88 }
63 89
64 if(nand_write(0, BOOT_IMAGE_SIZE, (const uint8_t*)buf)) { 90 rc = nand_erase(0, IMAGE_SIZE);
65 status = ERR_FLASH_WRITE_FAILED; 91 if(rc < 0) {
66 goto _exit; 92 rc = INSTALL_ERR_FLASH(NAND_ERASE, rc);
93 goto error;
67 } 94 }
68 95
69 if(nand_enable_writes(false)) { 96 rc = nand_write(0, IMAGE_SIZE, buffer);
70 status = ERR_FLASH_ENABLE_WP_FAILED; 97 if(rc < 0) {
71 goto _exit; 98 rc = INSTALL_ERR_FLASH(NAND_WRITE, rc);
99 goto error;
72 } 100 }
73 101
74 _exit: 102 error:
75 nand_close(); 103 flash_finish();
76 return status; 104 return rc;
77} 105}
78 106
79static int dump_to_buffer(void* buf) 107static int patch_img(mtar_t* tar, uint8_t* buffer, const char* filename,
108 size_t patch_offset, size_t patch_size)
80{ 109{
81 int status = INSTALL_SUCCESS; 110 /* Seek to file */
82 int mf_id, dev_id; 111 mtar_header_t h;
83 112 int rc = mtar_find(tar, filename, &h);
84 if(nand_open()) 113 if(rc != MTAR_ESUCCESS) {
85 return ERR_FLASH_OPEN_FAILED; 114 rc = INSTALL_ERR_MTAR(TAR_FIND, rc);
86 if(nand_identify(&mf_id, &dev_id)) { 115 return rc;
87 status = ERR_FLASH_OPEN_FAILED;
88 goto _exit;
89 } 116 }
90 117
91 if(nand_read(0, BOOT_IMAGE_SIZE, (uint8_t*)buf)) { 118 /* We need a normal file */
92 status = ERR_FLASH_READ_FAILED; 119 if(h.type != 0 && h.type != MTAR_TREG)
93 goto _exit; 120 return INSTALL_ERR_BAD_FORMAT;
121
122 /* Check size does not exceed patch area */
123 if(h.size > patch_size)
124 return INSTALL_ERR_BAD_FORMAT;
125
126 /* Read data directly into patch area, fill unused bytes with 0xff */
127 memset(&buffer[patch_offset], 0xff, patch_size);
128 rc = mtar_read_data(tar, &buffer[patch_offset], h.size);
129 if(rc != MTAR_ESUCCESS) {
130 rc = INSTALL_ERR_MTAR(TAR_READ, rc);
131 return rc;
94 } 132 }
95 133
96 _exit: 134 return INSTALL_SUCCESS;
97 nand_close();
98 return status;
99} 135}
100 136
101int install_bootloader(const char* path) 137int install_boot(const char* srcfile)
102{ 138{
103 /* Allocate memory to hold image */ 139 int rc;
104 size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1; 140 mtar_t* tar = NULL;
105 int handle = core_alloc("boot_image", bufsize); 141 int handle = -1;
106 if(handle < 0)
107 return ERR_OUT_OF_MEMORY;
108
109 int status = INSTALL_SUCCESS;
110 void* buffer = core_get_data(handle);
111 CACHEALIGN_BUFFER(buffer, bufsize);
112 142
113 /* Open the boot image */ 143 /* Allocate enough memory for image and tar state */
114 int fd = open(path, O_RDONLY); 144 size_t bufsize = IMAGE_SIZE + sizeof(mtar_t) + 2*CACHEALIGN_SIZE;
115 if(fd < 0) { 145 handle = core_alloc("boot_image", bufsize);
116 status = ERR_CANNOT_READ_FILE; 146 if(handle < 0) {
117 goto _exit; 147 rc = INSTALL_ERR_OUT_OF_MEMORY;
148 goto error;
118 } 149 }
119 150
120 /* Check file size */ 151 uint8_t* buffer = core_get_data(handle);
121 off_t fsize = filesize(fd); 152
122 if(fsize != BOOT_IMAGE_SIZE) { 153 /* Tar state alloc */
123 status = ERR_WRONG_SIZE; 154 CACHEALIGN_BUFFER(buffer, bufsize);
124 goto _exit; 155 tar = (mtar_t*)buffer;
125 } 156 memset(tar, 0, sizeof(tar));
157
158 /* Image buffer alloc */
159 buffer += sizeof(mtar_t);
160 CACHEALIGN_BUFFER(buffer, bufsize);
161
162 /* Read the flash -- we need an existing image to patch */
163 rc = flash_img_read(buffer);
164 if(rc < 0)
165 goto error;
126 166
127 /* Read the file into the buffer */ 167 /* Open the tarball */
128 ssize_t cnt = read(fd, buffer, BOOT_IMAGE_SIZE); 168 rc = mtar_open(tar, srcfile, "r");
129 if(cnt != BOOT_IMAGE_SIZE) { 169 if(rc != MTAR_ESUCCESS) {
130 status = ERR_CANNOT_READ_FILE; 170 rc = INSTALL_ERR_MTAR(TAR_OPEN, rc);
131 goto _exit; 171 goto error;
132 } 172 }
133 173
134 /* Perform the installation */ 174 /* Extract the needed files & patch 'em in */
135 status = install_from_buffer(buffer); 175 rc = patch_img(tar, buffer, "spl.m3k", 0, 12 * 1024);
176 if(rc < 0)
177 goto error;
136 178
137 _exit: 179 rc = patch_img(tar, buffer, "bootloader.ucl", 0x6800, 102 * 1024);
138 if(fd >= 0) 180 if(rc < 0)
139 close(fd); 181 goto error;
140 core_free(handle); 182
141 return status; 183 /* Flash the new image */
184 rc = flash_img_write(buffer);
185 if(rc < 0)
186 goto error;
187
188 rc = INSTALL_SUCCESS;
189
190 error:
191 if(tar && tar->close)
192 mtar_close(tar);
193 if(handle >= 0)
194 core_free(handle);
195 return rc;
142} 196}
143 197
144/* Dump the current bootloader to a file */ 198int backup_boot(const char* destfile)
145int dump_bootloader(const char* path)
146{ 199{
147 /* Allocate memory to hold image */ 200 int rc;
148 size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1; 201 int handle = -1;
149 int handle = core_alloc("boot_image", bufsize);
150 if(handle < 0)
151 return -1;
152
153 /* Read data from flash */
154 int fd = -1; 202 int fd = -1;
155 void* buffer = core_get_data(handle); 203 size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
204 handle = core_alloc("boot_image", bufsize);
205 if(handle < 0) {
206 rc = INSTALL_ERR_OUT_OF_MEMORY;
207 goto error;
208 }
209
210 uint8_t* buffer = core_get_data(handle);
156 CACHEALIGN_BUFFER(buffer, bufsize); 211 CACHEALIGN_BUFFER(buffer, bufsize);
157 int status = dump_to_buffer(buffer);
158 if(status)
159 goto _exit;
160 212
161 /* Open file */ 213 rc = flash_img_read(buffer);
162 fd = open(path, O_CREAT|O_TRUNC|O_WRONLY); 214 if(rc < 0)
215 goto error;
216
217 fd = open(destfile, O_CREAT|O_TRUNC|O_WRONLY);
163 if(fd < 0) { 218 if(fd < 0) {
164 status = ERR_CANNOT_WRITE_FILE; 219 rc = INSTALL_ERR_FILE_IO;
165 goto _exit; 220 goto error;
166 } 221 }
167 222
168 /* Write data to file */ 223 ssize_t cnt = write(fd, buffer, IMAGE_SIZE);
169 ssize_t cnt = write(fd, buffer, BOOT_IMAGE_SIZE); 224 if(cnt != IMAGE_SIZE) {
170 if(cnt != BOOT_IMAGE_SIZE) { 225 rc = INSTALL_ERR_FILE_IO;
171 status = ERR_CANNOT_WRITE_FILE; 226 goto error;
172 goto _exit;
173 } 227 }
174 228
175 _exit: 229 error:
176 if(fd >= 0) 230 if(fd >= 0)
177 close(fd); 231 close(fd);
178 core_free(handle); 232 if(handle >= 0)
179 return status; 233 core_free(handle);
234 return rc;
180} 235}
181 236
182const char* installer_strerror(int rc) 237int restore_boot(const char* srcfile)
183{ 238{
184 switch(rc) { 239 int rc;
185 case INSTALL_SUCCESS: 240 int handle = -1;
186 return "Success"; 241 int fd = -1;
187 case ERR_FLASH_OPEN_FAILED: 242 size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
188 return "Can't open flash device"; 243 handle = core_alloc("boot_image", bufsize);
189 case ERR_FLASH_ENABLE_WP_FAILED: 244 if(handle < 0) {
190 return "Couldn't re-enable write protect"; 245 rc = INSTALL_ERR_OUT_OF_MEMORY;
191 case ERR_FLASH_DISABLE_WP_FAILED: 246 goto error;
192 return "Can't disable write protect";
193 case ERR_FLASH_ERASE_FAILED:
194 return "Flash erase failed";
195 case ERR_FLASH_WRITE_FAILED:
196 return "Flash write error";
197 case ERR_FLASH_READ_FAILED:
198 return "Flash read error";
199 case ERR_OUT_OF_MEMORY:
200 return "Out of memory";
201 case ERR_CANNOT_READ_FILE:
202 return "Error reading file";
203 case ERR_CANNOT_WRITE_FILE:
204 return "Error writing file";
205 case ERR_WRONG_SIZE:
206 return "Wrong file size";
207 default:
208 return "Unknown error";
209 } 247 }
248
249 uint8_t* buffer = core_get_data(handle);
250 CACHEALIGN_BUFFER(buffer, bufsize);
251
252 fd = open(srcfile, O_RDONLY);
253 if(fd < 0) {
254 rc = INSTALL_ERR_FILE_NOT_FOUND;
255 goto error;
256 }
257
258 off_t fsize = filesize(fd);
259 if(fsize != IMAGE_SIZE) {
260 rc = INSTALL_ERR_BAD_FORMAT;
261 goto error;
262 }
263
264 ssize_t cnt = read(fd, buffer, IMAGE_SIZE);
265 if(cnt != IMAGE_SIZE) {
266 rc = INSTALL_ERR_FILE_IO;
267 goto error;
268 }
269
270 close(fd);
271 fd = -1;
272
273 rc = flash_img_write(buffer);
274 if(rc < 0)
275 goto error;
276
277 error:
278 if(fd >= 0)
279 close(fd);
280 if(handle >= 0)
281 core_free(handle);
282 return rc;
210} 283}
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h
new file mode 100644
index 0000000000..eb700e6689
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.h
@@ -0,0 +1,51 @@
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 __INSTALLER_FIIOM3K_H__
23#define __INSTALLER_FIIOM3K_H__
24
25#include <stddef.h>
26
27#define INSTALL_SUCCESS 0
28#define INSTALL_ERR_OUT_OF_MEMORY (-1)
29#define INSTALL_ERR_FILE_NOT_FOUND (-2)
30#define INSTALL_ERR_FILE_IO (-3)
31#define INSTALL_ERR_BAD_FORMAT (-4)
32#define INSTALL_ERR_NAND_OPEN (-5)
33#define INSTALL_ERR_NAND_IDENTIFY (-6)
34#define INSTALL_ERR_NAND_READ (-7)
35#define INSTALL_ERR_NAND_ENABLE_WRITES (-8)
36#define INSTALL_ERR_NAND_ERASE (-9)
37#define INSTALL_ERR_NAND_WRITE (-10)
38#define INSTALL_ERR_TAR_OPEN (-11)
39#define INSTALL_ERR_TAR_FIND (-12)
40#define INSTALL_ERR_TAR_READ (-13)
41#define INSTALL_ERR_MTAR(x,y) ((INSTALL_ERR_##x)*100 + (y))
42#define INSTALL_ERR_FLASH(x,y) ((INSTALL_ERR_##x)*100 + (y))
43
44/* Install the Rockbox bootloader from a bootloader.m3k image */
45extern int install_boot(const char* srcfile);
46
47/* Backup or restore the bootloader from a raw NAND image */
48extern int backup_boot(const char* destfile);
49extern int restore_boot(const char* srcfile);
50
51#endif /* __INSTALLER_FIIOM3K_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
index bdd0ffc2e0..efea5aa323 100644
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
@@ -25,6 +25,11 @@
25#include "system.h" 25#include "system.h"
26#include <string.h> 26#include <string.h>
27 27
28/* Available boot options */
29#define BOOTOPTION_ROCKBOX 0
30#define BOOTOPTION_ORIG_FW 1
31#define BOOTOPTION_RECOVERY 2
32
28/* Boot select button state must remain stable for this duration 33/* Boot select button state must remain stable for this duration
29 * before the choice will be accepted. Currently 100ms. 34 * before the choice will be accepted. Currently 100ms.
30 */ 35 */
@@ -56,7 +61,7 @@ const struct spl_boot_option spl_boot_options[] = {
56 */ 61 */
57 .nand_addr = 0x6800, 62 .nand_addr = 0x6800,
58 .nand_size = 0x19800, 63 .nand_size = 0x19800,
59 .load_addr = X1000_DRAM_BASE - 8, /* first 8 bytes are bootloader ID */ 64 .load_addr = X1000_DRAM_END - 0x19800,
60 .exec_addr = X1000_DRAM_BASE, 65 .exec_addr = X1000_DRAM_BASE,
61 .cmdline = NULL, 66 .cmdline = NULL,
62 }, 67 },
@@ -80,7 +85,7 @@ const struct spl_boot_option spl_boot_options[] = {
80 85
81void spl_error(void) 86void spl_error(void)
82{ 87{
83 const int pin = (1 << 24); 88 const uint32_t pin = (1 << 24);
84 89
85 /* Turn on button light */ 90 /* Turn on button light */
86 jz_clr(GPIO_INT(GPIO_C), pin); 91 jz_clr(GPIO_INT(GPIO_C), pin);
@@ -105,6 +110,10 @@ int spl_get_boot_option(void)
105 110
106 uint32_t pin = 1, lastpin = 0; 111 uint32_t pin = 1, lastpin = 0;
107 uint32_t deadline = 0; 112 uint32_t deadline = 0;
113 /* Iteration count guards against unlikely case of broken buttons
114 * which never stabilize; if this occurs, we always boot Rockbox. */
115 int iter_count = 0;
116 const int max_iter_count = 30;
108 117
109 /* Configure the button GPIOs as inputs */ 118 /* Configure the button GPIOs as inputs */
110 gpio_config(GPIO_A, pinmask, GPIO_INPUT); 119 gpio_config(GPIO_A, pinmask, GPIO_INPUT);
@@ -116,19 +125,18 @@ int spl_get_boot_option(void)
116 if(pin != lastpin) { 125 if(pin != lastpin) {
117 /* This will always be set on the first iteration */ 126 /* This will always be set on the first iteration */
118 deadline = __ost_read32() + BTN_STABLE_TIME; 127 deadline = __ost_read32() + BTN_STABLE_TIME;
128 iter_count += 1;
119 } 129 }
120 } while(__ost_read32() < deadline); 130 } while(iter_count < max_iter_count && __ost_read32() < deadline);
121
122 /* Play button boots original firmware */
123 if(pin == (1 << 17))
124 return SPL_BOOTOPT_ORIG_FW;
125
126 /* Volume up boots recovery */
127 if(pin == (1 << 19))
128 return SPL_BOOTOPT_RECOVERY;
129 131
130 /* Default is to boot Rockbox */ 132 if(iter_count < max_iter_count && (pin & (1 << 17))) {
131 return SPL_BOOTOPT_ROCKBOX; 133 if(pin & (1 << 19))
134 return BOOTOPTION_RECOVERY; /* Play+Volume Up */
135 else
136 return BOOTOPTION_ORIG_FW; /* Play */
137 } else {
138 return BOOTOPTION_ROCKBOX; /* Volume Up or no buttons */
139 }
132} 140}
133 141
134void spl_handle_pre_boot(int bootopt) 142void spl_handle_pre_boot(int bootopt)
@@ -145,7 +153,7 @@ void spl_handle_pre_boot(int bootopt)
145 /* System clock setup -- common to Rockbox and FiiO firmware 153 /* System clock setup -- common to Rockbox and FiiO firmware
146 * ---- 154 * ----
147 * CPU at 1 GHz, L2 cache at 500 MHz 155 * CPU at 1 GHz, L2 cache at 500 MHz
148 * AHB0 and AHB2 and 200 MHz 156 * AHB0 and AHB2 at 200 MHz
149 * PCLK at 100 MHz 157 * PCLK at 100 MHz
150 * DDR at 200 MHz 158 * DDR at 200 MHz
151 */ 159 */
@@ -153,7 +161,7 @@ void spl_handle_pre_boot(int bootopt)
153 clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) | 161 clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) |
154 CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A)); 162 CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A));
155 163
156 if(bootopt == SPL_BOOTOPT_ROCKBOX) { 164 if(bootopt == BOOTOPTION_ROCKBOX) {
157 /* We don't use MPLL in Rockbox, so switch DDR memory to APLL */ 165 /* We don't use MPLL in Rockbox, so switch DDR memory to APLL */
158 clk_set_ddr(X1000_CLK_SCLK_A, 5); 166 clk_set_ddr(X1000_CLK_SCLK_A, 5);
159 167
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h
deleted file mode 100644
index ac90508f44..0000000000
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h
+++ /dev/null
@@ -1,29 +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#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/nand-x1000-err.h b/firmware/target/mips/ingenic_x1000/nand-x1000-err.h
deleted file mode 100644
index 869fe73ac9..0000000000
--- a/firmware/target/mips/ingenic_x1000/nand-x1000-err.h
+++ /dev/null
@@ -1,27 +0,0 @@
1#ifndef __NAND_X1000_ERR_H__
2#define __NAND_X1000_ERR_H__
3
4/* Error codes which can be returned by the nand-x1000 API. These codes are
5 * also used by host-side tools, so we define them here to avoid polluting
6 * the namespace with useless X1000 APIs. */
7#define NANDERR_CHIP_UNSUPPORTED (-1)
8#define NANDERR_WRITE_PROTECTED (-2)
9#define NANDERR_UNALIGNED_ADDRESS (-3)
10#define NANDERR_UNALIGNED_LENGTH (-4)
11#define NANDERR_READ_FAILED (-5)
12#define NANDERR_ECC_FAILED (-6)
13#define NANDERR_ERASE_FAILED (-7)
14#define NANDERR_PROGRAM_FAILED (-8)
15#define NANDERR_COMMAND_FAILED (-9)
16#define NANDERR_OTHER (-99)
17
18/* TEMPORARY -- compatibility hack for jztool's sake.
19 * This will go away once the new bootloader gets merged */
20#define NAND_SUCCESS 0
21#define NAND_ERR_UNKNOWN_CHIP NANDERR_CHIP_UNSUPPORTED
22#define NAND_ERR_UNALIGNED NANDERR_UNALIGNED_ADDRESS
23#define NAND_ERR_WRITE_PROTECT NANDERR_WRITE_PROTECTED
24#define NAND_ERR_CONTROLLER NANDERR_OTHER
25#define NAND_ERR_COMMAND NANDERR_COMMAND_FAILED
26
27#endif /* __NAND_X1000_ERR_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c
index 1770324fb3..fbac824789 100644
--- a/firmware/target/mips/ingenic_x1000/nand-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c
@@ -200,11 +200,8 @@ static int nand_rdwr(bool write, uint32_t addr, uint32_t size, uint8_t* buf)
200 return NAND_SUCCESS; 200 return NAND_SUCCESS;
201 if(write && !nand_drv.write_enabled) 201 if(write && !nand_drv.write_enabled)
202 return NAND_ERR_WRITE_PROTECT; 202 return NAND_ERR_WRITE_PROTECT;
203 /* FIXME: re-enable this check after merging new SPL+bootloader. 203 if((uint32_t)buf & (CACHEALIGN_SIZE - 1))
204 * It's only necessary for DMA, which is currently not used, but it's a 204 return NAND_ERR_UNALIGNED;
205 * good practice anyway. Disable for now due to SPL complications. */
206 /*if((uint32_t)buf & (CACHEALIGN_SIZE - 1))
207 return NAND_ERR_UNALIGNED;*/
208 205
209 addr >>= nand_drv.chip_data->log2_page_size; 206 addr >>= nand_drv.chip_data->log2_page_size;
210 size >>= nand_drv.chip_data->log2_page_size; 207 size >>= nand_drv.chip_data->log2_page_size;
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h
index 6c415b1170..f5db0bbfa5 100644
--- a/firmware/target/mips/ingenic_x1000/nand-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h
@@ -36,7 +36,14 @@
36#include <stdint.h> 36#include <stdint.h>
37#include <stdbool.h> 37#include <stdbool.h>
38#include <stddef.h> 38#include <stddef.h>
39#include "nand-x1000-err.h" 39
40/* Error codes which can be returned by the NAND API */
41#define NAND_SUCCESS 0
42#define NAND_ERR_UNKNOWN_CHIP (-1)
43#define NAND_ERR_UNALIGNED (-2)
44#define NAND_ERR_WRITE_PROTECT (-3)
45#define NAND_ERR_CONTROLLER (-4)
46#define NAND_ERR_COMMAND (-5)
40 47
41/* Chip supports quad I/O for page read/write */ 48/* Chip supports quad I/O for page read/write */
42#define NANDCHIP_FLAG_QUAD 0x01 49#define NANDCHIP_FLAG_QUAD 0x01
diff --git a/firmware/target/mips/ingenic_x1000/spl-start.S b/firmware/target/mips/ingenic_x1000/spl-start.S
new file mode 100644
index 0000000000..58346fe750
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/spl-start.S
@@ -0,0 +1,97 @@
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 "mips.h"
24
25 .text
26 .extern spl_main
27 .global _spl_start
28
29 .set push
30 .set mips32
31 .set noreorder
32 .set noat
33
34 .section .init.spl
35
36_spl_start:
37 /* Clear data watchpoint */
38 mtc0 zero, C0_WATCHLO
39 mtc0 zero, C0_WATCHHI
40
41 /* Set BEV, ERL, mask interrupts */
42 li v0, 0x40fc04
43 mtc0 v0, C0_Status
44
45 /* Set Cause_IV to 1 (use special interrupt vector) */
46 li v0, M_CauseIV
47 mtc0 v0, C0_Cause
48
49 /* Set CPU_MODE and BUS_MODE to 1 in CPM_OPCR (Ingenic does this) */
50 lui v0, 0xb000
51 lw v1, 0x24(v0)
52 ori v1, v1, 0x22
53 sw v1, 0x24(v0)
54
55 /* Enable kseg0 cacheability */
56 li v0, 3
57 mtc0 v0, C0_Config
58 nop
59
60 /* According to ingenic: "enable idx-store-data cache insn" */
61 li v0, 0x20000000
62 mtc0 v0, C0_ErrCtl
63
64 /* Cache init */
65 li v0, 0x80000000
66 ori v1, v0, 0x4000
67 mtc0 zero, C0_TAGLO
68 mtc0 zero, C0_TAGHI
69_cache_loop:
70 cache ICIndexStTag, 0(v0)
71 cache DCIndexStTag, 0(v0)
72 addiu v0, v0, 32
73 bne v0, v1, _cache_loop
74 nop
75
76 /* Invalidate BTB */
77 mfc0 v0, C0_Config, 7
78 nop
79 ori v0, v0, 2
80 mtc0 v0, C0_Config, 7
81 nop
82
83 /* Clear the BSS segment (needed to zero-initialize C static values) */
84 la t0, _bssbegin
85 la t1, _bssend
86 beq t0, t1, _bss_done
87_bss_loop:
88 addiu t0, 4
89 bne t0, t1, _bss_loop
90 sw zero, -4(t0)
91_bss_done:
92
93 /* Jump to C code */
94 j spl_main
95 nop
96
97 .set pop
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h b/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h
deleted file mode 100644
index 1d9f120ee2..0000000000
--- a/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h
+++ /dev/null
@@ -1,66 +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#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/firmware/target/mips/ingenic_x1000/spl-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c
index 6505cabbef..07453f6182 100644
--- a/firmware/target/mips/ingenic_x1000/spl-x1000.c
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c
@@ -20,7 +20,6 @@
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "spl-x1000.h" 22#include "spl-x1000.h"
23#include "spl-target.h"
24#include "clk-x1000.h" 23#include "clk-x1000.h"
25#include "nand-x1000.h" 24#include "nand-x1000.h"
26#include "system.h" 25#include "system.h"
@@ -29,16 +28,15 @@
29#include "x1000/ddrc.h" 28#include "x1000/ddrc.h"
30#include "x1000/ddrc_apb.h" 29#include "x1000/ddrc_apb.h"
31#include "x1000/ddrphy.h" 30#include "x1000/ddrphy.h"
31#include "ucl_decompress.h"
32 32
33struct x1000_spl_arguments* const spl_arguments = 33#ifdef FIIO_M3K
34 (struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS; 34# define SPL_DDR_MEMORYSIZE 64
35 35# define SPL_DDR_AUTOSR_EN 1
36struct x1000_spl_status* const spl_status = 36# define SPL_DDR_NEED_BYPASS 1
37 (struct x1000_spl_status*)SPL_STATUS_ADDRESS; 37#else
38 38# error "please add SPL memory definitions"
39/* defined to be Linux compatible; Rockbox needs no arguments so there 39#endif
40 * is no harm in passing them and we save a little code size */
41typedef void(*entry_fn)(int, char**, int, int);
42 40
43/* Note: This is based purely on disassembly of the SPL from the FiiO M3K. 41/* 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 42 * The code there is somewhat generic and corresponds roughly to Ingenic's
@@ -243,83 +241,70 @@ static int nandread(uint32_t addr, uint32_t size, void* buffer)
243 return rc; 241 return rc;
244} 242}
245 243
246static int nandwrite(uint32_t addr, uint32_t size, const void* buffer) 244/* Entry point function type, defined to be Linux compatible. */
247{ 245typedef void(*entry_fn)(int, char**, int, int);
248 int rc;
249 int mf_id, dev_id;
250 246
251 if((rc = nand_open())) 247/* Kernel command line arguments */
252 return rc; 248static char* argv[2];
253 if((rc = nand_identify(&mf_id, &dev_id))) {
254 nand_close();
255 return rc;
256 }
257 249
258 if((rc = nand_enable_writes(true))) 250/* This variable is defined by the maskrom. It's simply the level of the
259 goto _end; 251 * boot_sel[2:0] pins (GPIOs B28-30) at boot time. Meaning of the bits:
252 *
253 * boot_sel[2] boot_sel[1] boot_sel[0] Description
254 * -----------------------------------------------------------------
255 * 1 X X EXCLK is 26 MHz
256 * 0 X X EXCLK is 24 MHz
257 * X 1 1 Boot from SFC0
258 * X 0 1 Boot from MSC0
259 * X 1 0 Boot from USB 2.0 device
260 * -----------------------------------------------------------------
261 * Source: X1000 PM pg. 687, "XBurst Boot ROM Specification"
262 */
263extern const uint32_t boot_sel;
260 264
261 if((rc = nand_erase(addr, size))) 265void spl_main(void)
262 goto _end1; 266{
267 int opt_index;
268 uint8_t* load_addr;
269 const struct spl_boot_option* opt;
263 270
264 rc = nand_write(addr, size, (const uint8_t*)buffer); 271 /* Basic hardware init */
272 init();
265 273
266 _end1: 274 /* If doing a USB boot, host PC will upload 2nd stage itself,
267 /* an error here is very unlikely, so ignore it */ 275 * we should not load anything from flash or change clocks. */
268 nand_enable_writes(false); 276 if((boot_sel & 3) == 2)
277 return;
269 278
270 _end: 279 /* Get the boot option */
271 nand_close(); 280 opt_index = spl_get_boot_option();
272 return rc; 281 opt = &spl_boot_options[opt_index];
273} 282 load_addr = (uint8_t*)opt->load_addr;
274 283
275/* Kernel command line arguments */ 284 /* Set up hardware, load stuff from flash */
276static char* argv[2]; 285 spl_handle_pre_boot(opt_index);
286 if(nandread(opt->nand_addr, opt->nand_size, load_addr))
287 spl_error();
277 288
278void main(void) 289 if(!opt->cmdline) {
279{ 290 /* No command line => we are booting Rockbox, decompress bootloader.
280 if(!(SPL_ARGUMENTS->flags & SPL_FLAG_SKIP_INIT)) 291 * In the case of Rockbox, load binary directly to exec address */
281 init(); 292 uint32_t out_size = X1000_DRAM_END - opt->exec_addr;
282 293 int rc = ucl_unpack(load_addr, opt->nand_size,
283 switch(SPL_ARGUMENTS->command) { 294 (uint8_t*)opt->exec_addr, &out_size);
284 case SPL_CMD_BOOT: { 295 if(rc != UCL_E_OK)
285 int option = SPL_ARGUMENTS->param1;
286 if(option == SPL_BOOTOPT_CHOOSE)
287 option = spl_get_boot_option();
288 if(option == SPL_BOOTOPT_NONE)
289 return;
290
291 const struct spl_boot_option* opt = &spl_boot_options[option-1];
292 if(nandread(opt->nand_addr, opt->nand_size, (void*)opt->load_addr))
293 spl_error(); 296 spl_error();
294
295 /* Let target handle necessary pre-boot setup */
296 spl_handle_pre_boot(option);
297
298 /* Reading the Linux command line from the bootloader is handled by
299 * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources.
300 *
301 * Rockbox doesn't use arguments, but passing them does not hurt and it
302 * saves an unnecessary branch.
303 */
304 entry_fn entry = (entry_fn)opt->exec_addr;
305 argv[0] = 0;
306 argv[1] = (char*)opt->cmdline;
307
308 commit_discard_idcache();
309 entry(2, argv, 0, 0);
310 __builtin_unreachable();
311 } 297 }
312 298
313 case SPL_CMD_FLASH_READ: 299 /* Reading the Linux command line from the bootloader is handled by
314 SPL_STATUS->err_code = nandread(SPL_ARGUMENTS->param1, 300 * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. It's
315 SPL_ARGUMENTS->param2, 301 * simply an (int argc, char* argv[]) thing.
316 (void*)SPL_BUFFER_ADDRESS); 302 */
317 return; 303 entry_fn entry = (entry_fn)opt->exec_addr;
318 304 argv[0] = 0;
319 case SPL_CMD_FLASH_WRITE: 305 argv[1] = (char*)opt->cmdline;
320 SPL_STATUS->err_code = nandwrite(SPL_ARGUMENTS->param1, 306
321 SPL_ARGUMENTS->param2, 307 commit_discard_idcache();
322 (const void*)SPL_BUFFER_ADDRESS); 308 entry(2, argv, 0, 0);
323 return; 309 __builtin_unreachable();
324 }
325} 310}
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.h b/firmware/target/mips/ingenic_x1000/spl-x1000.h
index d2255a8d05..062cb40f88 100644
--- a/firmware/target/mips/ingenic_x1000/spl-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000.h
@@ -22,10 +22,7 @@
22#ifndef __SPL_X1000_H__ 22#ifndef __SPL_X1000_H__
23#define __SPL_X1000_H__ 23#define __SPL_X1000_H__
24 24
25#include "spl-x1000-defs.h" 25#include <stdint.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 26
30struct spl_boot_option { 27struct spl_boot_option {
31 uint32_t nand_addr; 28 uint32_t nand_addr;
@@ -35,15 +32,13 @@ struct spl_boot_option {
35 const char* cmdline; /* for Linux */ 32 const char* cmdline; /* for Linux */
36}; 33};
37 34
38/* Defined by target, indices are 0 = ROCKBOX, 1 = ORIG_FW, etc... */ 35/* Defined by target, order is not important */
39extern const struct spl_boot_option spl_boot_options[]; 36extern const struct spl_boot_option spl_boot_options[];
40 37
41/* Called on a fatal error */ 38/* Called on a fatal error */
42extern void spl_error(void) __attribute__((noreturn)); 39extern void spl_error(void) __attribute__((noreturn));
43 40
44/* When SPL boots with SPL_BOOTOPTION_CHOOSE, this function is invoked 41/* Invoked by SPL main routine to determine the boot option */
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); 42extern int spl_get_boot_option(void);
48 43
49/* Do any setup/initialization needed for the given boot option, this 44/* Do any setup/initialization needed for the given boot option, this
diff --git a/firmware/target/mips/ingenic_x1000/spl.lds b/firmware/target/mips/ingenic_x1000/spl.lds
index 36ae8c34d1..e932bd9c2e 100644
--- a/firmware/target/mips/ingenic_x1000/spl.lds
+++ b/firmware/target/mips/ingenic_x1000/spl.lds
@@ -3,8 +3,8 @@
3 3
4OUTPUT_FORMAT("elf32-littlemips") 4OUTPUT_FORMAT("elf32-littlemips")
5OUTPUT_ARCH(MIPS) 5OUTPUT_ARCH(MIPS)
6ENTRY(_start) 6ENTRY(_spl_start)
7STARTUP(target/mips/ingenic_x1000/crt0.o) 7STARTUP(target/mips/ingenic_x1000/spl-start.o)
8 8
9MEMORY { 9MEMORY {
10 /* First 4k of TCSM is used by mask ROM for stack + variables, 10 /* First 4k of TCSM is used by mask ROM for stack + variables,
@@ -15,9 +15,12 @@ MEMORY {
15 15
16SECTIONS 16SECTIONS
17{ 17{
18 /* Mask ROM variables, addresses found by disassembly */
19 boot_sel = X1000_TCSM_BASE + 0x1ec;
20
18 .text : 21 .text :
19 { 22 {
20 *(.init.text); 23 *(.init.spl);
21 *(.text*); 24 *(.text*);
22 *(.icode*); 25 *(.icode*);
23 } > TCSM 26 } > TCSM
diff --git a/firmware/target/mips/ingenic_x1000/x1000boot.make b/firmware/target/mips/ingenic_x1000/x1000boot.make
new file mode 100644
index 0000000000..e69b6a1439
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/x1000boot.make
@@ -0,0 +1,53 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10INCLUDES += -I$(APPSDIR)
11SRC += $(call preprocess, $(APPSDIR)/SOURCES)
12
13LDSDEP := $(FIRMDIR)/export/cpu.h $(FIRMDIR)/export/config/$(MODELNAME).h
14
15BOOTLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/boot.lds
16BOOTLINK := $(BUILDDIR)/boot.link
17
18SPLLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/spl.lds
19SPLLINK := $(BUILDDIR)/spl.link
20
21CLEANOBJS += $(BUILDDIR)/bootloader.* $(BUILDDIR)/spl.*
22
23include $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/$(MODELNAME)/boot.make
24
25.SECONDEXPANSION:
26
27$(BOOTLINK): $(BOOTLDS) $(LDSDEP)
28 $(call PRINTS,PP $(@F))
29 $(call preprocess2file,$<,$@,)
30
31$(BUILDDIR)/bootloader.elf: $$(OBJ) $(FIRMLIB) $(CORE_LIBS) $$(BOOTLINK)
32 $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \
33 -L$(BUILDDIR)/firmware -lfirmware \
34 -L$(BUILDDIR)/lib $(call a2lnk, $(CORE_LIBS)) \
35 -lgcc -T$(BOOTLINK) $(GLOBAL_LDOPTS) \
36 -Wl,--gc-sections -Wl,-Map,$(BUILDDIR)/bootloader.map
37
38$(BUILDDIR)/bootloader.bin: $(BUILDDIR)/bootloader.elf
39 $(call PRINTS,OC $(@F))$(call objcopy,$<,$@)
40
41$(SPLLINK): $(SPLLDS) $(LDSDEP)
42 $(call PRINTS,PP $(@F))
43 $(call preprocess2file,$<,$@,)
44
45$(BUILDDIR)/spl.elf: $$(OBJ) $(FIRMLIB) $(CORE_LIBS) $$(SPLLINK)
46 $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \
47 -L$(BUILDDIR)/firmware -lfirmware \
48 -L$(BUILDDIR)/lib $(call a2lnk, $(CORE_LIBS)) \
49 -lgcc -T$(SPLLINK) $(GLOBAL_LDOPTS) \
50 -Wl,--gc-sections -Wl,-Map,$(BUILDDIR)/spl.map
51
52$(BUILDDIR)/spl.bin: $(BUILDDIR)/spl.elf
53 $(call PRINTS,OC $(@F))$(call objcopy,$<,$@)
diff --git a/tools/configure b/tools/configure
index f1aa03fd08..9539dc687c 100755
--- a/tools/configure
+++ b/tools/configure
@@ -1624,7 +1624,8 @@ fi
1624 genericbitmaptools="$toolset bmp2rb" 1624 genericbitmaptools="$toolset bmp2rb"
1625 # scramble is used by all other targets 1625 # scramble is used by all other targets
1626 scramblebitmaptools="$genericbitmaptools scramble" 1626 scramblebitmaptools="$genericbitmaptools scramble"
1627 1627 # used by X1000 targets
1628 x1000tools="$genericbitmaptools scramble mkspl-x1000 uclpack"
1628 1629
1629 # ---- For each target ---- 1630 # ---- For each target ----
1630 # 1631 #
@@ -4100,15 +4101,13 @@ fi
4100 appextra="recorder:gui" 4101 appextra="recorder:gui"
4101 plugins="yes" 4102 plugins="yes"
4102 tool="$rootdir/tools/scramble -add=fiiom3k " 4103 tool="$rootdir/tools/scramble -add=fiiom3k "
4103 boottool="$rootdir/tools/scramble -add=fiiom3k " 4104 boottool="" # not used
4104 spltool="$rootdir/tools/mkspl-x1000 -type=nand -ppb=2 -bpp=2 "
4105 output="rockbox.m3k" 4105 output="rockbox.m3k"
4106 bootoutput="bootloader.m3k" 4106 bootoutput="bootloader.m3k"
4107 sploutput="spl.m3k"
4108 sysfontbl="16-Terminus" 4107 sysfontbl="16-Terminus"
4109 # toolset is the tools within the tools directory that we build for 4108 # toolset is the tools within the tools directory that we build for
4110 # this particular target. 4109 # this particular target.
4111 toolset="$toolset mkspl-x1000" 4110 toolset="$x1000tools"
4112 bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" 4111 bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
4113 bmp2rb_native="$rootdir/tools/bmp2rb -f 4" 4112 bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
4114 # architecture, manufacturer and model for the target-tree build 4113 # architecture, manufacturer and model for the target-tree build
@@ -4187,9 +4186,6 @@ case $modelname in
4187 sansae200) 4186 sansae200)
4188 gdbstub=", (E)raser" 4187 gdbstub=", (E)raser"
4189 ;; 4188 ;;
4190 fiiom3k)
4191 gdbstub=", (X) SPL loader"
4192 ;;
4193 *) 4189 *)
4194 ;; 4190 ;;
4195esac 4191esac
@@ -4215,15 +4211,6 @@ fi
4215 bootloader="1" 4211 bootloader="1"
4216 echo "sansa eraser build selected" 4212 echo "sansa eraser build selected"
4217 ;; 4213 ;;
4218 [Xx])
4219 appsdir='$(ROOTDIR)/bootloader'
4220 apps="bootloader"
4221 extradefines="$extradefines -DBOOTLOADER -DBOOTLOADER_SPL -ffunction-sections -fdata-sections"
4222 bootloader="1"
4223 tool="$spltool"
4224 output="$sploutput"
4225 echo "SPL bootloader build selected"
4226 ;;
4227 [Bb]) 4214 [Bb])
4228 appsdir='$(ROOTDIR)/bootloader' 4215 appsdir='$(ROOTDIR)/bootloader'
4229 apps="bootloader" 4216 apps="bootloader"
diff --git a/tools/root.make b/tools/root.make
index 70f81c0165..22834b3324 100644
--- a/tools/root.make
+++ b/tools/root.make
@@ -109,6 +109,8 @@ ifneq (,$(findstring bootloader,$(APPSDIR)))
109 include $(ROOTDIR)/firmware/target/hosted/aigo/erosq.make 109 include $(ROOTDIR)/firmware/target/hosted/aigo/erosq.make
110 else ifneq (,$(findstring fiio,$(APP_TYPE))) 110 else ifneq (,$(findstring fiio,$(APP_TYPE)))
111 include $(ROOTDIR)/firmware/target/hosted/fiio/fiio.make 111 include $(ROOTDIR)/firmware/target/hosted/fiio/fiio.make
112 else ifneq (,$(findstring ingenic_x1000,$(MANUFACTURER)))
113 include $(ROOTDIR)/firmware/target/mips/ingenic_x1000/x1000boot.make
112 else 114 else
113 include $(APPSDIR)/bootloader.make 115 include $(APPSDIR)/bootloader.make
114 endif 116 endif