Root/target/linux/xburst/patches-3.0/0024-forward-code-to-linux-3.0.patch

1From 87eb40e63e1b149ef87fe05765b97328bfbd1c1f Mon Sep 17 00:00:00 2001
2From: Xiangfu Liu <xiangfu@macbook.openmobilefree.net>
3Date: Wed, 14 Sep 2011 14:29:37 +0800
4Subject: [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
25diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
26index 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"
38diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
39index 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 */
53diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
54index 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)
76diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_fb.h b/arch/mips/include/asm/mach-jz4740/jz4740_fb.h
77index 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
102diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
103index 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
113diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
114index 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;
433diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
434index 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);
455diff --git a/arch/mips/jz4740/cpufreq.c b/arch/mips/jz4740/cpufreq.c
456new file mode 100644
457index 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");
687diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
688index 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);
945diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
946index 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,
1087diff --git a/arch/mips/jz4740/irq.h b/arch/mips/jz4740/irq.h
1088index 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
1103diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
1104index 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 = {
1138diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c
1139index 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 }
1162diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c
1163index 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 
1235diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig
1236index 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--
12741.7.4.1
1275
1276

Archive Download this file



interactive