summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/dualboot-imx233.c
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-09-26 21:22:21 +0100
committerGerrit Rockbox <gerrit@rockbox.org>2016-12-12 12:03:08 +0100
commita983859291e29e2cfe26df8e00814b546d865b5c (patch)
tree7ba94ae05153124a52bc546d46aecb91715578b3 /firmware/target/arm/imx233/dualboot-imx233.c
parent5c50efc9cec9b0b2f0af216c4e9bf82dc3046d04 (diff)
downloadrockbox-a983859291e29e2cfe26df8e00814b546d865b5c.tar.gz
rockbox-a983859291e29e2cfe26df8e00814b546d865b5c.zip
imx233: add capability to boot OF or updater instead of Rockbox
This commit adds the necessary code in the dualboot stub (bootloader) to let rockbox control the boot process. In particular, rockbox can now choose if the next boot will be normal (boot rockbox or OF on magic key), to OF or to updater. The intents (to be added in follow-up commits) are: 1) Let the user more easily reboot to the OF. On some targets it is not trivial, especially in USB mode. 2) Automatically reboot to updater when the user drop firmware.sb at the root of the drive (currently, the user needs to do that in OF USB mode) 3) Document this OF magic Change-Id: I86df651dec048c318c6a22de74abb8c6b41aa9ad
Diffstat (limited to 'firmware/target/arm/imx233/dualboot-imx233.c')
-rw-r--r--firmware/target/arm/imx233/dualboot-imx233.c221
1 files changed, 221 insertions, 0 deletions
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 */