imx233: rework frequency scaling
[maemo-rb.git] / firmware / target / arm / imx233 / system-imx233.c
blob64309b672014cb158432dae563c9bd34cbccb4a5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2011 by Amaury Pouly
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "kernel.h"
23 #include "system.h"
24 #include "gcc_extensions.h"
25 #include "system-target.h"
26 #include "cpu.h"
27 #include "clkctrl-imx233.h"
28 #include "pinctrl-imx233.h"
29 #include "timrot-imx233.h"
30 #include "dma-imx233.h"
31 #include "ssp-imx233.h"
32 #include "i2c-imx233.h"
33 #include "dcp-imx233.h"
34 #include "pwm-imx233.h"
35 #include "icoll-imx233.h"
36 #include "lradc-imx233.h"
37 #include "rtc-imx233.h"
38 #include "power-imx233.h"
39 #include "emi-imx233.h"
40 #include "lcd.h"
41 #include "backlight-target.h"
42 #include "button.h"
43 #include "fmradio_i2c.h"
45 void imx233_chip_reset(void)
47 HW_CLKCTRL_RESET = HW_CLKCTRL_RESET_CHIP;
50 void system_reboot(void)
52 _backlight_off();
54 disable_irq();
56 /* use watchdog to reset */
57 imx233_chip_reset();
58 while(1);
61 void system_exception_wait(void)
63 /* make sure lcd and backlight are on */
64 lcd_update();
65 _backlight_on();
66 _backlight_set_brightness(DEFAULT_BRIGHTNESS_SETTING);
67 /* wait until button release (if a button is pressed) */
68 #ifdef HAVE_BUTTON_DATA
69 int data;
70 while(button_read_device(&data));
71 /* then wait until next button press */
72 while(!button_read_device(&data));
73 #else
74 while(button_read_device());
75 /* then wait until next button press */
76 while(!button_read_device());
77 #endif
80 int system_memory_guard(int newmode)
82 (void)newmode;
83 return 0;
86 static void set_page_tables(void)
88 /* map every memory region to itself */
89 map_section(0, 0, 0x1000, CACHE_NONE);
91 /* map RAM and enable caching for it */
92 map_section(DRAM_ORIG, CACHED_DRAM_ADDR, MEMORYSIZE, CACHE_ALL);
93 map_section(DRAM_ORIG, BUFFERED_DRAM_ADDR, MEMORYSIZE, BUFFERED);
96 void memory_init(void)
98 ttb_init();
99 set_page_tables();
100 enable_mmu();
103 void system_init(void)
105 /* NOTE: don't use anything here that might require tick task !
106 * It is initialized by kernel_init *after* system_init().
107 * The main() will naturally set cpu speed to normal after kernel_init()
108 * so don't bother if the cpu is running at 24MHz here. */
109 imx233_clkctrl_enable_clock(CLK_PLL, true);
110 imx233_rtc_init();
111 imx233_icoll_init();
112 imx233_pinctrl_init();
113 imx233_timrot_init();
114 imx233_dma_init();
115 imx233_ssp_init();
116 imx233_dcp_init();
117 imx233_pwm_init();
118 imx233_lradc_init();
119 imx233_power_init();
120 imx233_i2c_init();
122 imx233_clkctrl_enable_auto_slow_monitor(AS_CPU_INSTR, true);
123 imx233_clkctrl_enable_auto_slow_monitor(AS_CPU_DATA, true);
124 imx233_clkctrl_enable_auto_slow_monitor(AS_TRAFFIC, true);
125 imx233_clkctrl_enable_auto_slow_monitor(AS_TRAFFIC_JAM, true);
126 imx233_clkctrl_enable_auto_slow_monitor(AS_APBXDMA, true);
127 imx233_clkctrl_enable_auto_slow_monitor(AS_APBHDMA, true);
128 imx233_clkctrl_set_auto_slow_divisor(AS_DIV_8);
129 imx233_clkctrl_enable_auto_slow(true);
131 cpu_frequency = imx233_clkctrl_get_clock_freq(CLK_CPU);
133 #if !defined(BOOTLOADER) &&(defined(SANSA_FUZEPLUS) || \
134 defined(CREATIVE_ZENXFI3) || defined(CREATIVE_ZENXFI2))
135 fmradio_i2c_init();
136 #endif
139 bool imx233_us_elapsed(uint32_t ref, unsigned us_delay)
141 uint32_t cur = HW_DIGCTL_MICROSECONDS;
142 if(ref + us_delay <= ref)
143 return !(cur > ref) && !(cur < (ref + us_delay));
144 else
145 return (cur < ref) || cur >= (ref + us_delay);
148 void imx233_reset_block(volatile uint32_t *block_reg)
150 /* soft-reset */
151 __REG_SET(*block_reg) = __BLOCK_SFTRST;
152 /* make sure block is gated off */
153 while(!(*block_reg & __BLOCK_CLKGATE));
154 /* bring block out of reset */
155 __REG_CLR(*block_reg) = __BLOCK_SFTRST;
156 while(*block_reg & __BLOCK_SFTRST);
157 /* make sure clock is running */
158 __REG_CLR(*block_reg) = __BLOCK_CLKGATE;
159 while(*block_reg & __BLOCK_CLKGATE);
162 void udelay(unsigned us)
164 uint32_t ref = HW_DIGCTL_MICROSECONDS;
165 while(!imx233_us_elapsed(ref, us));
168 void imx233_digctl_set_arm_cache_timings(unsigned timings)
170 HW_DIGCTL_ARMCACHE =
171 timings << HW_DIGCTL_ARMCACHE__ITAG_SS_BP |
172 timings << HW_DIGCTL_ARMCACHE__DTAG_SS_BP |
173 timings << HW_DIGCTL_ARMCACHE__CACHE_SS_BP |
174 timings << HW_DIGCTL_ARMCACHE__DRTY_SS_BP |
175 timings << HW_DIGCTL_ARMCACHE__VALID_SS_BP;
178 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
179 struct cpufreq_profile_t
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;
191 static struct cpufreq_profile_t cpu_profiles[] =
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}
203 #define NR_CPU_PROFILES ((int)(sizeof(cpu_profiles)/sizeof(cpu_profiles[0])))
205 void set_cpu_frequency(long frequency)
207 /* don't change the frequency if it is useless (changes are expensive) */
208 if(cpu_frequency == frequency)
209 return;
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;
216 /* disable auto-slow (enable back afterwards) */
217 bool as = imx233_clkctrl_is_auto_slow_enabled();
218 imx233_clkctrl_enable_auto_slow(false);
220 /* WARNING watch out the order ! */
221 if(frequency > cpu_frequency)
223 /* Change VDDD regulator */
224 imx233_power_set_regulator(REGULATOR_VDDD, prof->vddd, prof->vddd_bo);
225 /* Change ARM cache timings */
226 imx233_digctl_set_arm_cache_timings(prof->arm_cache_timings);
227 /* Switch CPU to crystal at 24MHz */
228 imx233_clkctrl_set_bypass_pll(CLK_CPU, true);
229 /* Program CPU divider for PLL */
230 imx233_clkctrl_set_fractional_divisor(CLK_CPU, prof->cpu_fdiv);
231 imx233_clkctrl_set_clock_divisor(CLK_CPU, prof->cpu_idiv);
232 /* Change the HBUS divider to its final value */
233 imx233_clkctrl_set_clock_divisor(CLK_HBUS, prof->hbus_div);
234 /* Switch back CPU to PLL */
235 imx233_clkctrl_set_bypass_pll(CLK_CPU, false);
236 /* Set the new EMI frequency */
237 imx233_emi_set_frequency(prof->emi_freq);
239 else
241 /* Switch CPU to crystal at 24MHz */
242 imx233_clkctrl_set_bypass_pll(CLK_CPU, true);
243 /* Program HBUS divider to its final value */
244 imx233_clkctrl_set_clock_divisor(CLK_HBUS, prof->hbus_div);
245 /* Program CPU divider for PLL */
246 imx233_clkctrl_set_fractional_divisor(CLK_CPU, prof->cpu_fdiv);
247 imx233_clkctrl_set_clock_divisor(CLK_CPU, prof->cpu_idiv);
248 /* Switch back CPU to PLL */
249 imx233_clkctrl_set_bypass_pll(CLK_CPU, false);
250 /* Set the new EMI frequency */
251 imx233_emi_set_frequency(prof->emi_freq);
252 /* Change ARM cache timings */
253 imx233_digctl_set_arm_cache_timings(prof->arm_cache_timings);
254 /* Change VDDD regulator */
255 imx233_power_set_regulator(REGULATOR_VDDD, prof->vddd, prof->vddd_bo);
257 /* enable auto slow again */
258 imx233_clkctrl_enable_auto_slow(as);
259 /* update frequency */
260 cpu_frequency = frequency;
262 #endif
264 void imx233_enable_usb_controller(bool enable)
266 if(enable)
267 __REG_CLR(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
268 else
269 __REG_SET(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
272 void imx233_enable_usb_phy(bool enable)
274 if(enable)
276 __REG_CLR(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;
277 __REG_CLR(HW_USBPHY_PWD) = HW_USBPHY_PWD__ALL;
279 else
281 __REG_SET(HW_USBPHY_PWD) = HW_USBPHY_PWD__ALL;
282 __REG_SET(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;