summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
#elif defined(SANSA_CONNECT)
sansaconnect.c
show_logo.c
-#elif defined(FIIO_M3K) && !defined(BOOTLOADER_SPL)
+#elif defined(FIIO_M3K)
fiiom3k.c
#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 @@
****************************************************************************/
#include "system.h"
+#include "core_alloc.h"
#include "kernel/kernel-internal.h"
#include "i2c.h"
#include "power.h"
@@ -35,6 +36,9 @@
#include "rb-loader.h"
#include "loader_strerror.h"
#include "version.h"
+#include "installer-fiiom3k.h"
+#include "spl-x1000.h"
+#include "x1000/cpm.h"
/* Load address where the binary needs to be placed */
extern unsigned char loadaddress[];
@@ -59,6 +63,7 @@ void exec(void* dst, const void* src, int bytes)
static bool lcd_inited = false;
static bool usb_inited = false;
+static bool disk_inited = false;
static void init_lcd(void)
{
@@ -79,6 +84,12 @@ static void init_lcd(void)
lcd_inited = true;
}
+static void put_version(void)
+{
+ lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2,
+ (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion);
+}
+
static void do_splash2(int delay, const char* msg, const char* msg2)
{
init_lcd();
@@ -90,8 +101,7 @@ static void do_splash2(int delay, const char* msg, const char* msg2)
(LCD_HEIGHT + 2*SYSFONT_HEIGHT) / 2, msg2);
}
- lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2,
- (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion);
+ put_version();
lcd_update();
sleep(delay);
}
@@ -109,20 +119,232 @@ static void do_usb(void)
usb_inited = true;
}
- do_splash(0, "Waiting for USB");
+ do_splash2(0, "Waiting for USB", "Press POWER to go back");
- while(button_get(true) != SYS_USB_CONNECTED);
- do_splash(0, "USB mode");
+ int btn;
+ while(1) {
+ btn = button_get(true);
+ if(btn == SYS_USB_CONNECTED)
+ break;
+ else if(btn == BUTTON_POWER)
+ return;
+ }
+ do_splash(0, "USB mode");
usb_acknowledge(SYS_USB_CONNECTED_ACK);
while(button_get(true) != SYS_USB_DISCONNECTED);
do_splash(3*HZ, "USB disconnected");
}
+static int init_disk(void)
+{
+ if(disk_inited)
+ return 0;
+
+ while(!storage_present(0)) {
+ do_splash2(0, "Insert SD card", "Press POWER for recovery");
+ int btn = button_get_w_tmo(HZ);
+ if(btn == BUTTON_POWER)
+ return 1;
+ }
+
+ if(disk_mount_all() <= 0) {
+ do_splash(5*HZ, "Cannot mount filesystem");
+ return 1;
+ }
+
+ disk_inited = true;
+ return 0;
+}
+
+static void do_boot(void)
+{
+ if(init_disk() != 0)
+ return;
+
+ int loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE);
+ if(loadsize <= 0) {
+ do_splash2(5*HZ, "Error loading Rockbox",
+ loader_strerror(loadsize));
+ do_usb();
+ return;
+ }
+
+ if(lcd_inited)
+ backlight_hw_off();
+
+ disable_irq();
+ exec(loadaddress, loadbuffer, loadsize);
+}
+
+#define INSTALL 0
+#define BACKUP 1
+#define RESTORE 2
+
+static void do_install(int which)
+{
+ int rc = init_disk();
+ if(rc != 0) {
+ do_splash2(5*HZ, "Install aborted", "No SD card present");
+ return;
+ }
+
+ const char* msg;
+ if(rc == INSTALL)
+ msg = "Installing";
+ else if(rc == BACKUP)
+ msg = "Backing up";
+ else
+ msg = "Restoring backup";
+
+ do_splash(0, msg);
+
+ if(which == INSTALL)
+ rc = install_boot("/bootloader.m3k");
+ else if(which == BACKUP)
+ rc = backup_boot("/fiiom3k-boot.bin");
+ else
+ rc = restore_boot("/fiiom3k-boot.bin");
+
+ char buf[32];
+ snprintf(buf, sizeof(buf), "Failed! Error: %d", rc);
+ const char* msg1 = rc == 0 ? "Success" : buf;
+ const char* msg2 = "Press POWER to continue";
+ do_splash2(0, msg1, msg2);
+
+ button_clear_queue();
+ while(button_get(true) != BUTTON_POWER);
+}
+
+static void recovery_menu(void)
+{
+ static const char* items[] = {
+ "--- Rockbox recovery menu ---",
+ "[System]",
+ " Start Rockbox",
+ " USB mode",
+ " Shutdown",
+ " Reboot",
+ "[Bootloader]",
+ " Install or update",
+ " Backup",
+ " Restore",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "VOL+/VOL- move cursor",
+ "PLAY select item",
+ "POWER power off",
+ };
+
+ static const int nitems = sizeof(items) / sizeof(char*);
+
+ init_lcd();
+
+ int selection = 2;
+ do {
+ /* Draw menu */
+ lcd_clear_display();
+
+ for(int i = 0; i < nitems; ++i)
+ lcd_puts(0, i, items[i]);
+
+ if(items[selection][0] == ' ')
+ lcd_puts(0, selection, "=>");
+
+ put_version();
+ lcd_update();
+
+ /* Clear queue to avoid accidental input */
+ button_clear_queue();
+
+ /* Get the button */
+ int btn = button_get(true);
+
+ /* Process user input */
+ if(btn == BUTTON_VOL_UP) {
+ for(int i = selection-1; i >= 0; --i) {
+ if(items[i][0] == ' ') {
+ selection = i;
+ break;
+ }
+ }
+
+ continue;
+ } else if(btn == BUTTON_VOL_DOWN) {
+ for(int i = selection+1; i < nitems; ++i) {
+ if(items[i][0] == ' ') {
+ selection = i;
+ break;
+ }
+ }
+
+ continue;
+ } else if(btn == BUTTON_POWER) {
+ selection = 4; /* Shutdown */
+ } else if(btn != BUTTON_PLAY) {
+ continue;
+ }
+
+ /* User pressed PLAY so decide what action to take */
+ switch(selection) {
+ case 2: /* Start rockbox */
+ do_boot();
+ break;
+
+ case 3: /* USB mode */
+ do_usb();
+ break;
+
+ case 4: /* Shutdown */
+ do_splash(HZ, "Shutting down");
+ power_off();
+ break;
+
+ case 5: /* Reboot */
+ do_splash(HZ, "Rebooting");
+ system_reboot();
+ break;
+
+ case 7: /* Install bootloader */
+ do_install(INSTALL);
+ break;
+
+ case 8: /* Backup bootloader */
+ do_install(BACKUP);
+ break;
+
+ case 9: /* Restore bootloader */
+ do_install(RESTORE);
+ break;
+
+ default:
+ break;
+ }
+ } while(1);
+}
+
void main(void)
{
+ bool recovery_mode = false;
+
+ /* This hack is needed because when USB booting, we cannot initialize
+ * clocks in the SPL -- it may break the mask ROM's USB code. So if the
+ * SPL has not already initialized the clocks, we need to do that now.
+ *
+ * Also use this as a sign that we should enter the recovery menu since
+ * this is probably the expected result if the user is USB booting...
+ */
+ if(jz_readf(CPM_MPCR, ENABLE)) {
+ spl_handle_pre_boot(0);
+ recovery_mode = true;
+ }
+
system_init();
+ core_allocator_init();
kernel_init();
i2c_init();
power_init();
@@ -136,32 +358,12 @@ void main(void)
filesystem_init();
- int loadsize = 0;
- do {
- if(!storage_present(0)) {
- do_splash(HZ, "Insert SD card");
- continue;
- }
-
- if(disk_mount_all() <= 0) {
- do_splash(5*HZ, "Cannot mount filesystem");
- do_usb();
- continue;
- }
-
- loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE);
- if(loadsize <= 0) {
- do_splash2(5*HZ, "Error loading Rockbox",
- loader_strerror(loadsize));
- do_usb();
- continue;
- }
- } while(loadsize <= 0);
+ if(button_read_device() & BUTTON_VOL_UP)
+ recovery_mode = true;
- if(lcd_inited)
- backlight_hw_off();
+ if(!recovery_mode)
+ do_boot();
- disable_irq();
-
- exec(loadaddress, loadbuffer, loadsize);
+ /* If boot fails or user holds Vol+, go to recovery menu */
+ recovery_menu();
}
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
#if (CONFIG_STORAGE & STORAGE_SD)
target/mips/ingenic_x1000/sd-x1000.c
#endif
-#ifdef BOOTLOADER_SPL
+target/mips/ingenic_x1000/spl-start.S
target/mips/ingenic_x1000/spl-x1000.c
-#endif
+common/ucl_decompress.c
#endif /* CONFIG_CPU == X1000 */
#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
@@ -1696,11 +1696,11 @@ target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c
target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c
target/mips/ingenic_x1000/fiiom3k/backlight-fiiom3k.c
target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
-target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
-#ifdef BOOTLOADER_SPL
target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
+#ifdef BOOTLOADER
+target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
#endif
#endif /* FIIO_M3K */
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 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2021 Aidan MacDonald
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-
-#ifndef _INSTALLER_H_
-#define _INSTALLER_H_
-
-/* Provisional interface for installing/dumping a bootloader */
-
-extern int install_bootloader(const char* path);
-extern int dump_bootloader(const char* path);
-extern const char* installer_strerror(int rc);
-
-#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 @@
-#ifdef BOOTLOADER_SPL
-# include "spl.lds"
-#else
-# include "app.lds"
-#endif
+#include "app.lds"
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 @@
.section .init.text
_start:
- /* Clear data watchpoint */
- mtc0 zero, C0_WATCHLO
- mtc0 zero, C0_WATCHHI
-
- /* Set BEV, ERL, mask interrupts */
- li v0, 0x40fc04
- mtc0 v0, C0_Status
-
- /* Set Cause_IV to 1 (use special interrupt vector) */
- li v0, M_CauseIV
- mtc0 v0, C0_Cause
-
- /* Set CPU_MODE and BUS_MODE to 1 in CPM_OPCR (Ingenic does this) */
- lui v0, 0xb000
- lw v1, 0x24(v0)
- ori v1, v1, 0x22
- sw v1, 0x24(v0)
-
- /* Enable kseg0 cacheability */
- li v0, 3
- mtc0 v0, C0_Config
- nop
-
- /* According to ingenic: "enable idx-store-data cache insn" */
- li v0, 0x20000000
- mtc0 v0, C0_ErrCtl
-
/* Cache init */
li v0, 0x80000000
ori v1, v0, 0x4000
@@ -80,7 +53,6 @@ _cache_loop:
mtc0 v0, C0_Config, 7
nop
-#ifndef BOOTLOADER_SPL
/* Copy IRAM from BSS to low memory. */
la t0, _iramcopy
la t1, _iramstart
@@ -91,7 +63,6 @@ _iram_loop:
addiu t0, 4
bne t1, t2, _iram_loop
sw t3, -4(t1)
-#endif
/* Clear the BSS segment (needed to zero-initialize C static values) */
la t0, _bssbegin
@@ -103,7 +74,6 @@ _bss_loop:
sw zero, -4(t0)
_bss_done:
-#ifndef BOOTLOADER_SPL
/* Set stack pointer and clear the stack */
la sp, stackend
la t0, stackbegin
@@ -120,13 +90,11 @@ _irqstack_loop:
addiu t0, 4
bne t0, k0, _irqstack_loop
sw t1, -4(t0)
-#endif
/* Jump to C code */
j main
nop
-#ifndef BOOTLOADER_SPL
/* Exception entry points */
.section .vectors.1, "ax", %progbits
j tlb_refill_handler
@@ -260,6 +228,5 @@ _exception_return:
lw sp, 0x80(sp)
eret
nop
-#endif
.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 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+
+include $(ROOTDIR)/lib/microtar/microtar.make
+
+.SECONDEXPANSION:
+
+$(BUILDDIR)/spl.m3k: $(BUILDDIR)/spl.bin
+ $(call PRINTS,MKSPL $(@F))$(TOOLSDIR)/mkspl-x1000 -type=nand -ppb=2 -bpp=2 $< $@
+
+$(BUILDDIR)/bootloader.ucl: $(BUILDDIR)/bootloader.bin
+ $(call PRINTS,UCLPACK $(@F))$(TOOLSDIR)/uclpack --nrv2e -9 $< $@ >/dev/null
+
+.PHONY: $(BUILDDIR)/bootloader-info.txt
+$(BUILDDIR)/bootloader-info.txt:
+ $(call PRINTS,GEN $(@F))echo $(SVNVERSION) > $@
+
+$(BUILDDIR)/$(BINARY): $(BUILDDIR)/spl.m3k \
+ $(BUILDDIR)/bootloader.ucl \
+ $(BUILDDIR)/bootloader-info.txt
+ $(call PRINTS,TAR $(@F))tar -C $(BUILDDIR) \
+ --numeric-owner --no-acls --no-xattrs --no-selinux \
+ --mode=0644 --owner=0 --group=0 \
+ -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 @@
*
****************************************************************************/
-#include "installer.h"
+#include "installer-fiiom3k.h"
#include "nand-x1000.h"
#include "system.h"
#include "core_alloc.h"
#include "file.h"
+#include "microtar.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
-#define INSTALL_SUCCESS 0
-#define ERR_FLASH_OPEN_FAILED (-1)
-#define ERR_FLASH_ENABLE_WP_FAILED (-2)
-#define ERR_FLASH_DISABLE_WP_FAILED (-3)
-#define ERR_FLASH_ERASE_FAILED (-4)
-#define ERR_FLASH_WRITE_FAILED (-5)
-#define ERR_FLASH_READ_FAILED (-6)
-#define ERR_OUT_OF_MEMORY (-7)
-#define ERR_CANNOT_READ_FILE (-8)
-#define ERR_CANNOT_WRITE_FILE (-9)
-#define ERR_WRONG_SIZE (-10)
-
-#define BOOT_IMAGE_SIZE (128 * 1024)
-
-static int install_from_buffer(const void* buf)
+#define IMAGE_SIZE (128 * 1024)
+#define TAR_SIZE (256 * 1024)
+
+static int flash_prepare(void)
{
- int status = INSTALL_SUCCESS;
int mf_id, dev_id;
+ int rc;
+
+ rc = nand_open();
+ if(rc < 0)
+ return INSTALL_ERR_FLASH(NAND_OPEN, rc);
- if(nand_open())
- return ERR_FLASH_OPEN_FAILED;
- if(nand_identify(&mf_id, &dev_id)) {
- status = ERR_FLASH_OPEN_FAILED;
- goto _exit;
+ rc = nand_identify(&mf_id, &dev_id);
+ if(rc < 0) {
+ nand_close();
+ return INSTALL_ERR_FLASH(NAND_IDENTIFY, rc);
}
- if(nand_enable_writes(true)) {
- status = ERR_FLASH_DISABLE_WP_FAILED;
- goto _exit;
+ return INSTALL_SUCCESS;
+}
+
+static void flash_finish(void)
+{
+ /* Ensure writes are always disabled when we finish.
+ * Errors are safe to ignore here, there's nothing we could do anyway. */
+ nand_enable_writes(false);
+ nand_close();
+}
+
+static int flash_img_read(uint8_t* buffer)
+{
+ int rc = flash_prepare();
+ if(rc < 0)
+ goto error;
+
+ rc = nand_read(0, IMAGE_SIZE, buffer);
+ if(rc < 0) {
+ rc = INSTALL_ERR_FLASH(NAND_READ, rc);
+ goto error;
}
- if(nand_erase(0, BOOT_IMAGE_SIZE)) {
- status = ERR_FLASH_ERASE_FAILED;
- goto _exit;
+ error:
+ flash_finish();
+ return rc;
+}
+
+static int flash_img_write(const uint8_t* buffer)
+{
+ int rc = flash_prepare();
+ if(rc < 0)
+ goto error;
+
+ rc = nand_enable_writes(true);
+ if(rc < 0) {
+ rc = INSTALL_ERR_FLASH(NAND_ENABLE_WRITES, rc);
+ goto error;
}
- if(nand_write(0, BOOT_IMAGE_SIZE, (const uint8_t*)buf)) {
- status = ERR_FLASH_WRITE_FAILED;
- goto _exit;
+ rc = nand_erase(0, IMAGE_SIZE);
+ if(rc < 0) {
+ rc = INSTALL_ERR_FLASH(NAND_ERASE, rc);
+ goto error;
}
- if(nand_enable_writes(false)) {
- status = ERR_FLASH_ENABLE_WP_FAILED;
- goto _exit;
+ rc = nand_write(0, IMAGE_SIZE, buffer);
+ if(rc < 0) {
+ rc = INSTALL_ERR_FLASH(NAND_WRITE, rc);
+ goto error;
}
- _exit:
- nand_close();
- return status;
+ error:
+ flash_finish();
+ return rc;
}
-static int dump_to_buffer(void* buf)
+static int patch_img(mtar_t* tar, uint8_t* buffer, const char* filename,
+ size_t patch_offset, size_t patch_size)
{
- int status = INSTALL_SUCCESS;
- int mf_id, dev_id;
-
- if(nand_open())
- return ERR_FLASH_OPEN_FAILED;
- if(nand_identify(&mf_id, &dev_id)) {
- status = ERR_FLASH_OPEN_FAILED;
- goto _exit;
+ /* Seek to file */
+ mtar_header_t h;
+ int rc = mtar_find(tar, filename, &h);
+ if(rc != MTAR_ESUCCESS) {
+ rc = INSTALL_ERR_MTAR(TAR_FIND, rc);
+ return rc;
}
- if(nand_read(0, BOOT_IMAGE_SIZE, (uint8_t*)buf)) {
- status = ERR_FLASH_READ_FAILED;
- goto _exit;
+ /* We need a normal file */
+ if(h.type != 0 && h.type != MTAR_TREG)
+ return INSTALL_ERR_BAD_FORMAT;
+
+ /* Check size does not exceed patch area */
+ if(h.size > patch_size)
+ return INSTALL_ERR_BAD_FORMAT;
+
+ /* Read data directly into patch area, fill unused bytes with 0xff */
+ memset(&buffer[patch_offset], 0xff, patch_size);
+ rc = mtar_read_data(tar, &buffer[patch_offset], h.size);
+ if(rc != MTAR_ESUCCESS) {
+ rc = INSTALL_ERR_MTAR(TAR_READ, rc);
+ return rc;
}
- _exit:
- nand_close();
- return status;
+ return INSTALL_SUCCESS;
}
-int install_bootloader(const char* path)
+int install_boot(const char* srcfile)
{
- /* Allocate memory to hold image */
- size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1;
- int handle = core_alloc("boot_image", bufsize);
- if(handle < 0)
- return ERR_OUT_OF_MEMORY;
-
- int status = INSTALL_SUCCESS;
- void* buffer = core_get_data(handle);
- CACHEALIGN_BUFFER(buffer, bufsize);
+ int rc;
+ mtar_t* tar = NULL;
+ int handle = -1;
- /* Open the boot image */
- int fd = open(path, O_RDONLY);
- if(fd < 0) {
- status = ERR_CANNOT_READ_FILE;
- goto _exit;
+ /* Allocate enough memory for image and tar state */
+ size_t bufsize = IMAGE_SIZE + sizeof(mtar_t) + 2*CACHEALIGN_SIZE;
+ handle = core_alloc("boot_image", bufsize);
+ if(handle < 0) {
+ rc = INSTALL_ERR_OUT_OF_MEMORY;
+ goto error;
}
- /* Check file size */
- off_t fsize = filesize(fd);
- if(fsize != BOOT_IMAGE_SIZE) {
- status = ERR_WRONG_SIZE;
- goto _exit;
- }
+ uint8_t* buffer = core_get_data(handle);
+
+ /* Tar state alloc */
+ CACHEALIGN_BUFFER(buffer, bufsize);
+ tar = (mtar_t*)buffer;
+ memset(tar, 0, sizeof(tar));
+
+ /* Image buffer alloc */
+ buffer += sizeof(mtar_t);
+ CACHEALIGN_BUFFER(buffer, bufsize);
+
+ /* Read the flash -- we need an existing image to patch */
+ rc = flash_img_read(buffer);
+ if(rc < 0)
+ goto error;
- /* Read the file into the buffer */
- ssize_t cnt = read(fd, buffer, BOOT_IMAGE_SIZE);
- if(cnt != BOOT_IMAGE_SIZE) {
- status = ERR_CANNOT_READ_FILE;
- goto _exit;
+ /* Open the tarball */
+ rc = mtar_open(tar, srcfile, "r");
+ if(rc != MTAR_ESUCCESS) {
+ rc = INSTALL_ERR_MTAR(TAR_OPEN, rc);
+ goto error;
}
- /* Perform the installation */
- status = install_from_buffer(buffer);
+ /* Extract the needed files & patch 'em in */
+ rc = patch_img(tar, buffer, "spl.m3k", 0, 12 * 1024);
+ if(rc < 0)
+ goto error;
- _exit:
- if(fd >= 0)
- close(fd);
- core_free(handle);
- return status;
+ rc = patch_img(tar, buffer, "bootloader.ucl", 0x6800, 102 * 1024);
+ if(rc < 0)
+ goto error;
+
+ /* Flash the new image */
+ rc = flash_img_write(buffer);
+ if(rc < 0)
+ goto error;
+
+ rc = INSTALL_SUCCESS;
+
+ error:
+ if(tar && tar->close)
+ mtar_close(tar);
+ if(handle >= 0)
+ core_free(handle);
+ return rc;
}
-/* Dump the current bootloader to a file */
-int dump_bootloader(const char* path)
+int backup_boot(const char* destfile)
{
- /* Allocate memory to hold image */
- size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1;
- int handle = core_alloc("boot_image", bufsize);
- if(handle < 0)
- return -1;
-
- /* Read data from flash */
+ int rc;
+ int handle = -1;
int fd = -1;
- void* buffer = core_get_data(handle);
+ size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
+ handle = core_alloc("boot_image", bufsize);
+ if(handle < 0) {
+ rc = INSTALL_ERR_OUT_OF_MEMORY;
+ goto error;
+ }
+
+ uint8_t* buffer = core_get_data(handle);
CACHEALIGN_BUFFER(buffer, bufsize);
- int status = dump_to_buffer(buffer);
- if(status)
- goto _exit;
- /* Open file */
- fd = open(path, O_CREAT|O_TRUNC|O_WRONLY);
+ rc = flash_img_read(buffer);
+ if(rc < 0)
+ goto error;
+
+ fd = open(destfile, O_CREAT|O_TRUNC|O_WRONLY);
if(fd < 0) {
- status = ERR_CANNOT_WRITE_FILE;
- goto _exit;
+ rc = INSTALL_ERR_FILE_IO;
+ goto error;
}
- /* Write data to file */
- ssize_t cnt = write(fd, buffer, BOOT_IMAGE_SIZE);
- if(cnt != BOOT_IMAGE_SIZE) {
- status = ERR_CANNOT_WRITE_FILE;
- goto _exit;
+ ssize_t cnt = write(fd, buffer, IMAGE_SIZE);
+ if(cnt != IMAGE_SIZE) {
+ rc = INSTALL_ERR_FILE_IO;
+ goto error;
}
- _exit:
+ error:
if(fd >= 0)
close(fd);
- core_free(handle);
- return status;
+ if(handle >= 0)
+ core_free(handle);
+ return rc;
}
-const char* installer_strerror(int rc)
+int restore_boot(const char* srcfile)
{
- switch(rc) {
- case INSTALL_SUCCESS:
- return "Success";
- case ERR_FLASH_OPEN_FAILED:
- return "Can't open flash device";
- case ERR_FLASH_ENABLE_WP_FAILED:
- return "Couldn't re-enable write protect";
- case ERR_FLASH_DISABLE_WP_FAILED:
- return "Can't disable write protect";
- case ERR_FLASH_ERASE_FAILED:
- return "Flash erase failed";
- case ERR_FLASH_WRITE_FAILED:
- return "Flash write error";
- case ERR_FLASH_READ_FAILED:
- return "Flash read error";
- case ERR_OUT_OF_MEMORY:
- return "Out of memory";
- case ERR_CANNOT_READ_FILE:
- return "Error reading file";
- case ERR_CANNOT_WRITE_FILE:
- return "Error writing file";
- case ERR_WRONG_SIZE:
- return "Wrong file size";
- default:
- return "Unknown error";
+ int rc;
+ int handle = -1;
+ int fd = -1;
+ size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1;
+ handle = core_alloc("boot_image", bufsize);
+ if(handle < 0) {
+ rc = INSTALL_ERR_OUT_OF_MEMORY;
+ goto error;
}
+
+ uint8_t* buffer = core_get_data(handle);
+ CACHEALIGN_BUFFER(buffer, bufsize);
+
+ fd = open(srcfile, O_RDONLY);
+ if(fd < 0) {
+ rc = INSTALL_ERR_FILE_NOT_FOUND;
+ goto error;
+ }
+
+ off_t fsize = filesize(fd);
+ if(fsize != IMAGE_SIZE) {
+ rc = INSTALL_ERR_BAD_FORMAT;
+ goto error;
+ }
+
+ ssize_t cnt = read(fd, buffer, IMAGE_SIZE);
+ if(cnt != IMAGE_SIZE) {
+ rc = INSTALL_ERR_FILE_IO;
+ goto error;
+ }
+
+ close(fd);
+ fd = -1;
+
+ rc = flash_img_write(buffer);
+ if(rc < 0)
+ goto error;
+
+ error:
+ if(fd >= 0)
+ close(fd);
+ if(handle >= 0)
+ core_free(handle);
+ return rc;
}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2021 Aidan MacDonald
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __INSTALLER_FIIOM3K_H__
+#define __INSTALLER_FIIOM3K_H__
+
+#include <stddef.h>
+
+#define INSTALL_SUCCESS 0
+#define INSTALL_ERR_OUT_OF_MEMORY (-1)
+#define INSTALL_ERR_FILE_NOT_FOUND (-2)
+#define INSTALL_ERR_FILE_IO (-3)
+#define INSTALL_ERR_BAD_FORMAT (-4)
+#define INSTALL_ERR_NAND_OPEN (-5)
+#define INSTALL_ERR_NAND_IDENTIFY (-6)
+#define INSTALL_ERR_NAND_READ (-7)
+#define INSTALL_ERR_NAND_ENABLE_WRITES (-8)
+#define INSTALL_ERR_NAND_ERASE (-9)
+#define INSTALL_ERR_NAND_WRITE (-10)
+#define INSTALL_ERR_TAR_OPEN (-11)
+#define INSTALL_ERR_TAR_FIND (-12)
+#define INSTALL_ERR_TAR_READ (-13)
+#define INSTALL_ERR_MTAR(x,y) ((INSTALL_ERR_##x)*100 + (y))
+#define INSTALL_ERR_FLASH(x,y) ((INSTALL_ERR_##x)*100 + (y))
+
+/* Install the Rockbox bootloader from a bootloader.m3k image */
+extern int install_boot(const char* srcfile);
+
+/* Backup or restore the bootloader from a raw NAND image */
+extern int backup_boot(const char* destfile);
+extern int restore_boot(const char* srcfile);
+
+#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 @@
#include "system.h"
#include <string.h>
+/* Available boot options */
+#define BOOTOPTION_ROCKBOX 0
+#define BOOTOPTION_ORIG_FW 1
+#define BOOTOPTION_RECOVERY 2
+
/* Boot select button state must remain stable for this duration
* before the choice will be accepted. Currently 100ms.
*/
@@ -56,7 +61,7 @@ const struct spl_boot_option spl_boot_options[] = {
*/
.nand_addr = 0x6800,
.nand_size = 0x19800,
- .load_addr = X1000_DRAM_BASE - 8, /* first 8 bytes are bootloader ID */
+ .load_addr = X1000_DRAM_END - 0x19800,
.exec_addr = X1000_DRAM_BASE,
.cmdline = NULL,
},
@@ -80,7 +85,7 @@ const struct spl_boot_option spl_boot_options[] = {
void spl_error(void)
{
- const int pin = (1 << 24);
+ const uint32_t pin = (1 << 24);
/* Turn on button light */
jz_clr(GPIO_INT(GPIO_C), pin);
@@ -105,6 +110,10 @@ int spl_get_boot_option(void)
uint32_t pin = 1, lastpin = 0;
uint32_t deadline = 0;
+ /* Iteration count guards against unlikely case of broken buttons
+ * which never stabilize; if this occurs, we always boot Rockbox. */
+ int iter_count = 0;
+ const int max_iter_count = 30;
/* Configure the button GPIOs as inputs */
gpio_config(GPIO_A, pinmask, GPIO_INPUT);
@@ -116,19 +125,18 @@ int spl_get_boot_option(void)
if(pin != lastpin) {
/* This will always be set on the first iteration */
deadline = __ost_read32() + BTN_STABLE_TIME;
+ iter_count += 1;
}
- } while(__ost_read32() < deadline);
-
- /* Play button boots original firmware */
- if(pin == (1 << 17))
- return SPL_BOOTOPT_ORIG_FW;
-
- /* Volume up boots recovery */
- if(pin == (1 << 19))
- return SPL_BOOTOPT_RECOVERY;
+ } while(iter_count < max_iter_count && __ost_read32() < deadline);
- /* Default is to boot Rockbox */
- return SPL_BOOTOPT_ROCKBOX;
+ if(iter_count < max_iter_count && (pin & (1 << 17))) {
+ if(pin & (1 << 19))
+ return BOOTOPTION_RECOVERY; /* Play+Volume Up */
+ else
+ return BOOTOPTION_ORIG_FW; /* Play */
+ } else {
+ return BOOTOPTION_ROCKBOX; /* Volume Up or no buttons */
+ }
}
void spl_handle_pre_boot(int bootopt)
@@ -145,7 +153,7 @@ void spl_handle_pre_boot(int bootopt)
/* System clock setup -- common to Rockbox and FiiO firmware
* ----
* CPU at 1 GHz, L2 cache at 500 MHz
- * AHB0 and AHB2 and 200 MHz
+ * AHB0 and AHB2 at 200 MHz
* PCLK at 100 MHz
* DDR at 200 MHz
*/
@@ -153,7 +161,7 @@ void spl_handle_pre_boot(int bootopt)
clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) |
CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A));
- if(bootopt == SPL_BOOTOPT_ROCKBOX) {
+ if(bootopt == BOOTOPTION_ROCKBOX) {
/* We don't use MPLL in Rockbox, so switch DDR memory to APLL */
clk_set_ddr(X1000_CLK_SCLK_A, 5);
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 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2021 Aidan MacDonald
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-
-#ifndef __SPL_TARGET_H__
-#define __SPL_TARGET_H__
-
-#define SPL_DDR_MEMORYSIZE 64
-#define SPL_DDR_AUTOSR_EN 1
-#define SPL_DDR_NEED_BYPASS 1
-
-#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 @@
-#ifndef __NAND_X1000_ERR_H__
-#define __NAND_X1000_ERR_H__
-
-/* Error codes which can be returned by the nand-x1000 API. These codes are
- * also used by host-side tools, so we define them here to avoid polluting
- * the namespace with useless X1000 APIs. */
-#define NANDERR_CHIP_UNSUPPORTED (-1)
-#define NANDERR_WRITE_PROTECTED (-2)
-#define NANDERR_UNALIGNED_ADDRESS (-3)
-#define NANDERR_UNALIGNED_LENGTH (-4)
-#define NANDERR_READ_FAILED (-5)
-#define NANDERR_ECC_FAILED (-6)
-#define NANDERR_ERASE_FAILED (-7)
-#define NANDERR_PROGRAM_FAILED (-8)
-#define NANDERR_COMMAND_FAILED (-9)
-#define NANDERR_OTHER (-99)
-
-/* TEMPORARY -- compatibility hack for jztool's sake.
- * This will go away once the new bootloader gets merged */
-#define NAND_SUCCESS 0
-#define NAND_ERR_UNKNOWN_CHIP NANDERR_CHIP_UNSUPPORTED
-#define NAND_ERR_UNALIGNED NANDERR_UNALIGNED_ADDRESS
-#define NAND_ERR_WRITE_PROTECT NANDERR_WRITE_PROTECTED
-#define NAND_ERR_CONTROLLER NANDERR_OTHER
-#define NAND_ERR_COMMAND NANDERR_COMMAND_FAILED
-
-#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)
return NAND_SUCCESS;
if(write && !nand_drv.write_enabled)
return NAND_ERR_WRITE_PROTECT;
- /* FIXME: re-enable this check after merging new SPL+bootloader.
- * It's only necessary for DMA, which is currently not used, but it's a
- * good practice anyway. Disable for now due to SPL complications. */
- /*if((uint32_t)buf & (CACHEALIGN_SIZE - 1))
- return NAND_ERR_UNALIGNED;*/
+ if((uint32_t)buf & (CACHEALIGN_SIZE - 1))
+ return NAND_ERR_UNALIGNED;
addr >>= nand_drv.chip_data->log2_page_size;
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 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
-#include "nand-x1000-err.h"
+
+/* Error codes which can be returned by the NAND API */
+#define NAND_SUCCESS 0
+#define NAND_ERR_UNKNOWN_CHIP (-1)
+#define NAND_ERR_UNALIGNED (-2)
+#define NAND_ERR_WRITE_PROTECT (-3)
+#define NAND_ERR_CONTROLLER (-4)
+#define NAND_ERR_COMMAND (-5)
/* Chip supports quad I/O for page read/write */
#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2021 Aidan MacDonald
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "mips.h"
+
+ .text
+ .extern spl_main
+ .global _spl_start
+
+ .set push
+ .set mips32
+ .set noreorder
+ .set noat
+
+ .section .init.spl
+
+_spl_start:
+ /* Clear data watchpoint */
+ mtc0 zero, C0_WATCHLO
+ mtc0 zero, C0_WATCHHI
+
+ /* Set BEV, ERL, mask interrupts */
+ li v0, 0x40fc04
+ mtc0 v0, C0_Status
+
+ /* Set Cause_IV to 1 (use special interrupt vector) */
+ li v0, M_CauseIV
+ mtc0 v0, C0_Cause
+
+ /* Set CPU_MODE and BUS_MODE to 1 in CPM_OPCR (Ingenic does this) */
+ lui v0, 0xb000
+ lw v1, 0x24(v0)
+ ori v1, v1, 0x22
+ sw v1, 0x24(v0)
+
+ /* Enable kseg0 cacheability */
+ li v0, 3
+ mtc0 v0, C0_Config
+ nop
+
+ /* According to ingenic: "enable idx-store-data cache insn" */
+ li v0, 0x20000000
+ mtc0 v0, C0_ErrCtl
+
+ /* Cache init */
+ li v0, 0x80000000
+ ori v1, v0, 0x4000
+ mtc0 zero, C0_TAGLO
+ mtc0 zero, C0_TAGHI
+_cache_loop:
+ cache ICIndexStTag, 0(v0)
+ cache DCIndexStTag, 0(v0)
+ addiu v0, v0, 32
+ bne v0, v1, _cache_loop
+ nop
+
+ /* Invalidate BTB */
+ mfc0 v0, C0_Config, 7
+ nop
+ ori v0, v0, 2
+ mtc0 v0, C0_Config, 7
+ nop
+
+ /* Clear the BSS segment (needed to zero-initialize C static values) */
+ la t0, _bssbegin
+ la t1, _bssend
+ beq t0, t1, _bss_done
+_bss_loop:
+ addiu t0, 4
+ bne t0, t1, _bss_loop
+ sw zero, -4(t0)
+_bss_done:
+
+ /* Jump to C code */
+ j spl_main
+ nop
+
+ .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 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2021 Aidan MacDonald
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-
-#ifndef __SPL_X1000_DEFS_H__
-#define __SPL_X1000_DEFS_H__
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SPL_CMD_BOOT 0
-#define SPL_CMD_FLASH_READ 1
-#define SPL_CMD_FLASH_WRITE 2
-
-#define SPL_BOOTOPT_CHOOSE 0
-#define SPL_BOOTOPT_ROCKBOX 1
-#define SPL_BOOTOPT_ORIG_FW 2
-#define SPL_BOOTOPT_RECOVERY 3
-#define SPL_BOOTOPT_NONE 4
-
-#define SPL_FLAG_SKIP_INIT (1 << 0)
-
-#define SPL_MAX_SIZE (12 * 1024)
-#define SPL_LOAD_ADDRESS 0xf4001000
-#define SPL_EXEC_ADDRESS 0xf4001800
-#define SPL_ARGUMENTS_ADDRESS 0xf40011f0
-#define SPL_STATUS_ADDRESS 0xf40011e0
-#define SPL_BUFFER_ADDRESS 0xa0004000
-
-struct x1000_spl_arguments {
- uint32_t command;
- uint32_t param1;
- uint32_t param2;
- uint32_t flags;
-};
-
-struct x1000_spl_status {
- int err_code;
- int reserved;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#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 @@
****************************************************************************/
#include "spl-x1000.h"
-#include "spl-target.h"
#include "clk-x1000.h"
#include "nand-x1000.h"
#include "system.h"
@@ -29,16 +28,15 @@
#include "x1000/ddrc.h"
#include "x1000/ddrc_apb.h"
#include "x1000/ddrphy.h"
+#include "ucl_decompress.h"
-struct x1000_spl_arguments* const spl_arguments =
- (struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS;
-
-struct x1000_spl_status* const spl_status =
- (struct x1000_spl_status*)SPL_STATUS_ADDRESS;
-
-/* defined to be Linux compatible; Rockbox needs no arguments so there
- * is no harm in passing them and we save a little code size */
-typedef void(*entry_fn)(int, char**, int, int);
+#ifdef FIIO_M3K
+# define SPL_DDR_MEMORYSIZE 64
+# define SPL_DDR_AUTOSR_EN 1
+# define SPL_DDR_NEED_BYPASS 1
+#else
+# error "please add SPL memory definitions"
+#endif
/* Note: This is based purely on disassembly of the SPL from the FiiO M3K.
* 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)
return rc;
}
-static int nandwrite(uint32_t addr, uint32_t size, const void* buffer)
-{
- int rc;
- int mf_id, dev_id;
+/* Entry point function type, defined to be Linux compatible. */
+typedef void(*entry_fn)(int, char**, int, int);
- if((rc = nand_open()))
- return rc;
- if((rc = nand_identify(&mf_id, &dev_id))) {
- nand_close();
- return rc;
- }
+/* Kernel command line arguments */
+static char* argv[2];
- if((rc = nand_enable_writes(true)))
- goto _end;
+/* This variable is defined by the maskrom. It's simply the level of the
+ * boot_sel[2:0] pins (GPIOs B28-30) at boot time. Meaning of the bits:
+ *
+ * boot_sel[2] boot_sel[1] boot_sel[0] Description
+ * -----------------------------------------------------------------
+ * 1 X X EXCLK is 26 MHz
+ * 0 X X EXCLK is 24 MHz
+ * X 1 1 Boot from SFC0
+ * X 0 1 Boot from MSC0
+ * X 1 0 Boot from USB 2.0 device
+ * -----------------------------------------------------------------
+ * Source: X1000 PM pg. 687, "XBurst Boot ROM Specification"
+ */
+extern const uint32_t boot_sel;
- if((rc = nand_erase(addr, size)))
- goto _end1;
+void spl_main(void)
+{
+ int opt_index;
+ uint8_t* load_addr;
+ const struct spl_boot_option* opt;
- rc = nand_write(addr, size, (const uint8_t*)buffer);
+ /* Basic hardware init */
+ init();
- _end1:
- /* an error here is very unlikely, so ignore it */
- nand_enable_writes(false);
+ /* If doing a USB boot, host PC will upload 2nd stage itself,
+ * we should not load anything from flash or change clocks. */
+ if((boot_sel & 3) == 2)
+ return;
- _end:
- nand_close();
- return rc;
-}
+ /* Get the boot option */
+ opt_index = spl_get_boot_option();
+ opt = &spl_boot_options[opt_index];
+ load_addr = (uint8_t*)opt->load_addr;
-/* Kernel command line arguments */
-static char* argv[2];
+ /* Set up hardware, load stuff from flash */
+ spl_handle_pre_boot(opt_index);
+ if(nandread(opt->nand_addr, opt->nand_size, load_addr))
+ spl_error();
-void main(void)
-{
- if(!(SPL_ARGUMENTS->flags & SPL_FLAG_SKIP_INIT))
- init();
-
- switch(SPL_ARGUMENTS->command) {
- case SPL_CMD_BOOT: {
- int option = SPL_ARGUMENTS->param1;
- if(option == SPL_BOOTOPT_CHOOSE)
- option = spl_get_boot_option();
- if(option == SPL_BOOTOPT_NONE)
- return;
-
- const struct spl_boot_option* opt = &spl_boot_options[option-1];
- if(nandread(opt->nand_addr, opt->nand_size, (void*)opt->load_addr))
+ if(!opt->cmdline) {
+ /* No command line => we are booting Rockbox, decompress bootloader.
+ * In the case of Rockbox, load binary directly to exec address */
+ uint32_t out_size = X1000_DRAM_END - opt->exec_addr;
+ int rc = ucl_unpack(load_addr, opt->nand_size,
+ (uint8_t*)opt->exec_addr, &out_size);
+ if(rc != UCL_E_OK)
spl_error();
-
- /* Let target handle necessary pre-boot setup */
- spl_handle_pre_boot(option);
-
- /* Reading the Linux command line from the bootloader is handled by
- * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources.
- *
- * Rockbox doesn't use arguments, but passing them does not hurt and it
- * saves an unnecessary branch.
- */
- entry_fn entry = (entry_fn)opt->exec_addr;
- argv[0] = 0;
- argv[1] = (char*)opt->cmdline;
-
- commit_discard_idcache();
- entry(2, argv, 0, 0);
- __builtin_unreachable();
}
- case SPL_CMD_FLASH_READ:
- SPL_STATUS->err_code = nandread(SPL_ARGUMENTS->param1,
- SPL_ARGUMENTS->param2,
- (void*)SPL_BUFFER_ADDRESS);
- return;
-
- case SPL_CMD_FLASH_WRITE:
- SPL_STATUS->err_code = nandwrite(SPL_ARGUMENTS->param1,
- SPL_ARGUMENTS->param2,
- (const void*)SPL_BUFFER_ADDRESS);
- return;
- }
+ /* Reading the Linux command line from the bootloader is handled by
+ * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. It's
+ * simply an (int argc, char* argv[]) thing.
+ */
+ entry_fn entry = (entry_fn)opt->exec_addr;
+ argv[0] = 0;
+ argv[1] = (char*)opt->cmdline;
+
+ commit_discard_idcache();
+ entry(2, argv, 0, 0);
+ __builtin_unreachable();
}
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 @@
#ifndef __SPL_X1000_H__
#define __SPL_X1000_H__
-#include "spl-x1000-defs.h"
-
-#define SPL_ARGUMENTS ((struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS)
-#define SPL_STATUS ((struct x1000_spl_status*)SPL_STATUS_ADDRESS)
+#include <stdint.h>
struct spl_boot_option {
uint32_t nand_addr;
@@ -35,15 +32,13 @@ struct spl_boot_option {
const char* cmdline; /* for Linux */
};
-/* Defined by target, indices are 0 = ROCKBOX, 1 = ORIG_FW, etc... */
+/* Defined by target, order is not important */
extern const struct spl_boot_option spl_boot_options[];
/* Called on a fatal error */
extern void spl_error(void) __attribute__((noreturn));
-/* When SPL boots with SPL_BOOTOPTION_CHOOSE, this function is invoked
- * to let the target figure out the boot option based on buttons the
- * user is pressing */
+/* Invoked by SPL main routine to determine the boot option */
extern int spl_get_boot_option(void);
/* 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 @@
OUTPUT_FORMAT("elf32-littlemips")
OUTPUT_ARCH(MIPS)
-ENTRY(_start)
-STARTUP(target/mips/ingenic_x1000/crt0.o)
+ENTRY(_spl_start)
+STARTUP(target/mips/ingenic_x1000/spl-start.o)
MEMORY {
/* First 4k of TCSM is used by mask ROM for stack + variables,
@@ -15,9 +15,12 @@ MEMORY {
SECTIONS
{
+ /* Mask ROM variables, addresses found by disassembly */
+ boot_sel = X1000_TCSM_BASE + 0x1ec;
+
.text :
{
- *(.init.text);
+ *(.init.spl);
*(.text*);
*(.icode*);
} > 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 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+
+INCLUDES += -I$(APPSDIR)
+SRC += $(call preprocess, $(APPSDIR)/SOURCES)
+
+LDSDEP := $(FIRMDIR)/export/cpu.h $(FIRMDIR)/export/config/$(MODELNAME).h
+
+BOOTLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/boot.lds
+BOOTLINK := $(BUILDDIR)/boot.link
+
+SPLLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/spl.lds
+SPLLINK := $(BUILDDIR)/spl.link
+
+CLEANOBJS += $(BUILDDIR)/bootloader.* $(BUILDDIR)/spl.*
+
+include $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/$(MODELNAME)/boot.make
+
+.SECONDEXPANSION:
+
+$(BOOTLINK): $(BOOTLDS) $(LDSDEP)
+ $(call PRINTS,PP $(@F))
+ $(call preprocess2file,$<,$@,)
+
+$(BUILDDIR)/bootloader.elf: $$(OBJ) $(FIRMLIB) $(CORE_LIBS) $$(BOOTLINK)
+ $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \
+ -L$(BUILDDIR)/firmware -lfirmware \
+ -L$(BUILDDIR)/lib $(call a2lnk, $(CORE_LIBS)) \
+ -lgcc -T$(BOOTLINK) $(GLOBAL_LDOPTS) \
+ -Wl,--gc-sections -Wl,-Map,$(BUILDDIR)/bootloader.map
+
+$(BUILDDIR)/bootloader.bin: $(BUILDDIR)/bootloader.elf
+ $(call PRINTS,OC $(@F))$(call objcopy,$<,$@)
+
+$(SPLLINK): $(SPLLDS) $(LDSDEP)
+ $(call PRINTS,PP $(@F))
+ $(call preprocess2file,$<,$@,)
+
+$(BUILDDIR)/spl.elf: $$(OBJ) $(FIRMLIB) $(CORE_LIBS) $$(SPLLINK)
+ $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \
+ -L$(BUILDDIR)/firmware -lfirmware \
+ -L$(BUILDDIR)/lib $(call a2lnk, $(CORE_LIBS)) \
+ -lgcc -T$(SPLLINK) $(GLOBAL_LDOPTS) \
+ -Wl,--gc-sections -Wl,-Map,$(BUILDDIR)/spl.map
+
+$(BUILDDIR)/spl.bin: $(BUILDDIR)/spl.elf
+ $(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
genericbitmaptools="$toolset bmp2rb"
# scramble is used by all other targets
scramblebitmaptools="$genericbitmaptools scramble"
-
+ # used by X1000 targets
+ x1000tools="$genericbitmaptools scramble mkspl-x1000 uclpack"
# ---- For each target ----
#
@@ -4100,15 +4101,13 @@ fi
appextra="recorder:gui"
plugins="yes"
tool="$rootdir/tools/scramble -add=fiiom3k "
- boottool="$rootdir/tools/scramble -add=fiiom3k "
- spltool="$rootdir/tools/mkspl-x1000 -type=nand -ppb=2 -bpp=2 "
+ boottool="" # not used
output="rockbox.m3k"
bootoutput="bootloader.m3k"
- sploutput="spl.m3k"
sysfontbl="16-Terminus"
# toolset is the tools within the tools directory that we build for
# this particular target.
- toolset="$toolset mkspl-x1000"
+ toolset="$x1000tools"
bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
# architecture, manufacturer and model for the target-tree build
@@ -4187,9 +4186,6 @@ case $modelname in
sansae200)
gdbstub=", (E)raser"
;;
- fiiom3k)
- gdbstub=", (X) SPL loader"
- ;;
*)
;;
esac
@@ -4215,15 +4211,6 @@ fi
bootloader="1"
echo "sansa eraser build selected"
;;
- [Xx])
- appsdir='$(ROOTDIR)/bootloader'
- apps="bootloader"
- extradefines="$extradefines -DBOOTLOADER -DBOOTLOADER_SPL -ffunction-sections -fdata-sections"
- bootloader="1"
- tool="$spltool"
- output="$sploutput"
- echo "SPL bootloader build selected"
- ;;
[Bb])
appsdir='$(ROOTDIR)/bootloader'
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)))
include $(ROOTDIR)/firmware/target/hosted/aigo/erosq.make
else ifneq (,$(findstring fiio,$(APP_TYPE)))
include $(ROOTDIR)/firmware/target/hosted/fiio/fiio.make
+ else ifneq (,$(findstring ingenic_x1000,$(MANUFACTURER)))
+ include $(ROOTDIR)/firmware/target/mips/ingenic_x1000/x1000boot.make
else
include $(APPSDIR)/bootloader.make
endif