summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/imx233/debug-imx233.c65
-rw-r--r--firmware/target/arm/imx233/dualboot-imx233.c221
-rw-r--r--firmware/target/arm/imx233/dualboot-imx233.h53
3 files changed, 336 insertions, 3 deletions
diff --git a/firmware/target/arm/imx233/debug-imx233.c b/firmware/target/arm/imx233/debug-imx233.c
index 89365cb148..68865efc8d 100644
--- a/firmware/target/arm/imx233/debug-imx233.c
+++ b/firmware/target/arm/imx233/debug-imx233.c
@@ -31,6 +31,7 @@
31#include "clkctrl-imx233.h" 31#include "clkctrl-imx233.h"
32#include "powermgmt-imx233.h" 32#include "powermgmt-imx233.h"
33#include "rtc-imx233.h" 33#include "rtc-imx233.h"
34#include "dualboot-imx233.h"
34#include "dcp-imx233.h" 35#include "dcp-imx233.h"
35#include "pinctrl-imx233.h" 36#include "pinctrl-imx233.h"
36#include "ocotp-imx233.h" 37#include "ocotp-imx233.h"
@@ -535,10 +536,11 @@ bool dbg_hw_info_rtc(void)
535 lcd_clear_display(); 536 lcd_clear_display();
536 struct imx233_rtc_info_t info = imx233_rtc_get_info(); 537 struct imx233_rtc_info_t info = imx233_rtc_get_info();
537 538
538 lcd_putsf(0, 0, "seconds: %lu", info.seconds); 539 int line = 0;
539 lcd_putsf(0, 1, "alarm: %lu", info.alarm); 540 lcd_putsf(0, line++, "seconds: %lu", info.seconds);
541 lcd_putsf(0, line++, "alarm: %lu", info.alarm);
540 for(int i = 0; i < 6; i++) 542 for(int i = 0; i < 6; i++)
541 lcd_putsf(0, i + 2, "persist%d: 0x%lx", i, info.persistent[i]); 543 lcd_putsf(0, line++, "persist%d: 0x%lx", i, info.persistent[i]);
542 544
543 lcd_update(); 545 lcd_update();
544 yield(); 546 yield();
@@ -1255,6 +1257,60 @@ bool dbg_hw_info_sdmmc(void)
1255 } 1257 }
1256} 1258}
1257 1259
1260#ifdef HAVE_DUALBOOT_STUB
1261bool dbg_hw_info_dualboot(void)
1262{
1263 lcd_setfont(FONT_SYSFIXED);
1264
1265 while(1)
1266 {
1267 int button = my_get_action(HZ / 10);
1268 switch(button)
1269 {
1270 case ACT_NEXT:
1271 case ACT_PREV:
1272 {
1273 /* only if boot mode is supported... */
1274 if(!imx233_dualboot_get_field(DUALBOOT_CAP_BOOT))
1275 break;
1276 /* change it */
1277 unsigned boot = imx233_dualboot_get_field(DUALBOOT_BOOT);
1278 if(boot == IMX233_BOOT_NORMAL)
1279 boot = IMX233_BOOT_OF;
1280 else if(boot == IMX233_BOOT_OF)
1281 boot = IMX233_BOOT_UPDATER;
1282 else
1283 boot = IMX233_BOOT_NORMAL;
1284 imx233_dualboot_set_field(DUALBOOT_BOOT, boot);
1285 break;
1286 }
1287 case ACT_OK:
1288 lcd_setfont(FONT_UI);
1289 return true;
1290 case ACT_CANCEL:
1291 lcd_setfont(FONT_UI);
1292 return false;
1293 }
1294
1295 lcd_clear_display();
1296 int line = 0;
1297 unsigned cap_boot = imx233_dualboot_get_field(DUALBOOT_CAP_BOOT);
1298 lcd_putsf(0, line++, "cap_boot: %s", cap_boot ? "yes" : "no");
1299 if(cap_boot)
1300 {
1301 unsigned boot = imx233_dualboot_get_field(DUALBOOT_BOOT);
1302 lcd_putsf(0, line++, "boot: %s",
1303 boot == IMX233_BOOT_NORMAL ? "normal"
1304 : boot == IMX233_BOOT_OF ? "of"
1305 : boot == IMX233_BOOT_UPDATER ? "updater" : "?");
1306 }
1307
1308 lcd_update();
1309 yield();
1310 }
1311}
1312#endif
1313
1258static struct 1314static struct
1259{ 1315{
1260 const char *name; 1316 const char *name;
@@ -1281,6 +1337,9 @@ static struct
1281 {"timrot", dbg_hw_info_timrot}, 1337 {"timrot", dbg_hw_info_timrot},
1282 {"button", dbg_hw_info_button}, 1338 {"button", dbg_hw_info_button},
1283 {"sdmmc", dbg_hw_info_sdmmc}, 1339 {"sdmmc", dbg_hw_info_sdmmc},
1340#ifdef HAVE_DUALBOOT_STUB
1341 {"dualboot", dbg_hw_info_dualboot},
1342#endif
1284 {"target", dbg_hw_target_info}, 1343 {"target", dbg_hw_target_info},
1285}; 1344};
1286 1345
diff --git a/firmware/target/arm/imx233/dualboot-imx233.c b/firmware/target/arm/imx233/dualboot-imx233.c
new file mode 100644
index 0000000000..39d70f17ea
--- /dev/null
+++ b/firmware/target/arm/imx233/dualboot-imx233.c
@@ -0,0 +1,221 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright © 2011 by Amaury Pouly
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/* IMPORTANT NOTE This file is used by both Rockbox (firmware and bootloader)
23 * and the dualboot stub. The stub #include this file directly, so make sure
24 * this file is independent and does not requires anything from the firmware */
25#include "dualboot-imx233.h"
26
27#ifdef HAVE_DUALBOOT_STUB
28/** Persistent registers usage by the OF based on the Firmware SDK
29 * and support for firmware upgrades in Rockbox
30 * (this includes the Fuze+, ZEN X-Fi3, NWZ-E360/E370/E380)
31 *
32 * The following are used:
33 * - PERSISTENT0: mostly standard stuff described in the datasheet
34 * - PERSISTENT1: mostly proprietary stuff + some bits described in the datasheet
35 * - PERSISTENT2: used to keep track of time (see below)
36 * - PERSISTENT3: proprietary stuff
37 * - PERSISTENT4: unused
38 * - PERSISTENT5: used by Rockbox to tell the dualboot stub what to do
39 *
40 * In particular, the following bits are involved in the firmware upgrade process
41 * and thus worth mentioning (Px means PERSISTENTx). Some of this information
42 * might not be entirely accurate:
43 * - P1[18]: when 0, indicates to the freescale boot stub to start the updater
44 * rather than the main firmware (play) or the usb firmware (host)
45 * - P1[22]: when 0, indicates that the OF database/store should be rebuilt
46 * - P3[10]: when 0, indicates that the firmware has been upgraded
47 * - P3[11]: when 1, indicates to the freescale boot stub to boot without
48 * requiring the user to hold the power button for a small delay
49 * - P3[12]: when 1, indicates that the internal drive or micro-sd card was
50 * modified in USB mode
51 * - P3[16]: when 1, indicates that a firmware upgrade was attempted but aborted
52 * due to a too low battery
53 *
54 * To understand how all this works out together, recall that the boot sequence
55 * usually looks as follows (fslx = freescale boot stub stage x, in section 0
56 * of the firmware; rb = rockbox dualboot stub), where arrows indicate boot flow
57 * (since every stage can choose to continue in the same section or jump to another):
58 *
59 * +---> host (usb)
60 * |
61 * fsl0 -> fsl1 -> fsl2 -> rb -> fsl3 -> fsl4 (updater)
62 * | |
63 * | +---> play (firmware)
64 * |
65 * +-----------> rock (bootloader) (-> loads rockbox)
66 *
67 * Note that the exact number of fsl stages is device-dependent, there 5 on the
68 * fuze+, 3 on the NWZs for example.
69 *
70 * The fsl3 decides which stage to boot based on the following logic (order is
71 * important):
72 * - if P1[18] is 0, it goes to fsl4, to perform a firmware upgrade
73 * - if usb is plugged, it goes to host, the OF USB mode
74 * - if P1[22] is 1, it requires the user to hold the power button for small
75 * delay and aborts boot if this is not the case
76 * - it goes to play, the OF normal firmware
77 *
78 * The fsl4 (updater) performs the following action:
79 * - it clears P1[18] so that next boot will be a normal boot (ie NOT updater)
80 * - if firmware.sb does not exist or is invalid, it reboots
81 * - if the battery is too low for an upgrade, it sets P3[16]
82 * otherwise, it performs a firmware upgrade and clear P1[22]
83 * - it shutdowns
84 *
85 * The play (firmware) performs the following actions:
86 * - if P1[22] is 0 or P3[12] is 1, it rebuilds the store (the 'loading' screen)
87 * and set P1[22] to 1 and P3[12] to 0
88 * - if P3[16] is 1, it displays a 'battery was too low to upgrade' message
89 * and clears P3[16]
90 * - if P3[10] is 0, it displays a 'firmware was successfully upgraded' message
91 * and sets P3[10] to 1
92 * - it performs its usual (crappy) functions
93 *
94 * The host (USB) performs the following actions:
95 * - it clears P1[18] so that the next boot will run the updater
96 * - it sets P3[11] to 1 so that the device will reboot without user intervention
97 * at the end
98 * - if the host modifies the internal drive or micro-SD card, it sets P3[12]
99 * to 1 and clears P1[22]
100 * - after USB is unplugged, it reboots
101 *
102 * Thus a typical firmware upgrade sequence will look like this:
103 * - initially, the main firmware is running and flags are in the following state:
104 * P1[18] = 1 (normal boot)
105 * P1[22] = 1 (store is clean)
106 * P3[10] = 1 (firmware has not been upgraded)
107 * P3[11] = 0 (user needs to hold power button to boot)
108 * P3[12] = 0 (drive is clean)
109 * - the user plugs the USB cable, play reboots, fsl3 boots to host because
110 * P1[18] = 1, the users put firmware.sb on the drive, thus modifying its
111 * content and then unplugs the drive; the device reboots with the following
112 * flags:
113 * P1[18] = 0 (updater boot)
114 * P1[22] = 0 (store is dirty)
115 * P3[10] = 1 (firmware has not been upgraded)
116 * P3[11] = 1 (user does not needs to hold power button to boot)
117 * P3[12] = 1 (drive is dirty)
118 * - fsl3 boots to the updater because P1[18] = 0, the updater sees firmware.sb
119 * and performs a firmware upgrade; the device then shutdowns with the following
120 * flags:
121 * P1[18] = 1 (normal boot)
122 * P1[22] = 0 (store is dirty)
123 * P3[10] = 0 (firmware has been upgraded)
124 * P3[11] = 1 (user does not needs to hold power button to boot)
125 * P3[12] = 1 (drive is dirty)
126 * - the user presses the power button, fsl3 boots to play (firmware) because
127 * P1[18] = 1, it rebuilds the store because P1[22] is clear, it then display
128 * a message to the user saying that the firmware has been upgraded because
129 * P3[10] is 0, and it resets the flags to same state as initially
130 *
131 * Note that the OF is lazy: it reboots to updater after USB mode in all cases
132 * (even if firmware.sb was not present). In this case, the updater simply clears
133 * the update flags and reboot immediately, thus it looks like a normal boot.
134 *
135 *
136 * To support firmware upgrades in Rockbox, we need to two things:
137 * - a way to tell rb (rockbox dual stub) to continue to fsl3 instead of booting
138 * rock (our bootloader)
139 * - a way to setup the persistent bits so that fsl3 will boot to fsl4 (updater)
140 * instead of booting host (usb) or play (firmware)
141 *
142 * The approach taken is to use PERSISTENT5 to tell the dualboot stub what we want
143 * to do. Since previous dualboot stubs did not support this, and that other actions
144 * may be added in the future, the registers stores both the capabilities of the
145 * dualboot stub (so that Rockbox can read them) and the actions that the dualboot
146 * stub must perform (so that Rockbox can write them). The register is encoded
147 * so that older/random values will be detected as garbage by newer Rockbox and
148 * dualboot stub, and that a value of 0 for a field always behaves as when it did
149 * not exist. More precisely, the bottom 16-bit must be 'RB' and
150 * the top 16-bit store the actual data. The following fields are currently defined:
151 * - CAP_BOOT(1 bit): supports booting to OF and UPDATER using the BOOT field
152 * - BOOT(2 bits): sets boot mode
153 *
154 * At the moment, BOOT supports three values:
155 * - IMX233_BOOT_NORMAL: the dualboot will do a normal boot (booting to Rockbox
156 * unless the user presses the magic button that boots to the OF)
157 * - IMX233_BOOT_OF: the dualboot stub will continue booting with fsl3 instead
158 * of Rockbox, but it will not touch any of OF persistent bits (this is useful
159 * to simply reboot to the OF for example)
160 * - IMX233_BOOT_UPDATER: the dualboot will setup OF persistents bits and
161 * continue so that fsl3 enters fsl4 (updater)
162 * In this scheme, Rockbox does not have to care about how exactly those actions
163 * are achieved, only the dualboot stub has to deal with the persistent bits.
164 * When the dualboot stubs see either OF or UPDATER, it clears BOOT back
165 * to NORMAL before continuing, so as to avoid any boot loop.
166 *
167 */
168
169#include "regs/rtc.h"
170
171/* the persistent register we use */
172#define REG_DUALBOOT HW_RTC_PERSISTENT5
173/* the bottom 16-bit are a magic value to indicate that the content is valid */
174#define MAGIC_MASK 0xffff
175#define MAGIC_VALUE ('R' | 'B' << 8)
176/* CAP_BOOT: 1-bit (16) */
177#define CAP_BOOT_POS 16
178#define CAP_BOOT_MASK (1 << 16)
179/* BOOT field: 2-bits (18-17) */
180#define BOOT_POS 17
181#define BOOT_MASK (3 << 17)
182
183unsigned imx233_dualboot_get_field(enum imx233_dualboot_field_t field)
184{
185 unsigned val = HW_RTC_PERSISTENT5;
186 /* if signature doesn't match, assume everything is 0 */
187 if((val & MAGIC_MASK) != MAGIC_VALUE)
188 return 0;
189#define match(field) \
190 case DUALBOOT_##field: return ((val & field##_MASK) >> field##_POS);
191 switch(field)
192 {
193 match(CAP_BOOT)
194 match(BOOT)
195 default: return 0; /* unknown */
196 }
197#undef match
198}
199
200void imx233_dualboot_set_field(enum imx233_dualboot_field_t field, unsigned fval)
201{
202 unsigned val = HW_RTC_PERSISTENT5;
203 /* if signature doesn't match, create an empty register */
204 if((val & MAGIC_MASK) != MAGIC_VALUE)
205 val = MAGIC_VALUE; /* all field are 0 */
206#define match(field) \
207 case DUALBOOT_##field: \
208 val &= ~field##_MASK; \
209 val |= (fval << field##_POS) & field##_MASK; \
210 break;
211 switch(field)
212 {
213 match(CAP_BOOT)
214 match(BOOT)
215 default: break;
216 }
217 HW_RTC_PERSISTENT5 = val;
218#undef match
219}
220
221#endif /* HAVE_DUALBOOT_STUB */
diff --git a/firmware/target/arm/imx233/dualboot-imx233.h b/firmware/target/arm/imx233/dualboot-imx233.h
new file mode 100644
index 0000000000..59b6b2f93c
--- /dev/null
+++ b/firmware/target/arm/imx233/dualboot-imx233.h
@@ -0,0 +1,53 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright © 2011 by Amaury Pouly
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#ifndef DUALBOOT_IMX233_H
22#define DUALBOOT_IMX233_H
23
24#include "config.h"
25
26/* IMPORTANT NOTE This file is used by both Rockbox (firmware and bootloader)
27 * and the dualboot stub. The stub #include this file directly with
28 * COMPILE_DUALBOOT_STUB defined, so make sure this file is independent and does
29 * not requires anything from the firmware */
30#ifndef COMPILE_DUALBOOT_STUB
31#include "stdint.h"
32#endif
33
34#ifdef HAVE_DUALBOOT_STUB
35/* See dualboot-imx233.c for documentation */
36
37enum imx233_dualboot_field_t
38{
39 DUALBOOT_CAP_BOOT, /* boot capability: 1 => BOOT field supports OF and UPDATER */
40 DUALBOOT_BOOT, /* boot mode: IMX23_BOOT_x */
41};
42
43#define IMX233_BOOT_NORMAL 0 /* boot Rockbox (or OF if magic button) */
44#define IMX233_BOOT_OF 1 /* boot OF */
45#define IMX233_BOOT_UPDATER 2 /* boot updater */
46
47/* get field value (or 0 if not present) */
48unsigned imx233_dualboot_get_field(enum imx233_dualboot_field_t field);
49/* write field value */
50void imx233_dualboot_set_field(enum imx233_dualboot_field_t field, unsigned val);
51#endif /* HAVE_DUALBOOT_STUB */
52
53#endif /* DUALBOOT_IMX233_H */