diff options
-rw-r--r-- | bootloader/SOURCES | 7 | ||||
-rw-r--r-- | firmware/SOURCES | 6 | ||||
-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.h | 29 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/spl-x1000-defs.h | 66 | ||||
-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.h | 49 |
7 files changed, 279 insertions, 126 deletions
diff --git a/bootloader/SOURCES b/bootloader/SOURCES index db9e05644c..446bdac0e1 100644 --- a/bootloader/SOURCES +++ b/bootloader/SOURCES | |||
@@ -89,11 +89,6 @@ show_logo.c | |||
89 | #elif defined(SANSA_CONNECT) | 89 | #elif defined(SANSA_CONNECT) |
90 | sansaconnect.c | 90 | sansaconnect.c |
91 | show_logo.c | 91 | show_logo.c |
92 | #elif defined(FIIO_M3K) | 92 | #elif defined(FIIO_M3K) && !defined(BOOTLOADER_SPL) |
93 | #ifdef BOOTLOADER_SPL | ||
94 | x1000-spl.c | ||
95 | fiiom3k-spl.c | ||
96 | #else | ||
97 | fiiom3k.c | 93 | fiiom3k.c |
98 | #endif | 94 | #endif |
99 | #endif | ||
diff --git a/firmware/SOURCES b/firmware/SOURCES index 3a42381003..ce3d8d52e2 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -1747,6 +1747,9 @@ target/mips/ingenic_x1000/msc-x1000.c | |||
1747 | #if (CONFIG_STORAGE & STORAGE_SD) | 1747 | #if (CONFIG_STORAGE & STORAGE_SD) |
1748 | target/mips/ingenic_x1000/sd-x1000.c | 1748 | target/mips/ingenic_x1000/sd-x1000.c |
1749 | #endif | 1749 | #endif |
1750 | #ifdef BOOTLOADER_SPL | ||
1751 | target/mips/ingenic_x1000/spl-x1000.c | ||
1752 | #endif | ||
1750 | #endif /* CONFIG_CPU == X1000 */ | 1753 | #endif /* CONFIG_CPU == X1000 */ |
1751 | 1754 | ||
1752 | #if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777) | 1755 | #if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777) |
@@ -1780,6 +1783,9 @@ target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c | |||
1780 | target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c | 1783 | target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c |
1781 | target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c | 1784 | target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c |
1782 | target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c | 1785 | target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c |
1786 | #ifdef BOOTLOADER_SPL | ||
1787 | target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c | ||
1788 | #endif | ||
1783 | #endif /* FIIO_M3K */ | 1789 | #endif /* FIIO_M3K */ |
1784 | 1790 | ||
1785 | #if defined(LYRE_PROTO1) | 1791 | #if defined(LYRE_PROTO1) |
diff --git a/bootloader/fiiom3k-spl.c b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c index 67b4b0a59c..0ebe11e24d 100644 --- a/bootloader/fiiom3k-spl.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c | |||
@@ -19,28 +19,16 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "config.h" | 22 | #include "spl-x1000.h" |
23 | #include "nand-x1000.h" | ||
24 | #include "gpio-x1000.h" | 23 | #include "gpio-x1000.h" |
25 | #include "mmu-mips.h" | 24 | #include "nand-x1000.h" |
25 | #include "system.h" | ||
26 | #include <string.h> | 26 | #include <string.h> |
27 | 27 | ||
28 | /* "fiio" in little endian */ | 28 | /* Boot select button state must remain stable for this duration |
29 | #define BOOTMAGIC 0x6f696966 | 29 | * before the choice will be accepted. Currently 100ms. |
30 | 30 | */ | |
31 | /* Argument structure needed by Linux */ | 31 | #define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000)) |
32 | struct linux_kargs { | ||
33 | void* arg0; | ||
34 | void* arg1; | ||
35 | }; | ||
36 | |||
37 | #define LINUX_KARGSADDR 0x80004000 | ||
38 | |||
39 | static const char recovery_cmdline[] = "mem=xxM@0x0\ | ||
40 | no_console_suspend\ | ||
41 | console=ttyS2,115200n8\ | ||
42 | lpj=5009408\ | ||
43 | ip=off"; | ||
44 | 32 | ||
45 | static const char normal_cmdline[] = "mem=64M@0x0\ | 33 | static const char normal_cmdline[] = "mem=64M@0x0\ |
46 | no_console_suspend\ | 34 | no_console_suspend\ |
@@ -55,18 +43,13 @@ static const char normal_cmdline[] = "mem=64M@0x0\ | |||
55 | rw\ | 43 | rw\ |
56 | loglevel=8"; | 44 | loglevel=8"; |
57 | 45 | ||
58 | #define BOOTOPTION_ROCKBOX 0 | 46 | static const char recovery_cmdline[] = "mem=64M@0x0\ |
59 | #define BOOTOPTION_FIIOLINUX 1 | 47 | no_console_suspend\ |
60 | #define BOOTOPTION_RECOVERY 2 | 48 | console=ttyS2,115200n8\ |
61 | #define NUM_BOOTOPTIONS 3 | 49 | lpj=5009408\ |
62 | 50 | ip=off"; | |
63 | static const struct bootoption { | 51 | |
64 | uint32_t nand_addr; | 52 | const struct spl_boot_option spl_boot_options[] = { |
65 | uint32_t nand_size; | ||
66 | unsigned long load_addr; | ||
67 | unsigned long exec_addr; | ||
68 | const char* cmdline; | ||
69 | } boot_options[NUM_BOOTOPTIONS] = { | ||
70 | { | 53 | { |
71 | /* Rockbox: the first unused NAND page is 26 KiB in, and the | 54 | /* Rockbox: the first unused NAND page is 26 KiB in, and the |
72 | * remainder of the block is unused, giving us 102 KiB to use. | 55 | * remainder of the block is unused, giving us 102 KiB to use. |
@@ -95,10 +78,7 @@ static const struct bootoption { | |||
95 | }, | 78 | }, |
96 | }; | 79 | }; |
97 | 80 | ||
98 | /* Simple diagnostic if something goes wrong -- a little nicer than wondering | 81 | void spl_error(void) |
99 | * what's going on when the machine hangs | ||
100 | */ | ||
101 | void die(void) | ||
102 | { | 82 | { |
103 | const int pin = (1 << 24); | 83 | const int pin = (1 << 24); |
104 | 84 | ||
@@ -119,12 +99,7 @@ void die(void) | |||
119 | } | 99 | } |
120 | } | 100 | } |
121 | 101 | ||
122 | /* Boot select button state must remain stable for this duration | 102 | int spl_get_boot_option(void) |
123 | * before the choice will be accepted. Currently 100ms. | ||
124 | */ | ||
125 | #define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000)) | ||
126 | |||
127 | int get_boot_option(void) | ||
128 | { | 103 | { |
129 | const uint32_t pinmask = (1 << 17) | (1 << 19); | 104 | const uint32_t pinmask = (1 << 17) | (1 << 19); |
130 | 105 | ||
@@ -146,61 +121,12 @@ int get_boot_option(void) | |||
146 | 121 | ||
147 | /* Play button boots original firmware */ | 122 | /* Play button boots original firmware */ |
148 | if(pin == (1 << 17)) | 123 | if(pin == (1 << 17)) |
149 | return BOOTOPTION_FIIOLINUX; | 124 | return SPL_BOOTOPT_ORIG_FW; |
150 | 125 | ||
151 | /* Volume up boots recovery */ | 126 | /* Volume up boots recovery */ |
152 | if(pin == (1 << 19)) | 127 | if(pin == (1 << 19)) |
153 | return BOOTOPTION_RECOVERY; | 128 | return SPL_BOOTOPT_RECOVERY; |
154 | 129 | ||
155 | /* Default is to boot Rockbox */ | 130 | /* Default is to boot Rockbox */ |
156 | return BOOTOPTION_ROCKBOX; | 131 | return SPL_BOOTOPT_ROCKBOX; |
157 | } | ||
158 | |||
159 | void spl_main(void) | ||
160 | { | ||
161 | /* Get user boot option */ | ||
162 | int booti = get_boot_option(); | ||
163 | const struct bootoption* opt = &boot_options[booti]; | ||
164 | |||
165 | /* Load selected firmware from flash */ | ||
166 | if(nand_open()) | ||
167 | die(); | ||
168 | if(nand_read_bytes(opt->nand_addr, opt->nand_size, (void*)opt->load_addr)) | ||
169 | die(); | ||
170 | |||
171 | if(booti == BOOTOPTION_ROCKBOX) { | ||
172 | /* If bootloader is not installed, return back to boot ROM. | ||
173 | * Also read in the first eraseblock of NAND flash so it can be | ||
174 | * dumped back over USB. | ||
175 | */ | ||
176 | if(*(unsigned*)(opt->load_addr + 4) != BOOTMAGIC) { | ||
177 | nand_read_bytes(0, 128 * 1024, (void*)0x80000000); | ||
178 | commit_discard_idcache(); | ||
179 | return; | ||
180 | } | ||
181 | } else { | ||
182 | /* TODO: Linux boot not implemented yet | ||
183 | * | ||
184 | * - Have to initialize UART2, as it's used for the serial console | ||
185 | * - Must initialize APLL and change clocks over | ||
186 | * - There are some other clocks which need to be initialized | ||
187 | * - We should turn off OST since the OF SPL does not turn it on | ||
188 | */ | ||
189 | die(); | ||
190 | } | ||
191 | |||
192 | if(boot_options[booti].cmdline) { | ||
193 | /* Handle Linux command line arguments */ | ||
194 | struct linux_kargs* kargs = (struct linux_kargs*)LINUX_KARGSADDR; | ||
195 | kargs->arg0 = 0; | ||
196 | kargs->arg1 = (void*)boot_options[booti].cmdline; | ||
197 | } | ||
198 | |||
199 | /* Flush caches and jump to address */ | ||
200 | void* execaddr = (void*)opt->exec_addr; | ||
201 | commit_discard_idcache(); | ||
202 | __asm__ __volatile__ ("jr %0\n" | ||
203 | "nop\n" | ||
204 | :: "r"(execaddr)); | ||
205 | __builtin_unreachable(); | ||
206 | } | 132 | } |
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h new file mode 100644 index 0000000000..ac90508f44 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-target.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __SPL_TARGET_H__ | ||
23 | #define __SPL_TARGET_H__ | ||
24 | |||
25 | #define SPL_DDR_MEMORYSIZE 64 | ||
26 | #define SPL_DDR_AUTOSR_EN 1 | ||
27 | #define SPL_DDR_NEED_BYPASS 1 | ||
28 | |||
29 | #endif /* __SPL_TARGET_H__ */ | ||
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h b/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h new file mode 100644 index 0000000000..1d9f120ee2 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/spl-x1000-defs.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __SPL_X1000_DEFS_H__ | ||
23 | #define __SPL_X1000_DEFS_H__ | ||
24 | |||
25 | #include <stdint.h> | ||
26 | |||
27 | #ifdef __cplusplus | ||
28 | extern "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 | |||
50 | struct x1000_spl_arguments { | ||
51 | uint32_t command; | ||
52 | uint32_t param1; | ||
53 | uint32_t param2; | ||
54 | uint32_t flags; | ||
55 | }; | ||
56 | |||
57 | struct x1000_spl_status { | ||
58 | int err_code; | ||
59 | int reserved; | ||
60 | }; | ||
61 | |||
62 | #ifdef __cplusplus | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | #endif /* __SPL_X1000_DEFS_H__ */ | ||
diff --git a/bootloader/x1000-spl.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c index 1c780a9843..59e0fb687d 100644 --- a/bootloader/x1000-spl.c +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c | |||
@@ -19,26 +19,26 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "system.h" | 22 | #include "spl-x1000.h" |
23 | #include "spl-target.h" | ||
23 | #include "clk-x1000.h" | 24 | #include "clk-x1000.h" |
25 | #include "nand-x1000.h" | ||
26 | #include "system.h" | ||
24 | #include "x1000/cpm.h" | 27 | #include "x1000/cpm.h" |
25 | #include "x1000/ost.h" | 28 | #include "x1000/ost.h" |
26 | #include "x1000/ddrc.h" | 29 | #include "x1000/ddrc.h" |
27 | #include "x1000/ddrc_apb.h" | 30 | #include "x1000/ddrc_apb.h" |
28 | #include "x1000/ddrphy.h" | 31 | #include "x1000/ddrphy.h" |
29 | 32 | ||
30 | #ifdef FIIO_M3K | 33 | struct x1000_spl_arguments* const spl_arguments = |
31 | # define DDR_USE_AUTOSR 1 | 34 | (struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS; |
32 | # define DDR_NEED_BYPASS 1 | ||
33 | # define DDR_MEMORYSIZE 64 | ||
34 | #else | ||
35 | # error "Please add DDR definitions for new target!" | ||
36 | #endif | ||
37 | 35 | ||
38 | #define hang() do { } while(1) | 36 | struct x1000_spl_status* const spl_status = |
37 | (struct x1000_spl_status*)SPL_STATUS_ADDRESS; | ||
39 | 38 | ||
40 | /* Target-specific routine to load & execute the Rockbox bootloader */ | 39 | /* defined to be Linux compatible; Rockbox needs no arguments so there |
41 | extern void spl_main(void); | 40 | * is no harm in passing them and we save a little code size */ |
41 | typedef void(*entry_fn)(int, char**, int, int); | ||
42 | 42 | ||
43 | /* Note: This is based purely on disassembly of the SPL from the FiiO M3K. | 43 | /* Note: This is based purely on disassembly of the SPL from the FiiO M3K. |
44 | * The code there is somewhat generic and corresponds roughly to Ingenic's | 44 | * The code there is somewhat generic and corresponds roughly to Ingenic's |
@@ -95,9 +95,9 @@ static void ddr_init(void) | |||
95 | while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f) | 95 | while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f) |
96 | i -= 1; | 96 | i -= 1; |
97 | if(i == 0) | 97 | if(i == 0) |
98 | hang(); | 98 | spl_error(); |
99 | 99 | ||
100 | #if DDR_NEED_BYPASS | 100 | #if SPL_DDR_NEED_BYPASS |
101 | REG_DDRPHY_ACDLLCR = 0x80000000; | 101 | REG_DDRPHY_ACDLLCR = 0x80000000; |
102 | REG_DDRPHY_DSGCR &= ~0x10; | 102 | REG_DDRPHY_DSGCR &= ~0x10; |
103 | REG_DDRPHY_DLLGCR |= 0x800000; | 103 | REG_DDRPHY_DLLGCR |= 0x800000; |
@@ -109,7 +109,7 @@ static void ddr_init(void) | |||
109 | while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f) | 109 | while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f) |
110 | i -= 1; | 110 | i -= 1; |
111 | if(i == 0) | 111 | if(i == 0) |
112 | hang(); | 112 | spl_error(); |
113 | 113 | ||
114 | REG_DDRC_APB_PHYRST_CFG = 0x400000; | 114 | REG_DDRC_APB_PHYRST_CFG = 0x400000; |
115 | mdelay(3); | 115 | mdelay(3); |
@@ -118,7 +118,7 @@ static void ddr_init(void) | |||
118 | 118 | ||
119 | REG_DDRC_CFG = 0xa468aec; | 119 | REG_DDRC_CFG = 0xa468aec; |
120 | REG_DDRC_CTRL = 2; | 120 | REG_DDRC_CTRL = 2; |
121 | #if DDR_NEED_BYPASS | 121 | #if SPL_DDR_NEED_BYPASS |
122 | REG_DDRPHY_PIR = 0x20020081; | 122 | REG_DDRPHY_PIR = 0x20020081; |
123 | #else | 123 | #else |
124 | REG_DDRPHY_PIR = 0x85; | 124 | REG_DDRPHY_PIR = 0x85; |
@@ -132,10 +132,10 @@ static void ddr_init(void) | |||
132 | } | 132 | } |
133 | 133 | ||
134 | if(i == 0) | 134 | if(i == 0) |
135 | hang(); | 135 | spl_error(); |
136 | 136 | ||
137 | if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0) | 137 | if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0) |
138 | hang(); | 138 | spl_error(); |
139 | 139 | ||
140 | REG_DDRC_CTRL = 0; | 140 | REG_DDRC_CTRL = 0; |
141 | REG_DDRC_CTRL = 10; | 141 | REG_DDRC_CTRL = 10; |
@@ -147,10 +147,10 @@ static void ddr_init(void) | |||
147 | REG_DDRC_TIMING4 = 0xb7a0251; | 147 | REG_DDRC_TIMING4 = 0xb7a0251; |
148 | REG_DDRC_TIMING5 = 0xff090200; | 148 | REG_DDRC_TIMING5 = 0xff090200; |
149 | REG_DDRC_TIMING6 = 0xa0a0202; | 149 | REG_DDRC_TIMING6 = 0xa0a0202; |
150 | #if DDR_MEMORYSIZE == 64 | 150 | #if SPL_DDR_MEMORYSIZE == 64 |
151 | REG_DDRC_MMAP0 = 0x20fc; | 151 | REG_DDRC_MMAP0 = 0x20fc; |
152 | REG_DDRC_MMAP1 = 0x2400; | 152 | REG_DDRC_MMAP1 = 0x2400; |
153 | #elif DDR_MEMORYSIZE == 32 | 153 | #elif SPL_DDR_MEMORYSIZE == 32 |
154 | REG_DDRC_MMAP0 = 0x20fe; | 154 | REG_DDRC_MMAP0 = 0x20fe; |
155 | REG_DDRC_MMAP1 = 0x2200; | 155 | REG_DDRC_MMAP1 = 0x2200; |
156 | #else | 156 | #else |
@@ -160,13 +160,13 @@ static void ddr_init(void) | |||
160 | REG_DDRC_REFCNT = 0x2f0003; | 160 | REG_DDRC_REFCNT = 0x2f0003; |
161 | REG_DDRC_CTRL = 0xc91e; | 161 | REG_DDRC_CTRL = 0xc91e; |
162 | 162 | ||
163 | #if DDR_MEMORYSIZE == 64 | 163 | #if SPL_DDR_MEMORYSIZE == 64 |
164 | REG_DDRC_REMAP1 = 0x03020c0b; | 164 | REG_DDRC_REMAP1 = 0x03020c0b; |
165 | REG_DDRC_REMAP2 = 0x07060504; | 165 | REG_DDRC_REMAP2 = 0x07060504; |
166 | REG_DDRC_REMAP3 = 0x000a0908; | 166 | REG_DDRC_REMAP3 = 0x000a0908; |
167 | REG_DDRC_REMAP4 = 0x0f0e0d01; | 167 | REG_DDRC_REMAP4 = 0x0f0e0d01; |
168 | REG_DDRC_REMAP5 = 0x13121110; | 168 | REG_DDRC_REMAP5 = 0x13121110; |
169 | #elif DDR_MEMORYSIZE == 32 | 169 | #elif SPL_DDR_MEMORYSIZE == 32 |
170 | REG_DDRC_REMAP1 = 0x03020b0a; | 170 | REG_DDRC_REMAP1 = 0x03020b0a; |
171 | REG_DDRC_REMAP2 = 0x07060504; | 171 | REG_DDRC_REMAP2 = 0x07060504; |
172 | REG_DDRC_REMAP3 = 0x01000908; | 172 | REG_DDRC_REMAP3 = 0x01000908; |
@@ -178,8 +178,8 @@ static void ddr_init(void) | |||
178 | 178 | ||
179 | REG_DDRC_STATUS &= ~0x40; | 179 | REG_DDRC_STATUS &= ~0x40; |
180 | 180 | ||
181 | #if DDR_USE_AUTOSR | 181 | #if SPL_DDR_AUTOSR_EN |
182 | #if DDR_NEED_BYPASS | 182 | #if SPL_DDR_NEED_BYPASS |
183 | jz_writef(CPM_DDRCDR, GATE_EN(1)); | 183 | jz_writef(CPM_DDRCDR, GATE_EN(1)); |
184 | REG_DDRC_APB_CLKSTP_CFG = 0x9000000f; | 184 | REG_DDRC_APB_CLKSTP_CFG = 0x9000000f; |
185 | #else | 185 | #else |
@@ -187,10 +187,10 @@ static void ddr_init(void) | |||
187 | #endif | 187 | #endif |
188 | #endif | 188 | #endif |
189 | 189 | ||
190 | REG_DDRC_AUTOSR_EN = DDR_USE_AUTOSR; | 190 | REG_DDRC_AUTOSR_EN = SPL_DDR_AUTOSR_EN; |
191 | } | 191 | } |
192 | 192 | ||
193 | void main(void) | 193 | static void init(void) |
194 | { | 194 | { |
195 | /* from original firmware SPL */ | 195 | /* from original firmware SPL */ |
196 | REG_CPM_PSWC0ST = 0x00; | 196 | REG_CPM_PSWC0ST = 0x00; |
@@ -224,7 +224,89 @@ void main(void) | |||
224 | 224 | ||
225 | /* init DDR memory */ | 225 | /* init DDR memory */ |
226 | ddr_init(); | 226 | ddr_init(); |
227 | } | ||
228 | |||
229 | static int nandread(uint32_t addr, uint32_t size, void* buffer) | ||
230 | { | ||
231 | int rc; | ||
232 | |||
233 | if((rc = nand_open())) | ||
234 | return rc; | ||
235 | |||
236 | rc = nand_read_bytes(addr, size, buffer); | ||
237 | nand_close(); | ||
238 | return rc; | ||
239 | } | ||
240 | |||
241 | static int nandwrite(uint32_t addr, uint32_t size, void* buffer) | ||
242 | { | ||
243 | int rc; | ||
244 | |||
245 | if((rc = nand_open())) | ||
246 | return rc; | ||
247 | |||
248 | if((rc = nand_enable_writes(true))) | ||
249 | goto _end; | ||
250 | |||
251 | if((rc = nand_erase_bytes(addr, size))) | ||
252 | goto _end1; | ||
227 | 253 | ||
228 | /* jump to the target's main routine */ | 254 | rc = nand_write_bytes(addr, size, buffer); |
229 | spl_main(); | 255 | |
256 | _end1: | ||
257 | /* an error here is very unlikely, so ignore it */ | ||
258 | nand_enable_writes(false); | ||
259 | |||
260 | _end: | ||
261 | nand_close(); | ||
262 | return rc; | ||
263 | } | ||
264 | |||
265 | void main(void) | ||
266 | { | ||
267 | if(!(SPL_ARGUMENTS->flags & SPL_FLAG_SKIP_INIT)) | ||
268 | init(); | ||
269 | |||
270 | switch(SPL_ARGUMENTS->command) { | ||
271 | case SPL_CMD_BOOT: { | ||
272 | int option = SPL_ARGUMENTS->param1; | ||
273 | if(option == SPL_BOOTOPT_CHOOSE) | ||
274 | option = spl_get_boot_option(); | ||
275 | if(option == SPL_BOOTOPT_NONE) | ||
276 | return; | ||
277 | |||
278 | const struct spl_boot_option* opt = &spl_boot_options[option-1]; | ||
279 | if(nandread(opt->nand_addr, opt->nand_size, (void*)opt->load_addr)) | ||
280 | spl_error(); | ||
281 | |||
282 | /* TODO: implement dual boot */ | ||
283 | |||
284 | /* Reading the Linux command line from the bootloader is handled by | ||
285 | * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. | ||
286 | * | ||
287 | * Rockbox doesn't use arguments, but passing them does not hurt and it | ||
288 | * saves an unnecessary branch. | ||
289 | */ | ||
290 | entry_fn entry = (entry_fn)opt->exec_addr; | ||
291 | char** argv = (char**)0x80004000; | ||
292 | argv[0] = 0; | ||
293 | argv[1] = (char*)opt->cmdline; | ||
294 | |||
295 | commit_discard_idcache(); | ||
296 | entry(2, argv, 0, 0); | ||
297 | __builtin_unreachable(); | ||
298 | } | ||
299 | |||
300 | case SPL_CMD_FLASH_READ: | ||
301 | SPL_STATUS->err_code = nandread(SPL_ARGUMENTS->param1, | ||
302 | SPL_ARGUMENTS->param2, | ||
303 | (void*)SPL_BUFFER_ADDRESS); | ||
304 | return; | ||
305 | |||
306 | case SPL_CMD_FLASH_WRITE: | ||
307 | SPL_STATUS->err_code = nandwrite(SPL_ARGUMENTS->param1, | ||
308 | SPL_ARGUMENTS->param2, | ||
309 | (void*)SPL_BUFFER_ADDRESS); | ||
310 | return; | ||
311 | } | ||
230 | } | 312 | } |
diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.h b/firmware/target/mips/ingenic_x1000/spl-x1000.h new file mode 100644 index 0000000000..44601438f3 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __SPL_X1000_H__ | ||
23 | #define __SPL_X1000_H__ | ||
24 | |||
25 | #include "spl-x1000-defs.h" | ||
26 | |||
27 | #define SPL_ARGUMENTS ((struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS) | ||
28 | #define SPL_STATUS ((struct x1000_spl_status*)SPL_STATUS_ADDRESS) | ||
29 | |||
30 | struct spl_boot_option { | ||
31 | uint32_t nand_addr; | ||
32 | uint32_t nand_size; | ||
33 | uint32_t load_addr; | ||
34 | uint32_t exec_addr; | ||
35 | const char* cmdline; /* for Linux */ | ||
36 | }; | ||
37 | |||
38 | /* Defined by target, indices are 0 = ROCKBOX, 1 = ORIG_FW, etc... */ | ||
39 | extern const struct spl_boot_option spl_boot_options[]; | ||
40 | |||
41 | /* Called on a fatal error */ | ||
42 | void spl_error(void) __attribute__((noreturn)); | ||
43 | |||
44 | /* When SPL boots with SPL_BOOTOPTION_CHOOSE, this function is invoked | ||
45 | * to let the target figure out the boot option based on buttons the | ||
46 | * user is pressing */ | ||
47 | extern int spl_get_boot_option(void); | ||
48 | |||
49 | #endif /* __SPL_X1000_H__ */ | ||