[target/xburst] level up target xburst to linux kernel version 3.2.1
[openwrt.git] / target / linux / xburst / patches-3.2 / 0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch
1 From 27ff621cd9a5347efda4be502abbef13a99146ce Mon Sep 17 00:00:00 2001
2 From: Maarten ter Huurne <maarten@treewalker.org>
3 Date: Sun, 29 Aug 2010 08:11:00 +0200
4 Subject: [PATCH 11/21] MIPS: JZ4740: Added setting of PLL rate and main
5 dividers.
6
7 This functionality makes a cpufreq driver possible.
8 Squashed version of the development done in the jz-2.6.39 branch.
9 ---
10 arch/mips/jz4740/clock.c | 230 ++++++++++++++++++++++++++++++++++++++++++++--
11 arch/mips/jz4740/clock.h | 4 +
12 2 files changed, 224 insertions(+), 10 deletions(-)
13
14 diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
15 index 118a8a5..da423d1 100644
16 --- a/arch/mips/jz4740/clock.c
17 +++ b/arch/mips/jz4740/clock.c
18 @@ -1,5 +1,8 @@
19 /*
20 + * Copyright (c) 2006-2007, Ingenic Semiconductor Inc.
21 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
22 + * Copyright (c) 2010, Ulrich Hecht <ulrich.hecht@gmail.com>
23 + * Copyright (c) 2010, Maarten ter Huurne <maarten@treewalker.org>
24 * JZ4740 SoC clock support
25 *
26 * This program is free software; you can redistribute it and/or modify it
27 @@ -41,16 +44,20 @@
28 #define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31)
29 #define JZ_CLOCK_CTRL_KO_ENABLE BIT(30)
30 #define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29)
31 -#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000
32 #define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22)
33 #define JZ_CLOCK_CTRL_PLL_HALF BIT(21)
34 -#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000
35 #define JZ_CLOCK_CTRL_UDIV_OFFSET 23
36 #define JZ_CLOCK_CTRL_LDIV_OFFSET 16
37 #define JZ_CLOCK_CTRL_MDIV_OFFSET 12
38 #define JZ_CLOCK_CTRL_PDIV_OFFSET 8
39 #define JZ_CLOCK_CTRL_HDIV_OFFSET 4
40 #define JZ_CLOCK_CTRL_CDIV_OFFSET 0
41 +#define JZ_CLOCK_CTRL_UDIV_MASK (0x3f << JZ_CLOCK_CTRL_UDIV_OFFSET)
42 +#define JZ_CLOCK_CTRL_LDIV_MASK (0x1f << JZ_CLOCK_CTRL_LDIV_OFFSET)
43 +#define JZ_CLOCK_CTRL_MDIV_MASK (0x0f << JZ_CLOCK_CTRL_MDIV_OFFSET)
44 +#define JZ_CLOCK_CTRL_PDIV_MASK (0x0f << JZ_CLOCK_CTRL_PDIV_OFFSET)
45 +#define JZ_CLOCK_CTRL_HDIV_MASK (0x0f << JZ_CLOCK_CTRL_HDIV_OFFSET)
46 +#define JZ_CLOCK_CTRL_CDIV_MASK (0x0f << JZ_CLOCK_CTRL_CDIV_OFFSET)
47
48 #define JZ_CLOCK_GATE_UART0 BIT(0)
49 #define JZ_CLOCK_GATE_TCU BIT(1)
50 @@ -90,6 +97,7 @@
51 #define JZ_CLOCK_PLL_M_OFFSET 23
52 #define JZ_CLOCK_PLL_N_OFFSET 18
53 #define JZ_CLOCK_PLL_OD_OFFSET 16
54 +#define JZ_CLOCK_PLL_STABILIZE_OFFSET 0
55
56 #define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
57 #define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
58 @@ -97,10 +105,15 @@
59 #define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
60 #define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
61
62 +#define JZ_REG_EMC_RTCNT 0x88
63 +#define JZ_REG_EMC_RTCOR 0x8C
64 +
65 static void __iomem *jz_clock_base;
66 static spinlock_t jz_clock_lock;
67 static LIST_HEAD(jz_clocks);
68
69 +static void __iomem *jz_emc_base;
70 +
71 struct main_clk {
72 struct clk clk;
73 uint32_t div_offset;
74 @@ -204,25 +217,88 @@ static int jz_clk_ko_is_enabled(struct clk *clk)
75 return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE);
76 }
77
78 +static struct static_clk jz_clk_ext;
79 +
80 +static unsigned long jz_clk_pll_calc_rate(
81 + unsigned int in_div, unsigned int feedback, unsigned int out_div)
82 +{
83 + return ((jz_clk_ext.rate / in_div) * feedback) / out_div;
84 +}
85 +
86 +static void jz_clk_pll_calc_dividers(unsigned long rate,
87 + unsigned int *in_div, unsigned int *feedback, unsigned int *out_div)
88 +{
89 + unsigned int target;
90 +
91 + /* The frequency after the input divider must be between 1 and 15 MHz.
92 + The highest divider yields the best resolution. */
93 + *in_div = jz_clk_ext.rate / 1000000;
94 + if (*in_div >= 34)
95 + *in_div = 33;
96 +
97 + /* The frequency before the output divider must be between 100 and
98 + 500 MHz. The lowest target rate is more energy efficient. */
99 + if (rate < 25000000) {
100 + *out_div = 4;
101 + target = 25000000 * 4;
102 + } else if (rate <= 50000000) {
103 + *out_div = 4;
104 + target = rate * 4;
105 + } else if (rate <= 100000000) {
106 + *out_div = 2;
107 + target = rate * 2;
108 + } else if (rate <= 500000000) {
109 + *out_div = 1;
110 + target = rate;
111 + } else {
112 + *out_div = 1;
113 + target = 500000000;
114 + }
115 +
116 + /* Compute the feedback divider.
117 + Since the divided input is at least 1 MHz and the target frequency
118 + at most 500 MHz, the feedback will be at most 500 and will therefore
119 + always fit in the 9-bit register.
120 + Similarly, the divided input is at most 15 MHz and the target
121 + frequency at least 100 MHz, so the feedback will be at least 6
122 + where the minimum supported value is 2. */
123 + *feedback = ((target / 1000) * *in_div) / (jz_clk_ext.rate / 1000);
124 +}
125 +
126 +static unsigned long jz_clk_pll_round_rate(struct clk *clk, unsigned long rate)
127 +{
128 + unsigned int in_div, feedback, out_div;
129 + /* The PLL frequency must be a multiple of 24 MHz, since the LCD pixel
130 + * clock must be exactly 12 MHz for the TV-out to work.
131 + * TODO: A multiple of 12 MHz for the PLL would work if the PLL would
132 + * not be divided by 2 before being passed to the set of derived
133 + * clocks that includes the LCD pixel clock.
134 + * TODO: Systemwide decisions like this should be made by the board
135 + * support code, so add some kind of hook for that.
136 + */
137 + unsigned long rate24 = (rate / 24000000) * 24000000;
138 +
139 + jz_clk_pll_calc_dividers(rate24, &in_div, &feedback, &out_div);
140 + return jz_clk_pll_calc_rate(in_div, feedback, out_div);
141 +}
142 +
143 static const int pllno[] = {1, 2, 2, 4};
144
145 static unsigned long jz_clk_pll_get_rate(struct clk *clk)
146 {
147 uint32_t val;
148 - int m;
149 - int n;
150 - int od;
151 + unsigned int in_div, feedback, out_div;
152
153 val = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
154
155 if (val & JZ_CLOCK_PLL_BYPASS)
156 return clk_get_rate(clk->parent);
157
158 - m = ((val >> 23) & 0x1ff) + 2;
159 - n = ((val >> 18) & 0x1f) + 2;
160 - od = (val >> 16) & 0x3;
161 + feedback = ((val >> 23) & 0x1ff) + 2;
162 + in_div = ((val >> 18) & 0x1f) + 2;
163 + out_div = pllno[(val >> 16) & 0x3];
164
165 - return ((clk_get_rate(clk->parent) / n) * m) / pllno[od];
166 + return jz_clk_pll_calc_rate(in_div, feedback, out_div);
167 }
168
169 static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
170 @@ -235,7 +311,77 @@ static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
171 return jz_clk_pll_get_rate(clk->parent) >> 1;
172 }
173
174 -static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
175 +#define SDRAM_TREF 15625 /* Refresh period: 4096 refresh cycles/64ms */
176 +
177 +static void sdram_set_pll(unsigned int pllin)
178 +{
179 + unsigned int ns, sdramclock;
180 +
181 + ns = 1000000000 / pllin;
182 + sdramclock = (SDRAM_TREF / ns) / 64 + 1;
183 + if (sdramclock > 0xff) sdramclock = 0xff;
184 + /* Set refresh registers */
185 + writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCOR);
186 + writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCNT);
187 +}
188 +
189 +static int jz_clk_pll_set_rate(struct clk *clk, unsigned long rate)
190 +{
191 + unsigned int ctrl, plcr1;
192 + unsigned int feedback, in_div, out_div, pllout, pllout2;
193 +
194 + jz_clk_pll_calc_dividers(rate, &in_div, &feedback, &out_div);
195 +
196 + ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
197 + pllout = jz_clk_pll_calc_rate(in_div, feedback, out_div);
198 + pllout2 = (ctrl & JZ_CLOCK_CTRL_PLL_HALF) ? pllout : (pllout / 2);
199 +
200 + /* Init UHC clock */
201 + writel(pllout2 / 48000000 - 1, jz_clock_base + JZ_REG_CLOCK_UHC);
202 +
203 + plcr1 = ((feedback - 2) << JZ_CLOCK_PLL_M_OFFSET) |
204 + ((in_div - 2) << JZ_CLOCK_PLL_N_OFFSET) |
205 + ((out_div - 1) << JZ_CLOCK_PLL_OD_OFFSET) |
206 + (0x20 << JZ_CLOCK_PLL_STABILIZE_OFFSET) |
207 + JZ_CLOCK_PLL_ENABLED;
208 +
209 + sdram_set_pll(pllout);
210 +
211 + /* LCD pixclock */
212 + writel(pllout2 / 12000000 - 1, jz_clock_base + JZ_REG_CLOCK_LCD);
213 +
214 + /* configure PLL */
215 + __asm__ __volatile__(
216 + ".set noreorder\n\t"
217 + ".align 5\n"
218 + "sw %1,0(%0)\n\t"
219 + "nop\n\t"
220 + "nop\n\t"
221 + "nop\n\t"
222 + "nop\n\t"
223 + "nop\n\t"
224 + "nop\n\t"
225 + "nop\n\t"
226 + ".set reorder\n\t"
227 + :
228 + : "r" (jz_clock_base + JZ_REG_CLOCK_PLL), "r" (plcr1));
229 +
230 + /* MtH: For some reason the MSC will have problems if this flag is not
231 + restored, even though the MSC is supposedly the only divider
232 + that is not affected by this flag. */
233 + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_CHANGE_ENABLE);
234 +
235 + return 0;
236 +}
237 +
238 +static const unsigned int jz_clk_main_divs[] = {
239 + 1, 2, 3, 4, 6, 8, 12, 16, 24, 32
240 +};
241 +static const unsigned int jz_clk_main_divs_inv[] = {
242 + -1, 0, 1, 2, 3, -1, 4, -1, 5, -1, -1, -1, 6, -1, -1, -1,
243 + 7, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1,
244 + 9
245 +};
246
247 static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
248 {
249 @@ -290,6 +436,64 @@ static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate)
250 return 0;
251 }
252
253 +static struct main_clk jz_clk_cpu;
254 +
255 +int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv,
256 + unsigned int mdiv, unsigned int pdiv)
257 +{
258 + unsigned int cdiv_enc, hdiv_enc, mdiv_enc, pdiv_enc;
259 + unsigned int ctrl;
260 + unsigned int tmp, wait;
261 +
262 + if (cdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) ||
263 + hdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) ||
264 + mdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) ||
265 + pdiv >= ARRAY_SIZE(jz_clk_main_divs_inv))
266 + return -EINVAL;
267 + cdiv_enc = jz_clk_main_divs_inv[cdiv];
268 + hdiv_enc = jz_clk_main_divs_inv[hdiv];
269 + mdiv_enc = jz_clk_main_divs_inv[mdiv];
270 + pdiv_enc = jz_clk_main_divs_inv[pdiv];
271 + if (cdiv_enc == (unsigned int)-1 ||
272 + hdiv_enc == (unsigned int)-1 ||
273 + mdiv_enc == (unsigned int)-1 ||
274 + pdiv_enc == (unsigned int)-1)
275 + return -EINVAL;
276 +
277 + ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
278 + ctrl &= ~(JZ_CLOCK_CTRL_CHANGE_ENABLE |
279 + JZ_CLOCK_CTRL_CDIV_MASK | JZ_CLOCK_CTRL_HDIV_MASK |
280 + JZ_CLOCK_CTRL_MDIV_MASK | JZ_CLOCK_CTRL_PDIV_MASK);
281 + if (immediate) ctrl |= JZ_CLOCK_CTRL_CHANGE_ENABLE;
282 + ctrl |= (cdiv_enc << JZ_CLOCK_CTRL_CDIV_OFFSET) |
283 + (hdiv_enc << JZ_CLOCK_CTRL_HDIV_OFFSET) |
284 + (mdiv_enc << JZ_CLOCK_CTRL_MDIV_OFFSET) |
285 + (pdiv_enc << JZ_CLOCK_CTRL_PDIV_OFFSET);
286 +
287 + /* set dividers */
288 + /* delay loops lifted from the old Ingenic cpufreq driver */
289 + wait = ((clk_get_rate(&jz_clk_cpu.clk) / 1000000) * 500) / 1000;
290 + __asm__ __volatile__(
291 + ".set noreorder\n\t"
292 + ".align 5\n"
293 + "sw %2,0(%1)\n\t"
294 + "li %0,0\n\t"
295 + "1:\n\t"
296 + "bne %0,%3,1b\n\t"
297 + "addi %0, 1\n\t"
298 + "nop\n\t"
299 + "nop\n\t"
300 + "nop\n\t"
301 + "nop\n\t"
302 + ".set reorder\n\t"
303 + : "=r" (tmp)
304 + : "r" (jz_clock_base + JZ_REG_CLOCK_CTRL), "r" (ctrl),
305 + "r" (wait));
306 +
307 + return 0;
308 +}
309 +EXPORT_SYMBOL_GPL(clk_main_set_dividers);
310 +
311 static struct clk_ops jz_clk_static_ops = {
312 .get_rate = jz_clk_static_get_rate,
313 .enable = jz_clk_enable_gating,
314 @@ -307,6 +511,8 @@ static struct static_clk jz_clk_ext = {
315
316 static struct clk_ops jz_clk_pll_ops = {
317 .get_rate = jz_clk_pll_get_rate,
318 + .set_rate = jz_clk_pll_set_rate,
319 + .round_rate = jz_clk_pll_round_rate,
320 };
321
322 static struct clk jz_clk_pll = {
323 @@ -897,6 +1103,10 @@ static int jz4740_clock_init(void)
324 if (!jz_clock_base)
325 return -EBUSY;
326
327 + jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100);
328 + if (!jz_emc_base)
329 + return -EBUSY;
330 +
331 spin_lock_init(&jz_clock_lock);
332
333 jz_clk_ext.rate = jz4740_clock_bdata.ext_rate;
334 diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
335 index 5d07499..cc8d1db 100644
336 --- a/arch/mips/jz4740/clock.h
337 +++ b/arch/mips/jz4740/clock.h
338 @@ -17,6 +17,7 @@
339 #define __MIPS_JZ4740_CLOCK_H__
340
341 #include <linux/list.h>
342 +#include <linux/types.h>
343
344 struct jz4740_clock_board_data {
345 unsigned long ext_rate;
346 @@ -63,6 +64,9 @@ struct clk {
347
348 int clk_is_enabled(struct clk *clk);
349
350 +int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv,
351 + unsigned int mdiv, unsigned int pdiv);
352 +
353 #ifdef CONFIG_DEBUG_FS
354 void jz4740_clock_debugfs_init(void);
355 void jz4740_clock_debugfs_add_clk(struct clk *clk);
356 --
357 1.7.5.4
358
This page took 0.076928 seconds and 5 git commands to generate.