diff options
Diffstat (limited to 'arch/sh/kernel/cpu')
-rw-r--r-- | arch/sh/kernel/cpu/clock.c | 287 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/Makefile | 7 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/clock-sh3.c | 89 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/clock-sh7300.c | 78 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/clock-sh7705.c | 84 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/clock-sh7709.c | 96 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/Makefile | 11 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/clock-sh4-202.c | 179 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/clock-sh4.c | 80 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/clock-sh73180.c | 81 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/clock-sh7770.c | 73 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4/clock-sh7780.c | 126 |
12 files changed, 1190 insertions, 1 deletions
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c new file mode 100644 index 000000000000..989e7fdd524d --- /dev/null +++ b/arch/sh/kernel/cpu/clock.c | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/clock.c - SuperH clock framework | ||
3 | * | ||
4 | * Copyright (C) 2005 Paul Mundt | ||
5 | * | ||
6 | * This clock framework is derived from the OMAP version by: | ||
7 | * | ||
8 | * Copyright (C) 2004 Nokia Corporation | ||
9 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/kref.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <asm/clock.h> | ||
23 | #include <asm/timer.h> | ||
24 | |||
25 | static LIST_HEAD(clock_list); | ||
26 | static DEFINE_SPINLOCK(clock_lock); | ||
27 | static DECLARE_MUTEX(clock_list_sem); | ||
28 | |||
29 | /* | ||
30 | * Each subtype is expected to define the init routines for these clocks, | ||
31 | * as each subtype (or processor family) will have these clocks at the | ||
32 | * very least. These are all provided through the CPG, which even some of | ||
33 | * the more quirky parts (such as ST40, SH4-202, etc.) still have. | ||
34 | * | ||
35 | * The processor-specific code is expected to register any additional | ||
36 | * clock sources that are of interest. | ||
37 | */ | ||
38 | static struct clk master_clk = { | ||
39 | .name = "master_clk", | ||
40 | .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, | ||
41 | #ifdef CONFIG_SH_PCLK_FREQ_BOOL | ||
42 | .rate = CONFIG_SH_PCLK_FREQ, | ||
43 | #endif | ||
44 | }; | ||
45 | |||
46 | static struct clk module_clk = { | ||
47 | .name = "module_clk", | ||
48 | .parent = &master_clk, | ||
49 | .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, | ||
50 | }; | ||
51 | |||
52 | static struct clk bus_clk = { | ||
53 | .name = "bus_clk", | ||
54 | .parent = &master_clk, | ||
55 | .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, | ||
56 | }; | ||
57 | |||
58 | static struct clk cpu_clk = { | ||
59 | .name = "cpu_clk", | ||
60 | .parent = &master_clk, | ||
61 | .flags = CLK_ALWAYS_ENABLED, | ||
62 | }; | ||
63 | |||
64 | /* | ||
65 | * The ordering of these clocks matters, do not change it. | ||
66 | */ | ||
67 | static struct clk *onchip_clocks[] = { | ||
68 | &master_clk, | ||
69 | &module_clk, | ||
70 | &bus_clk, | ||
71 | &cpu_clk, | ||
72 | }; | ||
73 | |||
74 | static void propagate_rate(struct clk *clk) | ||
75 | { | ||
76 | struct clk *clkp; | ||
77 | |||
78 | list_for_each_entry(clkp, &clock_list, node) { | ||
79 | if (likely(clkp->parent != clk)) | ||
80 | continue; | ||
81 | if (likely(clkp->ops && clkp->ops->recalc)) | ||
82 | clkp->ops->recalc(clkp); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | int __clk_enable(struct clk *clk) | ||
87 | { | ||
88 | /* | ||
89 | * See if this is the first time we're enabling the clock, some | ||
90 | * clocks that are always enabled still require "special" | ||
91 | * initialization. This is especially true if the clock mode | ||
92 | * changes and the clock needs to hunt for the proper set of | ||
93 | * divisors to use before it can effectively recalc. | ||
94 | */ | ||
95 | if (unlikely(atomic_read(&clk->kref.refcount) == 1)) | ||
96 | if (clk->ops && clk->ops->init) | ||
97 | clk->ops->init(clk); | ||
98 | |||
99 | if (clk->flags & CLK_ALWAYS_ENABLED) | ||
100 | return 0; | ||
101 | |||
102 | if (likely(clk->ops && clk->ops->enable)) | ||
103 | clk->ops->enable(clk); | ||
104 | |||
105 | kref_get(&clk->kref); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | int clk_enable(struct clk *clk) | ||
110 | { | ||
111 | unsigned long flags; | ||
112 | int ret; | ||
113 | |||
114 | spin_lock_irqsave(&clock_lock, flags); | ||
115 | ret = __clk_enable(clk); | ||
116 | spin_unlock_irqrestore(&clock_lock, flags); | ||
117 | |||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | static void clk_kref_release(struct kref *kref) | ||
122 | { | ||
123 | /* Nothing to do */ | ||
124 | } | ||
125 | |||
126 | void __clk_disable(struct clk *clk) | ||
127 | { | ||
128 | if (clk->flags & CLK_ALWAYS_ENABLED) | ||
129 | return; | ||
130 | |||
131 | kref_put(&clk->kref, clk_kref_release); | ||
132 | } | ||
133 | |||
134 | void clk_disable(struct clk *clk) | ||
135 | { | ||
136 | unsigned long flags; | ||
137 | |||
138 | spin_lock_irqsave(&clock_lock, flags); | ||
139 | __clk_disable(clk); | ||
140 | spin_unlock_irqrestore(&clock_lock, flags); | ||
141 | } | ||
142 | |||
143 | int clk_register(struct clk *clk) | ||
144 | { | ||
145 | down(&clock_list_sem); | ||
146 | |||
147 | list_add(&clk->node, &clock_list); | ||
148 | kref_init(&clk->kref); | ||
149 | |||
150 | up(&clock_list_sem); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | void clk_unregister(struct clk *clk) | ||
156 | { | ||
157 | down(&clock_list_sem); | ||
158 | list_del(&clk->node); | ||
159 | up(&clock_list_sem); | ||
160 | } | ||
161 | |||
162 | inline unsigned long clk_get_rate(struct clk *clk) | ||
163 | { | ||
164 | return clk->rate; | ||
165 | } | ||
166 | |||
167 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
168 | { | ||
169 | int ret = -EOPNOTSUPP; | ||
170 | |||
171 | if (likely(clk->ops && clk->ops->set_rate)) { | ||
172 | unsigned long flags; | ||
173 | |||
174 | spin_lock_irqsave(&clock_lock, flags); | ||
175 | ret = clk->ops->set_rate(clk, rate); | ||
176 | spin_unlock_irqrestore(&clock_lock, flags); | ||
177 | } | ||
178 | |||
179 | if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) | ||
180 | propagate_rate(clk); | ||
181 | |||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | void clk_recalc_rate(struct clk *clk) | ||
186 | { | ||
187 | if (likely(clk->ops && clk->ops->recalc)) { | ||
188 | unsigned long flags; | ||
189 | |||
190 | spin_lock_irqsave(&clock_lock, flags); | ||
191 | clk->ops->recalc(clk); | ||
192 | spin_unlock_irqrestore(&clock_lock, flags); | ||
193 | } | ||
194 | |||
195 | if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) | ||
196 | propagate_rate(clk); | ||
197 | } | ||
198 | |||
199 | struct clk *clk_get(const char *id) | ||
200 | { | ||
201 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
202 | |||
203 | down(&clock_list_sem); | ||
204 | list_for_each_entry(p, &clock_list, node) { | ||
205 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
206 | clk = p; | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | up(&clock_list_sem); | ||
211 | |||
212 | return clk; | ||
213 | } | ||
214 | |||
215 | void clk_put(struct clk *clk) | ||
216 | { | ||
217 | if (clk && !IS_ERR(clk)) | ||
218 | module_put(clk->owner); | ||
219 | } | ||
220 | |||
221 | void __init __attribute__ ((weak)) | ||
222 | arch_init_clk_ops(struct clk_ops **ops, int type) | ||
223 | { | ||
224 | } | ||
225 | |||
226 | int __init clk_init(void) | ||
227 | { | ||
228 | int i, ret = 0; | ||
229 | |||
230 | if (unlikely(!master_clk.rate)) | ||
231 | /* | ||
232 | * NOTE: This will break if the default divisor has been | ||
233 | * changed. | ||
234 | * | ||
235 | * No one should be changing the default on us however, | ||
236 | * expect that a sane value for CONFIG_SH_PCLK_FREQ will | ||
237 | * be defined in the event of a different divisor. | ||
238 | */ | ||
239 | master_clk.rate = get_timer_frequency() * 4; | ||
240 | |||
241 | for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) { | ||
242 | struct clk *clk = onchip_clocks[i]; | ||
243 | |||
244 | arch_init_clk_ops(&clk->ops, i); | ||
245 | ret |= clk_register(clk); | ||
246 | clk_enable(clk); | ||
247 | } | ||
248 | |||
249 | /* Kick the child clocks.. */ | ||
250 | propagate_rate(&master_clk); | ||
251 | propagate_rate(&bus_clk); | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | int show_clocks(struct seq_file *m) | ||
257 | { | ||
258 | struct clk *clk; | ||
259 | |||
260 | list_for_each_entry_reverse(clk, &clock_list, node) { | ||
261 | unsigned long rate = clk_get_rate(clk); | ||
262 | |||
263 | /* | ||
264 | * Don't bother listing dummy clocks with no ancestry | ||
265 | * that only support enable and disable ops. | ||
266 | */ | ||
267 | if (unlikely(!rate && !clk->parent)) | ||
268 | continue; | ||
269 | |||
270 | seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name, | ||
271 | rate / 1000000, (rate % 1000000) / 10000); | ||
272 | } | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | EXPORT_SYMBOL_GPL(clk_register); | ||
278 | EXPORT_SYMBOL_GPL(clk_unregister); | ||
279 | EXPORT_SYMBOL_GPL(clk_get); | ||
280 | EXPORT_SYMBOL_GPL(clk_put); | ||
281 | EXPORT_SYMBOL_GPL(clk_enable); | ||
282 | EXPORT_SYMBOL_GPL(clk_disable); | ||
283 | EXPORT_SYMBOL_GPL(__clk_enable); | ||
284 | EXPORT_SYMBOL_GPL(__clk_disable); | ||
285 | EXPORT_SYMBOL_GPL(clk_get_rate); | ||
286 | EXPORT_SYMBOL_GPL(clk_set_rate); | ||
287 | EXPORT_SYMBOL_GPL(clk_recalc_rate); | ||
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile index a64532e4dc63..b54dbb9a0c86 100644 --- a/arch/sh/kernel/cpu/sh3/Makefile +++ b/arch/sh/kernel/cpu/sh3/Makefile | |||
@@ -4,3 +4,10 @@ | |||
4 | 4 | ||
5 | obj-y := ex.o probe.o | 5 | obj-y := ex.o probe.o |
6 | 6 | ||
7 | clock-$(CONFIG_CPU_SH3) := clock-sh3.o | ||
8 | clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o | ||
9 | clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o | ||
10 | clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o | ||
11 | |||
12 | obj-y += $(clock-y) | ||
13 | |||
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh3.c b/arch/sh/kernel/cpu/sh3/clock-sh3.c new file mode 100644 index 000000000000..c3c945958baf --- /dev/null +++ b/arch/sh/kernel/cpu/sh3/clock-sh3.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh3/clock-sh3.c | ||
3 | * | ||
4 | * Generic SH-3 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * FRQCR parsing hacked out of arch/sh/kernel/time.c | ||
9 | * | ||
10 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
11 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
12 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | ||
13 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | ||
14 | * | ||
15 | * This file is subject to the terms and conditions of the GNU General Public | ||
16 | * License. See the file "COPYING" in the main directory of this archive | ||
17 | * for more details. | ||
18 | */ | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <asm/clock.h> | ||
22 | #include <asm/freq.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
26 | static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; | ||
27 | static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
28 | |||
29 | static void master_clk_init(struct clk *clk) | ||
30 | { | ||
31 | int frqcr = ctrl_inw(FRQCR); | ||
32 | int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); | ||
33 | |||
34 | clk->rate *= pfc_divisors[idx]; | ||
35 | } | ||
36 | |||
37 | static struct clk_ops sh3_master_clk_ops = { | ||
38 | .init = master_clk_init, | ||
39 | }; | ||
40 | |||
41 | static void module_clk_recalc(struct clk *clk) | ||
42 | { | ||
43 | int frqcr = ctrl_inw(FRQCR); | ||
44 | int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); | ||
45 | |||
46 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
47 | } | ||
48 | |||
49 | static struct clk_ops sh3_module_clk_ops = { | ||
50 | .recalc = module_clk_recalc, | ||
51 | }; | ||
52 | |||
53 | static void bus_clk_recalc(struct clk *clk) | ||
54 | { | ||
55 | int frqcr = ctrl_inw(FRQCR); | ||
56 | int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4); | ||
57 | |||
58 | clk->rate = clk->parent->rate / stc_multipliers[idx]; | ||
59 | } | ||
60 | |||
61 | static struct clk_ops sh3_bus_clk_ops = { | ||
62 | .recalc = bus_clk_recalc, | ||
63 | }; | ||
64 | |||
65 | static void cpu_clk_recalc(struct clk *clk) | ||
66 | { | ||
67 | int frqcr = ctrl_inw(FRQCR); | ||
68 | int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); | ||
69 | |||
70 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
71 | } | ||
72 | |||
73 | static struct clk_ops sh3_cpu_clk_ops = { | ||
74 | .recalc = cpu_clk_recalc, | ||
75 | }; | ||
76 | |||
77 | static struct clk_ops *sh3_clk_ops[] = { | ||
78 | &sh3_master_clk_ops, | ||
79 | &sh3_module_clk_ops, | ||
80 | &sh3_bus_clk_ops, | ||
81 | &sh3_cpu_clk_ops, | ||
82 | }; | ||
83 | |||
84 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
85 | { | ||
86 | if (idx < ARRAY_SIZE(sh3_clk_ops)) | ||
87 | *ops = sh3_clk_ops[idx]; | ||
88 | } | ||
89 | |||
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7300.c b/arch/sh/kernel/cpu/sh3/clock-sh7300.c new file mode 100644 index 000000000000..e804174b9625 --- /dev/null +++ b/arch/sh/kernel/cpu/sh3/clock-sh7300.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh3/clock-sh7300.c | ||
3 | * | ||
4 | * SH7300 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * FRQCR parsing hacked out of arch/sh/kernel/time.c | ||
9 | * | ||
10 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
11 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
12 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | ||
13 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | ||
14 | * | ||
15 | * This file is subject to the terms and conditions of the GNU General Public | ||
16 | * License. See the file "COPYING" in the main directory of this archive | ||
17 | * for more details. | ||
18 | */ | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <asm/clock.h> | ||
22 | #include <asm/freq.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 }; | ||
26 | |||
27 | static void master_clk_init(struct clk *clk) | ||
28 | { | ||
29 | clk->rate *= md_table[ctrl_inw(FRQCR) & 0x0007]; | ||
30 | } | ||
31 | |||
32 | static struct clk_ops sh7300_master_clk_ops = { | ||
33 | .init = master_clk_init, | ||
34 | }; | ||
35 | |||
36 | static void module_clk_recalc(struct clk *clk) | ||
37 | { | ||
38 | int idx = (ctrl_inw(FRQCR) & 0x0007); | ||
39 | clk->rate = clk->parent->rate / md_table[idx]; | ||
40 | } | ||
41 | |||
42 | static struct clk_ops sh7300_module_clk_ops = { | ||
43 | .recalc = module_clk_recalc, | ||
44 | }; | ||
45 | |||
46 | static void bus_clk_recalc(struct clk *clk) | ||
47 | { | ||
48 | int idx = (ctrl_inw(FRQCR) & 0x0700) >> 8; | ||
49 | clk->rate = clk->parent->rate / md_table[idx]; | ||
50 | } | ||
51 | |||
52 | static struct clk_ops sh7300_bus_clk_ops = { | ||
53 | .recalc = bus_clk_recalc, | ||
54 | }; | ||
55 | |||
56 | static void cpu_clk_recalc(struct clk *clk) | ||
57 | { | ||
58 | int idx = (ctrl_inw(FRQCR) & 0x0070) >> 4; | ||
59 | clk->rate = clk->parent->rate / md_table[idx]; | ||
60 | } | ||
61 | |||
62 | static struct clk_ops sh7300_cpu_clk_ops = { | ||
63 | .recalc = cpu_clk_recalc, | ||
64 | }; | ||
65 | |||
66 | static struct clk_ops *sh7300_clk_ops[] = { | ||
67 | &sh7300_master_clk_ops, | ||
68 | &sh7300_module_clk_ops, | ||
69 | &sh7300_bus_clk_ops, | ||
70 | &sh7300_cpu_clk_ops, | ||
71 | }; | ||
72 | |||
73 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
74 | { | ||
75 | if (idx < ARRAY_SIZE(sh7300_clk_ops)) | ||
76 | *ops = sh7300_clk_ops[idx]; | ||
77 | } | ||
78 | |||
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7705.c b/arch/sh/kernel/cpu/sh3/clock-sh7705.c new file mode 100644 index 000000000000..dfdbf3277fd7 --- /dev/null +++ b/arch/sh/kernel/cpu/sh3/clock-sh7705.c | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh3/clock-sh7705.c | ||
3 | * | ||
4 | * SH7705 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * FRQCR parsing hacked out of arch/sh/kernel/time.c | ||
9 | * | ||
10 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
11 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
12 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | ||
13 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | ||
14 | * | ||
15 | * This file is subject to the terms and conditions of the GNU General Public | ||
16 | * License. See the file "COPYING" in the main directory of this archive | ||
17 | * for more details. | ||
18 | */ | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <asm/clock.h> | ||
22 | #include <asm/freq.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | /* | ||
26 | * SH7705 uses the same divisors as the generic SH-3 case, it's just the | ||
27 | * FRQCR layout that is a bit different.. | ||
28 | */ | ||
29 | static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
30 | static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; | ||
31 | static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
32 | |||
33 | static void master_clk_init(struct clk *clk) | ||
34 | { | ||
35 | clk->rate *= pfc_divisors[ctrl_inw(FRQCR) & 0x0003]; | ||
36 | } | ||
37 | |||
38 | static struct clk_ops sh7705_master_clk_ops = { | ||
39 | .init = master_clk_init, | ||
40 | }; | ||
41 | |||
42 | static void module_clk_recalc(struct clk *clk) | ||
43 | { | ||
44 | int idx = ctrl_inw(FRQCR) & 0x0003; | ||
45 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
46 | } | ||
47 | |||
48 | static struct clk_ops sh7705_module_clk_ops = { | ||
49 | .recalc = module_clk_recalc, | ||
50 | }; | ||
51 | |||
52 | static void bus_clk_recalc(struct clk *clk) | ||
53 | { | ||
54 | int idx = (ctrl_inw(FRQCR) & 0x0300) >> 8; | ||
55 | clk->rate = clk->parent->rate / stc_multipliers[idx]; | ||
56 | } | ||
57 | |||
58 | static struct clk_ops sh7705_bus_clk_ops = { | ||
59 | .recalc = bus_clk_recalc, | ||
60 | }; | ||
61 | |||
62 | static void cpu_clk_recalc(struct clk *clk) | ||
63 | { | ||
64 | int idx = (ctrl_inw(FRQCR) & 0x0030) >> 4; | ||
65 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
66 | } | ||
67 | |||
68 | static struct clk_ops sh7705_cpu_clk_ops = { | ||
69 | .recalc = cpu_clk_recalc, | ||
70 | }; | ||
71 | |||
72 | static struct clk_ops *sh7705_clk_ops[] = { | ||
73 | &sh7705_master_clk_ops, | ||
74 | &sh7705_module_clk_ops, | ||
75 | &sh7705_bus_clk_ops, | ||
76 | &sh7705_cpu_clk_ops, | ||
77 | }; | ||
78 | |||
79 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
80 | { | ||
81 | if (idx < ARRAY_SIZE(sh7705_clk_ops)) | ||
82 | *ops = sh7705_clk_ops[idx]; | ||
83 | } | ||
84 | |||
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7709.c b/arch/sh/kernel/cpu/sh3/clock-sh7709.c new file mode 100644 index 000000000000..10461a745e5f --- /dev/null +++ b/arch/sh/kernel/cpu/sh3/clock-sh7709.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh3/clock-sh7709.c | ||
3 | * | ||
4 | * SH7709 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Andriy Skulysh | ||
7 | * | ||
8 | * Based on arch/sh/kernel/cpu/sh3/clock-sh7705.c | ||
9 | * Copyright (C) 2005 Paul Mundt | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <asm/clock.h> | ||
18 | #include <asm/freq.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | static int stc_multipliers[] = { 1, 2, 4, 8, 3, 6, 1, 1 }; | ||
22 | static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 }; | ||
23 | static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; | ||
24 | |||
25 | static void set_bus_parent(struct clk *clk) | ||
26 | { | ||
27 | struct clk *bus_clk = clk_get("bus_clk"); | ||
28 | clk->parent = bus_clk; | ||
29 | clk_put(bus_clk); | ||
30 | } | ||
31 | |||
32 | static void master_clk_init(struct clk *clk) | ||
33 | { | ||
34 | int frqcr = ctrl_inw(FRQCR); | ||
35 | int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); | ||
36 | |||
37 | clk->rate *= pfc_divisors[idx]; | ||
38 | } | ||
39 | |||
40 | static struct clk_ops sh7709_master_clk_ops = { | ||
41 | .init = master_clk_init, | ||
42 | }; | ||
43 | |||
44 | static void module_clk_recalc(struct clk *clk) | ||
45 | { | ||
46 | int frqcr = ctrl_inw(FRQCR); | ||
47 | int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); | ||
48 | |||
49 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
50 | } | ||
51 | |||
52 | static struct clk_ops sh7709_module_clk_ops = { | ||
53 | #ifdef CLOCK_MODE_0_1_2_7 | ||
54 | .init = set_bus_parent, | ||
55 | #endif | ||
56 | .recalc = module_clk_recalc, | ||
57 | }; | ||
58 | |||
59 | static void bus_clk_recalc(struct clk *clk) | ||
60 | { | ||
61 | int frqcr = ctrl_inw(FRQCR); | ||
62 | int idx = (frqcr & 0x0080) ? | ||
63 | ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4) : 1; | ||
64 | |||
65 | clk->rate = clk->parent->rate * stc_multipliers[idx]; | ||
66 | } | ||
67 | |||
68 | static struct clk_ops sh7709_bus_clk_ops = { | ||
69 | .recalc = bus_clk_recalc, | ||
70 | }; | ||
71 | |||
72 | static void cpu_clk_recalc(struct clk *clk) | ||
73 | { | ||
74 | int frqcr = ctrl_inw(FRQCR); | ||
75 | int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); | ||
76 | |||
77 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
78 | } | ||
79 | |||
80 | static struct clk_ops sh7709_cpu_clk_ops = { | ||
81 | .init = set_bus_parent, | ||
82 | .recalc = cpu_clk_recalc, | ||
83 | }; | ||
84 | |||
85 | static struct clk_ops *sh7709_clk_ops[] = { | ||
86 | &sh7709_master_clk_ops, | ||
87 | &sh7709_module_clk_ops, | ||
88 | &sh7709_bus_clk_ops, | ||
89 | &sh7709_cpu_clk_ops, | ||
90 | }; | ||
91 | |||
92 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
93 | { | ||
94 | if (idx < ARRAY_SIZE(sh7709_clk_ops)) | ||
95 | *ops = sh7709_clk_ops[idx]; | ||
96 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile index ead1071eac73..3d5cafc71ae3 100644 --- a/arch/sh/kernel/cpu/sh4/Makefile +++ b/arch/sh/kernel/cpu/sh4/Makefile | |||
@@ -5,6 +5,15 @@ | |||
5 | obj-y := ex.o probe.o | 5 | obj-y := ex.o probe.o |
6 | 6 | ||
7 | obj-$(CONFIG_SH_FPU) += fpu.o | 7 | obj-$(CONFIG_SH_FPU) += fpu.o |
8 | obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += irq_intc2.o | ||
9 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o | 8 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o |
10 | 9 | ||
10 | # Primary on-chip clocks (common) | ||
11 | clock-$(CONFIG_CPU_SH4) := clock-sh4.o | ||
12 | clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o | ||
13 | clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o | ||
14 | clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o | ||
15 | |||
16 | # Additional clocks by subtype | ||
17 | clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o | ||
18 | |||
19 | obj-y += $(clock-y) | ||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c new file mode 100644 index 000000000000..bfdf5fe8d948 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4/clock-sh4-202.c | ||
3 | * | ||
4 | * Additional SH4-202 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <asm/clock.h> | ||
16 | #include <asm/freq.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #define CPG2_FRQCR3 0xfe0a0018 | ||
20 | |||
21 | static int frqcr3_divisors[] = { 1, 2, 3, 4, 6, 8, 16 }; | ||
22 | static int frqcr3_values[] = { 0, 1, 2, 3, 4, 5, 6 }; | ||
23 | |||
24 | static void emi_clk_recalc(struct clk *clk) | ||
25 | { | ||
26 | int idx = ctrl_inl(CPG2_FRQCR3) & 0x0007; | ||
27 | clk->rate = clk->parent->rate / frqcr3_divisors[idx]; | ||
28 | } | ||
29 | |||
30 | static inline int frqcr3_lookup(struct clk *clk, unsigned long rate) | ||
31 | { | ||
32 | int divisor = clk->parent->rate / rate; | ||
33 | int i; | ||
34 | |||
35 | for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) | ||
36 | if (frqcr3_divisors[i] == divisor) | ||
37 | return frqcr3_values[i]; | ||
38 | |||
39 | /* Safe fallback */ | ||
40 | return 5; | ||
41 | } | ||
42 | |||
43 | static struct clk_ops sh4202_emi_clk_ops = { | ||
44 | .recalc = emi_clk_recalc, | ||
45 | }; | ||
46 | |||
47 | static struct clk sh4202_emi_clk = { | ||
48 | .name = "emi_clk", | ||
49 | .flags = CLK_ALWAYS_ENABLED, | ||
50 | .ops = &sh4202_emi_clk_ops, | ||
51 | }; | ||
52 | |||
53 | static void femi_clk_recalc(struct clk *clk) | ||
54 | { | ||
55 | int idx = (ctrl_inl(CPG2_FRQCR3) >> 3) & 0x0007; | ||
56 | clk->rate = clk->parent->rate / frqcr3_divisors[idx]; | ||
57 | } | ||
58 | |||
59 | static struct clk_ops sh4202_femi_clk_ops = { | ||
60 | .recalc = femi_clk_recalc, | ||
61 | }; | ||
62 | |||
63 | static struct clk sh4202_femi_clk = { | ||
64 | .name = "femi_clk", | ||
65 | .flags = CLK_ALWAYS_ENABLED, | ||
66 | .ops = &sh4202_femi_clk_ops, | ||
67 | }; | ||
68 | |||
69 | static void shoc_clk_init(struct clk *clk) | ||
70 | { | ||
71 | int i; | ||
72 | |||
73 | /* | ||
74 | * For some reason, the shoc_clk seems to be set to some really | ||
75 | * insane value at boot (values outside of the allowable frequency | ||
76 | * range for instance). We deal with this by scaling it back down | ||
77 | * to something sensible just in case. | ||
78 | * | ||
79 | * Start scaling from the high end down until we find something | ||
80 | * that passes rate verification.. | ||
81 | */ | ||
82 | for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) { | ||
83 | int divisor = frqcr3_divisors[i]; | ||
84 | |||
85 | if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0) | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | WARN_ON(i == ARRAY_SIZE(frqcr3_divisors)); /* Undefined clock */ | ||
90 | } | ||
91 | |||
92 | static void shoc_clk_recalc(struct clk *clk) | ||
93 | { | ||
94 | int idx = (ctrl_inl(CPG2_FRQCR3) >> 6) & 0x0007; | ||
95 | clk->rate = clk->parent->rate / frqcr3_divisors[idx]; | ||
96 | } | ||
97 | |||
98 | static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) | ||
99 | { | ||
100 | struct clk *bclk = clk_get("bus_clk"); | ||
101 | unsigned long bclk_rate = clk_get_rate(bclk); | ||
102 | |||
103 | clk_put(bclk); | ||
104 | |||
105 | if (rate > bclk_rate) | ||
106 | return 1; | ||
107 | if (rate > 66000000) | ||
108 | return 1; | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int shoc_clk_set_rate(struct clk *clk, unsigned long rate) | ||
114 | { | ||
115 | unsigned long frqcr3; | ||
116 | unsigned int tmp; | ||
117 | |||
118 | /* Make sure we have something sensible to switch to */ | ||
119 | if (shoc_clk_verify_rate(clk, rate) != 0) | ||
120 | return -EINVAL; | ||
121 | |||
122 | tmp = frqcr3_lookup(clk, rate); | ||
123 | |||
124 | frqcr3 = ctrl_inl(CPG2_FRQCR3); | ||
125 | frqcr3 &= ~(0x0007 << 6); | ||
126 | frqcr3 |= tmp << 6; | ||
127 | ctrl_outl(frqcr3, CPG2_FRQCR3); | ||
128 | |||
129 | clk->rate = clk->parent->rate / frqcr3_divisors[tmp]; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static struct clk_ops sh4202_shoc_clk_ops = { | ||
135 | .init = shoc_clk_init, | ||
136 | .recalc = shoc_clk_recalc, | ||
137 | .set_rate = shoc_clk_set_rate, | ||
138 | }; | ||
139 | |||
140 | static struct clk sh4202_shoc_clk = { | ||
141 | .name = "shoc_clk", | ||
142 | .flags = CLK_ALWAYS_ENABLED, | ||
143 | .ops = &sh4202_shoc_clk_ops, | ||
144 | }; | ||
145 | |||
146 | static struct clk *sh4202_onchip_clocks[] = { | ||
147 | &sh4202_emi_clk, | ||
148 | &sh4202_femi_clk, | ||
149 | &sh4202_shoc_clk, | ||
150 | }; | ||
151 | |||
152 | static int __init sh4202_clk_init(void) | ||
153 | { | ||
154 | struct clk *clk = clk_get("master_clk"); | ||
155 | int i; | ||
156 | |||
157 | for (i = 0; i < ARRAY_SIZE(sh4202_onchip_clocks); i++) { | ||
158 | struct clk *clkp = sh4202_onchip_clocks[i]; | ||
159 | |||
160 | clkp->parent = clk; | ||
161 | clk_register(clkp); | ||
162 | clk_enable(clkp); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Now that we have the rest of the clocks registered, we need to | ||
167 | * force the parent clock to propagate so that these clocks will | ||
168 | * automatically figure out their rate. We cheat by handing the | ||
169 | * parent clock its current rate and forcing child propagation. | ||
170 | */ | ||
171 | clk_set_rate(clk, clk_get_rate(clk)); | ||
172 | |||
173 | clk_put(clk); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | arch_initcall(sh4202_clk_init); | ||
179 | |||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4.c b/arch/sh/kernel/cpu/sh4/clock-sh4.c new file mode 100644 index 000000000000..dca9f87a12d6 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4/clock-sh4.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4/clock-sh4.c | ||
3 | * | ||
4 | * Generic SH-4 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * FRQCR parsing hacked out of arch/sh/kernel/time.c | ||
9 | * | ||
10 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
11 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
12 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | ||
13 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | ||
14 | * | ||
15 | * This file is subject to the terms and conditions of the GNU General Public | ||
16 | * License. See the file "COPYING" in the main directory of this archive | ||
17 | * for more details. | ||
18 | */ | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <asm/clock.h> | ||
22 | #include <asm/freq.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; | ||
26 | #define bfc_divisors ifc_divisors /* Same */ | ||
27 | static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; | ||
28 | |||
29 | static void master_clk_init(struct clk *clk) | ||
30 | { | ||
31 | clk->rate *= pfc_divisors[ctrl_inw(FRQCR) & 0x0007]; | ||
32 | } | ||
33 | |||
34 | static struct clk_ops sh4_master_clk_ops = { | ||
35 | .init = master_clk_init, | ||
36 | }; | ||
37 | |||
38 | static void module_clk_recalc(struct clk *clk) | ||
39 | { | ||
40 | int idx = (ctrl_inw(FRQCR) & 0x0007); | ||
41 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
42 | } | ||
43 | |||
44 | static struct clk_ops sh4_module_clk_ops = { | ||
45 | .recalc = module_clk_recalc, | ||
46 | }; | ||
47 | |||
48 | static void bus_clk_recalc(struct clk *clk) | ||
49 | { | ||
50 | int idx = (ctrl_inw(FRQCR) >> 3) & 0x0007; | ||
51 | clk->rate = clk->parent->rate / bfc_divisors[idx]; | ||
52 | } | ||
53 | |||
54 | static struct clk_ops sh4_bus_clk_ops = { | ||
55 | .recalc = bus_clk_recalc, | ||
56 | }; | ||
57 | |||
58 | static void cpu_clk_recalc(struct clk *clk) | ||
59 | { | ||
60 | int idx = (ctrl_inw(FRQCR) >> 6) & 0x0007; | ||
61 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
62 | } | ||
63 | |||
64 | static struct clk_ops sh4_cpu_clk_ops = { | ||
65 | .recalc = cpu_clk_recalc, | ||
66 | }; | ||
67 | |||
68 | static struct clk_ops *sh4_clk_ops[] = { | ||
69 | &sh4_master_clk_ops, | ||
70 | &sh4_module_clk_ops, | ||
71 | &sh4_bus_clk_ops, | ||
72 | &sh4_cpu_clk_ops, | ||
73 | }; | ||
74 | |||
75 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
76 | { | ||
77 | if (idx < ARRAY_SIZE(sh4_clk_ops)) | ||
78 | *ops = sh4_clk_ops[idx]; | ||
79 | } | ||
80 | |||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh73180.c b/arch/sh/kernel/cpu/sh4/clock-sh73180.c new file mode 100644 index 000000000000..2fa5cb2ae68d --- /dev/null +++ b/arch/sh/kernel/cpu/sh4/clock-sh73180.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4/clock-sh73180.c | ||
3 | * | ||
4 | * SH73180 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * FRQCR parsing hacked out of arch/sh/kernel/time.c | ||
9 | * | ||
10 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | ||
11 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
12 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | ||
13 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | ||
14 | * | ||
15 | * This file is subject to the terms and conditions of the GNU General Public | ||
16 | * License. See the file "COPYING" in the main directory of this archive | ||
17 | * for more details. | ||
18 | */ | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <asm/clock.h> | ||
22 | #include <asm/freq.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | /* | ||
26 | * SH73180 uses a common set of divisors, so this is quite simple.. | ||
27 | */ | ||
28 | static int divisors[] = { 1, 2, 3, 4, 6, 8, 12, 16 }; | ||
29 | |||
30 | static void master_clk_init(struct clk *clk) | ||
31 | { | ||
32 | clk->rate *= divisors[ctrl_inl(FRQCR) & 0x0007]; | ||
33 | } | ||
34 | |||
35 | static struct clk_ops sh73180_master_clk_ops = { | ||
36 | .init = master_clk_init, | ||
37 | }; | ||
38 | |||
39 | static void module_clk_recalc(struct clk *clk) | ||
40 | { | ||
41 | int idx = (ctrl_inl(FRQCR) & 0x0007); | ||
42 | clk->rate = clk->parent->rate / divisors[idx]; | ||
43 | } | ||
44 | |||
45 | static struct clk_ops sh73180_module_clk_ops = { | ||
46 | .recalc = module_clk_recalc, | ||
47 | }; | ||
48 | |||
49 | static void bus_clk_recalc(struct clk *clk) | ||
50 | { | ||
51 | int idx = (ctrl_inl(FRQCR) >> 12) & 0x0007; | ||
52 | clk->rate = clk->parent->rate / divisors[idx]; | ||
53 | } | ||
54 | |||
55 | static struct clk_ops sh73180_bus_clk_ops = { | ||
56 | .recalc = bus_clk_recalc, | ||
57 | }; | ||
58 | |||
59 | static void cpu_clk_recalc(struct clk *clk) | ||
60 | { | ||
61 | int idx = (ctrl_inl(FRQCR) >> 20) & 0x0007; | ||
62 | clk->rate = clk->parent->rate / divisors[idx]; | ||
63 | } | ||
64 | |||
65 | static struct clk_ops sh73180_cpu_clk_ops = { | ||
66 | .recalc = cpu_clk_recalc, | ||
67 | }; | ||
68 | |||
69 | static struct clk_ops *sh73180_clk_ops[] = { | ||
70 | &sh73180_master_clk_ops, | ||
71 | &sh73180_module_clk_ops, | ||
72 | &sh73180_bus_clk_ops, | ||
73 | &sh73180_cpu_clk_ops, | ||
74 | }; | ||
75 | |||
76 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
77 | { | ||
78 | if (idx < ARRAY_SIZE(sh73180_clk_ops)) | ||
79 | *ops = sh73180_clk_ops[idx]; | ||
80 | } | ||
81 | |||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh7770.c b/arch/sh/kernel/cpu/sh4/clock-sh7770.c new file mode 100644 index 000000000000..c8694bac6477 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4/clock-sh7770.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4/clock-sh7770.c | ||
3 | * | ||
4 | * SH7770 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <asm/clock.h> | ||
15 | #include <asm/freq.h> | ||
16 | #include <asm/io.h> | ||
17 | |||
18 | static int ifc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 1 }; | ||
19 | static int bfc_divisors[] = { 1, 1, 1, 1, 1, 8,12, 1 }; | ||
20 | static int pfc_divisors[] = { 1, 8, 1,10,12,16, 1, 1 }; | ||
21 | |||
22 | static void master_clk_init(struct clk *clk) | ||
23 | { | ||
24 | clk->rate *= pfc_divisors[(ctrl_inl(FRQCR) >> 28) & 0x000f]; | ||
25 | } | ||
26 | |||
27 | static struct clk_ops sh7770_master_clk_ops = { | ||
28 | .init = master_clk_init, | ||
29 | }; | ||
30 | |||
31 | static void module_clk_recalc(struct clk *clk) | ||
32 | { | ||
33 | int idx = ((ctrl_inl(FRQCR) >> 28) & 0x000f); | ||
34 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
35 | } | ||
36 | |||
37 | static struct clk_ops sh7770_module_clk_ops = { | ||
38 | .recalc = module_clk_recalc, | ||
39 | }; | ||
40 | |||
41 | static void bus_clk_recalc(struct clk *clk) | ||
42 | { | ||
43 | int idx = (ctrl_inl(FRQCR) & 0x000f); | ||
44 | clk->rate = clk->parent->rate / bfc_divisors[idx]; | ||
45 | } | ||
46 | |||
47 | static struct clk_ops sh7770_bus_clk_ops = { | ||
48 | .recalc = bus_clk_recalc, | ||
49 | }; | ||
50 | |||
51 | static void cpu_clk_recalc(struct clk *clk) | ||
52 | { | ||
53 | int idx = ((ctrl_inl(FRQCR) >> 24) & 0x000f); | ||
54 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
55 | } | ||
56 | |||
57 | static struct clk_ops sh7770_cpu_clk_ops = { | ||
58 | .recalc = cpu_clk_recalc, | ||
59 | }; | ||
60 | |||
61 | static struct clk_ops *sh7770_clk_ops[] = { | ||
62 | &sh7770_master_clk_ops, | ||
63 | &sh7770_module_clk_ops, | ||
64 | &sh7770_bus_clk_ops, | ||
65 | &sh7770_cpu_clk_ops, | ||
66 | }; | ||
67 | |||
68 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
69 | { | ||
70 | if (idx < ARRAY_SIZE(sh7770_clk_ops)) | ||
71 | *ops = sh7770_clk_ops[idx]; | ||
72 | } | ||
73 | |||
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh7780.c b/arch/sh/kernel/cpu/sh4/clock-sh7780.c new file mode 100644 index 000000000000..93ad367342c9 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4/clock-sh7780.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4/clock-sh7780.c | ||
3 | * | ||
4 | * SH7780 support for the clock framework | ||
5 | * | ||
6 | * Copyright (C) 2005 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <asm/clock.h> | ||
15 | #include <asm/freq.h> | ||
16 | #include <asm/io.h> | ||
17 | |||
18 | static int ifc_divisors[] = { 2, 4 }; | ||
19 | static int bfc_divisors[] = { 1, 1, 1, 8, 12, 16, 24, 1 }; | ||
20 | static int pfc_divisors[] = { 1, 24, 24, 1 }; | ||
21 | static int cfc_divisors[] = { 1, 1, 4, 1, 6, 1, 1, 1 }; | ||
22 | |||
23 | static void master_clk_init(struct clk *clk) | ||
24 | { | ||
25 | clk->rate *= pfc_divisors[ctrl_inl(FRQCR) & 0x0003]; | ||
26 | } | ||
27 | |||
28 | static struct clk_ops sh7780_master_clk_ops = { | ||
29 | .init = master_clk_init, | ||
30 | }; | ||
31 | |||
32 | static void module_clk_recalc(struct clk *clk) | ||
33 | { | ||
34 | int idx = (ctrl_inl(FRQCR) & 0x0003); | ||
35 | clk->rate = clk->parent->rate / pfc_divisors[idx]; | ||
36 | } | ||
37 | |||
38 | static struct clk_ops sh7780_module_clk_ops = { | ||
39 | .recalc = module_clk_recalc, | ||
40 | }; | ||
41 | |||
42 | static void bus_clk_recalc(struct clk *clk) | ||
43 | { | ||
44 | int idx = ((ctrl_inl(FRQCR) >> 16) & 0x0007); | ||
45 | clk->rate = clk->parent->rate / bfc_divisors[idx]; | ||
46 | } | ||
47 | |||
48 | static struct clk_ops sh7780_bus_clk_ops = { | ||
49 | .recalc = bus_clk_recalc, | ||
50 | }; | ||
51 | |||
52 | static void cpu_clk_recalc(struct clk *clk) | ||
53 | { | ||
54 | int idx = ((ctrl_inl(FRQCR) >> 24) & 0x0001); | ||
55 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
56 | } | ||
57 | |||
58 | static struct clk_ops sh7780_cpu_clk_ops = { | ||
59 | .recalc = cpu_clk_recalc, | ||
60 | }; | ||
61 | |||
62 | static struct clk_ops *sh7780_clk_ops[] = { | ||
63 | &sh7780_master_clk_ops, | ||
64 | &sh7780_module_clk_ops, | ||
65 | &sh7780_bus_clk_ops, | ||
66 | &sh7780_cpu_clk_ops, | ||
67 | }; | ||
68 | |||
69 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | ||
70 | { | ||
71 | if (idx < ARRAY_SIZE(sh7780_clk_ops)) | ||
72 | *ops = sh7780_clk_ops[idx]; | ||
73 | } | ||
74 | |||
75 | static void shyway_clk_recalc(struct clk *clk) | ||
76 | { | ||
77 | int idx = ((ctrl_inl(FRQCR) >> 20) & 0x0007); | ||
78 | clk->rate = clk->parent->rate / cfc_divisors[idx]; | ||
79 | } | ||
80 | |||
81 | static struct clk_ops sh7780_shyway_clk_ops = { | ||
82 | .recalc = shyway_clk_recalc, | ||
83 | }; | ||
84 | |||
85 | static struct clk sh7780_shyway_clk = { | ||
86 | .name = "shyway_clk", | ||
87 | .flags = CLK_ALWAYS_ENABLED, | ||
88 | .ops = &sh7780_shyway_clk_ops, | ||
89 | }; | ||
90 | |||
91 | /* | ||
92 | * Additional SH7780-specific on-chip clocks that aren't already part of the | ||
93 | * clock framework | ||
94 | */ | ||
95 | static struct clk *sh7780_onchip_clocks[] = { | ||
96 | &sh7780_shyway_clk, | ||
97 | }; | ||
98 | |||
99 | static int __init sh7780_clk_init(void) | ||
100 | { | ||
101 | struct clk *clk = clk_get("master_clk"); | ||
102 | int i; | ||
103 | |||
104 | for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) { | ||
105 | struct clk *clkp = sh7780_onchip_clocks[i]; | ||
106 | |||
107 | clkp->parent = clk; | ||
108 | clk_register(clkp); | ||
109 | clk_enable(clkp); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Now that we have the rest of the clocks registered, we need to | ||
114 | * force the parent clock to propagate so that these clocks will | ||
115 | * automatically figure out their rate. We cheat by handing the | ||
116 | * parent clock its current rate and forcing child propagation. | ||
117 | */ | ||
118 | clk_set_rate(clk, clk_get_rate(clk)); | ||
119 | |||
120 | clk_put(clk); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | arch_initcall(sh7780_clk_init); | ||
126 | |||