diff options
-rw-r--r-- | arch/sh/boards/overdrive/Makefile | 2 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/setup.c | 6 | ||||
-rw-r--r-- | arch/sh/boards/overdrive/time.c | 119 | ||||
-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 | ||||
-rw-r--r-- | arch/sh/kernel/time.c | 518 | ||||
-rw-r--r-- | include/asm-sh/clock.h | 61 | ||||
-rw-r--r-- | include/asm-sh/cpu-sh4/freq.h | 2 | ||||
-rw-r--r-- | include/asm-sh/freq.h | 11 |
19 files changed, 1287 insertions, 623 deletions
diff --git a/arch/sh/boards/overdrive/Makefile b/arch/sh/boards/overdrive/Makefile index 1762b59e9279..245f03baf762 100644 --- a/arch/sh/boards/overdrive/Makefile +++ b/arch/sh/boards/overdrive/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for the STMicroelectronics Overdrive specific parts of the kernel | 2 | # Makefile for the STMicroelectronics Overdrive specific parts of the kernel |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := mach.o setup.o io.o irq.o led.o time.o | 5 | obj-y := mach.o setup.o io.o irq.o led.o |
6 | 6 | ||
7 | obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o | 7 | obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o |
8 | 8 | ||
diff --git a/arch/sh/boards/overdrive/setup.c b/arch/sh/boards/overdrive/setup.c index a36ce0284ed3..94f6165d33b8 100644 --- a/arch/sh/boards/overdrive/setup.c +++ b/arch/sh/boards/overdrive/setup.c | |||
@@ -17,8 +17,6 @@ | |||
17 | #include <asm/overdrive/overdrive.h> | 17 | #include <asm/overdrive/overdrive.h> |
18 | #include <asm/overdrive/fpga.h> | 18 | #include <asm/overdrive/fpga.h> |
19 | 19 | ||
20 | extern void od_time_init(void); | ||
21 | |||
22 | const char *get_system_type(void) | 20 | const char *get_system_type(void) |
23 | { | 21 | { |
24 | return "SH7750 Overdrive"; | 22 | return "SH7750 Overdrive"; |
@@ -31,11 +29,9 @@ int __init platform_setup(void) | |||
31 | { | 29 | { |
32 | #ifdef CONFIG_PCI | 30 | #ifdef CONFIG_PCI |
33 | init_overdrive_fpga(); | 31 | init_overdrive_fpga(); |
34 | galileo_init(); | 32 | galileo_init(); |
35 | #endif | 33 | #endif |
36 | 34 | ||
37 | board_time_init = od_time_init; | ||
38 | |||
39 | /* Enable RS232 receive buffers */ | 35 | /* Enable RS232 receive buffers */ |
40 | writel(0x1e, OVERDRIVE_CTRL); | 36 | writel(0x1e, OVERDRIVE_CTRL); |
41 | } | 37 | } |
diff --git a/arch/sh/boards/overdrive/time.c b/arch/sh/boards/overdrive/time.c deleted file mode 100644 index 68533690e097..000000000000 --- a/arch/sh/boards/overdrive/time.c +++ /dev/null | |||
@@ -1,119 +0,0 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/overdrive/time.c | ||
3 | * | ||
4 | * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) | ||
5 | * Copyright (C) 2002 Paul Mundt (lethal@chaoticdreams.org) | ||
6 | * | ||
7 | * May be copied or modified under the terms of the GNU General Public | ||
8 | * License. See linux/COPYING for more information. | ||
9 | * | ||
10 | * STMicroelectronics Overdrive Support. | ||
11 | */ | ||
12 | |||
13 | void od_time_init(void) | ||
14 | { | ||
15 | struct frqcr_data { | ||
16 | unsigned short frqcr; | ||
17 | struct { | ||
18 | unsigned char multiplier; | ||
19 | unsigned char divisor; | ||
20 | } factor[3]; | ||
21 | }; | ||
22 | |||
23 | static struct frqcr_data st40_frqcr_table[] = { | ||
24 | { 0x000, {{1,1}, {1,1}, {1,2}}}, | ||
25 | { 0x002, {{1,1}, {1,1}, {1,4}}}, | ||
26 | { 0x004, {{1,1}, {1,1}, {1,8}}}, | ||
27 | { 0x008, {{1,1}, {1,2}, {1,2}}}, | ||
28 | { 0x00A, {{1,1}, {1,2}, {1,4}}}, | ||
29 | { 0x00C, {{1,1}, {1,2}, {1,8}}}, | ||
30 | { 0x011, {{1,1}, {2,3}, {1,6}}}, | ||
31 | { 0x013, {{1,1}, {2,3}, {1,3}}}, | ||
32 | { 0x01A, {{1,1}, {1,2}, {1,4}}}, | ||
33 | { 0x01C, {{1,1}, {1,2}, {1,8}}}, | ||
34 | { 0x023, {{1,1}, {2,3}, {1,3}}}, | ||
35 | { 0x02C, {{1,1}, {1,2}, {1,8}}}, | ||
36 | { 0x048, {{1,2}, {1,2}, {1,4}}}, | ||
37 | { 0x04A, {{1,2}, {1,2}, {1,6}}}, | ||
38 | { 0x04C, {{1,2}, {1,2}, {1,8}}}, | ||
39 | { 0x05A, {{1,2}, {1,3}, {1,6}}}, | ||
40 | { 0x05C, {{1,2}, {1,3}, {1,6}}}, | ||
41 | { 0x063, {{1,2}, {1,4}, {1,4}}}, | ||
42 | { 0x06C, {{1,2}, {1,4}, {1,8}}}, | ||
43 | { 0x091, {{1,3}, {1,3}, {1,6}}}, | ||
44 | { 0x093, {{1,3}, {1,3}, {1,6}}}, | ||
45 | { 0x0A3, {{1,3}, {1,6}, {1,6}}}, | ||
46 | { 0x0DA, {{1,4}, {1,4}, {1,8}}}, | ||
47 | { 0x0DC, {{1,4}, {1,4}, {1,8}}}, | ||
48 | { 0x0EC, {{1,4}, {1,8}, {1,8}}}, | ||
49 | { 0x123, {{1,4}, {1,4}, {1,8}}}, | ||
50 | { 0x16C, {{1,4}, {1,8}, {1,8}}}, | ||
51 | }; | ||
52 | |||
53 | struct memclk_data { | ||
54 | unsigned char multiplier; | ||
55 | unsigned char divisor; | ||
56 | }; | ||
57 | static struct memclk_data st40_memclk_table[8] = { | ||
58 | {1,1}, // 000 | ||
59 | {1,2}, // 001 | ||
60 | {1,3}, // 010 | ||
61 | {2,3}, // 011 | ||
62 | {1,4}, // 100 | ||
63 | {1,6}, // 101 | ||
64 | {1,8}, // 110 | ||
65 | {1,8} // 111 | ||
66 | }; | ||
67 | |||
68 | unsigned long pvr; | ||
69 | |||
70 | /* | ||
71 | * This should probably be moved into the SH3 probing code, and then | ||
72 | * use the processor structure to determine which CPU we are running | ||
73 | * on. | ||
74 | */ | ||
75 | pvr = ctrl_inl(CCN_PVR); | ||
76 | printk("PVR %08x\n", pvr); | ||
77 | |||
78 | if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) { | ||
79 | /* | ||
80 | * Unfortunatly the STB1 FRQCR values are different from the | ||
81 | * 7750 ones. | ||
82 | */ | ||
83 | struct frqcr_data *d; | ||
84 | int a; | ||
85 | unsigned long memclkcr; | ||
86 | struct memclk_data *e; | ||
87 | |||
88 | for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) { | ||
89 | d = &st40_frqcr_table[a]; | ||
90 | if (d->frqcr == (frqcr & 0x1ff)) | ||
91 | break; | ||
92 | } | ||
93 | if (a == ARRAY_SIZE(st40_frqcr_table)) { | ||
94 | d = st40_frqcr_table; | ||
95 | printk("ERROR: Unrecognised FRQCR value, using default multipliers\n"); | ||
96 | } | ||
97 | |||
98 | memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); | ||
99 | e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; | ||
100 | |||
101 | printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n", | ||
102 | d->factor[0].multiplier, d->factor[0].divisor, | ||
103 | d->factor[1].multiplier, d->factor[1].divisor, | ||
104 | e->multiplier, e->divisor, | ||
105 | d->factor[2].multiplier, d->factor[2].divisor); | ||
106 | |||
107 | current_cpu_data.master_clock = current_cpu_data.module_clock * | ||
108 | d->factor[2].divisor / | ||
109 | d->factor[2].multiplier; | ||
110 | current_cpu_data.bus_clock = current_cpu_data.master_clock * | ||
111 | d->factor[1].multiplier / | ||
112 | d->factor[1].divisor; | ||
113 | current_cpu_data.memory_clock = current_cpu_data.master_clock * | ||
114 | e->multiplier / e->divisor; | ||
115 | current_cpu_data.cpu_clock = current_cpu_data.master_clock * | ||
116 | d->factor[0].multiplier / | ||
117 | d->factor[0].divisor; | ||
118 | } | ||
119 | |||
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 | |||
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 671b876416bf..314a275c04e0 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | 4 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka |
5 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | 5 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> |
6 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | 6 | * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt |
7 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | 7 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> |
8 | * | 8 | * |
9 | * Some code taken from i386 version. | 9 | * Some code taken from i386 version. |
@@ -11,50 +11,21 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/config.h> | 13 | #include <linux/config.h> |
14 | #include <linux/errno.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
18 | #include <linux/param.h> | 15 | #include <linux/module.h> |
19 | #include <linux/string.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/time.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/init.h> | 16 | #include <linux/init.h> |
25 | #include <linux/smp.h> | ||
26 | #include <linux/profile.h> | 17 | #include <linux/profile.h> |
27 | 18 | #include <asm/clock.h> | |
28 | #include <asm/processor.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/delay.h> | ||
33 | #include <asm/machvec.h> | ||
34 | #include <asm/rtc.h> | 19 | #include <asm/rtc.h> |
35 | #include <asm/freq.h> | 20 | #include <asm/timer.h> |
36 | #include <asm/cpu/timer.h> | ||
37 | #ifdef CONFIG_SH_KGDB | ||
38 | #include <asm/kgdb.h> | 21 | #include <asm/kgdb.h> |
39 | #endif | ||
40 | |||
41 | #include <linux/timex.h> | ||
42 | #include <linux/irq.h> | ||
43 | |||
44 | #define TMU_TOCR_INIT 0x00 | ||
45 | #define TMU0_TCR_INIT 0x0020 | ||
46 | #define TMU_TSTR_INIT 1 | ||
47 | |||
48 | #define TMU0_TCR_CALIB 0x0000 | ||
49 | |||
50 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
51 | #define CLOCKGEN_MEMCLKCR 0xbb040038 | ||
52 | #define MEMCLKCR_RATIO_MASK 0x7 | ||
53 | #endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */ | ||
54 | 22 | ||
55 | extern unsigned long wall_jiffies; | 23 | extern unsigned long wall_jiffies; |
56 | #define TICK_SIZE (tick_nsec / 1000) | 24 | struct sys_timer *sys_timer; |
57 | DEFINE_SPINLOCK(tmu0_lock); | 25 | |
26 | /* Move this somewhere more sensible.. */ | ||
27 | DEFINE_SPINLOCK(rtc_lock); | ||
28 | EXPORT_SYMBOL(rtc_lock); | ||
58 | 29 | ||
59 | /* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want | 30 | /* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want |
60 | * these routines anywhere... */ | 31 | * these routines anywhere... */ |
@@ -66,98 +37,14 @@ void (*rtc_get_time)(struct timespec *); | |||
66 | int (*rtc_set_time)(const time_t); | 37 | int (*rtc_set_time)(const time_t); |
67 | #endif | 38 | #endif |
68 | 39 | ||
69 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
70 | static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 }; | ||
71 | #endif | ||
72 | #if defined(CONFIG_CPU_SH3) | ||
73 | static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
74 | static int stc_values[] = { 0, 1, 4, 2, 5, 0, 0, 0 }; | ||
75 | #define bfc_divisors stc_multipliers | ||
76 | #define bfc_values stc_values | ||
77 | static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; | ||
78 | static int ifc_values[] = { 0, 1, 4, 2, 0, 0, 0, 0 }; | ||
79 | static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | ||
80 | static int pfc_values[] = { 0, 1, 4, 2, 5, 0, 0, 0 }; | ||
81 | #elif defined(CONFIG_CPU_SH4) | ||
82 | #if defined(CONFIG_CPU_SUBTYPE_SH73180) | ||
83 | static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 12, 16 }; | ||
84 | static int ifc_values[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; | ||
85 | #define bfc_divisors ifc_divisors /* Same */ | ||
86 | #define bfc_values ifc_values | ||
87 | #define pfc_divisors ifc_divisors /* Same */ | ||
88 | #define pfc_values ifc_values | ||
89 | #else | ||
90 | static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; | ||
91 | static int ifc_values[] = { 0, 1, 2, 3, 0, 4, 0, 5 }; | ||
92 | #define bfc_divisors ifc_divisors /* Same */ | ||
93 | #define bfc_values ifc_values | ||
94 | static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; | ||
95 | static int pfc_values[] = { 0, 0, 1, 2, 0, 3, 0, 4 }; | ||
96 | #endif | ||
97 | #else | ||
98 | #error "Unknown ifc/bfc/pfc/stc values for this processor" | ||
99 | #endif | ||
100 | |||
101 | /* | 40 | /* |
102 | * Scheduler clock - returns current time in nanosec units. | 41 | * Scheduler clock - returns current time in nanosec units. |
103 | */ | 42 | */ |
104 | unsigned long long sched_clock(void) | 43 | unsigned long long __attribute__ ((weak)) sched_clock(void) |
105 | { | 44 | { |
106 | return (unsigned long long)jiffies * (1000000000 / HZ); | 45 | return (unsigned long long)jiffies * (1000000000 / HZ); |
107 | } | 46 | } |
108 | 47 | ||
109 | static unsigned long do_gettimeoffset(void) | ||
110 | { | ||
111 | int count; | ||
112 | unsigned long flags; | ||
113 | |||
114 | static int count_p = 0x7fffffff; /* for the first call after boot */ | ||
115 | static unsigned long jiffies_p = 0; | ||
116 | |||
117 | /* | ||
118 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
119 | */ | ||
120 | unsigned long jiffies_t; | ||
121 | |||
122 | spin_lock_irqsave(&tmu0_lock, flags); | ||
123 | /* timer count may underflow right here */ | ||
124 | count = ctrl_inl(TMU0_TCNT); /* read the latched count */ | ||
125 | |||
126 | jiffies_t = jiffies; | ||
127 | |||
128 | /* | ||
129 | * avoiding timer inconsistencies (they are rare, but they happen)... | ||
130 | * there is one kind of problem that must be avoided here: | ||
131 | * 1. the timer counter underflows | ||
132 | */ | ||
133 | |||
134 | if( jiffies_t == jiffies_p ) { | ||
135 | if( count > count_p ) { | ||
136 | /* the nutcase */ | ||
137 | |||
138 | if(ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */ | ||
139 | /* | ||
140 | * We cannot detect lost timer interrupts ... | ||
141 | * well, that's why we call them lost, don't we? :) | ||
142 | * [hmm, on the Pentium and Alpha we can ... sort of] | ||
143 | */ | ||
144 | count -= LATCH; | ||
145 | } else { | ||
146 | printk("do_slow_gettimeoffset(): hardware timer problem?\n"); | ||
147 | } | ||
148 | } | ||
149 | } else | ||
150 | jiffies_p = jiffies_t; | ||
151 | |||
152 | count_p = count; | ||
153 | spin_unlock_irqrestore(&tmu0_lock, flags); | ||
154 | |||
155 | count = ((LATCH-1) - count) * TICK_SIZE; | ||
156 | count = (count + LATCH/2) / LATCH; | ||
157 | |||
158 | return count; | ||
159 | } | ||
160 | |||
161 | void do_gettimeofday(struct timeval *tv) | 48 | void do_gettimeofday(struct timeval *tv) |
162 | { | 49 | { |
163 | unsigned long seq; | 50 | unsigned long seq; |
@@ -166,7 +53,7 @@ void do_gettimeofday(struct timeval *tv) | |||
166 | 53 | ||
167 | do { | 54 | do { |
168 | seq = read_seqbegin(&xtime_lock); | 55 | seq = read_seqbegin(&xtime_lock); |
169 | usec = do_gettimeoffset(); | 56 | usec = get_timer_offset(); |
170 | 57 | ||
171 | lost = jiffies - wall_jiffies; | 58 | lost = jiffies - wall_jiffies; |
172 | if (lost) | 59 | if (lost) |
@@ -202,7 +89,7 @@ int do_settimeofday(struct timespec *tv) | |||
202 | * wall time. Discover what correction gettimeofday() would have | 89 | * wall time. Discover what correction gettimeofday() would have |
203 | * made, and then undo it! | 90 | * made, and then undo it! |
204 | */ | 91 | */ |
205 | nsec -= 1000 * (do_gettimeoffset() + | 92 | nsec -= 1000 * (get_timer_offset() + |
206 | (jiffies - wall_jiffies) * (1000000 / HZ)); | 93 | (jiffies - wall_jiffies) * (1000000 / HZ)); |
207 | 94 | ||
208 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | 95 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); |
@@ -224,10 +111,10 @@ EXPORT_SYMBOL(do_settimeofday); | |||
224 | static long last_rtc_update; | 111 | static long last_rtc_update; |
225 | 112 | ||
226 | /* | 113 | /* |
227 | * timer_interrupt() needs to keep up the real-time clock, | 114 | * handle_timer_tick() needs to keep up the real-time clock, |
228 | * as well as call the "do_timer()" routine every clocktick | 115 | * as well as call the "do_timer()" routine every clocktick |
229 | */ | 116 | */ |
230 | static inline void do_timer_interrupt(int irq, struct pt_regs *regs) | 117 | void handle_timer_tick(struct pt_regs *regs) |
231 | { | 118 | { |
232 | do_timer(regs); | 119 | do_timer(regs); |
233 | #ifndef CONFIG_SMP | 120 | #ifndef CONFIG_SMP |
@@ -252,337 +139,35 @@ static inline void do_timer_interrupt(int irq, struct pt_regs *regs) | |||
252 | if (rtc_set_time(xtime.tv_sec) == 0) | 139 | if (rtc_set_time(xtime.tv_sec) == 0) |
253 | last_rtc_update = xtime.tv_sec; | 140 | last_rtc_update = xtime.tv_sec; |
254 | else | 141 | else |
255 | last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ | 142 | /* do it again in 60s */ |
143 | last_rtc_update = xtime.tv_sec - 600; | ||
256 | } | 144 | } |
257 | } | 145 | } |
258 | 146 | ||
259 | /* | 147 | static struct sysdev_class timer_sysclass = { |
260 | * This is the same as the above, except we _also_ save the current | 148 | set_kset_name("timer"), |
261 | * Time Stamp Counter value at the time of the timer interrupt, so that | ||
262 | * we later on can estimate the time of day more exactly. | ||
263 | */ | ||
264 | static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
265 | { | ||
266 | unsigned long timer_status; | ||
267 | |||
268 | /* Clear UNF bit */ | ||
269 | timer_status = ctrl_inw(TMU0_TCR); | ||
270 | timer_status &= ~0x100; | ||
271 | ctrl_outw(timer_status, TMU0_TCR); | ||
272 | |||
273 | /* | ||
274 | * Here we are in the timer irq handler. We just have irqs locally | ||
275 | * disabled but we don't know if the timer_bh is running on the other | ||
276 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
277 | * the irq version of write_lock because as just said we have irq | ||
278 | * locally disabled. -arca | ||
279 | */ | ||
280 | write_seqlock(&xtime_lock); | ||
281 | do_timer_interrupt(irq, regs); | ||
282 | write_sequnlock(&xtime_lock); | ||
283 | |||
284 | return IRQ_HANDLED; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Hah! We'll see if this works (switching from usecs to nsecs). | ||
289 | */ | ||
290 | static unsigned int __init get_timer_frequency(void) | ||
291 | { | ||
292 | u32 freq; | ||
293 | struct timespec ts1, ts2; | ||
294 | unsigned long diff_nsec; | ||
295 | unsigned long factor; | ||
296 | |||
297 | /* Setup the timer: We don't want to generate interrupts, just | ||
298 | * have it count down at its natural rate. | ||
299 | */ | ||
300 | ctrl_outb(0, TMU_TSTR); | ||
301 | #if !defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
302 | ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); | ||
303 | #endif | ||
304 | ctrl_outw(TMU0_TCR_CALIB, TMU0_TCR); | ||
305 | ctrl_outl(0xffffffff, TMU0_TCOR); | ||
306 | ctrl_outl(0xffffffff, TMU0_TCNT); | ||
307 | |||
308 | rtc_get_time(&ts2); | ||
309 | |||
310 | do { | ||
311 | rtc_get_time(&ts1); | ||
312 | } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); | ||
313 | |||
314 | /* actually start the timer */ | ||
315 | ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); | ||
316 | |||
317 | do { | ||
318 | rtc_get_time(&ts2); | ||
319 | } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); | ||
320 | |||
321 | freq = 0xffffffff - ctrl_inl(TMU0_TCNT); | ||
322 | if (ts2.tv_nsec < ts1.tv_nsec) { | ||
323 | ts2.tv_nsec += 1000000000; | ||
324 | ts2.tv_sec--; | ||
325 | } | ||
326 | |||
327 | diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec); | ||
328 | |||
329 | /* this should work well if the RTC has a precision of n Hz, where | ||
330 | * n is an integer. I don't think we have to worry about the other | ||
331 | * cases. */ | ||
332 | factor = (1000000000 + diff_nsec/2) / diff_nsec; | ||
333 | |||
334 | if (factor * diff_nsec > 1100000000 || | ||
335 | factor * diff_nsec < 900000000) | ||
336 | panic("weird RTC (diff_nsec %ld)", diff_nsec); | ||
337 | |||
338 | return freq * factor; | ||
339 | } | ||
340 | |||
341 | void (*board_time_init)(void); | ||
342 | void (*board_timer_setup)(struct irqaction *irq); | ||
343 | |||
344 | static unsigned int sh_pclk_freq __initdata = CONFIG_SH_PCLK_FREQ; | ||
345 | |||
346 | static int __init sh_pclk_setup(char *str) | ||
347 | { | ||
348 | unsigned int freq; | ||
349 | |||
350 | if (get_option(&str, &freq)) | ||
351 | sh_pclk_freq = freq; | ||
352 | |||
353 | return 1; | ||
354 | } | ||
355 | __setup("sh_pclk=", sh_pclk_setup); | ||
356 | |||
357 | static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL}; | ||
358 | |||
359 | void get_current_frequency_divisors(unsigned int *ifc, unsigned int *bfc, unsigned int *pfc) | ||
360 | { | ||
361 | unsigned int frqcr = ctrl_inw(FRQCR); | ||
362 | |||
363 | #if defined(CONFIG_CPU_SH3) | ||
364 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
365 | *ifc = md_table[((frqcr & 0x0070) >> 4)]; | ||
366 | *bfc = md_table[((frqcr & 0x0700) >> 8)]; | ||
367 | *pfc = md_table[frqcr & 0x0007]; | ||
368 | #elif defined(CONFIG_CPU_SUBTYPE_SH7705) | ||
369 | *bfc = stc_multipliers[(frqcr & 0x0300) >> 8]; | ||
370 | *ifc = ifc_divisors[(frqcr & 0x0030) >> 4]; | ||
371 | *pfc = pfc_divisors[frqcr & 0x0003]; | ||
372 | #else | ||
373 | unsigned int tmp; | ||
374 | |||
375 | tmp = (frqcr & 0x8000) >> 13; | ||
376 | tmp |= (frqcr & 0x0030) >> 4; | ||
377 | *bfc = stc_multipliers[tmp]; | ||
378 | tmp = (frqcr & 0x4000) >> 12; | ||
379 | tmp |= (frqcr & 0x000c) >> 2; | ||
380 | *ifc = ifc_divisors[tmp]; | ||
381 | tmp = (frqcr & 0x2000) >> 11; | ||
382 | tmp |= frqcr & 0x0003; | ||
383 | *pfc = pfc_divisors[tmp]; | ||
384 | #endif | ||
385 | #elif defined(CONFIG_CPU_SH4) | ||
386 | #if defined(CONFIG_CPU_SUBTYPE_SH73180) | ||
387 | *ifc = ifc_divisors[(frqcr>> 20) & 0x0007]; | ||
388 | *bfc = bfc_divisors[(frqcr>> 12) & 0x0007]; | ||
389 | *pfc = pfc_divisors[frqcr & 0x0007]; | ||
390 | #else | ||
391 | *ifc = ifc_divisors[(frqcr >> 6) & 0x0007]; | ||
392 | *bfc = bfc_divisors[(frqcr >> 3) & 0x0007]; | ||
393 | *pfc = pfc_divisors[frqcr & 0x0007]; | ||
394 | #endif | ||
395 | #endif | ||
396 | } | ||
397 | |||
398 | /* | ||
399 | * This bit of ugliness builds up accessor routines to get at both | ||
400 | * the divisors and the physical values. | ||
401 | */ | ||
402 | #define _FREQ_TABLE(x) \ | ||
403 | unsigned int get_##x##_divisor(unsigned int value) \ | ||
404 | { return x##_divisors[value]; } \ | ||
405 | \ | ||
406 | unsigned int get_##x##_value(unsigned int divisor) \ | ||
407 | { return x##_values[(divisor - 1)]; } | ||
408 | |||
409 | _FREQ_TABLE(ifc); | ||
410 | _FREQ_TABLE(bfc); | ||
411 | _FREQ_TABLE(pfc); | ||
412 | |||
413 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
414 | |||
415 | /* | ||
416 | * The ST40 divisors are totally different so we set the cpu data | ||
417 | * clocks using a different algorithm | ||
418 | * | ||
419 | * I've just plugged this from the 2.4 code | ||
420 | * - Alex Bennee <kernel-hacker@bennee.com> | ||
421 | */ | ||
422 | #define CCN_PVR_CHIP_SHIFT 24 | ||
423 | #define CCN_PVR_CHIP_MASK 0xff | ||
424 | #define CCN_PVR_CHIP_ST40STB1 0x4 | ||
425 | |||
426 | |||
427 | struct frqcr_data { | ||
428 | unsigned short frqcr; | ||
429 | |||
430 | struct { | ||
431 | unsigned char multiplier; | ||
432 | unsigned char divisor; | ||
433 | } factor[3]; | ||
434 | }; | ||
435 | |||
436 | static struct frqcr_data st40_frqcr_table[] = { | ||
437 | { 0x000, {{1,1}, {1,1}, {1,2}}}, | ||
438 | { 0x002, {{1,1}, {1,1}, {1,4}}}, | ||
439 | { 0x004, {{1,1}, {1,1}, {1,8}}}, | ||
440 | { 0x008, {{1,1}, {1,2}, {1,2}}}, | ||
441 | { 0x00A, {{1,1}, {1,2}, {1,4}}}, | ||
442 | { 0x00C, {{1,1}, {1,2}, {1,8}}}, | ||
443 | { 0x011, {{1,1}, {2,3}, {1,6}}}, | ||
444 | { 0x013, {{1,1}, {2,3}, {1,3}}}, | ||
445 | { 0x01A, {{1,1}, {1,2}, {1,4}}}, | ||
446 | { 0x01C, {{1,1}, {1,2}, {1,8}}}, | ||
447 | { 0x023, {{1,1}, {2,3}, {1,3}}}, | ||
448 | { 0x02C, {{1,1}, {1,2}, {1,8}}}, | ||
449 | { 0x048, {{1,2}, {1,2}, {1,4}}}, | ||
450 | { 0x04A, {{1,2}, {1,2}, {1,6}}}, | ||
451 | { 0x04C, {{1,2}, {1,2}, {1,8}}}, | ||
452 | { 0x05A, {{1,2}, {1,3}, {1,6}}}, | ||
453 | { 0x05C, {{1,2}, {1,3}, {1,6}}}, | ||
454 | { 0x063, {{1,2}, {1,4}, {1,4}}}, | ||
455 | { 0x06C, {{1,2}, {1,4}, {1,8}}}, | ||
456 | { 0x091, {{1,3}, {1,3}, {1,6}}}, | ||
457 | { 0x093, {{1,3}, {1,3}, {1,6}}}, | ||
458 | { 0x0A3, {{1,3}, {1,6}, {1,6}}}, | ||
459 | { 0x0DA, {{1,4}, {1,4}, {1,8}}}, | ||
460 | { 0x0DC, {{1,4}, {1,4}, {1,8}}}, | ||
461 | { 0x0EC, {{1,4}, {1,8}, {1,8}}}, | ||
462 | { 0x123, {{1,4}, {1,4}, {1,8}}}, | ||
463 | { 0x16C, {{1,4}, {1,8}, {1,8}}}, | ||
464 | }; | 149 | }; |
465 | 150 | ||
466 | struct memclk_data { | 151 | static int __init timer_init_sysfs(void) |
467 | unsigned char multiplier; | ||
468 | unsigned char divisor; | ||
469 | }; | ||
470 | |||
471 | static struct memclk_data st40_memclk_table[8] = { | ||
472 | {1,1}, // 000 | ||
473 | {1,2}, // 001 | ||
474 | {1,3}, // 010 | ||
475 | {2,3}, // 011 | ||
476 | {1,4}, // 100 | ||
477 | {1,6}, // 101 | ||
478 | {1,8}, // 110 | ||
479 | {1,8} // 111 | ||
480 | }; | ||
481 | |||
482 | static void st40_specific_time_init(unsigned int module_clock, unsigned short frqcr) | ||
483 | { | 152 | { |
484 | unsigned int cpu_clock, master_clock, bus_clock, memory_clock; | 153 | int ret = sysdev_class_register(&timer_sysclass); |
485 | struct frqcr_data *d; | 154 | if (ret != 0) |
486 | int a; | 155 | return ret; |
487 | unsigned long memclkcr; | ||
488 | struct memclk_data *e; | ||
489 | 156 | ||
490 | for (a = 0; a < ARRAY_SIZE(st40_frqcr_table); a++) { | 157 | sys_timer->dev.cls = &timer_sysclass; |
491 | d = &st40_frqcr_table[a]; | 158 | return sysdev_register(&sys_timer->dev); |
492 | 159 | } | |
493 | if (d->frqcr == (frqcr & 0x1ff)) | ||
494 | break; | ||
495 | } | ||
496 | 160 | ||
497 | if (a == ARRAY_SIZE(st40_frqcr_table)) { | 161 | device_initcall(timer_init_sysfs); |
498 | d = st40_frqcr_table; | ||
499 | 162 | ||
500 | printk("ERROR: Unrecognised FRQCR value (0x%x), " | 163 | void (*board_time_init)(void); |
501 | "using default multipliers\n", frqcr); | ||
502 | } | ||
503 | |||
504 | memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); | ||
505 | e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; | ||
506 | |||
507 | printk(KERN_INFO "Clock multipliers: CPU: %d/%d Bus: %d/%d " | ||
508 | "Mem: %d/%d Periph: %d/%d\n", | ||
509 | d->factor[0].multiplier, d->factor[0].divisor, | ||
510 | d->factor[1].multiplier, d->factor[1].divisor, | ||
511 | e->multiplier, e->divisor, | ||
512 | d->factor[2].multiplier, d->factor[2].divisor); | ||
513 | |||
514 | master_clock = module_clock * d->factor[2].divisor | ||
515 | / d->factor[2].multiplier; | ||
516 | bus_clock = master_clock * d->factor[1].multiplier | ||
517 | / d->factor[1].divisor; | ||
518 | memory_clock = master_clock * e->multiplier | ||
519 | / e->divisor; | ||
520 | cpu_clock = master_clock * d->factor[0].multiplier | ||
521 | / d->factor[0].divisor; | ||
522 | |||
523 | current_cpu_data.cpu_clock = cpu_clock; | ||
524 | current_cpu_data.master_clock = master_clock; | ||
525 | current_cpu_data.bus_clock = bus_clock; | ||
526 | current_cpu_data.memory_clock = memory_clock; | ||
527 | current_cpu_data.module_clock = module_clock; | ||
528 | } | ||
529 | #endif | ||
530 | 164 | ||
531 | void __init time_init(void) | 165 | void __init time_init(void) |
532 | { | 166 | { |
533 | unsigned int timer_freq = 0; | ||
534 | unsigned int ifc, pfc, bfc; | ||
535 | unsigned long interval; | ||
536 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
537 | unsigned long pvr; | ||
538 | unsigned short frqcr; | ||
539 | #endif | ||
540 | |||
541 | if (board_time_init) | 167 | if (board_time_init) |
542 | board_time_init(); | 168 | board_time_init(); |
543 | 169 | ||
544 | /* | 170 | clk_init(); |
545 | * If we don't have an RTC (such as with the SH7300), don't attempt to | ||
546 | * probe the timer frequency. Rely on an either hardcoded peripheral | ||
547 | * clock value, or on the sh_pclk command line option. Note that we | ||
548 | * still need to have CONFIG_SH_PCLK_FREQ set in order for things like | ||
549 | * CLOCK_TICK_RATE to be sane. | ||
550 | */ | ||
551 | current_cpu_data.module_clock = sh_pclk_freq; | ||
552 | |||
553 | #ifdef CONFIG_SH_PCLK_CALC | ||
554 | /* XXX: Switch this over to a more generic test. */ | ||
555 | { | ||
556 | unsigned int freq; | ||
557 | |||
558 | /* | ||
559 | * If we've specified a peripheral clock frequency, and we have | ||
560 | * an RTC, compare it against the autodetected value. Complain | ||
561 | * if there's a mismatch. | ||
562 | */ | ||
563 | timer_freq = get_timer_frequency(); | ||
564 | freq = timer_freq * 4; | ||
565 | |||
566 | if (sh_pclk_freq && (sh_pclk_freq/100*99 > freq || sh_pclk_freq/100*101 < freq)) { | ||
567 | printk(KERN_NOTICE "Calculated peripheral clock value " | ||
568 | "%d differs from sh_pclk value %d, fixing..\n", | ||
569 | freq, sh_pclk_freq); | ||
570 | current_cpu_data.module_clock = freq; | ||
571 | } | ||
572 | } | ||
573 | #endif | ||
574 | |||
575 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
576 | /* XXX: Update ST40 code to use board_time_init() */ | ||
577 | pvr = ctrl_inl(CCN_PVR); | ||
578 | frqcr = ctrl_inw(FRQCR); | ||
579 | printk("time.c ST40 Probe: PVR %08lx, FRQCR %04hx\n", pvr, frqcr); | ||
580 | |||
581 | if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) | ||
582 | st40_specific_time_init(current_cpu_data.module_clock, frqcr); | ||
583 | else | ||
584 | #endif | ||
585 | get_current_frequency_divisors(&ifc, &bfc, &pfc); | ||
586 | 171 | ||
587 | if (rtc_get_time) { | 172 | if (rtc_get_time) { |
588 | rtc_get_time(&xtime); | 173 | rtc_get_time(&xtime); |
@@ -594,51 +179,12 @@ void __init time_init(void) | |||
594 | set_normalized_timespec(&wall_to_monotonic, | 179 | set_normalized_timespec(&wall_to_monotonic, |
595 | -xtime.tv_sec, -xtime.tv_nsec); | 180 | -xtime.tv_sec, -xtime.tv_nsec); |
596 | 181 | ||
597 | if (board_timer_setup) { | ||
598 | board_timer_setup(&irq0); | ||
599 | } else { | ||
600 | setup_irq(TIMER_IRQ, &irq0); | ||
601 | } | ||
602 | |||
603 | /* | 182 | /* |
604 | * for ST40 chips the current_cpu_data should already be set | 183 | * Find the timer to use as the system timer, it will be |
605 | * so not having valid pfc/bfc/ifc shouldn't be a problem | 184 | * initialized for us. |
606 | */ | 185 | */ |
607 | if (!current_cpu_data.master_clock) | 186 | sys_timer = get_sys_timer(); |
608 | current_cpu_data.master_clock = current_cpu_data.module_clock * pfc; | 187 | printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); |
609 | if (!current_cpu_data.bus_clock) | ||
610 | current_cpu_data.bus_clock = current_cpu_data.master_clock / bfc; | ||
611 | if (!current_cpu_data.cpu_clock) | ||
612 | current_cpu_data.cpu_clock = current_cpu_data.master_clock / ifc; | ||
613 | |||
614 | printk("CPU clock: %d.%02dMHz\n", | ||
615 | (current_cpu_data.cpu_clock / 1000000), | ||
616 | (current_cpu_data.cpu_clock % 1000000)/10000); | ||
617 | printk("Bus clock: %d.%02dMHz\n", | ||
618 | (current_cpu_data.bus_clock / 1000000), | ||
619 | (current_cpu_data.bus_clock % 1000000)/10000); | ||
620 | #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 | ||
621 | printk("Memory clock: %d.%02dMHz\n", | ||
622 | (current_cpu_data.memory_clock / 1000000), | ||
623 | (current_cpu_data.memory_clock % 1000000)/10000); | ||
624 | #endif | ||
625 | printk("Module clock: %d.%02dMHz\n", | ||
626 | (current_cpu_data.module_clock / 1000000), | ||
627 | (current_cpu_data.module_clock % 1000000)/10000); | ||
628 | |||
629 | interval = (current_cpu_data.module_clock/4 + HZ/2) / HZ; | ||
630 | |||
631 | printk("Interval = %ld\n", interval); | ||
632 | |||
633 | /* Start TMU0 */ | ||
634 | ctrl_outb(0, TMU_TSTR); | ||
635 | #if !defined(CONFIG_CPU_SUBTYPE_SH7300) | ||
636 | ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); | ||
637 | #endif | ||
638 | ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); | ||
639 | ctrl_outl(interval, TMU0_TCOR); | ||
640 | ctrl_outl(interval, TMU0_TCNT); | ||
641 | ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); | ||
642 | 188 | ||
643 | #if defined(CONFIG_SH_KGDB) | 189 | #if defined(CONFIG_SH_KGDB) |
644 | /* | 190 | /* |
diff --git a/include/asm-sh/clock.h b/include/asm-sh/clock.h new file mode 100644 index 000000000000..fdfb75b30f0d --- /dev/null +++ b/include/asm-sh/clock.h | |||
@@ -0,0 +1,61 @@ | |||
1 | #ifndef __ASM_SH_CLOCK_H | ||
2 | #define __ASM_SH_CLOCK_H | ||
3 | |||
4 | #include <linux/kref.h> | ||
5 | #include <linux/list.h> | ||
6 | #include <linux/seq_file.h> | ||
7 | |||
8 | struct clk; | ||
9 | |||
10 | struct clk_ops { | ||
11 | void (*init)(struct clk *clk); | ||
12 | void (*enable)(struct clk *clk); | ||
13 | void (*disable)(struct clk *clk); | ||
14 | void (*recalc)(struct clk *clk); | ||
15 | int (*set_rate)(struct clk *clk, unsigned long rate); | ||
16 | }; | ||
17 | |||
18 | struct clk { | ||
19 | struct list_head node; | ||
20 | const char *name; | ||
21 | |||
22 | struct module *owner; | ||
23 | |||
24 | struct clk *parent; | ||
25 | struct clk_ops *ops; | ||
26 | |||
27 | struct kref kref; | ||
28 | |||
29 | unsigned long rate; | ||
30 | unsigned long flags; | ||
31 | }; | ||
32 | |||
33 | #define CLK_ALWAYS_ENABLED (1 << 0) | ||
34 | #define CLK_RATE_PROPAGATES (1 << 1) | ||
35 | |||
36 | /* Should be defined by processor-specific code */ | ||
37 | void arch_init_clk_ops(struct clk_ops **, int type); | ||
38 | |||
39 | /* arch/sh/kernel/cpu/clock.c */ | ||
40 | int clk_init(void); | ||
41 | |||
42 | int __clk_enable(struct clk *); | ||
43 | int clk_enable(struct clk *); | ||
44 | |||
45 | void __clk_disable(struct clk *); | ||
46 | void clk_disable(struct clk *); | ||
47 | |||
48 | int clk_set_rate(struct clk *, unsigned long rate); | ||
49 | unsigned long clk_get_rate(struct clk *); | ||
50 | void clk_recalc_rate(struct clk *); | ||
51 | |||
52 | struct clk *clk_get(const char *id); | ||
53 | void clk_put(struct clk *); | ||
54 | |||
55 | int clk_register(struct clk *); | ||
56 | void clk_unregister(struct clk *); | ||
57 | |||
58 | int show_clocks(struct seq_file *m); | ||
59 | |||
60 | #endif /* __ASM_SH_CLOCK_H */ | ||
61 | |||
diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h index 201d94fd214f..ef2b9b1ae41f 100644 --- a/include/asm-sh/cpu-sh4/freq.h +++ b/include/asm-sh/cpu-sh4/freq.h | |||
@@ -12,6 +12,8 @@ | |||
12 | 12 | ||
13 | #if defined(CONFIG_CPU_SUBTYPE_SH73180) | 13 | #if defined(CONFIG_CPU_SUBTYPE_SH73180) |
14 | #define FRQCR 0xa4150000 | 14 | #define FRQCR 0xa4150000 |
15 | #elif defined(CONFIG_CPU_SUBTYPE_SH7780) | ||
16 | #define FRQCR 0xffc80000 | ||
15 | #else | 17 | #else |
16 | #define FRQCR 0xffc00000 | 18 | #define FRQCR 0xffc00000 |
17 | #endif | 19 | #endif |
diff --git a/include/asm-sh/freq.h b/include/asm-sh/freq.h index 2c0fde46a0ed..39c0e091cf58 100644 --- a/include/asm-sh/freq.h +++ b/include/asm-sh/freq.h | |||
@@ -14,16 +14,5 @@ | |||
14 | 14 | ||
15 | #include <asm/cpu/freq.h> | 15 | #include <asm/cpu/freq.h> |
16 | 16 | ||
17 | /* arch/sh/kernel/time.c */ | ||
18 | extern void get_current_frequency_divisors(unsigned int *ifc, unsigned int *pfc, unsigned int *bfc); | ||
19 | |||
20 | extern unsigned int get_ifc_divisor(unsigned int value); | ||
21 | extern unsigned int get_ifc_divisor(unsigned int value); | ||
22 | extern unsigned int get_ifc_divisor(unsigned int value); | ||
23 | |||
24 | extern unsigned int get_ifc_value(unsigned int divisor); | ||
25 | extern unsigned int get_pfc_value(unsigned int divisor); | ||
26 | extern unsigned int get_bfc_value(unsigned int divisor); | ||
27 | |||
28 | #endif /* __KERNEL__ */ | 17 | #endif /* __KERNEL__ */ |
29 | #endif /* __ASM_SH_FREQ_H */ | 18 | #endif /* __ASM_SH_FREQ_H */ |