aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-06-04 03:37:59 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-06-11 02:15:15 -0400
commit46e9371c0eaade8391b3969431a72272b9007158 (patch)
treea7482cdfe6d208a51571e004c155688b227f8255 /arch
parent4ed37394842e5f9c0c4ea087e8716d4458d03bfb (diff)
sh: sh7722 clock framework rewrite
This patch rewrites the sh7722 clock framework code. The new code makes use of the recently merged div4, div6 and mstp32 helper code. Both extal and dll are supported as input clocks to the pll. While at it, now when all SuperH Mobile processors are converted, fix CONFIG_SH_CLK_CPG_LEGACY to depend on CONFIG_ARCH_SHMOBILE. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/Kconfig2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c796
2 files changed, 138 insertions, 660 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index dbc10ff495a9..b5629cdc37a0 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -516,7 +516,7 @@ config SH_CLK_CPG
516 516
517config SH_CLK_CPG_LEGACY 517config SH_CLK_CPG_LEGACY
518 depends on SH_CLK_CPG 518 depends on SH_CLK_CPG
519 def_bool y if !CPU_SUBTYPE_SH7785 && !CPU_SUBTYPE_SH7723 && !CPU_SUBTYPE_SH7724 && !CPU_SUBTYPE_SH7343 && !CPU_SUBTYPE_SH7366 519 def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE
520 520
521config SH_CLK_MD 521config SH_CLK_MD
522 int "CPU Mode Pin Setting" 522 int "CPU Mode Pin Setting"
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index 6ca7c745580d..40f859354f79 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -1,719 +1,197 @@
1/* 1/*
2 * arch/sh/kernel/cpu/sh4a/clock-sh7722.c 2 * arch/sh/kernel/cpu/sh4a/clock-sh7722.c
3 * 3 *
4 * SH7722 support for the clock framework 4 * SH7722 clock framework support
5 * 5 *
6 * Copyright (c) 2006-2007 Nomad Global Solutions Inc 6 * Copyright (C) 2009 Magnus Damm
7 * Based on code for sh7343 by Paul Mundt
8 * 7 *
9 * This file is subject to the terms and conditions of the GNU General Public 8 * This program is free software; you can redistribute it and/or modify
10 * License. See the file "COPYING" in the main directory of this archive 9 * it under the terms of the GNU General Public License as published by
11 * for more details. 10 * the Free Software Foundation; either version 2 of the License
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
12 */ 20 */
13#include <linux/init.h> 21#include <linux/init.h>
14#include <linux/kernel.h> 22#include <linux/kernel.h>
15#include <linux/io.h> 23#include <linux/io.h>
16#include <linux/errno.h>
17#include <linux/stringify.h>
18#include <asm/clock.h> 24#include <asm/clock.h>
19#include <asm/freq.h>
20
21#define N (-1)
22#define NM (-2)
23#define ROUND_NEAREST 0
24#define ROUND_DOWN -1
25#define ROUND_UP +1
26
27static int adjust_algos[][3] = {
28 {}, /* NO_CHANGE */
29 { NM, N, 1 }, /* N:1, N:1 */
30 { 3, 2, 2 }, /* 3:2:2 */
31 { 5, 2, 2 }, /* 5:2:2 */
32 { N, 1, 1 }, /* N:1:1 */
33
34 { N, 1 }, /* N:1 */
35 25
36 { N, 1 }, /* N:1 */ 26/* SH7722 registers */
37 { 3, 2 }, 27#define FRQCR 0xa4150000
38 { 4, 3 }, 28#define VCLKCR 0xa4150004
39 { 5, 4 }, 29#define SCLKACR 0xa4150008
40 30#define SCLKBCR 0xa415000c
41 { N, 1 } 31#define IRDACLKCR 0xa4150018
32#define PLLCR 0xa4150024
33#define MSTPCR0 0xa4150030
34#define MSTPCR1 0xa4150034
35#define MSTPCR2 0xa4150038
36#define DLLFRQ 0xa4150050
37
38/* Fixed 32 KHz root clock for RTC and Power Management purposes */
39static struct clk r_clk = {
40 .name = "rclk",
41 .id = -1,
42 .rate = 32768,
42}; 43};
43 44
44static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2,
45 int m1, int m2, int round_flag)
46{
47 unsigned long rem, div;
48 int the_one = 0;
49
50 pr_debug( "Actual values: r1 = %ld\n", r1);
51 pr_debug( "...............r2 = %ld\n", r2);
52
53 if (m1 == m2) {
54 r2 = r1;
55 pr_debug( "setting equal rates: r2 now %ld\n", r2);
56 } else if ((m2 == N && m1 == 1) ||
57 (m2 == NM && m1 == N)) { /* N:1 or NM:N */
58 pr_debug( "Setting rates as 1:N (N:N*M)\n");
59 rem = r2 % r1;
60 pr_debug( "...remainder = %ld\n", rem);
61 if (rem) {
62 div = r2 / r1;
63 pr_debug( "...div = %ld\n", div);
64 switch (round_flag) {
65 case ROUND_NEAREST:
66 the_one = rem >= r1/2 ? 1 : 0; break;
67 case ROUND_UP:
68 the_one = 1; break;
69 case ROUND_DOWN:
70 the_one = 0; break;
71 }
72
73 r2 = r1 * (div + the_one);
74 pr_debug( "...setting r2 to %ld\n", r2);
75 }
76 } else if ((m2 == 1 && m1 == N) ||
77 (m2 == N && m1 == NM)) { /* 1:N or N:NM */
78 pr_debug( "Setting rates as N:1 (N*M:N)\n");
79 rem = r1 % r2;
80 pr_debug( "...remainder = %ld\n", rem);
81 if (rem) {
82 div = r1 / r2;
83 pr_debug( "...div = %ld\n", div);
84 switch (round_flag) {
85 case ROUND_NEAREST:
86 the_one = rem > r2/2 ? 1 : 0; break;
87 case ROUND_UP:
88 the_one = 0; break;
89 case ROUND_DOWN:
90 the_one = 1; break;
91 }
92
93 r2 = r1 / (div + the_one);
94 pr_debug( "...setting r2 to %ld\n", r2);
95 }
96 } else { /* value:value */
97 pr_debug( "Setting rates as %d:%d\n", m1, m2);
98 div = r1 / m1;
99 r2 = div * m2;
100 pr_debug( "...div = %ld\n", div);
101 pr_debug( "...setting r2 to %ld\n", r2);
102 }
103
104 return r2;
105}
106
107static void adjust_clocks(int originate, int *l, unsigned long v[],
108 int n_in_line)
109{
110 int x;
111
112 pr_debug( "Go down from %d...\n", originate);
113 /* go up recalculation clocks */
114 for (x = originate; x>0; x -- )
115 v[x-1] = adjust_pair_of_clocks(v[x], v[x-1],
116 l[x], l[x-1],
117 ROUND_UP);
118
119 pr_debug( "Go up from %d...\n", originate);
120 /* go down recalculation clocks */
121 for (x = originate; x<n_in_line - 1; x ++ )
122 v[x+1] = adjust_pair_of_clocks(v[x], v[x+1],
123 l[x], l[x+1],
124 ROUND_UP);
125}
126
127
128/* 45/*
129 * SH7722 uses a common set of multipliers and divisors, so this 46 * Default rate for the root input clock, reset this with clk_set_rate()
130 * is quite simple.. 47 * from the platform code.
131 */ 48 */
132 49struct clk extal_clk = {
133#define STCPLL(frqcr) (((frqcr >> 24) & 0x1f) + 1) 50 .name = "extal",
134 51 .id = -1,
135/* 52 .rate = 33333333,
136 * Instead of having two separate multipliers/divisors set, like this:
137 *
138 * static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
139 * static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
140 *
141 * I created the divisors2 array, which is used to calculate rate like
142 * rate = parent * 2 / divisors2[ divisor ];
143*/
144static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
145
146static unsigned long master_clk_recalc(struct clk *clk)
147{
148 unsigned frqcr = ctrl_inl(FRQCR);
149
150 return CONFIG_SH_PCLK_FREQ * STCPLL(frqcr);
151}
152
153static void master_clk_init(struct clk *clk)
154{
155 clk->parent = NULL;
156 clk->rate = master_clk_recalc(clk);
157}
158
159static unsigned long module_clk_recalc(struct clk *clk)
160{
161 unsigned long frqcr = ctrl_inl(FRQCR);
162
163 return clk->parent->rate / STCPLL(frqcr);
164}
165
166#define MASTERDIVS { 2, 3, 4, 6, 8, 16 }
167#define STCMASK 0x1f
168#define DIVCALC(div) (div-1)
169#define FRQCRKICK 0x00000000
170
171static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
172{
173 int div = rate / clk->rate;
174 int master_divs[] = MASTERDIVS;
175 int index;
176 unsigned long frqcr;
177
178 for (index = 1; index < ARRAY_SIZE(master_divs); index++)
179 if (div >= master_divs[index - 1] && div < master_divs[index])
180 break;
181
182 if (index >= ARRAY_SIZE(master_divs))
183 index = ARRAY_SIZE(master_divs);
184 div = master_divs[index - 1];
185
186 frqcr = ctrl_inl(FRQCR);
187 frqcr &= ~(STCMASK << 24);
188 frqcr |= (DIVCALC(div) << 24);
189 frqcr |= FRQCRKICK;
190 ctrl_outl(frqcr, FRQCR);
191
192 return 0;
193}
194
195static struct clk_ops sh7722_master_clk_ops = {
196 .init = master_clk_init,
197 .recalc = master_clk_recalc,
198 .set_rate = master_clk_setrate,
199};
200
201static struct clk_ops sh7722_module_clk_ops = {
202 .recalc = module_clk_recalc,
203};
204
205struct frqcr_context {
206 unsigned mask;
207 unsigned shift;
208};
209
210struct frqcr_context sh7722_get_clk_context(const char *name)
211{
212 struct frqcr_context ctx = { 0, };
213
214 if (!strcmp(name, "peripheral_clk")) {
215 ctx.shift = 0;
216 ctx.mask = 0xF;
217 } else if (!strcmp(name, "sdram_clk")) {
218 ctx.shift = 4;
219 ctx.mask = 0xF;
220 } else if (!strcmp(name, "bus_clk")) {
221 ctx.shift = 8;
222 ctx.mask = 0xF;
223 } else if (!strcmp(name, "sh_clk")) {
224 ctx.shift = 12;
225 ctx.mask = 0xF;
226 } else if (!strcmp(name, "umem_clk")) {
227 ctx.shift = 16;
228 ctx.mask = 0xF;
229 } else if (!strcmp(name, "cpu_clk")) {
230 ctx.shift = 20;
231 ctx.mask = 7;
232 }
233 return ctx;
234}
235
236/**
237 * sh7722_find_div_index - find divisor for setting rate
238 *
239 * All sh7722 clocks use the same set of multipliers/divisors. This function
240 * chooses correct divisor to set the rate of clock with parent clock that
241 * generates frequency of 'parent_rate'
242 *
243 * @parent_rate: rate of parent clock
244 * @rate: requested rate to be set
245 */
246static int sh7722_find_div_index(unsigned long parent_rate, unsigned rate)
247{
248 unsigned div2 = parent_rate * 2 / rate;
249 int index;
250
251 if (rate > parent_rate)
252 return -EINVAL;
253
254 for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
255 if (div2 > divisors2[index - 1] && div2 <= divisors2[index])
256 break;
257 }
258 if (index >= ARRAY_SIZE(divisors2))
259 index = ARRAY_SIZE(divisors2) - 1;
260 return index;
261}
262
263static unsigned long sh7722_frqcr_recalc(struct clk *clk)
264{
265 struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
266 unsigned long frqcr = ctrl_inl(FRQCR);
267 int index;
268
269 index = (frqcr >> ctx.shift) & ctx.mask;
270 return clk->parent->rate * 2 / divisors2[index];
271}
272
273static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
274 int algo_id)
275{
276 struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
277 unsigned long parent_rate = clk->parent->rate;
278 int div;
279 unsigned long frqcr;
280 int err = 0;
281
282 /* pretty invalid */
283 if (parent_rate < rate)
284 return -EINVAL;
285
286 /* look for multiplier/divisor pair */
287 div = sh7722_find_div_index(parent_rate, rate);
288 if (div<0)
289 return div;
290
291 /* calculate new value of clock rate */
292 clk->rate = parent_rate * 2 / divisors2[div];
293 frqcr = ctrl_inl(FRQCR);
294
295 /* FIXME: adjust as algo_id specifies */
296 if (algo_id != NO_CHANGE) {
297 int originator;
298 char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" };
299 char *algo_group_2[] = { "sh_clk", "bus_clk" };
300 char *algo_group_3[] = { "sh_clk", "sdram_clk" };
301 char *algo_group_4[] = { "bus_clk", "peripheral_clk" };
302 char *algo_group_5[] = { "cpu_clk", "peripheral_clk" };
303 char **algo_current = NULL;
304 /* 3 is the maximum number of clocks in relation */
305 struct clk *ck[3];
306 unsigned long values[3]; /* the same comment as above */
307 int part_length = -1;
308 int i;
309
310 /*
311 * all the steps below only required if adjustion was
312 * requested
313 */
314 if (algo_id == IUS_N1_N1 ||
315 algo_id == IUS_322 ||
316 algo_id == IUS_522 ||
317 algo_id == IUS_N11) {
318 algo_current = algo_group_1;
319 part_length = 3;
320 }
321 if (algo_id == SB_N1) {
322 algo_current = algo_group_2;
323 part_length = 2;
324 }
325 if (algo_id == SB3_N1 ||
326 algo_id == SB3_32 ||
327 algo_id == SB3_43 ||
328 algo_id == SB3_54) {
329 algo_current = algo_group_3;
330 part_length = 2;
331 }
332 if (algo_id == BP_N1) {
333 algo_current = algo_group_4;
334 part_length = 2;
335 }
336 if (algo_id == IP_N1) {
337 algo_current = algo_group_5;
338 part_length = 2;
339 }
340 if (!algo_current)
341 goto incorrect_algo_id;
342
343 originator = -1;
344 for (i = 0; i < part_length; i ++ ) {
345 if (originator >= 0 && !strcmp(clk->name,
346 algo_current[i]))
347 originator = i;
348 ck[i] = clk_get(NULL, algo_current[i]);
349 values[i] = clk_get_rate(ck[i]);
350 }
351
352 if (originator >= 0)
353 adjust_clocks(originator, adjust_algos[algo_id],
354 values, part_length);
355
356 for (i = 0; i < part_length; i ++ ) {
357 struct frqcr_context part_ctx;
358 int part_div;
359
360 if (likely(!err)) {
361 part_div = sh7722_find_div_index(parent_rate,
362 rate);
363 if (part_div > 0) {
364 part_ctx = sh7722_get_clk_context(
365 ck[i]->name);
366 frqcr &= ~(part_ctx.mask <<
367 part_ctx.shift);
368 frqcr |= part_div << part_ctx.shift;
369 } else
370 err = part_div;
371 }
372
373 ck[i]->ops->recalc(ck[i]);
374 clk_put(ck[i]);
375 }
376 }
377
378 /* was there any error during recalculation ? If so, bail out.. */
379 if (unlikely(err!=0))
380 goto out_err;
381
382 /* clear FRQCR bits */
383 frqcr &= ~(ctx.mask << ctx.shift);
384 frqcr |= div << ctx.shift;
385 frqcr |= FRQCRKICK;
386
387 /* ...and perform actual change */
388 ctrl_outl(frqcr, FRQCR);
389 return 0;
390
391incorrect_algo_id:
392 return -EINVAL;
393out_err:
394 return err;
395}
396
397static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate)
398{
399 unsigned long parent_rate = clk->parent->rate;
400 int div;
401
402 /* look for multiplier/divisor pair */
403 div = sh7722_find_div_index(parent_rate, rate);
404 if (div < 0)
405 return clk->rate;
406
407 /* calculate new value of clock rate */
408 return parent_rate * 2 / divisors2[div];
409}
410
411static struct clk_ops sh7722_frqcr_clk_ops = {
412 .recalc = sh7722_frqcr_recalc,
413 .set_rate = sh7722_frqcr_set_rate,
414 .round_rate = sh7722_frqcr_round_rate,
415}; 53};
416 54
417/* 55/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
418 * clock ops methods for SIU A/B and IrDA clock 56static unsigned long dll_recalc(struct clk *clk)
419 */
420static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
421{
422 unsigned long r;
423 int div;
424
425 r = ctrl_inl(clk->arch_flags);
426 div = sh7722_find_div_index(clk->parent->rate, rate);
427 if (div < 0)
428 return div;
429 r = (r & ~0xF) | div;
430 ctrl_outl(r, clk->arch_flags);
431 return 0;
432}
433
434static unsigned long sh7722_siu_recalc(struct clk *clk)
435{
436 unsigned long r;
437
438 r = ctrl_inl(clk->arch_flags);
439 return clk->parent->rate * 2 / divisors2[r & 0xF];
440}
441
442static int sh7722_siu_start_stop(struct clk *clk, int enable)
443{ 57{
444 unsigned long r; 58 unsigned long mult;
445 59
446 r = ctrl_inl(clk->arch_flags); 60 if (__raw_readl(PLLCR) & 0x1000)
447 if (enable) 61 mult = __raw_readl(DLLFRQ);
448 ctrl_outl(r & ~(1 << 8), clk->arch_flags);
449 else 62 else
450 ctrl_outl(r | (1 << 8), clk->arch_flags); 63 mult = 0;
451 return 0;
452}
453 64
454static int sh7722_siu_enable(struct clk *clk) 65 return clk->parent->rate * mult;
455{
456 return sh7722_siu_start_stop(clk, 1);
457}
458
459static void sh7722_siu_disable(struct clk *clk)
460{
461 sh7722_siu_start_stop(clk, 0);
462} 66}
463 67
464static struct clk_ops sh7722_siu_clk_ops = { 68static struct clk_ops dll_clk_ops = {
465 .recalc = sh7722_siu_recalc, 69 .recalc = dll_recalc,
466 .set_rate = sh7722_siu_set_rate,
467 .enable = sh7722_siu_enable,
468 .disable = sh7722_siu_disable,
469}; 70};
470 71
471static int sh7722_video_enable(struct clk *clk) 72static struct clk dll_clk = {
472{ 73 .name = "dll_clk",
473 unsigned long r; 74 .id = -1,
474 75 .ops = &dll_clk_ops,
475 r = ctrl_inl(VCLKCR); 76 .parent = &r_clk,
476 ctrl_outl( r & ~(1<<8), VCLKCR); 77 .flags = CLK_ENABLE_ON_INIT,
477 return 0; 78};
478}
479
480static void sh7722_video_disable(struct clk *clk)
481{
482 unsigned long r;
483
484 r = ctrl_inl(VCLKCR);
485 ctrl_outl( r | (1<<8), VCLKCR);
486}
487 79
488static int sh7722_video_set_rate(struct clk *clk, unsigned long rate, 80static unsigned long pll_recalc(struct clk *clk)
489 int algo_id)
490{ 81{
491 unsigned long r; 82 unsigned long mult = 1;
83 unsigned long div = 1;
492 84
493 r = ctrl_inl(VCLKCR); 85 if (__raw_readl(PLLCR) & 0x4000)
494 r &= ~0x3F; 86 mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
495 r |= ((clk->parent->rate / rate - 1) & 0x3F); 87 else
496 ctrl_outl(r, VCLKCR); 88 div = 2;
497 return 0;
498}
499
500static unsigned long sh7722_video_recalc(struct clk *clk)
501{
502 unsigned long r;
503 89
504 r = ctrl_inl(VCLKCR); 90 return (clk->parent->rate * mult) / div;
505 return clk->parent->rate / ((r & 0x3F) + 1);
506} 91}
507 92
508static struct clk_ops sh7722_video_clk_ops = { 93static struct clk_ops pll_clk_ops = {
509 .recalc = sh7722_video_recalc, 94 .recalc = pll_recalc,
510 .set_rate = sh7722_video_set_rate,
511 .enable = sh7722_video_enable,
512 .disable = sh7722_video_disable,
513};
514/*
515 * and at last, clock definitions themselves
516 */
517static struct clk sh7722_umem_clock = {
518 .name = "umem_clk",
519 .ops = &sh7722_frqcr_clk_ops,
520}; 95};
521 96
522static struct clk sh7722_sh_clock = { 97static struct clk pll_clk = {
523 .name = "sh_clk", 98 .name = "pll_clk",
524 .ops = &sh7722_frqcr_clk_ops, 99 .id = -1,
100 .ops = &pll_clk_ops,
101 .flags = CLK_ENABLE_ON_INIT,
525}; 102};
526 103
527static struct clk sh7722_peripheral_clock = { 104struct clk *main_clks[] = {
528 .name = "peripheral_clk", 105 &r_clk,
529 .ops = &sh7722_frqcr_clk_ops, 106 &extal_clk,
107 &dll_clk,
108 &pll_clk,
530}; 109};
531 110
532static struct clk sh7722_sdram_clock = { 111static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
533 .name = "sdram_clk", 112static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
534 .ops = &sh7722_frqcr_clk_ops,
535};
536 113
537static struct clk sh7722_r_clock = { 114static struct clk_div_mult_table div4_table = {
538 .name = "r_clk", 115 .divisors = divisors,
539 .rate = 32768, 116 .nr_divisors = ARRAY_SIZE(divisors),
117 .multipliers = multipliers,
118 .nr_multipliers = ARRAY_SIZE(multipliers),
540}; 119};
541 120
542/* 121enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
543 * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops 122 DIV4_SIUA, DIV4_SIUB, DIV4_IRDA, DIV4_NR };
544 * methods of clk_ops determine which register they should access by
545 * examining clk->name field
546 */
547static struct clk sh7722_siu_a_clock = {
548 .name = "siu_a_clk",
549 .arch_flags = SCLKACR,
550 .ops = &sh7722_siu_clk_ops,
551};
552 123
553static struct clk sh7722_siu_b_clock = { 124#define DIV4(_str, _reg, _bit, _mask, _flags) \
554 .name = "siu_b_clk", 125 SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
555 .arch_flags = SCLKBCR,
556 .ops = &sh7722_siu_clk_ops,
557};
558 126
559#if defined(CONFIG_CPU_SUBTYPE_SH7722) 127struct clk div4_clks[DIV4_NR] = {
560static struct clk sh7722_irda_clock = { 128 [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
561 .name = "irda_clk", 129 [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
562 .arch_flags = IrDACLKCR, 130 [DIV4_SH] = DIV4("shyway_clk", FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
563 .ops = &sh7722_siu_clk_ops, 131 [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
132 [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
133 [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0),
134 [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0),
135 [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0),
136 [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x1fff, 0),
564}; 137};
565#endif
566 138
567static struct clk sh7722_video_clock = { 139struct clk div6_clks[] = {
568 .name = "video_clk", 140 SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0),
569 .ops = &sh7722_video_clk_ops,
570}; 141};
571 142
572#define MSTPCR_ARCH_FLAGS(reg, bit) (((reg) << 8) | (bit)) 143#define MSTP(_str, _parent, _reg, _bit, _flags) \
573#define MSTPCR_ARCH_FLAGS_REG(value) ((value) >> 8) 144 SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags)
574#define MSTPCR_ARCH_FLAGS_BIT(value) ((value) & 0xff)
575
576static int sh7722_mstpcr_start_stop(struct clk *clk, int enable)
577{
578 unsigned long bit = MSTPCR_ARCH_FLAGS_BIT(clk->arch_flags);
579 unsigned long reg;
580 unsigned long r;
581 145
582 switch(MSTPCR_ARCH_FLAGS_REG(clk->arch_flags)) { 146static struct clk mstp_clks[] = {
583 case 0: 147 MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
584 reg = MSTPCR0; 148 MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
585 break; 149 MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0),
586 case 1: 150 MSTP("cmt0", &r_clk, MSTPCR0, 14, 0),
587 reg = MSTPCR1; 151 MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0),
588 break; 152 MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0),
589 case 2: 153 MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0),
590 reg = MSTPCR2; 154 MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0),
591 break; 155 MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0),
592 default:
593 return -EINVAL;
594 }
595 156
596 r = ctrl_inl(reg); 157 MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0),
597 158 MSTP("rtc0", &r_clk, MSTPCR1, 8, 0),
598 if (enable)
599 r &= ~(1 << bit);
600 else
601 r |= (1 << bit);
602 159
603 ctrl_outl(r, reg); 160 MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0),
604 return 0; 161 MSTP("keysc0", &r_clk, MSTPCR2, 14, 0),
605} 162 MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0),
606 163 MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 9, 0),
607static int sh7722_mstpcr_enable(struct clk *clk) 164 MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0),
608{ 165 MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0),
609 return sh7722_mstpcr_start_stop(clk, 1); 166 MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
610} 167 MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0),
611 168 MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0),
612static void sh7722_mstpcr_disable(struct clk *clk) 169 MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
613{ 170 MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
614 sh7722_mstpcr_start_stop(clk, 0); 171 MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0),
615}
616
617static struct clk_ops sh7722_mstpcr_clk_ops = {
618 .enable = sh7722_mstpcr_enable,
619 .disable = sh7722_mstpcr_disable,
620 .recalc = followparent_recalc,
621};
622
623#define MSTPCR(_name, _parent, regnr, bitnr, _flags) \
624{ \
625 .name = _name, \
626 .flags = _flags, \
627 .arch_flags = MSTPCR_ARCH_FLAGS(regnr, bitnr), \
628 .ops = (void *)_parent, \
629}
630
631static struct clk sh7722_mstpcr_clocks[] = {
632#if defined(CONFIG_CPU_SUBTYPE_SH7722)
633 MSTPCR("uram0", "umem_clk", 0, 28, CLK_ENABLE_ON_INIT),
634 MSTPCR("xymem0", "bus_clk", 0, 26, CLK_ENABLE_ON_INIT),
635 MSTPCR("tmu0", "peripheral_clk", 0, 15, 0),
636 MSTPCR("cmt0", "r_clk", 0, 14, 0),
637 MSTPCR("rwdt0", "r_clk", 0, 13, 0),
638 MSTPCR("flctl0", "peripheral_clk", 0, 10, 0),
639 MSTPCR("scif0", "peripheral_clk", 0, 7, 0),
640 MSTPCR("scif1", "peripheral_clk", 0, 6, 0),
641 MSTPCR("scif2", "peripheral_clk", 0, 5, 0),
642 MSTPCR("i2c0", "peripheral_clk", 1, 9, 0),
643 MSTPCR("rtc0", "r_clk", 1, 8, 0),
644 MSTPCR("sdhi0", "peripheral_clk", 2, 18, 0),
645 MSTPCR("keysc0", "r_clk", 2, 14, 0),
646 MSTPCR("usbf0", "peripheral_clk", 2, 11, 0),
647 MSTPCR("2dg0", "bus_clk", 2, 9, 0),
648 MSTPCR("siu0", "bus_clk", 2, 8, 0),
649 MSTPCR("vou0", "bus_clk", 2, 5, 0),
650 MSTPCR("jpu0", "bus_clk", 2, 6, CLK_ENABLE_ON_INIT),
651 MSTPCR("beu0", "bus_clk", 2, 4, 0),
652 MSTPCR("ceu0", "bus_clk", 2, 3, 0),
653 MSTPCR("veu0", "bus_clk", 2, 2, CLK_ENABLE_ON_INIT),
654 MSTPCR("vpu0", "bus_clk", 2, 1, CLK_ENABLE_ON_INIT),
655 MSTPCR("lcdc0", "bus_clk", 2, 0, 0),
656#endif
657};
658
659static struct clk *sh7722_clocks[] = {
660 &sh7722_umem_clock,
661 &sh7722_sh_clock,
662 &sh7722_peripheral_clock,
663 &sh7722_sdram_clock,
664 &sh7722_siu_a_clock,
665 &sh7722_siu_b_clock,
666#if defined(CONFIG_CPU_SUBTYPE_SH7722)
667 &sh7722_irda_clock,
668#endif
669 &sh7722_video_clock,
670};
671
672/*
673 * init in order: master, module, bus, cpu
674 */
675struct clk_ops *onchip_ops[] = {
676 &sh7722_master_clk_ops,
677 &sh7722_module_clk_ops,
678 &sh7722_frqcr_clk_ops,
679 &sh7722_frqcr_clk_ops,
680}; 172};
681 173
682void __init
683arch_init_clk_ops(struct clk_ops **ops, int type)
684{
685 BUG_ON(type < 0 || type >= ARRAY_SIZE(onchip_ops));
686 *ops = onchip_ops[type];
687}
688
689int __init arch_clk_init(void) 174int __init arch_clk_init(void)
690{ 175{
691 struct clk *clk; 176 int k, ret = 0;
692 int i;
693 177
694 cpg_clk_init(); 178 /* autodetect extal or dll configuration */
179 if (__raw_readl(PLLCR) & 0x1000)
180 pll_clk.parent = &dll_clk;
181 else
182 pll_clk.parent = &extal_clk;
695 183
696 clk = clk_get(NULL, "master_clk"); 184 for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
697 for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) { 185 ret = clk_register(main_clks[k]);
698 pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
699 sh7722_clocks[i]->parent = clk;
700 clk_register(sh7722_clocks[i]);
701 }
702 clk_put(clk);
703 186
704 clk_register(&sh7722_r_clock); 187 if (!ret)
188 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
705 189
706 for (i = 0; i < ARRAY_SIZE(sh7722_mstpcr_clocks); i++) { 190 if (!ret)
707 pr_debug( "Registering mstpcr clock '%s'\n", 191 ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
708 sh7722_mstpcr_clocks[i].name);
709 clk = clk_get(NULL, (void *) sh7722_mstpcr_clocks[i].ops);
710 sh7722_mstpcr_clocks[i].parent = clk;
711 sh7722_mstpcr_clocks[i].ops = &sh7722_mstpcr_clk_ops;
712 clk_register(&sh7722_mstpcr_clocks[i]);
713 clk_put(clk);
714 }
715 192
716 propagate_rate(&sh7722_r_clock); /* make sure rate gets propagated */ 193 if (!ret)
194 ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks));
717 195
718 return 0; 196 return ret;
719} 197}