diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2013-01-13 00:55:34 +0000 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2013-01-13 00:58:46 +0000 |
commit | 4307f95a1f57d3038a2d41f0f4c0ddf33f50630d (patch) | |
tree | 027623d732f64d886c1ee2b0341fba68282feb96 | |
parent | 29e51a17775df5040b12d93834c45b3f1171ed9d (diff) | |
download | rockbox-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.c | 140 |
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 |
179 | struct 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 | |||
191 | static 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 | |||
177 | void set_cpu_frequency(long frequency) | 205 | void 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 | ||