summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-01-13 00:55:34 +0000
committerAmaury Pouly <amaury.pouly@gmail.com>2013-01-13 00:58:46 +0000
commit4307f95a1f57d3038a2d41f0f4c0ddf33f50630d (patch)
tree027623d732f64d886c1ee2b0341fba68282feb96
parent29e51a17775df5040b12d93834c45b3f1171ed9d (diff)
downloadrockbox-4307f95a1f57d3038a2d41f0f4c0ddf33f50630d.tar.gz
rockbox-4307f95a1f57d3038a2d41f0f4c0ddf33f50630d.zip
imx233: rework frequency scaling
Move to a table based approach (scales better) and distinguish between upward changes (increase frequency) and downward changes (decrease frequency). This provides a better ordering of operations and in particular it allows to avoid changing the regulator while running at low speed since it takes a long time ! This should result in a much smoother scaling. Change-Id: Iad7e5b61277e215f31c07877fbbad07ddde1171f
-rw-r--r--firmware/target/arm/imx233/system-imx233.c140
1 files changed, 71 insertions, 69 deletions
diff --git a/firmware/target/arm/imx233/system-imx233.c b/firmware/target/arm/imx233/system-imx233.c
index dfa6b569a8..64309b6720 100644
--- a/firmware/target/arm/imx233/system-imx233.c
+++ b/firmware/target/arm/imx233/system-imx233.c
@@ -128,6 +128,8 @@ void system_init(void)
128 imx233_clkctrl_set_auto_slow_divisor(AS_DIV_8); 128 imx233_clkctrl_set_auto_slow_divisor(AS_DIV_8);
129 imx233_clkctrl_enable_auto_slow(true); 129 imx233_clkctrl_enable_auto_slow(true);
130 130
131 cpu_frequency = imx233_clkctrl_get_clock_freq(CLK_CPU);
132
131#if !defined(BOOTLOADER) &&(defined(SANSA_FUZEPLUS) || \ 133#if !defined(BOOTLOADER) &&(defined(SANSA_FUZEPLUS) || \
132 defined(CREATIVE_ZENXFI3) || defined(CREATIVE_ZENXFI2)) 134 defined(CREATIVE_ZENXFI3) || defined(CREATIVE_ZENXFI2))
133 fmradio_i2c_init(); 135 fmradio_i2c_init();
@@ -174,88 +176,88 @@ void imx233_digctl_set_arm_cache_timings(unsigned timings)
174} 176}
175 177
176#ifdef HAVE_ADJUSTABLE_CPU_FREQ 178#ifdef HAVE_ADJUSTABLE_CPU_FREQ
179struct cpufreq_profile_t
180{
181 /* key */
182 long cpu_freq;
183 /* parameters */
184 int vddd, vddd_bo;
185 int hbus_div;
186 int cpu_idiv, cpu_fdiv;
187 long emi_freq;
188 int arm_cache_timings;
189};
190
191static struct cpufreq_profile_t cpu_profiles[] =
192{
193 /* clk_p@454.74 MHz, clk_h@130.91 MHz, clk_emi@130.91 MHz */
194 {IMX233_CPUFREQ_454_MHz, 1550, 1450, 3, 1, 19, IMX233_EMIFREQ_130_MHz, 0},
195 /* clk_p@261.82 MHz, clk_h@130.91 MHz, clk_emi@130.91 MHz */
196 {IMX233_CPUFREQ_261_MHz, 1275, 1175, 2, 1, 33, IMX233_EMIFREQ_130_MHz, 0},
197 /* clk_p@64 MHz, clk_h@64 MHz, clk_emi@64 MHz */
198 {IMX233_CPUFREQ_64_MHz, 1050, 975, 1, 5, 27, IMX233_EMIFREQ_64_MHz, 0},
199 /* dummy */
200 {0, 0, 0, 0, 0, 0, 0, 0}
201};
202
203#define NR_CPU_PROFILES ((int)(sizeof(cpu_profiles)/sizeof(cpu_profiles[0])))
204
177void set_cpu_frequency(long frequency) 205void set_cpu_frequency(long frequency)
178{ 206{
179 /* don't change the frequency if it is useless (changes are expensive) */ 207 /* don't change the frequency if it is useless (changes are expensive) */
180 if(cpu_frequency == frequency) 208 if(cpu_frequency == frequency)
181 return; 209 return;
182 210
183 cpu_frequency = frequency; 211 struct cpufreq_profile_t *prof = cpu_profiles;
212 while(prof->cpu_freq != 0 && prof->cpu_freq != frequency)
213 prof++;
214 if(prof->cpu_freq == 0)
215 return;
184 /* disable auto-slow (enable back afterwards) */ 216 /* disable auto-slow (enable back afterwards) */
185 bool as = imx233_clkctrl_is_auto_slow_enabled(); 217 bool as = imx233_clkctrl_is_auto_slow_enabled();
186 imx233_clkctrl_enable_auto_slow(false); 218 imx233_clkctrl_enable_auto_slow(false);
187 /* go back to a known state in safe way:
188 * clk_p@24 MHz
189 * clk_h@6 MHz
190 * WARNING: we must absolutely avoid that clk_h be too low or too high
191 * during the change. We first change the clk_p/clk_h ratio to 4 so
192 * that it cannot be too high (480/4=120 MHz max) or too low
193 * (24/4=6 MHz min). Then we switch clk_p to bypass. We chose a ratio of 4
194 * which is greater than all clk_p/clk_h ratios used below so that further
195 * changes are safe too */
196 imx233_clkctrl_set_clock_divisor(CLK_HBUS, 4);
197 imx233_clkctrl_set_bypass_pll(CLK_CPU, true);
198 imx233_digctl_set_arm_cache_timings(0);
199 219
200 switch(frequency) 220 /* WARNING watch out the order ! */
221 if(frequency > cpu_frequency)
201 { 222 {
202 case IMX233_CPUFREQ_454_MHz: 223 /* Change VDDD regulator */
203 /* set VDDD to 1.550 mV (brownout at 1.450 mV) */ 224 imx233_power_set_regulator(REGULATOR_VDDD, prof->vddd, prof->vddd_bo);
204 imx233_power_set_regulator(REGULATOR_VDDD, 1550, 1450); 225 /* Change ARM cache timings */
205 /* clk_h@clk_p/3 */ 226 imx233_digctl_set_arm_cache_timings(prof->arm_cache_timings);
206 imx233_clkctrl_set_clock_divisor(CLK_HBUS, 3); 227 /* Switch CPU to crystal at 24MHz */
207 /* clk_p@ref_cpu/1*18/19 */ 228 imx233_clkctrl_set_bypass_pll(CLK_CPU, true);
208 imx233_clkctrl_set_fractional_divisor(CLK_CPU, 19); 229 /* Program CPU divider for PLL */
209 imx233_clkctrl_set_clock_divisor(CLK_CPU, 1); 230 imx233_clkctrl_set_fractional_divisor(CLK_CPU, prof->cpu_fdiv);
210 imx233_clkctrl_set_bypass_pll(CLK_CPU, false); 231 imx233_clkctrl_set_clock_divisor(CLK_CPU, prof->cpu_idiv);
211 232 /* Change the HBUS divider to its final value */
212 imx233_emi_set_frequency(IMX233_EMIFREQ_130_MHz); 233 imx233_clkctrl_set_clock_divisor(CLK_HBUS, prof->hbus_div);
213 /* ref_cpu@480 MHz 234 /* Switch back CPU to PLL */
214 * ref_emi@480 MHz 235 imx233_clkctrl_set_bypass_pll(CLK_CPU, false);
215 * clk_emi@130.91 MHz 236 /* Set the new EMI frequency */
216 * clk_p@454.74 MHz 237 imx233_emi_set_frequency(prof->emi_freq);
217 * clk_h@130.91 MHz */ 238 }
218 break; 239 else
219 case IMX233_CPUFREQ_261_MHz: 240 {
220 /* set VDDD to 1.275 mV (brownout at 1.175 mV) */ 241 /* Switch CPU to crystal at 24MHz */
221 imx233_power_set_regulator(REGULATOR_VDDD, 1275, 1175); 242 imx233_clkctrl_set_bypass_pll(CLK_CPU, true);
222 /* clk_h@clk_p/2 */ 243 /* Program HBUS divider to its final value */
223 imx233_clkctrl_set_clock_divisor(CLK_HBUS, 2); 244 imx233_clkctrl_set_clock_divisor(CLK_HBUS, prof->hbus_div);
224 /* clk_p@ref_cpu/1*18/33 */ 245 /* Program CPU divider for PLL */
225 imx233_clkctrl_set_fractional_divisor(CLK_CPU, 33); 246 imx233_clkctrl_set_fractional_divisor(CLK_CPU, prof->cpu_fdiv);
226 imx233_clkctrl_set_clock_divisor(CLK_CPU, 1); 247 imx233_clkctrl_set_clock_divisor(CLK_CPU, prof->cpu_idiv);
227 imx233_clkctrl_set_bypass_pll(CLK_CPU, false); 248 /* Switch back CPU to PLL */
228 249 imx233_clkctrl_set_bypass_pll(CLK_CPU, false);
229 imx233_emi_set_frequency(IMX233_EMIFREQ_130_MHz); 250 /* Set the new EMI frequency */
230 /* ref_cpu@480 MHz 251 imx233_emi_set_frequency(prof->emi_freq);
231 * ref_emi@480 MHz 252 /* Change ARM cache timings */
232 * clk_emi@130.91 MHz 253 imx233_digctl_set_arm_cache_timings(prof->arm_cache_timings);
233 * clk_p@261.82 MHz 254 /* Change VDDD regulator */
234 * clk_h@130.91 MHz */ 255 imx233_power_set_regulator(REGULATOR_VDDD, prof->vddd, prof->vddd_bo);
235 break;
236 case IMX233_CPUFREQ_64_MHz:
237 /* set VDDD to 1.050 mV (brownout at 0.975 mV) */
238 imx233_power_set_regulator(REGULATOR_VDDD, 1050, 975);
239 /* clk_h@clk_p */
240 imx233_clkctrl_set_clock_divisor(CLK_HBUS, 1);
241 /* clk_p@ref_cpu/5*18/27 */
242 imx233_clkctrl_set_fractional_divisor(CLK_CPU, 27);
243 imx233_clkctrl_set_clock_divisor(CLK_CPU, 5);
244 imx233_clkctrl_set_bypass_pll(CLK_CPU, false);
245
246 imx233_emi_set_frequency(IMX233_EMIFREQ_64_MHz);
247 imx233_digctl_set_arm_cache_timings(3);
248 /* ref_cpu@480 MHz
249 * ref_emi@480 MHz
250 * clk_emi@64 MHz
251 * clk_p@64 MHz
252 * clk_h@64 MHz */
253 default:
254 break;
255 } 256 }
256
257 /* enable auto slow again */ 257 /* enable auto slow again */
258 imx233_clkctrl_enable_auto_slow(as); 258 imx233_clkctrl_enable_auto_slow(as);
259 /* update frequency */
260 cpu_frequency = frequency;
259} 261}
260#endif 262#endif
261 263