summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-04-23 15:32:50 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-04-23 15:32:50 +0000
commit11cca264ff57ad0b234bd1cd2c9a2366b967feb7 (patch)
tree7693e7150d5abc9687966cc248bfbd550d356964 /firmware/target/arm/imx31/gigabeat-s
parent6cee7579dbdc4d41c4df08c9395cf96c952ebab1 (diff)
downloadrockbox-11cca264ff57ad0b234bd1cd2c9a2366b967feb7.tar.gz
rockbox-11cca264ff57ad0b234bd1cd2c9a2366b967feb7.zip
i.MX31/Gigabeat S: Implement frequency and voltage scaling-- 1.6V for 528MHz, and 1.35V for 264MHz and 132MHz. Keep DPTC overdrive ( > 400MHz) voltage scaling off for now because of uncertainties. Simplify the (working) mess later.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25699 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h279
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c7
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c8
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c43
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/system-target.h15
5 files changed, 331 insertions, 21 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h b/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h
new file mode 100644
index 0000000000..2356e23252
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h
@@ -0,0 +1,279 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 by Michael Sevakis
11 *
12 * Target-specific i.MX31 DVFS and DPTC driver declarations
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#ifndef _DVFS_DPTC_TARGET_H_
24#define _DVFS_DPTC_TARGET_H_
25
26#define DVFS_LEVEL_DEFAULT 1 /* 264 MHz - safe frequency for 1.35V */
27#define DVFS_NUM_LEVELS 3 /* 528 MHz, 264 MHz, 132 MHz */
28#define DVFS_NO_PWRRDY /* PWRRDY is connected to different SoC port */
29
30#define DPTC_WP_DEFAULT 1 /* 1.600, 1.350, 1.350 */
31#define DPTC_WP_PANIC 3 /* Up to minimum for > 400 MHz */
32#define DPTC_NUM_WP 17
33
34#define VOLTAGE_SETTING_MIN MC13783_SW_1_350
35#define VOLTAGE_SETTING_MAX MC13783_SW_1_625
36
37/* Frequency increase threshold. Increase frequency change request
38 * will be sent if DVFS counter value will be more than this value. */
39#define DVFS_UPTHR 30
40
41/* Frequency decrease threshold. Decrease frequency change request
42 * will be sent if DVFS counter value will be less than this value. */
43#define DVFS_DNTHR 18
44
45/* Panic threshold. Panic frequency change request
46 * will be sent if DVFS counter value will be more than this value. */
47#define DVFS_PNCTHR 63
48
49/* With the ARM clocked at 532, this setting yields a DIV_3_CLK of 2.03 kHz.
50 *
51 * Note: To get said clock, the divider would have to be 262144. The values
52 * and their meanings are not published in the reference manual for i.MX31
53 * but show up in the i.MX35 reference manual. Either that chip is different
54 * and the values have an additional division or the comments in the BSP are
55 * incorrect.
56 */
57#define DVFS_DIV3CK CCM_LTR0_DIV3CK_131072
58
59/* UPCNT defines the amount of times the up threshold should be exceeded
60 * before DVFS will trigger frequency increase request. */
61
62#if 0
63/* Freescale BSP value: a bit too agressive IMHO */
64#define DVFS_UPCNT 0x33
65#endif
66#define DVFS_UPCNT 0x48
67
68/* DNCNT defines the amount of times the down threshold should be undershot
69 * before DVFS will trigger frequency decrease request. */
70#define DVFS_DNCNT 0x33
71
72/* EMAC defines how many samples are included in EMA calculation */
73#define DVFS_EMAC 0x20
74
75/* Define mask of which reference circuits are employed for DPTC */
76#define DPTC_DRCE_MASK (CCM_PMCR0_DRCE1 | CCM_PMCR0_DRCE3)
77
78/* When panicing, this working point is used */
79#define DPTC_PANIC_WP
80
81/* Due to a hardware bug in chip revisions < 2.0, when switching between
82 * Serial and MCU PLLs, DVFS forces the target PLL to go into reset and
83 * relock, only post divider frequency scaling is possible.
84 */
85
86static const union dvfs_dptc_voltage_table_entry
87dvfs_dptc_voltage_table[DPTC_NUM_WP] =
88{
89 /* For each working point, there are four DVFS settings, chosen by the
90 * DVS pin states on the PMIC set by the DVFS routines. Pins are reversed
91 * and actual order as used by PMIC for DVSUP values of 00, 01, 10 and 11
92 * is below.
93 *
94 * SW1A SW1ADVS SW1BDVS SW1BSTBY
95 * 0 2 1 3 */
96 { { MC13783_SW_1_625, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
97 { { MC13783_SW_1_600, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
98 { { MC13783_SW_1_575, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
99 { { MC13783_SW_1_550, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
100 { { MC13783_SW_1_525, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
101 { { MC13783_SW_1_500, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
102 { { MC13783_SW_1_475, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
103 { { MC13783_SW_1_450, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
104 { { MC13783_SW_1_425, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
105 { { MC13783_SW_1_400, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
106 { { MC13783_SW_1_375, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
107 { { MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
108 { { MC13783_SW_1_325, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
109 { { MC13783_SW_1_300, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
110 { { MC13783_SW_1_275, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
111 { { MC13783_SW_1_250, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
112 { { MC13783_SW_1_225, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } },
113};
114
115#if 1
116/* For 27 MHz PLL reference clock */
117static const struct dptc_dcvr_table_entry
118dptc_dcvr_table[DVFS_NUM_LEVELS][DPTC_NUM_WP] =
119{
120 /* DCVR0 DCVR1 DCVR2 DCVR3 */
121 { /* 528 MHz */
122 { 0xffc00000, 0x90400000, 0xffc00000, 0xdd000000 },
123 { 0xffc00000, 0x90629890, 0xffc00000, 0xdd34ed20 },
124 { 0xffc00000, 0x90629890, 0xffc00000, 0xdd34ed20 },
125 { 0xffc00000, 0x90629894, 0xffc00000, 0xdd74fd24 },
126 { 0xffc00000, 0x90a2a894, 0xffc00000, 0xddb50d28 },
127 { 0xffc00000, 0x90e2b89c, 0xffc00000, 0xde352d30 },
128 { 0xffc00000, 0x9162d8a0, 0xffc00000, 0xdef55d38 },
129 { 0xffc00000, 0x91e2f8a8, 0xffc00000, 0xdfb58d44 },
130 { 0xffc00000, 0x926308b0, 0xffc00000, 0xe0b5cd54 },
131 { 0xffc00000, 0x92e328bc, 0xffc00000, 0xe1f60d64 },
132 { 0xffc00000, 0x93a358c0, 0xffc00000, 0xe3365d74 },
133 { 0xffc00000, 0xf66388cc, 0xffc00000, 0xf6768d84 },
134 { 0xffc00000, 0xf663b8d4, 0xffc00000, 0xf676dd98 },
135 { 0xffc00000, 0xf663e8e0, 0xffc00000, 0xf6773da4 },
136 { 0xffc00000, 0xf66418ec, 0xffc00000, 0xf6778dbc },
137 { 0xffc00000, 0xf66458fc, 0xffc00000, 0xf677edd0 },
138 { 0xffc00000, 0xf6648908, 0xffc00000, 0xf6783de8 },
139
140 },
141 { /* 264 MHz */
142 { 0xffc00000, 0x90400000, 0xffc00000, 0xdd000000 },
143 { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 },
144 { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 },
145 { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd4d4348 },
146 { 0xffc00000, 0x9088b228, 0xffc00000, 0xdd8d434c },
147 { 0xffc00000, 0x90c8b228, 0xffc00000, 0xde0d534c },
148 { 0xffc00000, 0x9148b228, 0xffc00000, 0xdecd5350 },
149 { 0xffc00000, 0x91c8c22c, 0xffc00000, 0xdf8d6354 },
150 { 0xffc00000, 0x9248d22c, 0xffc00000, 0xe08d7354 },
151 { 0xffc00000, 0x92c8d230, 0xffc00000, 0xe1cd8358 },
152 { 0xffc00000, 0x9388e234, 0xffc00000, 0xe30d935c },
153 { 0xffc00000, 0xf648e234, 0xffc00000, 0xf64db364 },
154 { 0xffc00000, 0xf648f238, 0xffc00000, 0xf64dc368 },
155 { 0xffc00000, 0xf648f23c, 0xffc00000, 0xf64dd36c },
156 { 0xffc00000, 0xf649023c, 0xffc00000, 0xf64de370 },
157 { 0xffc00000, 0xf649123c, 0xffc00000, 0xf64df374 },
158 { 0xffc00000, 0xf6492240, 0xffc00000, 0xf64e1378 },
159
160 },
161 { /* 132 MHz */
162 { 0xffc00000, 0x90400000, 0xffc00000, 0xdd000000 },
163 { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 },
164 { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 },
165 { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd4d4348 },
166 { 0xffc00000, 0x9088b228, 0xffc00000, 0xdd8d434c },
167 { 0xffc00000, 0x90c8b228, 0xffc00000, 0xde0d534c },
168 { 0xffc00000, 0x9148b228, 0xffc00000, 0xdecd5350 },
169 { 0xffc00000, 0x91c8c22c, 0xffc00000, 0xdf8d6354 },
170 { 0xffc00000, 0x9248d22c, 0xffc00000, 0xe08d7354 },
171 { 0xffc00000, 0x92c8d230, 0xffc00000, 0xe1cd8358 },
172 { 0xffc00000, 0x9388e234, 0xffc00000, 0xe30d935c },
173 { 0xffc00000, 0xf648e234, 0xffc00000, 0xf64db364 },
174 { 0xffc00000, 0xf648f238, 0xffc00000, 0xf64dc368 },
175 { 0xffc00000, 0xf648f23c, 0xffc00000, 0xf64dd36c },
176 { 0xffc00000, 0xf649023c, 0xffc00000, 0xf64de370 },
177 { 0xffc00000, 0xf649123c, 0xffc00000, 0xf64df374 },
178 { 0xffc00000, 0xf6492240, 0xffc00000, 0xf64e1378 },
179 },
180};
181#else/* For 26 MHz PLL reference clock */
182static const struct dptc_dcvr_table_entry
183dptc_dcvr_table[DVFS_NUM_LEVELS][DPTC_NUM_WP] =
184{
185 /* DCVR0 DCVR1 DCVR2 DCVR3 */
186 { /* 528 MHz */
187 { 0xffc00000, 0x95c00000, 0xffc00000, 0xe5800000 },
188 { 0xffc00000, 0x95e3e8e4, 0xffc00000, 0xe5b6fda0 },
189 { 0xffc00000, 0x95e3e8e4, 0xffc00000, 0xe5b6fda0 },
190 { 0xffc00000, 0x95e3e8e8, 0xffc00000, 0xe5f70da4 },
191 { 0xffc00000, 0x9623f8e8, 0xffc00000, 0xe6371da8 },
192 { 0xffc00000, 0x966408f0, 0xffc00000, 0xe6b73db0 },
193 { 0xffc00000, 0x96e428f4, 0xffc00000, 0xe7776dbc },
194 { 0xffc00000, 0x976448fc, 0xffc00000, 0xe8379dc8 },
195 { 0xffc00000, 0x97e46904, 0xffc00000, 0xe977ddd8 },
196 { 0xffc00000, 0x98a48910, 0xffc00000, 0xeab81de8 },
197 { 0xffc00000, 0x9964b918, 0xffc00000, 0xebf86df8 },
198 { 0xffc00000, 0xffe4e924, 0xffc00000, 0xfff8ae08 },
199 { 0xffc00000, 0xffe5192c, 0xffc00000, 0xfff8fe1c },
200 { 0xffc00000, 0xffe54938, 0xffc00000, 0xfff95e2c },
201 { 0xffc00000, 0xffe57944, 0xffc00000, 0xfff9ae44 },
202 { 0xffc00000, 0xffe5b954, 0xffc00000, 0xfffa0e58 },
203 { 0xffc00000, 0xffe5e960, 0xffc00000, 0xfffa6e70 },
204 },
205 { /* 264 MHz */
206 { 0xffc00000, 0x95c00000, 0xffc00000, 0xe5800000 },
207 { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 },
208 { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 },
209 { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe5cdc368 },
210 { 0xffc00000, 0x9609023c, 0xffc00000, 0xe60dc36c },
211 { 0xffc00000, 0x9649023c, 0xffc00000, 0xe68dd36c },
212 { 0xffc00000, 0x96c9023c, 0xffc00000, 0xe74dd370 },
213 { 0xffc00000, 0x97491240, 0xffc00000, 0xe80de374 },
214 { 0xffc00000, 0x97c92240, 0xffc00000, 0xe94df374 },
215 { 0xffc00000, 0x98892244, 0xffc00000, 0xea8e0378 },
216 { 0xffc00000, 0x99493248, 0xffc00000, 0xebce137c },
217 { 0xffc00000, 0xffc93248, 0xffc00000, 0xffce3384 },
218 { 0xffc00000, 0xffc9424c, 0xffc00000, 0xffce4388 },
219 { 0xffc00000, 0xffc95250, 0xffc00000, 0xffce538c },
220 { 0xffc00000, 0xffc96250, 0xffc00000, 0xffce7390 },
221 { 0xffc00000, 0xffc97254, 0xffc00000, 0xffce8394 },
222 { 0xffc00000, 0xffc98258, 0xffc00000, 0xffcea39c },
223 },
224 { /* 132 MHz */
225 { 0xffc00000, 0x95c00000, 0xffc00000, 0xe5800000 },
226 { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 },
227 { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 },
228 { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe5cdc368 },
229 { 0xffc00000, 0x9609023c, 0xffc00000, 0xe60dc36c },
230 { 0xffc00000, 0x9649023c, 0xffc00000, 0xe68dd36c },
231 { 0xffc00000, 0x96c9023c, 0xffc00000, 0xe74dd370 },
232 { 0xffc00000, 0x97491240, 0xffc00000, 0xe80de374 },
233 { 0xffc00000, 0x97c92240, 0xffc00000, 0xe94df374 },
234 { 0xffc00000, 0x98892244, 0xffc00000, 0xea8e0378 },
235 { 0xffc00000, 0x99493248, 0xffc00000, 0xebce137c },
236 { 0xffc00000, 0xffc93248, 0xffc00000, 0xffce3384 },
237 { 0xffc00000, 0xffc9424c, 0xffc00000, 0xffce4388 },
238 { 0xffc00000, 0xffc95250, 0xffc00000, 0xffce538c },
239 { 0xffc00000, 0xffc96250, 0xffc00000, 0xffce7390 },
240 { 0xffc00000, 0xffc97254, 0xffc00000, 0xffce8394 },
241 { 0xffc00000, 0xffc98258, 0xffc00000, 0xffcea39c },
242 },
243};
244#endif
245
246
247/* For 27 MHz PLL reference clock */
248static const struct dvfs_clock_table_entry
249dvfs_clock_table[DVFS_NUM_LEVELS] =
250{
251 /* PLL val PDR0 val PLL VSCNT */
252 { 0x00082407, 0xff841e58, 1, 7 }, /* MCUPLL, 528 MHz, /1 = 528 MHz */
253 { 0x00082407, 0xff841e59, 1, 7 }, /* MCUPLL, 528 MHz, /2 = 264 MHz */
254 { 0x00082407, 0xff841e5b, 1, 7 }, /* MCUPLL, 528 MHz, /4 = 132 MHz */
255};
256
257
258/* DVFS load-tracking signal weights and detect modes */
259static const struct dvfs_lt_signal_descriptor lt_signals[16] =
260{
261 { 0, 0 }, /* DVFS_LT_SIG_M3IF_M0_BUF */
262 { 0, 0 }, /* DVFS_LT_SIG_M3IF_M1 */
263 { 0, 0 }, /* DVFS_LT_SIG_MBX_MBXCLKGATE */
264 { 0, 0 }, /* DVFS_LT_SIG_M3IF_M3 */
265 { 0, 0 }, /* DVFS_LT_SIG_M3IF_M4 */
266 { 0, 0 }, /* DVFS_LT_SIG_M3IF_M5 */
267 { 0, 0 }, /* DVFS_LT_SIG_M3IF_M6 */
268 { 0, 0 }, /* DVFS_LT_SIG_M3IF_M7 */
269 { 0, 0 }, /* DVFS_LT_SIG_ARM11_P_IRQ_B_RBT_GATE */
270 { 0, 0 }, /* DVFS_LT_SIG_ARM11_P_FIQ_B_RBT_GATE */
271 { 0, 0 }, /* DVFS_LT_SIG_IPI_GPIO1_INT0 */
272 { 0, 0 }, /* DVFS_LT_SIG_IPI_INT_IPU_FUNC */
273 { 7, 0 }, /* DVFS_LT_SIG_DVGP0 */
274 { 7, 0 }, /* DVFS_LT_SIG_DVGP1 */
275 { 7, 0 }, /* DVFS_LT_SIG_DVGP2 */
276 { 7, 0 }, /* DVFS_LT_SIG_DVGP3 */
277};
278
279#endif /* _DVFS_DPTC_TARGET_H_ */
diff --git a/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c
index 8e81447bd3..894aea4fd3 100644
--- a/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c
@@ -70,10 +70,11 @@ void kernel_device_init(void)
70 sdma_init(); 70 sdma_init();
71 spi_init(); 71 spi_init();
72 mc13783_init(); 72 mc13783_init();
73 dvfs_dptc_start(); 73 dvfs_dptc_init();
74 dvfs_wfi_monitor(true); /* Monitor the WFI signal */
75 dvfs_dptc_start(); /* Should be ok to start even so early */
74} 76}
75 77
76#ifdef BOOTLOADER
77void tick_stop(void) 78void tick_stop(void)
78{ 79{
79 avic_disable_int(INT_EPIT1); /* Disable insterrupt */ 80 avic_disable_int(INT_EPIT1); /* Disable insterrupt */
@@ -81,4 +82,4 @@ void tick_stop(void)
81 EPITSR1 = EPITSR_OCIF; /* Clear pending */ 82 EPITSR1 = EPITSR_OCIF; /* Clear pending */
82 ccm_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */ 83 ccm_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */
83} 84}
84#endif 85
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c
index 7e3b39dba8..d7fe87f168 100644
--- a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c
@@ -28,6 +28,7 @@
28#include "backlight-target.h" 28#include "backlight-target.h"
29#include "avic-imx31.h" 29#include "avic-imx31.h"
30#include "mc13783.h" 30#include "mc13783.h"
31#include "dvfs_dptc-imx31.h"
31#if CONFIG_TUNER 32#if CONFIG_TUNER
32#include "fmradio_i2c.h" 33#include "fmradio_i2c.h"
33#endif 34#endif
@@ -121,6 +122,9 @@ bool tuner_powered(void)
121 122
122void power_off(void) 123void power_off(void)
123{ 124{
125 /* Turn off voltage and frequency scaling */
126 dvfs_dptc_stop();
127
124 /* Cut backlight */ 128 /* Cut backlight */
125 _backlight_off(); 129 _backlight_off();
126 130
@@ -131,9 +135,7 @@ void power_off(void)
131 mc13783_set(MC13783_POWER_CONTROL0, MC13783_USEROFFSPI); 135 mc13783_set(MC13783_POWER_CONTROL0, MC13783_USEROFFSPI);
132 136
133 /* Wait for power cut */ 137 /* Wait for power cut */
134 disable_interrupt(IRQ_FIQ_STATUS); 138 system_halt();
135
136 while (1);
137} 139}
138 140
139void power_init(void) 141void power_init(void)
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c
index cd684e77ac..7c0d30c783 100644
--- a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c
@@ -26,6 +26,7 @@
26#include "gpio-imx31.h" 26#include "gpio-imx31.h"
27#include "mmu-imx31.h" 27#include "mmu-imx31.h"
28#include "system-target.h" 28#include "system-target.h"
29#include "powermgmt-target.h"
29#include "lcd.h" 30#include "lcd.h"
30#include "serial-imx31.h" 31#include "serial-imx31.h"
31#include "debug.h" 32#include "debug.h"
@@ -115,18 +116,24 @@ int system_memory_guard(int newmode)
115 return 0; 116 return 0;
116} 117}
117 118
119void system_halt(void)
120{
121 disable_interrupt(IRQ_FIQ_STATUS);
122 avic_set_ni_level(AVIC_NIL_DISABLE);
123 while (1)
124 core_idle();
125}
126
118void system_reboot(void) 127void system_reboot(void)
119{ 128{
120 /* Multi-context so no SPI available (WDT?) */ 129 /* Multi-context so no SPI available (WDT?) */
121 while (1); 130 system_halt();
122} 131}
123 132
124void system_exception_wait(void) 133void system_exception_wait(void)
125{ 134{
126 /* Called in many contexts so button reading may be a chore */ 135 /* Called in many contexts so button reading may be a chore */
127 avic_disable_int(INT_ALL); 136 system_halt();
128 core_idle();
129 while (1);
130} 137}
131 138
132void system_init(void) 139void system_init(void)
@@ -175,6 +182,9 @@ void system_init(void)
175 182
176 unsigned int i; 183 unsigned int i;
177 184
185 /* Initialize frequency with current */
186 cpu_frequency = ccm_get_mcu_clk();
187
178 /* MCR WFI enables wait mode (CCM_CCMR_LPM_WAIT_MODE = 0) */ 188 /* MCR WFI enables wait mode (CCM_CCMR_LPM_WAIT_MODE = 0) */
179 imx31_regclr32(&CCM_CCMR, CCM_CCMR_LPM); 189 imx31_regclr32(&CCM_CCMR, CCM_CCMR_LPM);
180 190
@@ -239,16 +249,33 @@ void __attribute__((naked)) imx31_regclr32(volatile uint32_t *reg_p,
239 (void)reg_p; (void)mask; 249 (void)reg_p; (void)mask;
240} 250}
241 251
242#ifdef BOOTLOADER 252
243void system_prepare_fw_start(void) 253void system_prepare_fw_start(void)
244{ 254{
245 dvfs_dptc_stop(); 255 dvfs_dptc_stop();
246 disable_interrupt(IRQ_FIQ_STATUS);
247 avic_disable_int(INT_ALL);
248 mc13783_close(); 256 mc13783_close();
249 tick_stop(); 257 tick_stop();
258 disable_interrupt(IRQ_FIQ_STATUS);
259 avic_set_ni_level(AVIC_NIL_DISABLE);
250} 260}
251#endif 261
262
263#ifndef BOOTLOADER
264void rolo_restart_firmware(const unsigned char *source, unsigned char *dest,
265 int length) __attribute__((noreturn));
266
267void __attribute__((noreturn))
268rolo_restart(const unsigned char *source, unsigned char *dest, int length)
269{
270 /* Some housekeeping tasks must be performed for a safe changeover */
271 charging_algorithm_close();
272 system_prepare_fw_start();
273
274 /* Copying routine where new image is run */
275 rolo_restart_firmware(source, dest, length);
276}
277#endif /* BOOTLOADER */
278
252 279
253inline void dumpregs(void) 280inline void dumpregs(void)
254{ 281{
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-target.h b/firmware/target/arm/imx31/gigabeat-s/system-target.h
index b859093c58..af95471db6 100644
--- a/firmware/target/arm/imx31/gigabeat-s/system-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/system-target.h
@@ -24,12 +24,12 @@
24#include "system-arm.h" 24#include "system-arm.h"
25#include "mmu-arm.h" 25#include "mmu-arm.h"
26 26
27#ifndef HAVE_ADJUSTABLE_CPU_FREQ 27/* High enough for most tasks but low enough for reduced voltage */
28/* TODO: implement CPU frequency scaling */ 28#define CPUFREQ_DEFAULT 264000000
29#define CPUFREQ_DEFAULT CPU_FREQ 29/* Still quite powerful, minimum possible frequency */
30#define CPUFREQ_NORMAL CPU_FREQ 30#define CPUFREQ_NORMAL 132000000
31#define CPUFREQ_MAX CPU_FREQ 31/* Overdrive mode */
32#endif 32#define CPUFREQ_MAX 528000000
33 33
34static inline void udelay(unsigned int usecs) 34static inline void udelay(unsigned int usecs)
35{ 35{
@@ -45,10 +45,11 @@ void gpt_stop(void);
45 45
46unsigned int iim_system_rev(void); 46unsigned int iim_system_rev(void);
47 47
48/* Prepare for transition to firmware */ 48/* Prepare for transition to (new) firmware */
49void system_prepare_fw_start(void); 49void system_prepare_fw_start(void);
50void tick_stop(void); 50void tick_stop(void);
51void kernel_device_init(void); 51void kernel_device_init(void);
52void system_halt(void);
52 53
53void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value, 54void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value,
54 uint32_t mask); 55 uint32_t mask);