imx233: rework cpu frequency scaling
[maemo-rb.git] / firmware / target / arm / imx233 / system-imx233.c
blob6dde16d8634be2a6cd50e9928aaa3b0ffe1469c2
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 "lcd.h"
40 #include "backlight-target.h"
41 #include "button.h"
42 #include "fmradio_i2c.h"
44 void imx233_chip_reset(void)
46 HW_CLKCTRL_RESET = HW_CLKCTRL_RESET_CHIP;
49 void system_reboot(void)
51 _backlight_off();
53 disable_irq();
55 /* use watchdog to reset */
56 imx233_chip_reset();
57 while(1);
60 void system_exception_wait(void)
62 /* make sure lcd and backlight are on */
63 lcd_update();
64 _backlight_on();
65 _backlight_set_brightness(DEFAULT_BRIGHTNESS_SETTING);
66 /* wait until button release (if a button is pressed) */
67 #ifdef HAVE_BUTTON_DATA
68 int data;
69 while(button_read_device(&data));
70 /* then wait until next button press */
71 while(!button_read_device(&data));
72 #else
73 while(button_read_device());
74 /* then wait until next button press */
75 while(!button_read_device());
76 #endif
79 int system_memory_guard(int newmode)
81 (void)newmode;
82 return 0;
85 static void set_page_tables(void)
87 /* map every memory region to itself */
88 map_section(0, 0, 0x1000, CACHE_NONE);
90 /* map RAM and enable caching for it */
91 map_section(DRAM_ORIG, CACHED_DRAM_ADDR, MEMORYSIZE, CACHE_ALL);
92 map_section(DRAM_ORIG, BUFFERED_DRAM_ADDR, MEMORYSIZE, BUFFERED);
95 void memory_init(void)
97 ttb_init();
98 set_page_tables();
99 enable_mmu();
102 void system_init(void)
104 imx233_clkctrl_enable_clock(CLK_PLL, true);
105 imx233_rtc_init();
106 imx233_icoll_init();
107 imx233_pinctrl_init();
108 imx233_timrot_init();
109 imx233_dma_init();
110 imx233_ssp_init();
111 imx233_dcp_init();
112 imx233_pwm_init();
113 imx233_lradc_init();
114 imx233_i2c_init();
115 #if !defined(BOOTLOADER) &&(defined(SANSA_FUZEPLUS) || \
116 defined(CREATIVE_ZENXFI3) || defined(CREATIVE_ZENXFI2))
117 fmradio_i2c_init();
118 #endif
119 imx233_clkctrl_enable_auto_slow_monitor(AS_CPU_INSTR, true);
120 imx233_clkctrl_enable_auto_slow_monitor(AS_CPU_DATA, true);
121 imx233_clkctrl_enable_auto_slow_monitor(AS_TRAFFIC, true);
122 imx233_clkctrl_enable_auto_slow_monitor(AS_TRAFFIC_JAM, true);
123 imx233_clkctrl_enable_auto_slow_monitor(AS_APBXDMA, true);
124 imx233_clkctrl_enable_auto_slow_monitor(AS_APBHDMA, true);
125 imx233_clkctrl_set_auto_slow_divisor(AS_DIV_8);
126 imx233_clkctrl_enable_auto_slow(true);
129 bool imx233_us_elapsed(uint32_t ref, unsigned us_delay)
131 uint32_t cur = HW_DIGCTL_MICROSECONDS;
132 if(ref + us_delay <= ref)
133 return !(cur > ref) && !(cur < (ref + us_delay));
134 else
135 return (cur < ref) || cur >= (ref + us_delay);
138 void imx233_reset_block(volatile uint32_t *block_reg)
140 /* soft-reset */
141 __REG_SET(*block_reg) = __BLOCK_SFTRST;
142 /* make sure block is gated off */
143 while(!(*block_reg & __BLOCK_CLKGATE));
144 /* bring block out of reset */
145 __REG_CLR(*block_reg) = __BLOCK_SFTRST;
146 while(*block_reg & __BLOCK_SFTRST);
147 /* make sure clock is running */
148 __REG_CLR(*block_reg) = __BLOCK_CLKGATE;
149 while(*block_reg & __BLOCK_CLKGATE);
152 void udelay(unsigned us)
154 uint32_t ref = HW_DIGCTL_MICROSECONDS;
155 while(!imx233_us_elapsed(ref, us));
158 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
159 void set_cpu_frequency(long frequency)
161 /* don't change the frequency if it is useless (changes are expensive) */
162 if(cpu_frequency == frequency)
163 return;
165 cpu_frequency = frequency;
166 /* disable auto-slow (enable back afterwards) */
167 imx233_clkctrl_enable_auto_slow(false);
168 /* go back to a known state in safe way:
169 * clk_p@24 MHz
170 * clk_h@6 MHz
171 * WARNING: we must absolutely avoid that clk_h be too low or too high
172 * during the change. We first change the clk_p/clk_h ratio to 4 so
173 * that it cannot be too high (480/4=120 MHz max) or too low
174 * (24/4=6 MHz min). Then we switch clk_p to bypass. We chose a ratio of 4
175 * which is greater than all clk_p/clk_h ratios used below so that further
176 * changes are safe too */
177 imx233_clkctrl_set_clock_divisor(CLK_HBUS, 4);
178 imx233_clkctrl_set_bypass_pll(CLK_CPU, true);
180 switch(frequency)
182 case IMX233_CPUFREQ_454_MHz:
183 /* set VDDD to 1.550 mV (brownout at 1.450 mV) */
184 imx233_power_set_regulator(REGULATOR_VDDD, 1550, 1450);
185 /* clk_h@clk_p/3 */
186 imx233_clkctrl_set_clock_divisor(CLK_HBUS, 3);
187 /* clk_p@ref_cpu/1*18/19 */
188 imx233_clkctrl_set_fractional_divisor(CLK_CPU, 19);
189 imx233_clkctrl_set_clock_divisor(CLK_CPU, 1);
190 imx233_clkctrl_set_bypass_pll(CLK_CPU, false);
191 /* ref_cpu@480 MHz
192 * ref_emi@480 MHz
193 * clk_emi@130.91 MHz
194 * clk_p@454.74 MHz
195 * clk_h@130.91 MHz */
196 break;
197 case IMX233_CPUFREQ_261_MHz:
198 /* set VDDD to 1.275 mV (brownout at 1.175 mV) */
199 imx233_power_set_regulator(REGULATOR_VDDD, 1275, 1175);
200 /* clk_h@clk_p/2 */
201 imx233_clkctrl_set_clock_divisor(CLK_HBUS, 2);
202 /* clk_p@ref_cpu/1*18/33 */
203 imx233_clkctrl_set_fractional_divisor(CLK_CPU, 33);
204 imx233_clkctrl_set_clock_divisor(CLK_CPU, 1);
205 imx233_clkctrl_set_bypass_pll(CLK_CPU, false);
206 /* ref_cpu@480 MHz
207 * ref_emi@480 MHz
208 * clk_emi@130.91 MHz
209 * clk_p@261.82 MHz
210 * clk_h@130.91 MHz */
211 break;
212 default:
213 break;
216 /* enable auto slow again */
217 imx233_clkctrl_enable_auto_slow(true);
219 #endif
221 void imx233_enable_usb_controller(bool enable)
223 if(enable)
224 __REG_CLR(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
225 else
226 __REG_SET(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
229 void imx233_enable_usb_phy(bool enable)
231 if(enable)
233 __REG_CLR(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;
234 __REG_CLR(HW_USBPHY_PWD) = HW_USBPHY_PWD__ALL;
236 else
238 __REG_SET(HW_USBPHY_PWD) = HW_USBPHY_PWD__ALL;
239 __REG_SET(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;