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