summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootloader/SOURCES7
-rw-r--r--firmware/SOURCES6
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c (renamed from bootloader/fiiom3k-spl.c)112
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h29
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000-defs.h66
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.c (renamed from bootloader/x1000-spl.c)136
-rw-r--r--firmware/target/mips/ingenic_x1000/spl-x1000.h49
7 files changed, 279 insertions, 126 deletions
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index db9e05644c..446bdac0e1 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -89,11 +89,6 @@ show_logo.c
#elif defined(SANSA_CONNECT)
sansaconnect.c
show_logo.c
-#elif defined(FIIO_M3K)
-#ifdef BOOTLOADER_SPL
-x1000-spl.c
-fiiom3k-spl.c
-#else
+#elif defined(FIIO_M3K) && !defined(BOOTLOADER_SPL)
fiiom3k.c
#endif
-#endif
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 3a42381003..ce3d8d52e2 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1747,6 +1747,9 @@ target/mips/ingenic_x1000/msc-x1000.c
#if (CONFIG_STORAGE & STORAGE_SD)
target/mips/ingenic_x1000/sd-x1000.c
#endif
+#ifdef BOOTLOADER_SPL
+target/mips/ingenic_x1000/spl-x1000.c
+#endif
#endif /* CONFIG_CPU == X1000 */
#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
@@ -1780,6 +1783,9 @@ target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c
target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
+#ifdef BOOTLOADER_SPL
+target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
+#endif
#endif /* FIIO_M3K */
#if defined(LYRE_PROTO1)
diff --git a/bootloader/fiiom3k-spl.c b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
index 67b4b0a59c..0ebe11e24d 100644
--- a/bootloader/fiiom3k-spl.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c
@@ -19,28 +19,16 @@
*
****************************************************************************/
-#include "config.h"
-#include "nand-x1000.h"
+#include "spl-x1000.h"
#include "gpio-x1000.h"
-#include "mmu-mips.h"
+#include "nand-x1000.h"
+#include "system.h"
#include <string.h>
-/* "fiio" in little endian */
-#define BOOTMAGIC 0x6f696966
-
-/* Argument structure needed by Linux */
-struct linux_kargs {
- void* arg0;
- void* arg1;
-};
-
-#define LINUX_KARGSADDR 0x80004000
-
-static const char recovery_cmdline[] = "mem=xxM@0x0\
- no_console_suspend\
- console=ttyS2,115200n8\
- lpj=5009408\
- ip=off";
+/* Boot select button state must remain stable for this duration
+ * before the choice will be accepted. Currently 100ms.
+ */
+#define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000))
static const char normal_cmdline[] = "mem=64M@0x0\
no_console_suspend\
@@ -55,18 +43,13 @@ static const char normal_cmdline[] = "mem=64M@0x0\
rw\
loglevel=8";
-#define BOOTOPTION_ROCKBOX 0
-#define BOOTOPTION_FIIOLINUX 1
-#define BOOTOPTION_RECOVERY 2
-#define NUM_BOOTOPTIONS 3
-
-static const struct bootoption {
- uint32_t nand_addr;
- uint32_t nand_size;
- unsigned long load_addr;
- unsigned long exec_addr;
- const char* cmdline;
-} boot_options[NUM_BOOTOPTIONS] = {
+static const char recovery_cmdline[] = "mem=64M@0x0\
+ no_console_suspend\
+ console=ttyS2,115200n8\
+ lpj=5009408\
+ ip=off";
+
+const struct spl_boot_option spl_boot_options[] = {
{
/* Rockbox: the first unused NAND page is 26 KiB in, and the
* remainder of the block is unused, giving us 102 KiB to use.
@@ -95,10 +78,7 @@ static const struct bootoption {
},
};
-/* Simple diagnostic if something goes wrong -- a little nicer than wondering
- * what's going on when the machine hangs
- */
-void die(void)
+void spl_error(void)
{
const int pin = (1 << 24);
@@ -119,12 +99,7 @@ void die(void)
}
}
-/* Boot select button state must remain stable for this duration
- * before the choice will be accepted. Currently 100ms.
- */
-#define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000))
-
-int get_boot_option(void)
+int spl_get_boot_option(void)
{
const uint32_t pinmask = (1 << 17) | (1 << 19);
@@ -146,61 +121,12 @@ int get_boot_option(void)
/* Play button boots original firmware */
if(pin == (1 << 17))
- return BOOTOPTION_FIIOLINUX;
+ return SPL_BOOTOPT_ORIG_FW;
/* Volume up boots recovery */
if(pin == (1 << 19))
- return BOOTOPTION_RECOVERY;
+ return SPL_BOOTOPT_RECOVERY;
/* Default is to boot Rockbox */
- return BOOTOPTION_ROCKBOX;
-}
-
-void spl_main(void)
-{
- /* Get user boot option */
- int booti = get_boot_option();
- const struct bootoption* opt = &boot_options[booti];
-
- /* Load selected firmware from flash */
- if(nand_open())
- die();
- if(nand_read_bytes(opt->nand_addr, opt->nand_size, (void*)opt->load_addr))
- die();
-
- if(booti == BOOTOPTION_ROCKBOX) {
- /* If bootloader is not installed, return back to boot ROM.
- * Also read in the first eraseblock of NAND flash so it can be
- * dumped back over USB.
- */
- if(*(unsigned*)(opt->load_addr + 4) != BOOTMAGIC) {
- nand_read_bytes(0, 128 * 1024, (void*)0x80000000);
- commit_discard_idcache();
- return;
- }
- } else {
- /* TODO: Linux boot not implemented yet
- *
- * - Have to initialize UART2, as it's used for the serial console
- * - Must initialize APLL and change clocks over
- * - There are some other clocks which need to be initialized
- * - We should turn off OST since the OF SPL does not turn it on
- */
- die();
- }
-
- if(boot_options[booti].cmdline) {
- /* Handle Linux command line arguments */
- struct linux_kargs* kargs = (struct linux_kargs*)LINUX_KARGSADDR;
- kargs->arg0 = 0;
- kargs->arg1 = (void*)boot_options[booti].cmdline;
- }
-
- /* Flush caches and jump to address */
- void* execaddr = (void*)opt->exec_addr;
- commit_discard_idcache();
- __asm__ __volatile__ ("jr %0\n"
- "nop\n"
- :: "r"(execaddr));
- __builtin_unreachable();
+ return SPL_BOOTOPT_ROCKBOX;
}
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h
new file mode 100644
index 0000000000..ac90508f44
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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/spl-x1000-defs.h b/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h
new file mode 100644
index 0000000000..1d9f120ee2
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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/bootloader/x1000-spl.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c
index 1c780a9843..59e0fb687d 100644
--- a/bootloader/x1000-spl.c
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c
@@ -19,26 +19,26 @@
*
****************************************************************************/
-#include "system.h"
+#include "spl-x1000.h"
+#include "spl-target.h"
#include "clk-x1000.h"
+#include "nand-x1000.h"
+#include "system.h"
#include "x1000/cpm.h"
#include "x1000/ost.h"
#include "x1000/ddrc.h"
#include "x1000/ddrc_apb.h"
#include "x1000/ddrphy.h"
-#ifdef FIIO_M3K
-# define DDR_USE_AUTOSR 1
-# define DDR_NEED_BYPASS 1
-# define DDR_MEMORYSIZE 64
-#else
-# error "Please add DDR definitions for new target!"
-#endif
+struct x1000_spl_arguments* const spl_arguments =
+ (struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS;
-#define hang() do { } while(1)
+struct x1000_spl_status* const spl_status =
+ (struct x1000_spl_status*)SPL_STATUS_ADDRESS;
-/* Target-specific routine to load & execute the Rockbox bootloader */
-extern void spl_main(void);
+/* 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);
/* 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
@@ -95,9 +95,9 @@ static void ddr_init(void)
while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f)
i -= 1;
if(i == 0)
- hang();
+ spl_error();
-#if DDR_NEED_BYPASS
+#if SPL_DDR_NEED_BYPASS
REG_DDRPHY_ACDLLCR = 0x80000000;
REG_DDRPHY_DSGCR &= ~0x10;
REG_DDRPHY_DLLGCR |= 0x800000;
@@ -109,7 +109,7 @@ static void ddr_init(void)
while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f)
i -= 1;
if(i == 0)
- hang();
+ spl_error();
REG_DDRC_APB_PHYRST_CFG = 0x400000;
mdelay(3);
@@ -118,7 +118,7 @@ static void ddr_init(void)
REG_DDRC_CFG = 0xa468aec;
REG_DDRC_CTRL = 2;
-#if DDR_NEED_BYPASS
+#if SPL_DDR_NEED_BYPASS
REG_DDRPHY_PIR = 0x20020081;
#else
REG_DDRPHY_PIR = 0x85;
@@ -132,10 +132,10 @@ static void ddr_init(void)
}
if(i == 0)
- hang();
+ spl_error();
if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0)
- hang();
+ spl_error();
REG_DDRC_CTRL = 0;
REG_DDRC_CTRL = 10;
@@ -147,10 +147,10 @@ static void ddr_init(void)
REG_DDRC_TIMING4 = 0xb7a0251;
REG_DDRC_TIMING5 = 0xff090200;
REG_DDRC_TIMING6 = 0xa0a0202;
-#if DDR_MEMORYSIZE == 64
+#if SPL_DDR_MEMORYSIZE == 64
REG_DDRC_MMAP0 = 0x20fc;
REG_DDRC_MMAP1 = 0x2400;
-#elif DDR_MEMORYSIZE == 32
+#elif SPL_DDR_MEMORYSIZE == 32
REG_DDRC_MMAP0 = 0x20fe;
REG_DDRC_MMAP1 = 0x2200;
#else
@@ -160,13 +160,13 @@ static void ddr_init(void)
REG_DDRC_REFCNT = 0x2f0003;
REG_DDRC_CTRL = 0xc91e;
-#if DDR_MEMORYSIZE == 64
+#if SPL_DDR_MEMORYSIZE == 64
REG_DDRC_REMAP1 = 0x03020c0b;
REG_DDRC_REMAP2 = 0x07060504;
REG_DDRC_REMAP3 = 0x000a0908;
REG_DDRC_REMAP4 = 0x0f0e0d01;
REG_DDRC_REMAP5 = 0x13121110;
-#elif DDR_MEMORYSIZE == 32
+#elif SPL_DDR_MEMORYSIZE == 32
REG_DDRC_REMAP1 = 0x03020b0a;
REG_DDRC_REMAP2 = 0x07060504;
REG_DDRC_REMAP3 = 0x01000908;
@@ -178,8 +178,8 @@ static void ddr_init(void)
REG_DDRC_STATUS &= ~0x40;
-#if DDR_USE_AUTOSR
-#if DDR_NEED_BYPASS
+#if SPL_DDR_AUTOSR_EN
+#if SPL_DDR_NEED_BYPASS
jz_writef(CPM_DDRCDR, GATE_EN(1));
REG_DDRC_APB_CLKSTP_CFG = 0x9000000f;
#else
@@ -187,10 +187,10 @@ static void ddr_init(void)
#endif
#endif
- REG_DDRC_AUTOSR_EN = DDR_USE_AUTOSR;
+ REG_DDRC_AUTOSR_EN = SPL_DDR_AUTOSR_EN;
}
-void main(void)
+static void init(void)
{
/* from original firmware SPL */
REG_CPM_PSWC0ST = 0x00;
@@ -224,7 +224,89 @@ void main(void)
/* init DDR memory */
ddr_init();
+}
+
+static int nandread(uint32_t addr, uint32_t size, void* buffer)
+{
+ int rc;
+
+ if((rc = nand_open()))
+ return rc;
+
+ rc = nand_read_bytes(addr, size, buffer);
+ nand_close();
+ return rc;
+}
+
+static int nandwrite(uint32_t addr, uint32_t size, void* buffer)
+{
+ int rc;
+
+ if((rc = nand_open()))
+ return rc;
+
+ if((rc = nand_enable_writes(true)))
+ goto _end;
+
+ if((rc = nand_erase_bytes(addr, size)))
+ goto _end1;
- /* jump to the target's main routine */
- spl_main();
+ rc = nand_write_bytes(addr, size, buffer);
+
+ _end1:
+ /* an error here is very unlikely, so ignore it */
+ nand_enable_writes(false);
+
+ _end:
+ nand_close();
+ return rc;
+}
+
+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))
+ spl_error();
+
+ /* TODO: implement dual boot */
+
+ /* 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;
+ char** argv = (char**)0x80004000;
+ 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,
+ (void*)SPL_BUFFER_ADDRESS);
+ return;
+ }
}
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.h b/firmware/target/mips/ingenic_x1000/spl-x1000.h
new file mode 100644
index 0000000000..44601438f3
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/spl-x1000.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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_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)
+
+struct spl_boot_option {
+ uint32_t nand_addr;
+ uint32_t nand_size;
+ uint32_t load_addr;
+ uint32_t exec_addr;
+ const char* cmdline; /* for Linux */
+};
+
+/* Defined by target, indices are 0 = ROCKBOX, 1 = ORIG_FW, etc... */
+extern const struct spl_boot_option spl_boot_options[];
+
+/* Called on a fatal error */
+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 */
+extern int spl_get_boot_option(void);
+
+#endif /* __SPL_X1000_H__ */