Root/
Source at commit dc637c9 created 12 years 4 months ago. By Xiangfu Liu, xburst: ben nanonote: first add WPAN(atben,atusb) driver take from qi-kernel.git thanks to Werner | |
---|---|
1 | From 87eb40e63e1b149ef87fe05765b97328bfbd1c1f Mon Sep 17 00:00:00 2001 |
2 | From: Xiangfu Liu <xiangfu@macbook.openmobilefree.net> |
3 | Date: Wed, 14 Sep 2011 14:29:37 +0800 |
4 | Subject: [PATCH 24/32] forward code to linux 3.0 |
5 | |
6 | --- |
7 | arch/mips/Kconfig | 2 + |
8 | arch/mips/include/asm/cacheflush.h | 6 + |
9 | arch/mips/include/asm/mach-jz4740/gpio.h | 5 + |
10 | arch/mips/include/asm/mach-jz4740/jz4740_fb.h | 8 + |
11 | arch/mips/jz4740/Makefile | 1 + |
12 | arch/mips/jz4740/clock.c | 230 +++++++++++++++++++++++- |
13 | arch/mips/jz4740/clock.h | 4 + |
14 | arch/mips/jz4740/cpufreq.c | 226 ++++++++++++++++++++++++ |
15 | arch/mips/jz4740/gpio.c | 148 ++++------------ |
16 | arch/mips/jz4740/irq.c | 92 ++++------ |
17 | arch/mips/jz4740/irq.h | 6 +- |
18 | arch/mips/jz4740/platform.c | 20 ++- |
19 | arch/mips/jz4740/pm.c | 3 - |
20 | arch/mips/jz4740/reset.c | 46 +++++- |
21 | arch/mips/kernel/cpufreq/Kconfig | 13 ++- |
22 | 15 files changed, 623 insertions(+), 187 deletions(-) |
23 | create mode 100644 arch/mips/jz4740/cpufreq.c |
24 | |
25 | diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig |
26 | index 653da62..42c4e6a 100644 |
27 | --- a/arch/mips/Kconfig |
28 | +++ b/arch/mips/Kconfig |
29 | @@ -211,6 +211,8 @@ config MACH_JZ4740 |
30 | select SYS_HAS_EARLY_PRINTK |
31 | select HAVE_PWM |
32 | select HAVE_CLK |
33 | + select CPU_SUPPORTS_CPUFREQ |
34 | + select GENERIC_IRQ_CHIP |
35 | |
36 | config LANTIQ |
37 | bool "Lantiq based platforms" |
38 | diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h |
39 | index 40bb9fd..2a26af0 100644 |
40 | --- a/arch/mips/include/asm/cacheflush.h |
41 | +++ b/arch/mips/include/asm/cacheflush.h |
42 | @@ -114,4 +114,10 @@ unsigned long run_uncached(void *func); |
43 | extern void *kmap_coherent(struct page *page, unsigned long addr); |
44 | extern void kunmap_coherent(void); |
45 | |
46 | +#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE |
47 | +static inline void flush_kernel_dcache_page(struct page *page) |
48 | +{ |
49 | + flush_dcache_page(page); |
50 | +} |
51 | + |
52 | #endif /* _ASM_CACHEFLUSH_H */ |
53 | diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h |
54 | index 7b74703..5a3675e 100644 |
55 | --- a/arch/mips/include/asm/mach-jz4740/gpio.h |
56 | +++ b/arch/mips/include/asm/mach-jz4740/gpio.h |
57 | @@ -253,6 +253,9 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask); |
58 | #define JZ_GPIO_MEM_WAIT JZ_GPIO_PORTC(27) |
59 | #define JZ_GPIO_MEM_FRE JZ_GPIO_PORTC(28) |
60 | #define JZ_GPIO_MEM_FWE JZ_GPIO_PORTC(29) |
61 | +/* Pins have different assignment in SLCD mode */ |
62 | +#define JZ_GPIO_SLCD_RS JZ_GPIO_PORTC(19) |
63 | +#define JZ_GPIO_SLCD_CS JZ_GPIO_PORTC(20) |
64 | |
65 | #define JZ_GPIO_FUNC_LCD_DATA0 JZ_GPIO_FUNC1 |
66 | #define JZ_GPIO_FUNC_LCD_DATA1 JZ_GPIO_FUNC1 |
67 | @@ -284,6 +287,8 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask); |
68 | #define JZ_GPIO_FUNC_MEM_WAIT JZ_GPIO_FUNC1 |
69 | #define JZ_GPIO_FUNC_MEM_FRE JZ_GPIO_FUNC1 |
70 | #define JZ_GPIO_FUNC_MEM_FWE JZ_GPIO_FUNC1 |
71 | +#define JZ_GPIO_FUNC_SLCD_RS JZ_GPIO_FUNC1 |
72 | +#define JZ_GPIO_FUNC_SLCD_CS JZ_GPIO_FUNC1 |
73 | |
74 | |
75 | #define JZ_GPIO_MEM_ADDR19 JZ_GPIO_PORTB(22) |
76 | diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_fb.h b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h |
77 | index 6a50e6f..b2b6dba 100644 |
78 | --- a/arch/mips/include/asm/mach-jz4740/jz4740_fb.h |
79 | +++ b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h |
80 | @@ -30,6 +30,12 @@ enum jz4740_fb_lcd_type { |
81 | JZ_LCD_TYPE_DUAL_COLOR_STN = 10, |
82 | JZ_LCD_TYPE_DUAL_MONOCHROME_STN = 11, |
83 | JZ_LCD_TYPE_8BIT_SERIAL = 12, |
84 | + JZ_LCD_TYPE_SMART_PARALLEL_8_BIT = 1 | (1 << 5), |
85 | + JZ_LCD_TYPE_SMART_PARALLEL_16_BIT = 0 | (1 << 5), |
86 | + JZ_LCD_TYPE_SMART_PARALLEL_18_BIT = 2 | (1 << 5), |
87 | + JZ_LCD_TYPE_SMART_SERIAL_8_BIT = 1 | (3 << 5), |
88 | + JZ_LCD_TYPE_SMART_SERIAL_16_BIT = 0 | (3 << 5), |
89 | + JZ_LCD_TYPE_SMART_SERIAL_18_BIT = 2 | (3 << 5), |
90 | }; |
91 | |
92 | #define JZ4740_FB_SPECIAL_TFT_CONFIG(start, stop) (((start) << 16) | (stop)) |
93 | @@ -62,6 +68,8 @@ struct jz4740_fb_platform_data { |
94 | |
95 | unsigned pixclk_falling_edge:1; |
96 | unsigned date_enable_active_low:1; |
97 | + unsigned chip_select_active_low:1; |
98 | + unsigned register_select_active_low:1; |
99 | }; |
100 | |
101 | #endif |
102 | diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile |
103 | index 72eb2ad..e88ab59 100644 |
104 | --- a/arch/mips/jz4740/Makefile |
105 | +++ b/arch/mips/jz4740/Makefile |
106 | @@ -19,5 +19,6 @@ obj-$(CONFIG_JZ4740_ID800WT) += board-id800wt.o |
107 | # PM support |
108 | |
109 | obj-$(CONFIG_PM) += pm.o |
110 | +obj-$(CONFIG_CPU_FREQ_JZ) += cpufreq.o |
111 | |
112 | ccflags-y := -Werror -Wall |
113 | diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c |
114 | index 118a8a5..da423d1 100644 |
115 | --- a/arch/mips/jz4740/clock.c |
116 | +++ b/arch/mips/jz4740/clock.c |
117 | @@ -1,5 +1,8 @@ |
118 | /* |
119 | + * Copyright (c) 2006-2007, Ingenic Semiconductor Inc. |
120 | * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> |
121 | + * Copyright (c) 2010, Ulrich Hecht <ulrich.hecht@gmail.com> |
122 | + * Copyright (c) 2010, Maarten ter Huurne <maarten@treewalker.org> |
123 | * JZ4740 SoC clock support |
124 | * |
125 | * This program is free software; you can redistribute it and/or modify it |
126 | @@ -41,16 +44,20 @@ |
127 | #define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31) |
128 | #define JZ_CLOCK_CTRL_KO_ENABLE BIT(30) |
129 | #define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29) |
130 | -#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000 |
131 | #define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22) |
132 | #define JZ_CLOCK_CTRL_PLL_HALF BIT(21) |
133 | -#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000 |
134 | #define JZ_CLOCK_CTRL_UDIV_OFFSET 23 |
135 | #define JZ_CLOCK_CTRL_LDIV_OFFSET 16 |
136 | #define JZ_CLOCK_CTRL_MDIV_OFFSET 12 |
137 | #define JZ_CLOCK_CTRL_PDIV_OFFSET 8 |
138 | #define JZ_CLOCK_CTRL_HDIV_OFFSET 4 |
139 | #define JZ_CLOCK_CTRL_CDIV_OFFSET 0 |
140 | +#define JZ_CLOCK_CTRL_UDIV_MASK (0x3f << JZ_CLOCK_CTRL_UDIV_OFFSET) |
141 | +#define JZ_CLOCK_CTRL_LDIV_MASK (0x1f << JZ_CLOCK_CTRL_LDIV_OFFSET) |
142 | +#define JZ_CLOCK_CTRL_MDIV_MASK (0x0f << JZ_CLOCK_CTRL_MDIV_OFFSET) |
143 | +#define JZ_CLOCK_CTRL_PDIV_MASK (0x0f << JZ_CLOCK_CTRL_PDIV_OFFSET) |
144 | +#define JZ_CLOCK_CTRL_HDIV_MASK (0x0f << JZ_CLOCK_CTRL_HDIV_OFFSET) |
145 | +#define JZ_CLOCK_CTRL_CDIV_MASK (0x0f << JZ_CLOCK_CTRL_CDIV_OFFSET) |
146 | |
147 | #define JZ_CLOCK_GATE_UART0 BIT(0) |
148 | #define JZ_CLOCK_GATE_TCU BIT(1) |
149 | @@ -90,6 +97,7 @@ |
150 | #define JZ_CLOCK_PLL_M_OFFSET 23 |
151 | #define JZ_CLOCK_PLL_N_OFFSET 18 |
152 | #define JZ_CLOCK_PLL_OD_OFFSET 16 |
153 | +#define JZ_CLOCK_PLL_STABILIZE_OFFSET 0 |
154 | |
155 | #define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2) |
156 | #define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0) |
157 | @@ -97,10 +105,15 @@ |
158 | #define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7) |
159 | #define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6) |
160 | |
161 | +#define JZ_REG_EMC_RTCNT 0x88 |
162 | +#define JZ_REG_EMC_RTCOR 0x8C |
163 | + |
164 | static void __iomem *jz_clock_base; |
165 | static spinlock_t jz_clock_lock; |
166 | static LIST_HEAD(jz_clocks); |
167 | |
168 | +static void __iomem *jz_emc_base; |
169 | + |
170 | struct main_clk { |
171 | struct clk clk; |
172 | uint32_t div_offset; |
173 | @@ -204,25 +217,88 @@ static int jz_clk_ko_is_enabled(struct clk *clk) |
174 | return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE); |
175 | } |
176 | |
177 | +static struct static_clk jz_clk_ext; |
178 | + |
179 | +static unsigned long jz_clk_pll_calc_rate( |
180 | + unsigned int in_div, unsigned int feedback, unsigned int out_div) |
181 | +{ |
182 | + return ((jz_clk_ext.rate / in_div) * feedback) / out_div; |
183 | +} |
184 | + |
185 | +static void jz_clk_pll_calc_dividers(unsigned long rate, |
186 | + unsigned int *in_div, unsigned int *feedback, unsigned int *out_div) |
187 | +{ |
188 | + unsigned int target; |
189 | + |
190 | + /* The frequency after the input divider must be between 1 and 15 MHz. |
191 | + The highest divider yields the best resolution. */ |
192 | + *in_div = jz_clk_ext.rate / 1000000; |
193 | + if (*in_div >= 34) |
194 | + *in_div = 33; |
195 | + |
196 | + /* The frequency before the output divider must be between 100 and |
197 | + 500 MHz. The lowest target rate is more energy efficient. */ |
198 | + if (rate < 25000000) { |
199 | + *out_div = 4; |
200 | + target = 25000000 * 4; |
201 | + } else if (rate <= 50000000) { |
202 | + *out_div = 4; |
203 | + target = rate * 4; |
204 | + } else if (rate <= 100000000) { |
205 | + *out_div = 2; |
206 | + target = rate * 2; |
207 | + } else if (rate <= 500000000) { |
208 | + *out_div = 1; |
209 | + target = rate; |
210 | + } else { |
211 | + *out_div = 1; |
212 | + target = 500000000; |
213 | + } |
214 | + |
215 | + /* Compute the feedback divider. |
216 | + Since the divided input is at least 1 MHz and the target frequency |
217 | + at most 500 MHz, the feedback will be at most 500 and will therefore |
218 | + always fit in the 9-bit register. |
219 | + Similarly, the divided input is at most 15 MHz and the target |
220 | + frequency at least 100 MHz, so the feedback will be at least 6 |
221 | + where the minimum supported value is 2. */ |
222 | + *feedback = ((target / 1000) * *in_div) / (jz_clk_ext.rate / 1000); |
223 | +} |
224 | + |
225 | +static unsigned long jz_clk_pll_round_rate(struct clk *clk, unsigned long rate) |
226 | +{ |
227 | + unsigned int in_div, feedback, out_div; |
228 | + /* The PLL frequency must be a multiple of 24 MHz, since the LCD pixel |
229 | + * clock must be exactly 12 MHz for the TV-out to work. |
230 | + * TODO: A multiple of 12 MHz for the PLL would work if the PLL would |
231 | + * not be divided by 2 before being passed to the set of derived |
232 | + * clocks that includes the LCD pixel clock. |
233 | + * TODO: Systemwide decisions like this should be made by the board |
234 | + * support code, so add some kind of hook for that. |
235 | + */ |
236 | + unsigned long rate24 = (rate / 24000000) * 24000000; |
237 | + |
238 | + jz_clk_pll_calc_dividers(rate24, &in_div, &feedback, &out_div); |
239 | + return jz_clk_pll_calc_rate(in_div, feedback, out_div); |
240 | +} |
241 | + |
242 | static const int pllno[] = {1, 2, 2, 4}; |
243 | |
244 | static unsigned long jz_clk_pll_get_rate(struct clk *clk) |
245 | { |
246 | uint32_t val; |
247 | - int m; |
248 | - int n; |
249 | - int od; |
250 | + unsigned int in_div, feedback, out_div; |
251 | |
252 | val = jz_clk_reg_read(JZ_REG_CLOCK_PLL); |
253 | |
254 | if (val & JZ_CLOCK_PLL_BYPASS) |
255 | return clk_get_rate(clk->parent); |
256 | |
257 | - m = ((val >> 23) & 0x1ff) + 2; |
258 | - n = ((val >> 18) & 0x1f) + 2; |
259 | - od = (val >> 16) & 0x3; |
260 | + feedback = ((val >> 23) & 0x1ff) + 2; |
261 | + in_div = ((val >> 18) & 0x1f) + 2; |
262 | + out_div = pllno[(val >> 16) & 0x3]; |
263 | |
264 | - return ((clk_get_rate(clk->parent) / n) * m) / pllno[od]; |
265 | + return jz_clk_pll_calc_rate(in_div, feedback, out_div); |
266 | } |
267 | |
268 | static unsigned long jz_clk_pll_half_get_rate(struct clk *clk) |
269 | @@ -235,7 +311,77 @@ static unsigned long jz_clk_pll_half_get_rate(struct clk *clk) |
270 | return jz_clk_pll_get_rate(clk->parent) >> 1; |
271 | } |
272 | |
273 | -static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; |
274 | +#define SDRAM_TREF 15625 /* Refresh period: 4096 refresh cycles/64ms */ |
275 | + |
276 | +static void sdram_set_pll(unsigned int pllin) |
277 | +{ |
278 | + unsigned int ns, sdramclock; |
279 | + |
280 | + ns = 1000000000 / pllin; |
281 | + sdramclock = (SDRAM_TREF / ns) / 64 + 1; |
282 | + if (sdramclock > 0xff) sdramclock = 0xff; |
283 | + /* Set refresh registers */ |
284 | + writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCOR); |
285 | + writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCNT); |
286 | +} |
287 | + |
288 | +static int jz_clk_pll_set_rate(struct clk *clk, unsigned long rate) |
289 | +{ |
290 | + unsigned int ctrl, plcr1; |
291 | + unsigned int feedback, in_div, out_div, pllout, pllout2; |
292 | + |
293 | + jz_clk_pll_calc_dividers(rate, &in_div, &feedback, &out_div); |
294 | + |
295 | + ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); |
296 | + pllout = jz_clk_pll_calc_rate(in_div, feedback, out_div); |
297 | + pllout2 = (ctrl & JZ_CLOCK_CTRL_PLL_HALF) ? pllout : (pllout / 2); |
298 | + |
299 | + /* Init UHC clock */ |
300 | + writel(pllout2 / 48000000 - 1, jz_clock_base + JZ_REG_CLOCK_UHC); |
301 | + |
302 | + plcr1 = ((feedback - 2) << JZ_CLOCK_PLL_M_OFFSET) | |
303 | + ((in_div - 2) << JZ_CLOCK_PLL_N_OFFSET) | |
304 | + ((out_div - 1) << JZ_CLOCK_PLL_OD_OFFSET) | |
305 | + (0x20 << JZ_CLOCK_PLL_STABILIZE_OFFSET) | |
306 | + JZ_CLOCK_PLL_ENABLED; |
307 | + |
308 | + sdram_set_pll(pllout); |
309 | + |
310 | + /* LCD pixclock */ |
311 | + writel(pllout2 / 12000000 - 1, jz_clock_base + JZ_REG_CLOCK_LCD); |
312 | + |
313 | + /* configure PLL */ |
314 | + __asm__ __volatile__( |
315 | + ".set noreorder\n\t" |
316 | + ".align 5\n" |
317 | + "sw %1,0(%0)\n\t" |
318 | + "nop\n\t" |
319 | + "nop\n\t" |
320 | + "nop\n\t" |
321 | + "nop\n\t" |
322 | + "nop\n\t" |
323 | + "nop\n\t" |
324 | + "nop\n\t" |
325 | + ".set reorder\n\t" |
326 | + : |
327 | + : "r" (jz_clock_base + JZ_REG_CLOCK_PLL), "r" (plcr1)); |
328 | + |
329 | + /* MtH: For some reason the MSC will have problems if this flag is not |
330 | + restored, even though the MSC is supposedly the only divider |
331 | + that is not affected by this flag. */ |
332 | + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_CHANGE_ENABLE); |
333 | + |
334 | + return 0; |
335 | +} |
336 | + |
337 | +static const unsigned int jz_clk_main_divs[] = { |
338 | + 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 |
339 | +}; |
340 | +static const unsigned int jz_clk_main_divs_inv[] = { |
341 | + -1, 0, 1, 2, 3, -1, 4, -1, 5, -1, -1, -1, 6, -1, -1, -1, |
342 | + 7, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, |
343 | + 9 |
344 | +}; |
345 | |
346 | static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate) |
347 | { |
348 | @@ -290,6 +436,64 @@ static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate) |
349 | return 0; |
350 | } |
351 | |
352 | +static struct main_clk jz_clk_cpu; |
353 | + |
354 | +int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv, |
355 | + unsigned int mdiv, unsigned int pdiv) |
356 | +{ |
357 | + unsigned int cdiv_enc, hdiv_enc, mdiv_enc, pdiv_enc; |
358 | + unsigned int ctrl; |
359 | + unsigned int tmp, wait; |
360 | + |
361 | + if (cdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || |
362 | + hdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || |
363 | + mdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || |
364 | + pdiv >= ARRAY_SIZE(jz_clk_main_divs_inv)) |
365 | + return -EINVAL; |
366 | + cdiv_enc = jz_clk_main_divs_inv[cdiv]; |
367 | + hdiv_enc = jz_clk_main_divs_inv[hdiv]; |
368 | + mdiv_enc = jz_clk_main_divs_inv[mdiv]; |
369 | + pdiv_enc = jz_clk_main_divs_inv[pdiv]; |
370 | + if (cdiv_enc == (unsigned int)-1 || |
371 | + hdiv_enc == (unsigned int)-1 || |
372 | + mdiv_enc == (unsigned int)-1 || |
373 | + pdiv_enc == (unsigned int)-1) |
374 | + return -EINVAL; |
375 | + |
376 | + ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); |
377 | + ctrl &= ~(JZ_CLOCK_CTRL_CHANGE_ENABLE | |
378 | + JZ_CLOCK_CTRL_CDIV_MASK | JZ_CLOCK_CTRL_HDIV_MASK | |
379 | + JZ_CLOCK_CTRL_MDIV_MASK | JZ_CLOCK_CTRL_PDIV_MASK); |
380 | + if (immediate) ctrl |= JZ_CLOCK_CTRL_CHANGE_ENABLE; |
381 | + ctrl |= (cdiv_enc << JZ_CLOCK_CTRL_CDIV_OFFSET) | |
382 | + (hdiv_enc << JZ_CLOCK_CTRL_HDIV_OFFSET) | |
383 | + (mdiv_enc << JZ_CLOCK_CTRL_MDIV_OFFSET) | |
384 | + (pdiv_enc << JZ_CLOCK_CTRL_PDIV_OFFSET); |
385 | + |
386 | + /* set dividers */ |
387 | + /* delay loops lifted from the old Ingenic cpufreq driver */ |
388 | + wait = ((clk_get_rate(&jz_clk_cpu.clk) / 1000000) * 500) / 1000; |
389 | + __asm__ __volatile__( |
390 | + ".set noreorder\n\t" |
391 | + ".align 5\n" |
392 | + "sw %2,0(%1)\n\t" |
393 | + "li %0,0\n\t" |
394 | + "1:\n\t" |
395 | + "bne %0,%3,1b\n\t" |
396 | + "addi %0, 1\n\t" |
397 | + "nop\n\t" |
398 | + "nop\n\t" |
399 | + "nop\n\t" |
400 | + "nop\n\t" |
401 | + ".set reorder\n\t" |
402 | + : "=r" (tmp) |
403 | + : "r" (jz_clock_base + JZ_REG_CLOCK_CTRL), "r" (ctrl), |
404 | + "r" (wait)); |
405 | + |
406 | + return 0; |
407 | +} |
408 | +EXPORT_SYMBOL_GPL(clk_main_set_dividers); |
409 | + |
410 | static struct clk_ops jz_clk_static_ops = { |
411 | .get_rate = jz_clk_static_get_rate, |
412 | .enable = jz_clk_enable_gating, |
413 | @@ -307,6 +511,8 @@ static struct static_clk jz_clk_ext = { |
414 | |
415 | static struct clk_ops jz_clk_pll_ops = { |
416 | .get_rate = jz_clk_pll_get_rate, |
417 | + .set_rate = jz_clk_pll_set_rate, |
418 | + .round_rate = jz_clk_pll_round_rate, |
419 | }; |
420 | |
421 | static struct clk jz_clk_pll = { |
422 | @@ -897,6 +1103,10 @@ static int jz4740_clock_init(void) |
423 | if (!jz_clock_base) |
424 | return -EBUSY; |
425 | |
426 | + jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100); |
427 | + if (!jz_emc_base) |
428 | + return -EBUSY; |
429 | + |
430 | spin_lock_init(&jz_clock_lock); |
431 | |
432 | jz_clk_ext.rate = jz4740_clock_bdata.ext_rate; |
433 | diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h |
434 | index 5d07499..cc8d1db 100644 |
435 | --- a/arch/mips/jz4740/clock.h |
436 | +++ b/arch/mips/jz4740/clock.h |
437 | @@ -17,6 +17,7 @@ |
438 | #define __MIPS_JZ4740_CLOCK_H__ |
439 | |
440 | #include <linux/list.h> |
441 | +#include <linux/types.h> |
442 | |
443 | struct jz4740_clock_board_data { |
444 | unsigned long ext_rate; |
445 | @@ -63,6 +64,9 @@ struct clk { |
446 | |
447 | int clk_is_enabled(struct clk *clk); |
448 | |
449 | +int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv, |
450 | + unsigned int mdiv, unsigned int pdiv); |
451 | + |
452 | #ifdef CONFIG_DEBUG_FS |
453 | void jz4740_clock_debugfs_init(void); |
454 | void jz4740_clock_debugfs_add_clk(struct clk *clk); |
455 | diff --git a/arch/mips/jz4740/cpufreq.c b/arch/mips/jz4740/cpufreq.c |
456 | new file mode 100644 |
457 | index 0000000..aa41e9f |
458 | --- /dev/null |
459 | +++ b/arch/mips/jz4740/cpufreq.c |
460 | @@ -0,0 +1,226 @@ |
461 | +/* |
462 | + * linux/arch/mips/jz4740/cpufreq.c |
463 | + * |
464 | + * cpufreq driver for JZ4740 |
465 | + * |
466 | + * Copyright (c) 2010 Ulrich Hecht <ulrich.hecht@gmail.com> |
467 | + * Copyright (c) 2010 Maarten ter Huurne <maarten@treewalker.org> |
468 | + * |
469 | + * This program is free software; you can redistribute it and/or modify |
470 | + * it under the terms of the GNU General Public License version 2 as |
471 | + * published by the Free Software Foundation. |
472 | + */ |
473 | + |
474 | +#include <linux/kernel.h> |
475 | +#include <linux/module.h> |
476 | +#include <linux/init.h> |
477 | +#include <linux/err.h> |
478 | + |
479 | +#include <linux/cpufreq.h> |
480 | + |
481 | +#include <linux/clk.h> |
482 | +#include <asm/mach-jz4740/base.h> |
483 | + |
484 | +#include "clock.h" |
485 | + |
486 | +#define DEBUG_CPUFREQ |
487 | + |
488 | +#ifdef DEBUG_CPUFREQ |
489 | +#define dprintk(X...) printk(KERN_INFO X) |
490 | +#else |
491 | +#define dprintk(X...) do { } while(0) |
492 | +#endif |
493 | + |
494 | +#define HCLK_MIN 30000 |
495 | +/* TODO: The maximum MCLK most likely depends on the SDRAM chips used, |
496 | + so it is board-specific. */ |
497 | +#define MCLK_MAX 140000 |
498 | + |
499 | +/* Same as jz_clk_main_divs, but with 24 and 32 removed because the hardware |
500 | + spec states those dividers must not be used for CCLK or HCLK. */ |
501 | +static const unsigned int jz4740_freq_cpu_divs[] = {1, 2, 3, 4, 6, 8, 12, 16}; |
502 | + |
503 | +struct jz4740_freq_percpu_info { |
504 | + unsigned int pll_rate; |
505 | + struct cpufreq_frequency_table table[ |
506 | + ARRAY_SIZE(jz4740_freq_cpu_divs) + 1]; |
507 | +}; |
508 | + |
509 | +static struct clk *pll; |
510 | +static struct clk *cclk; |
511 | + |
512 | +static struct jz4740_freq_percpu_info jz4740_freq_info; |
513 | + |
514 | +static struct cpufreq_driver cpufreq_jz4740_driver; |
515 | + |
516 | +static void jz4740_freq_fill_table(struct cpufreq_policy *policy, |
517 | + unsigned int pll_rate) |
518 | +{ |
519 | + struct cpufreq_frequency_table *table = &jz4740_freq_info.table[0]; |
520 | + int i; |
521 | + |
522 | +#ifdef CONFIG_CPU_FREQ_STAT_DETAILS |
523 | + /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ |
524 | + static bool init = false; |
525 | + if (init) |
526 | + cpufreq_frequency_table_put_attr(policy->cpu); |
527 | + else |
528 | + init = true; |
529 | +#endif |
530 | + |
531 | + jz4740_freq_info.pll_rate = pll_rate; |
532 | + |
533 | + for (i = 0; i < ARRAY_SIZE(jz4740_freq_cpu_divs); i++) { |
534 | + unsigned int freq = pll_rate / jz4740_freq_cpu_divs[i]; |
535 | + if (freq < HCLK_MIN) break; |
536 | + table[i].index = i; |
537 | + table[i].frequency = freq; |
538 | + } |
539 | + table[i].index = i; |
540 | + table[i].frequency = CPUFREQ_TABLE_END; |
541 | + |
542 | + policy->min = table[i - 1].frequency; |
543 | + policy->max = table[0].frequency; |
544 | + |
545 | +#ifdef CONFIG_CPU_FREQ_STAT_DETAILS |
546 | + cpufreq_frequency_table_get_attr(table, policy->cpu); |
547 | +#endif |
548 | +} |
549 | + |
550 | +static unsigned int jz4740_freq_get(unsigned int cpu) |
551 | +{ |
552 | + return clk_get_rate(cclk) / 1000; |
553 | +} |
554 | + |
555 | +static int jz4740_freq_verify(struct cpufreq_policy *policy) |
556 | +{ |
557 | + unsigned int new_pll; |
558 | + |
559 | + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, |
560 | + policy->cpuinfo.max_freq); |
561 | + |
562 | + new_pll = clk_round_rate(pll, policy->max * 1000) / 1000; |
563 | + if (jz4740_freq_info.pll_rate != new_pll) |
564 | + jz4740_freq_fill_table(policy, new_pll); |
565 | + |
566 | + return 0; |
567 | +} |
568 | + |
569 | +static int jz4740_freq_target(struct cpufreq_policy *policy, |
570 | + unsigned int target_freq, |
571 | + unsigned int relation) |
572 | +{ |
573 | + struct cpufreq_frequency_table *table = &jz4740_freq_info.table[0]; |
574 | + struct cpufreq_freqs freqs; |
575 | + unsigned int new_index = 0; |
576 | + unsigned int old_pll = clk_get_rate(pll) / 1000; |
577 | + unsigned int new_pll = jz4740_freq_info.pll_rate; |
578 | + int ret = 0; |
579 | + |
580 | + if (cpufreq_frequency_table_target(policy, table, |
581 | + target_freq, relation, &new_index)) |
582 | + return -EINVAL; |
583 | + freqs = (struct cpufreq_freqs) { |
584 | + .old = jz4740_freq_get(policy->cpu), |
585 | + .new = table[new_index].frequency, |
586 | + .cpu = policy->cpu, |
587 | + .flags = cpufreq_jz4740_driver.flags, |
588 | + }; |
589 | + if (freqs.new != freqs.old || new_pll != old_pll) { |
590 | + unsigned int cdiv, hdiv, mdiv, pdiv; |
591 | + cdiv = jz4740_freq_cpu_divs[new_index]; |
592 | + hdiv = (cdiv == 3 || cdiv == 6) ? cdiv * 2 : cdiv * 3; |
593 | + while (new_pll < HCLK_MIN * hdiv) |
594 | + hdiv -= cdiv; |
595 | + mdiv = hdiv; |
596 | + if (new_pll > MCLK_MAX * mdiv) { |
597 | + /* 4,4 performs better than 3,6 */ |
598 | + if (new_pll > MCLK_MAX * 4) |
599 | + mdiv *= 2; |
600 | + else |
601 | + hdiv = mdiv = cdiv * 4; |
602 | + } |
603 | + pdiv = mdiv; |
604 | + dprintk(KERN_INFO "%s: cclk %p, setting from %d to %d, " |
605 | + "dividers %d, %d, %d, %d\n", |
606 | + __FUNCTION__, cclk, freqs.old, freqs.new, |
607 | + cdiv, hdiv, mdiv, pdiv); |
608 | + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); |
609 | + ret = clk_main_set_dividers(new_pll == old_pll, |
610 | + cdiv, hdiv, mdiv, pdiv); |
611 | + if (ret) { |
612 | + dprintk(KERN_INFO "failed to set dividers\n"); |
613 | + } else if (new_pll != old_pll) { |
614 | + dprintk(KERN_INFO "%s: pll %p, setting from %d to %d\n", |
615 | + __FUNCTION__, pll, old_pll, new_pll); |
616 | + ret = clk_set_rate(pll, new_pll * 1000); |
617 | + } |
618 | + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
619 | + } |
620 | + |
621 | + return ret; |
622 | +} |
623 | + |
624 | +static int jz4740_cpufreq_driver_init(struct cpufreq_policy *policy) |
625 | +{ |
626 | + int ret; |
627 | + |
628 | + dprintk(KERN_INFO "Jz4740 cpufreq driver\n"); |
629 | + |
630 | + if (policy->cpu != 0) |
631 | + return -EINVAL; |
632 | + |
633 | + pll = clk_get(NULL, "pll"); |
634 | + if (IS_ERR(pll)) { |
635 | + ret = PTR_ERR(pll); |
636 | + goto err_exit; |
637 | + } |
638 | + |
639 | + cclk = clk_get(NULL, "cclk"); |
640 | + if (IS_ERR(cclk)) { |
641 | + ret = PTR_ERR(cclk); |
642 | + goto err_clk_put_pll; |
643 | + } |
644 | + |
645 | + policy->cpuinfo.min_freq = HCLK_MIN; |
646 | + policy->cpuinfo.max_freq = 500000; |
647 | + policy->cpuinfo.transition_latency = 100000; /* in nanoseconds */ |
648 | + policy->cur = jz4740_freq_get(policy->cpu); |
649 | + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; |
650 | + /* min and max are set by jz4740_freq_fill_table() */ |
651 | + |
652 | + jz4740_freq_fill_table(policy, clk_get_rate(pll) / 1000 /* in kHz */); |
653 | + |
654 | + return 0; |
655 | + |
656 | +err_clk_put_pll: |
657 | + clk_put(pll); |
658 | +err_exit: |
659 | + return ret; |
660 | +} |
661 | + |
662 | +static struct cpufreq_driver cpufreq_jz4740_driver = { |
663 | + .init = jz4740_cpufreq_driver_init, |
664 | + .verify = jz4740_freq_verify, |
665 | + .target = jz4740_freq_target, |
666 | + .get = jz4740_freq_get, |
667 | + .name = "jz4740", |
668 | +}; |
669 | + |
670 | +static int __init jz4740_cpufreq_init(void) |
671 | +{ |
672 | + return cpufreq_register_driver(&cpufreq_jz4740_driver); |
673 | +} |
674 | + |
675 | +static void __exit jz4740_cpufreq_exit(void) |
676 | +{ |
677 | + cpufreq_unregister_driver(&cpufreq_jz4740_driver); |
678 | +} |
679 | + |
680 | +module_init(jz4740_cpufreq_init); |
681 | +module_exit(jz4740_cpufreq_exit); |
682 | + |
683 | +MODULE_AUTHOR("Ulrich Hecht <ulrich.hecht@gmail.com>, " |
684 | + "Maarten ter Huurne <maarten@treewalker.org>"); |
685 | +MODULE_DESCRIPTION("cpufreq driver for Jz4740"); |
686 | +MODULE_LICENSE("GPL"); |
687 | diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c |
688 | index 73031f7..e1ddb95 100644 |
689 | --- a/arch/mips/jz4740/gpio.c |
690 | +++ b/arch/mips/jz4740/gpio.c |
691 | @@ -17,8 +17,6 @@ |
692 | #include <linux/module.h> |
693 | #include <linux/init.h> |
694 | |
695 | -#include <linux/spinlock.h> |
696 | -#include <linux/sysdev.h> |
697 | #include <linux/io.h> |
698 | #include <linux/gpio.h> |
699 | #include <linux/delay.h> |
700 | @@ -30,6 +28,8 @@ |
701 | |
702 | #include <asm/mach-jz4740/base.h> |
703 | |
704 | +#include "irq.h" |
705 | + |
706 | #define JZ4740_GPIO_BASE_A (32*0) |
707 | #define JZ4740_GPIO_BASE_B (32*1) |
708 | #define JZ4740_GPIO_BASE_C (32*2) |
709 | @@ -77,16 +77,11 @@ |
710 | struct jz_gpio_chip { |
711 | unsigned int irq; |
712 | unsigned int irq_base; |
713 | - uint32_t wakeup; |
714 | - uint32_t suspend_mask; |
715 | uint32_t edge_trigger_both; |
716 | |
717 | void __iomem *base; |
718 | |
719 | - spinlock_t lock; |
720 | - |
721 | struct gpio_chip gpio_chip; |
722 | - struct sys_device sysdev; |
723 | }; |
724 | |
725 | static struct jz_gpio_chip jz4740_gpio_chips[]; |
726 | @@ -103,7 +98,8 @@ static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *g |
727 | |
728 | static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data) |
729 | { |
730 | - return irq_data_get_irq_chip_data(data); |
731 | + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); |
732 | + return gc->private; |
733 | } |
734 | |
735 | static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg) |
736 | @@ -305,21 +301,15 @@ static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc) |
737 | { |
738 | uint32_t flag; |
739 | unsigned int gpio_irq; |
740 | - unsigned int gpio_bank; |
741 | struct jz_gpio_chip *chip = irq_desc_get_handler_data(desc); |
742 | |
743 | - gpio_bank = JZ4740_IRQ_GPIO0 - irq; |
744 | - |
745 | flag = readl(chip->base + JZ_REG_GPIO_FLAG); |
746 | - |
747 | if (!flag) |
748 | return; |
749 | |
750 | - gpio_irq = __fls(flag); |
751 | - |
752 | - jz_gpio_check_trigger_both(chip, irq); |
753 | + gpio_irq = chip->irq_base + __fls(flag); |
754 | |
755 | - gpio_irq += (gpio_bank << 5) + JZ4740_IRQ_GPIO(0); |
756 | + jz_gpio_check_trigger_both(chip, gpio_irq); |
757 | |
758 | generic_handle_irq(gpio_irq); |
759 | }; |
760 | @@ -330,18 +320,12 @@ static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg) |
761 | writel(IRQ_TO_BIT(data->irq), chip->base + reg); |
762 | } |
763 | |
764 | -static void jz_gpio_irq_mask(struct irq_data *data) |
765 | -{ |
766 | - jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_SET); |
767 | -}; |
768 | - |
769 | static void jz_gpio_irq_unmask(struct irq_data *data) |
770 | { |
771 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
772 | |
773 | jz_gpio_check_trigger_both(chip, data->irq); |
774 | - |
775 | - jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_CLEAR); |
776 | + irq_gc_unmask_enable_reg(data); |
777 | }; |
778 | |
779 | /* TODO: Check if function is gpio */ |
780 | @@ -354,18 +338,13 @@ static unsigned int jz_gpio_irq_startup(struct irq_data *data) |
781 | |
782 | static void jz_gpio_irq_shutdown(struct irq_data *data) |
783 | { |
784 | - jz_gpio_irq_mask(data); |
785 | + irq_gc_mask_disable_reg(data); |
786 | |
787 | /* Set direction to input */ |
788 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR); |
789 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR); |
790 | } |
791 | |
792 | -static void jz_gpio_irq_ack(struct irq_data *data) |
793 | -{ |
794 | - jz_gpio_set_irq_bit(data, JZ_REG_GPIO_FLAG_CLEAR); |
795 | -}; |
796 | - |
797 | static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) |
798 | { |
799 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
800 | @@ -409,35 +388,13 @@ static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) |
801 | static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on) |
802 | { |
803 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
804 | - spin_lock(&chip->lock); |
805 | - if (on) |
806 | - chip->wakeup |= IRQ_TO_BIT(data->irq); |
807 | - else |
808 | - chip->wakeup &= ~IRQ_TO_BIT(data->irq); |
809 | - spin_unlock(&chip->lock); |
810 | |
811 | + irq_gc_set_wake(data, on); |
812 | irq_set_irq_wake(chip->irq, on); |
813 | + |
814 | return 0; |
815 | } |
816 | |
817 | -static struct irq_chip jz_gpio_irq_chip = { |
818 | - .name = "GPIO", |
819 | - .irq_mask = jz_gpio_irq_mask, |
820 | - .irq_unmask = jz_gpio_irq_unmask, |
821 | - .irq_ack = jz_gpio_irq_ack, |
822 | - .irq_startup = jz_gpio_irq_startup, |
823 | - .irq_shutdown = jz_gpio_irq_shutdown, |
824 | - .irq_set_type = jz_gpio_irq_set_type, |
825 | - .irq_set_wake = jz_gpio_irq_set_wake, |
826 | - .flags = IRQCHIP_SET_TYPE_MASKED, |
827 | -}; |
828 | - |
829 | -/* |
830 | - * This lock class tells lockdep that GPIO irqs are in a different |
831 | - * category than their parents, so it won't report false recursion. |
832 | - */ |
833 | -static struct lock_class_key gpio_lock_class; |
834 | - |
835 | #define JZ4740_GPIO_CHIP(_bank) { \ |
836 | .irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \ |
837 | .gpio_chip = { \ |
838 | @@ -459,78 +416,49 @@ static struct jz_gpio_chip jz4740_gpio_chips[] = { |
839 | JZ4740_GPIO_CHIP(D), |
840 | }; |
841 | |
842 | -static inline struct jz_gpio_chip *sysdev_to_chip(struct sys_device *dev) |
843 | -{ |
844 | - return container_of(dev, struct jz_gpio_chip, sysdev); |
845 | -} |
846 | - |
847 | -static int jz4740_gpio_suspend(struct sys_device *dev, pm_message_t state) |
848 | -{ |
849 | - struct jz_gpio_chip *chip = sysdev_to_chip(dev); |
850 | - |
851 | - chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK); |
852 | - writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET); |
853 | - writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR); |
854 | - |
855 | - return 0; |
856 | -} |
857 | - |
858 | -static int jz4740_gpio_resume(struct sys_device *dev) |
859 | +static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) |
860 | { |
861 | - struct jz_gpio_chip *chip = sysdev_to_chip(dev); |
862 | - uint32_t mask = chip->suspend_mask; |
863 | - |
864 | - writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR); |
865 | - writel(mask, chip->base + JZ_REG_GPIO_MASK_SET); |
866 | + struct irq_chip_generic *gc; |
867 | + struct irq_chip_type *ct; |
868 | |
869 | - return 0; |
870 | -} |
871 | + chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); |
872 | |
873 | -static struct sysdev_class jz4740_gpio_sysdev_class = { |
874 | - .name = "gpio", |
875 | - .suspend = jz4740_gpio_suspend, |
876 | - .resume = jz4740_gpio_resume, |
877 | -}; |
878 | + chip->irq = JZ4740_IRQ_INTC_GPIO(id); |
879 | + irq_set_handler_data(chip->irq, chip); |
880 | + irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); |
881 | |
882 | -static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) |
883 | -{ |
884 | - int ret, irq; |
885 | + gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base, |
886 | + chip->base, handle_level_irq); |
887 | |
888 | - chip->sysdev.id = id; |
889 | - chip->sysdev.cls = &jz4740_gpio_sysdev_class; |
890 | - ret = sysdev_register(&chip->sysdev); |
891 | + gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio); |
892 | + gc->private = chip; |
893 | |
894 | - if (ret) |
895 | - return ret; |
896 | + ct = gc->chip_types; |
897 | + ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR; |
898 | + ct->regs.disable = JZ_REG_GPIO_MASK_SET; |
899 | + ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR; |
900 | |
901 | - spin_lock_init(&chip->lock); |
902 | + ct->chip.name = "GPIO"; |
903 | + ct->chip.irq_mask = irq_gc_mask_disable_reg; |
904 | + ct->chip.irq_unmask = jz_gpio_irq_unmask; |
905 | + ct->chip.irq_ack = irq_gc_ack_set_bit; |
906 | + ct->chip.irq_suspend = jz4740_irq_suspend; |
907 | + ct->chip.irq_resume = jz4740_irq_resume; |
908 | + ct->chip.irq_startup = jz_gpio_irq_startup; |
909 | + ct->chip.irq_shutdown = jz_gpio_irq_shutdown; |
910 | + ct->chip.irq_set_type = jz_gpio_irq_set_type; |
911 | + ct->chip.irq_set_wake = jz_gpio_irq_set_wake; |
912 | + ct->chip.flags = IRQCHIP_SET_TYPE_MASKED; |
913 | |
914 | - chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); |
915 | + irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio), |
916 | + IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL); |
917 | |
918 | gpiochip_add(&chip->gpio_chip); |
919 | - |
920 | - chip->irq = JZ4740_IRQ_INTC_GPIO(id); |
921 | - irq_set_handler_data(chip->irq, chip); |
922 | - irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); |
923 | - |
924 | - for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) { |
925 | - irq_set_lockdep_class(irq, &gpio_lock_class); |
926 | - irq_set_chip_data(irq, chip); |
927 | - irq_set_chip_and_handler(irq, &jz_gpio_irq_chip, |
928 | - handle_level_irq); |
929 | - } |
930 | - |
931 | - return 0; |
932 | } |
933 | |
934 | static int __init jz4740_gpio_init(void) |
935 | { |
936 | unsigned int i; |
937 | - int ret; |
938 | - |
939 | - ret = sysdev_class_register(&jz4740_gpio_sysdev_class); |
940 | - if (ret) |
941 | - return ret; |
942 | |
943 | for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i) |
944 | jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i); |
945 | diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c |
946 | index d82c0c4..fc57ded 100644 |
947 | --- a/arch/mips/jz4740/irq.c |
948 | +++ b/arch/mips/jz4740/irq.c |
949 | @@ -32,8 +32,6 @@ |
950 | #include <asm/mach-jz4740/base.h> |
951 | |
952 | static void __iomem *jz_intc_base; |
953 | -static uint32_t jz_intc_wakeup; |
954 | -static uint32_t jz_intc_saved; |
955 | |
956 | #define JZ_REG_INTC_STATUS 0x00 |
957 | #define JZ_REG_INTC_MASK 0x04 |
958 | @@ -41,51 +39,36 @@ static uint32_t jz_intc_saved; |
959 | #define JZ_REG_INTC_CLEAR_MASK 0x0c |
960 | #define JZ_REG_INTC_PENDING 0x10 |
961 | |
962 | -#define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE) |
963 | - |
964 | -static inline unsigned long intc_irq_bit(struct irq_data *data) |
965 | +static irqreturn_t jz4740_cascade(int irq, void *data) |
966 | { |
967 | - return (unsigned long)irq_data_get_irq_chip_data(data); |
968 | -} |
969 | + uint32_t irq_reg; |
970 | |
971 | -static void intc_irq_unmask(struct irq_data *data) |
972 | -{ |
973 | - writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_CLEAR_MASK); |
974 | -} |
975 | + irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING); |
976 | |
977 | -static void intc_irq_mask(struct irq_data *data) |
978 | -{ |
979 | - writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_SET_MASK); |
980 | + if (irq_reg) |
981 | + generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE); |
982 | + |
983 | + return IRQ_HANDLED; |
984 | } |
985 | |
986 | -static int intc_irq_set_wake(struct irq_data *data, unsigned int on) |
987 | +static void jz4740_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask) |
988 | { |
989 | - if (on) |
990 | - jz_intc_wakeup |= intc_irq_bit(data); |
991 | - else |
992 | - jz_intc_wakeup &= ~intc_irq_bit(data); |
993 | + struct irq_chip_regs *regs = &gc->chip_types->regs; |
994 | |
995 | - return 0; |
996 | + writel(mask, gc->reg_base + regs->enable); |
997 | + writel(~mask, gc->reg_base + regs->disable); |
998 | } |
999 | |
1000 | -static struct irq_chip intc_irq_type = { |
1001 | - .name = "INTC", |
1002 | - .irq_mask = intc_irq_mask, |
1003 | - .irq_mask_ack = intc_irq_mask, |
1004 | - .irq_unmask = intc_irq_unmask, |
1005 | - .irq_set_wake = intc_irq_set_wake, |
1006 | -}; |
1007 | - |
1008 | -static irqreturn_t jz4740_cascade(int irq, void *data) |
1009 | +void jz4740_irq_suspend(struct irq_data *data) |
1010 | { |
1011 | - uint32_t irq_reg; |
1012 | - |
1013 | - irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING); |
1014 | - |
1015 | - if (irq_reg) |
1016 | - generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE); |
1017 | + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); |
1018 | + jz4740_irq_set_mask(gc, gc->wake_active); |
1019 | +} |
1020 | |
1021 | - return IRQ_HANDLED; |
1022 | +void jz4740_irq_resume(struct irq_data *data) |
1023 | +{ |
1024 | + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); |
1025 | + jz4740_irq_set_mask(gc, gc->mask_cache); |
1026 | } |
1027 | |
1028 | static struct irqaction jz4740_cascade_action = { |
1029 | @@ -95,7 +78,9 @@ static struct irqaction jz4740_cascade_action = { |
1030 | |
1031 | void __init arch_init_irq(void) |
1032 | { |
1033 | - int i; |
1034 | + struct irq_chip_generic *gc; |
1035 | + struct irq_chip_type *ct; |
1036 | + |
1037 | mips_cpu_irq_init(); |
1038 | |
1039 | jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14); |
1040 | @@ -103,10 +88,22 @@ void __init arch_init_irq(void) |
1041 | /* Mask all irqs */ |
1042 | writel(0xffffffff, jz_intc_base + JZ_REG_INTC_SET_MASK); |
1043 | |
1044 | - for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) { |
1045 | - irq_set_chip_data(i, (void *)IRQ_BIT(i)); |
1046 | - irq_set_chip_and_handler(i, &intc_irq_type, handle_level_irq); |
1047 | - } |
1048 | + gc = irq_alloc_generic_chip("INTC", 1, JZ4740_IRQ_BASE, jz_intc_base, |
1049 | + handle_level_irq); |
1050 | + |
1051 | + gc->wake_enabled = IRQ_MSK(32); |
1052 | + |
1053 | + ct = gc->chip_types; |
1054 | + ct->regs.enable = JZ_REG_INTC_CLEAR_MASK; |
1055 | + ct->regs.disable = JZ_REG_INTC_SET_MASK; |
1056 | + ct->chip.irq_unmask = irq_gc_unmask_enable_reg; |
1057 | + ct->chip.irq_mask = irq_gc_mask_disable_reg; |
1058 | + ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; |
1059 | + ct->chip.irq_set_wake = irq_gc_set_wake; |
1060 | + ct->chip.irq_suspend = jz4740_irq_suspend; |
1061 | + ct->chip.irq_resume = jz4740_irq_resume; |
1062 | + |
1063 | + irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); |
1064 | |
1065 | setup_irq(2, &jz4740_cascade_action); |
1066 | } |
1067 | @@ -122,19 +119,6 @@ asmlinkage void plat_irq_dispatch(void) |
1068 | spurious_interrupt(); |
1069 | } |
1070 | |
1071 | -void jz4740_intc_suspend(void) |
1072 | -{ |
1073 | - jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK); |
1074 | - writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK); |
1075 | - writel(jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); |
1076 | -} |
1077 | - |
1078 | -void jz4740_intc_resume(void) |
1079 | -{ |
1080 | - writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); |
1081 | - writel(jz_intc_saved, jz_intc_base + JZ_REG_INTC_SET_MASK); |
1082 | -} |
1083 | - |
1084 | #ifdef CONFIG_DEBUG_FS |
1085 | |
1086 | static inline void intc_seq_reg(struct seq_file *s, const char *name, |
1087 | diff --git a/arch/mips/jz4740/irq.h b/arch/mips/jz4740/irq.h |
1088 | index 56b5ead..f75e39d 100644 |
1089 | --- a/arch/mips/jz4740/irq.h |
1090 | +++ b/arch/mips/jz4740/irq.h |
1091 | @@ -15,7 +15,9 @@ |
1092 | #ifndef __MIPS_JZ4740_IRQ_H__ |
1093 | #define __MIPS_JZ4740_IRQ_H__ |
1094 | |
1095 | -extern void jz4740_intc_suspend(void); |
1096 | -extern void jz4740_intc_resume(void); |
1097 | +#include <linux/irq.h> |
1098 | + |
1099 | +extern void jz4740_irq_suspend(struct irq_data *data); |
1100 | +extern void jz4740_irq_resume(struct irq_data *data); |
1101 | |
1102 | #endif |
1103 | diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c |
1104 | index cc6de5b..a5647d9 100644 |
1105 | --- a/arch/mips/jz4740/platform.c |
1106 | +++ b/arch/mips/jz4740/platform.c |
1107 | @@ -157,11 +157,29 @@ static struct resource jz4740_nand_resources[] = { |
1108 | .flags = IORESOURCE_MEM, |
1109 | }, |
1110 | { |
1111 | - .name = "bank", |
1112 | + .name = "bank1", |
1113 | .start = 0x18000000, |
1114 | .end = 0x180C0000 - 1, |
1115 | .flags = IORESOURCE_MEM, |
1116 | }, |
1117 | + { |
1118 | + .name = "bank2", |
1119 | + .start = 0x14000000, |
1120 | + .end = 0x140C0000 - 1, |
1121 | + .flags = IORESOURCE_MEM, |
1122 | + }, |
1123 | + { |
1124 | + .name = "bank3", |
1125 | + .start = 0x0C000000, |
1126 | + .end = 0x0C0C0000 - 1, |
1127 | + .flags = IORESOURCE_MEM, |
1128 | + }, |
1129 | + { |
1130 | + .name = "bank4", |
1131 | + .start = 0x08000000, |
1132 | + .end = 0x080C0000 - 1, |
1133 | + .flags = IORESOURCE_MEM, |
1134 | + }, |
1135 | }; |
1136 | |
1137 | struct platform_device jz4740_nand_device = { |
1138 | diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c |
1139 | index 902d5b5..6744fa7 100644 |
1140 | --- a/arch/mips/jz4740/pm.c |
1141 | +++ b/arch/mips/jz4740/pm.c |
1142 | @@ -21,11 +21,9 @@ |
1143 | #include <asm/mach-jz4740/clock.h> |
1144 | |
1145 | #include "clock.h" |
1146 | -#include "irq.h" |
1147 | |
1148 | static int jz4740_pm_enter(suspend_state_t state) |
1149 | { |
1150 | - jz4740_intc_suspend(); |
1151 | jz4740_clock_suspend(); |
1152 | |
1153 | jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_SLEEP); |
1154 | @@ -37,7 +35,6 @@ static int jz4740_pm_enter(suspend_state_t state) |
1155 | jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_IDLE); |
1156 | |
1157 | jz4740_clock_resume(); |
1158 | - jz4740_intc_resume(); |
1159 | |
1160 | return 0; |
1161 | } |
1162 | diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c |
1163 | index 5f1fb95..e6d1d7b 100644 |
1164 | --- a/arch/mips/jz4740/reset.c |
1165 | +++ b/arch/mips/jz4740/reset.c |
1166 | @@ -21,6 +21,9 @@ |
1167 | #include <asm/mach-jz4740/base.h> |
1168 | #include <asm/mach-jz4740/timer.h> |
1169 | |
1170 | +#include "reset.h" |
1171 | +#include "clock.h" |
1172 | + |
1173 | static void jz4740_halt(void) |
1174 | { |
1175 | while (1) { |
1176 | @@ -53,21 +56,52 @@ static void jz4740_restart(char *command) |
1177 | jz4740_halt(); |
1178 | } |
1179 | |
1180 | -#define JZ_REG_RTC_CTRL 0x00 |
1181 | -#define JZ_REG_RTC_HIBERNATE 0x20 |
1182 | +#define JZ_REG_RTC_CTRL 0x00 |
1183 | +#define JZ_REG_RTC_HIBERNATE 0x20 |
1184 | +#define JZ_REG_RTC_WAKEUP_FILTER 0x24 |
1185 | +#define JZ_REG_RTC_RESET_COUNTER 0x28 |
1186 | |
1187 | -#define JZ_RTC_CTRL_WRDY BIT(7) |
1188 | +#define JZ_RTC_CTRL_WRDY BIT(7) |
1189 | +#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 |
1190 | +#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 |
1191 | |
1192 | -static void jz4740_power_off(void) |
1193 | +static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base) |
1194 | { |
1195 | - void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x24); |
1196 | uint32_t ctrl; |
1197 | - |
1198 | do { |
1199 | ctrl = readl(rtc_base + JZ_REG_RTC_CTRL); |
1200 | } while (!(ctrl & JZ_RTC_CTRL_WRDY)); |
1201 | +} |
1202 | |
1203 | +static void jz4740_power_off(void) |
1204 | +{ |
1205 | + void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38); |
1206 | + unsigned long long wakeup_filter_ticks; |
1207 | + unsigned long long reset_counter_ticks; |
1208 | + |
1209 | + /* Set minimum wakeup pin assertion time: 100 ms. |
1210 | + Range is 0 to 2 sec if RTC is clocked at 32 kHz. */ |
1211 | + wakeup_filter_ticks = (100 * jz4740_clock_bdata.rtc_rate) / 1000; |
1212 | + if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK) |
1213 | + wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; |
1214 | + else |
1215 | + wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK; |
1216 | + jz4740_rtc_wait_ready(rtc_base); |
1217 | + writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER); |
1218 | + |
1219 | + /* Set reset pin low-level assertion time after wakeup: 60 ms. |
1220 | + Range is 0 to 125 ms if RTC is clocked at 32 kHz. */ |
1221 | + reset_counter_ticks = (60 * jz4740_clock_bdata.rtc_rate) / 1000; |
1222 | + if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK) |
1223 | + reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK; |
1224 | + else |
1225 | + reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK; |
1226 | + jz4740_rtc_wait_ready(rtc_base); |
1227 | + writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER); |
1228 | + |
1229 | + jz4740_rtc_wait_ready(rtc_base); |
1230 | writel(1, rtc_base + JZ_REG_RTC_HIBERNATE); |
1231 | + |
1232 | jz4740_halt(); |
1233 | } |
1234 | |
1235 | diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig |
1236 | index 58c601e..11af8e8 100644 |
1237 | --- a/arch/mips/kernel/cpufreq/Kconfig |
1238 | +++ b/arch/mips/kernel/cpufreq/Kconfig |
1239 | @@ -8,7 +8,7 @@ config MIPS_EXTERNAL_TIMER |
1240 | config MIPS_CPUFREQ |
1241 | bool |
1242 | default y |
1243 | - depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER |
1244 | + depends on CPU_SUPPORTS_CPUFREQ |
1245 | |
1246 | if MIPS_CPUFREQ |
1247 | |
1248 | @@ -24,6 +24,7 @@ config LOONGSON2_CPUFREQ |
1249 | tristate "Loongson2 CPUFreq Driver" |
1250 | select CPU_FREQ_TABLE |
1251 | depends on MIPS_CPUFREQ |
1252 | + depends on MIPS_EXTERNAL_TIMER |
1253 | help |
1254 | This option adds a CPUFreq driver for loongson processors which |
1255 | support software configurable cpu frequency. |
1256 | @@ -34,6 +35,16 @@ config LOONGSON2_CPUFREQ |
1257 | |
1258 | If in doubt, say N. |
1259 | |
1260 | +config CPU_FREQ_JZ |
1261 | + tristate "CPUfreq driver for JZ CPUs" |
1262 | + select CPU_FREQ_TABLE |
1263 | + depends on MACH_JZ4740 |
1264 | + default n |
1265 | + help |
1266 | + This enables the CPUfreq driver for JZ CPUs. |
1267 | + |
1268 | + If in doubt, say N. |
1269 | + |
1270 | endif # CPU_FREQ |
1271 | |
1272 | endmenu |
1273 | -- |
1274 | 1.7.4.1 |
1275 | |
1276 |