aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu')
-rw-r--r--arch/sh/kernel/cpu/clock.c102
-rw-r--r--arch/sh/kernel/cpu/init.c19
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile2
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c3
-rw-r--r--arch/sh/kernel/cpu/irq/pint.c56
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c3
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c54
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c29
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c60
-rw-r--r--arch/sh/kernel/cpu/sh4/clock-sh4-202.c3
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c8
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c600
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7785.c162
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c103
16 files changed, 1155 insertions, 54 deletions
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index abb586b12565..014f318f5a05 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * arch/sh/kernel/cpu/clock.c - SuperH clock framework 2 * arch/sh/kernel/cpu/clock.c - SuperH clock framework
3 * 3 *
4 * Copyright (C) 2005, 2006 Paul Mundt 4 * Copyright (C) 2005, 2006, 2007 Paul Mundt
5 * 5 *
6 * This clock framework is derived from the OMAP version by: 6 * This clock framework is derived from the OMAP version by:
7 * 7 *
@@ -23,6 +23,7 @@
23#include <linux/seq_file.h> 23#include <linux/seq_file.h>
24#include <linux/err.h> 24#include <linux/err.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/proc_fs.h>
26#include <asm/clock.h> 27#include <asm/clock.h>
27#include <asm/timer.h> 28#include <asm/timer.h>
28 29
@@ -98,15 +99,17 @@ int __clk_enable(struct clk *clk)
98 if (clk->ops && clk->ops->init) 99 if (clk->ops && clk->ops->init)
99 clk->ops->init(clk); 100 clk->ops->init(clk);
100 101
102 kref_get(&clk->kref);
103
101 if (clk->flags & CLK_ALWAYS_ENABLED) 104 if (clk->flags & CLK_ALWAYS_ENABLED)
102 return 0; 105 return 0;
103 106
104 if (likely(clk->ops && clk->ops->enable)) 107 if (likely(clk->ops && clk->ops->enable))
105 clk->ops->enable(clk); 108 clk->ops->enable(clk);
106 109
107 kref_get(&clk->kref);
108 return 0; 110 return 0;
109} 111}
112EXPORT_SYMBOL_GPL(__clk_enable);
110 113
111int clk_enable(struct clk *clk) 114int clk_enable(struct clk *clk)
112{ 115{
@@ -119,6 +122,7 @@ int clk_enable(struct clk *clk)
119 122
120 return ret; 123 return ret;
121} 124}
125EXPORT_SYMBOL_GPL(clk_enable);
122 126
123static void clk_kref_release(struct kref *kref) 127static void clk_kref_release(struct kref *kref)
124{ 128{
@@ -127,11 +131,17 @@ static void clk_kref_release(struct kref *kref)
127 131
128void __clk_disable(struct clk *clk) 132void __clk_disable(struct clk *clk)
129{ 133{
134 int count = kref_put(&clk->kref, clk_kref_release);
135
130 if (clk->flags & CLK_ALWAYS_ENABLED) 136 if (clk->flags & CLK_ALWAYS_ENABLED)
131 return; 137 return;
132 138
133 kref_put(&clk->kref, clk_kref_release); 139 if (!count) { /* count reaches zero, disable the clock */
140 if (likely(clk->ops && clk->ops->disable))
141 clk->ops->disable(clk);
142 }
134} 143}
144EXPORT_SYMBOL_GPL(__clk_disable);
135 145
136void clk_disable(struct clk *clk) 146void clk_disable(struct clk *clk)
137{ 147{
@@ -141,6 +151,7 @@ void clk_disable(struct clk *clk)
141 __clk_disable(clk); 151 __clk_disable(clk);
142 spin_unlock_irqrestore(&clock_lock, flags); 152 spin_unlock_irqrestore(&clock_lock, flags);
143} 153}
154EXPORT_SYMBOL_GPL(clk_disable);
144 155
145int clk_register(struct clk *clk) 156int clk_register(struct clk *clk)
146{ 157{
@@ -151,8 +162,18 @@ int clk_register(struct clk *clk)
151 162
152 mutex_unlock(&clock_list_sem); 163 mutex_unlock(&clock_list_sem);
153 164
165 if (clk->flags & CLK_ALWAYS_ENABLED) {
166 pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
167 if (clk->ops && clk->ops->init)
168 clk->ops->init(clk);
169 if (clk->ops && clk->ops->enable)
170 clk->ops->enable(clk);
171 pr_debug( "Enabled.");
172 }
173
154 return 0; 174 return 0;
155} 175}
176EXPORT_SYMBOL_GPL(clk_register);
156 177
157void clk_unregister(struct clk *clk) 178void clk_unregister(struct clk *clk)
158{ 179{
@@ -160,21 +181,29 @@ void clk_unregister(struct clk *clk)
160 list_del(&clk->node); 181 list_del(&clk->node);
161 mutex_unlock(&clock_list_sem); 182 mutex_unlock(&clock_list_sem);
162} 183}
184EXPORT_SYMBOL_GPL(clk_unregister);
163 185
164inline unsigned long clk_get_rate(struct clk *clk) 186unsigned long clk_get_rate(struct clk *clk)
165{ 187{
166 return clk->rate; 188 return clk->rate;
167} 189}
190EXPORT_SYMBOL_GPL(clk_get_rate);
168 191
169int clk_set_rate(struct clk *clk, unsigned long rate) 192int clk_set_rate(struct clk *clk, unsigned long rate)
170{ 193{
194 return clk_set_rate_ex(clk, rate, 0);
195}
196EXPORT_SYMBOL_GPL(clk_set_rate);
197
198int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
199{
171 int ret = -EOPNOTSUPP; 200 int ret = -EOPNOTSUPP;
172 201
173 if (likely(clk->ops && clk->ops->set_rate)) { 202 if (likely(clk->ops && clk->ops->set_rate)) {
174 unsigned long flags; 203 unsigned long flags;
175 204
176 spin_lock_irqsave(&clock_lock, flags); 205 spin_lock_irqsave(&clock_lock, flags);
177 ret = clk->ops->set_rate(clk, rate); 206 ret = clk->ops->set_rate(clk, rate, algo_id);
178 spin_unlock_irqrestore(&clock_lock, flags); 207 spin_unlock_irqrestore(&clock_lock, flags);
179 } 208 }
180 209
@@ -183,6 +212,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
183 212
184 return ret; 213 return ret;
185} 214}
215EXPORT_SYMBOL_GPL(clk_set_rate_ex);
186 216
187void clk_recalc_rate(struct clk *clk) 217void clk_recalc_rate(struct clk *clk)
188{ 218{
@@ -197,6 +227,7 @@ void clk_recalc_rate(struct clk *clk)
197 if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) 227 if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
198 propagate_rate(clk); 228 propagate_rate(clk);
199} 229}
230EXPORT_SYMBOL_GPL(clk_recalc_rate);
200 231
201/* 232/*
202 * Returns a clock. Note that we first try to use device id on the bus 233 * Returns a clock. Note that we first try to use device id on the bus
@@ -233,18 +264,43 @@ found:
233 264
234 return clk; 265 return clk;
235} 266}
267EXPORT_SYMBOL_GPL(clk_get);
236 268
237void clk_put(struct clk *clk) 269void clk_put(struct clk *clk)
238{ 270{
239 if (clk && !IS_ERR(clk)) 271 if (clk && !IS_ERR(clk))
240 module_put(clk->owner); 272 module_put(clk->owner);
241} 273}
274EXPORT_SYMBOL_GPL(clk_put);
242 275
243void __init __attribute__ ((weak)) 276void __init __attribute__ ((weak))
244arch_init_clk_ops(struct clk_ops **ops, int type) 277arch_init_clk_ops(struct clk_ops **ops, int type)
245{ 278{
246} 279}
247 280
281static int show_clocks(char *buf, char **start, off_t off,
282 int len, int *eof, void *data)
283{
284 struct clk *clk;
285 char *p = buf;
286
287 list_for_each_entry_reverse(clk, &clock_list, node) {
288 unsigned long rate = clk_get_rate(clk);
289
290 /*
291 * Don't bother listing dummy clocks with no ancestry
292 * that only support enable and disable ops.
293 */
294 if (unlikely(!rate && !clk->parent))
295 continue;
296
297 p += sprintf(p, "%-12s\t: %ld.%02ldMHz\n", clk->name,
298 rate / 1000000, (rate % 1000000) / 10000);
299 }
300
301 return p - buf;
302}
303
248int __init clk_init(void) 304int __init clk_init(void)
249{ 305{
250 int i, ret = 0; 306 int i, ret = 0;
@@ -256,7 +312,6 @@ int __init clk_init(void)
256 312
257 arch_init_clk_ops(&clk->ops, i); 313 arch_init_clk_ops(&clk->ops, i);
258 ret |= clk_register(clk); 314 ret |= clk_register(clk);
259 clk_enable(clk);
260 } 315 }
261 316
262 /* Kick the child clocks.. */ 317 /* Kick the child clocks.. */
@@ -266,35 +321,14 @@ int __init clk_init(void)
266 return ret; 321 return ret;
267} 322}
268 323
269int show_clocks(struct seq_file *m) 324static int __init clk_proc_init(void)
270{ 325{
271 struct clk *clk; 326 struct proc_dir_entry *p;
272 327 p = create_proc_read_entry("clocks", S_IRUSR, NULL,
273 list_for_each_entry_reverse(clk, &clock_list, node) { 328 show_clocks, NULL);
274 unsigned long rate = clk_get_rate(clk); 329 if (unlikely(!p))
275 330 return -EINVAL;
276 /*
277 * Don't bother listing dummy clocks with no ancestry
278 * that only support enable and disable ops.
279 */
280 if (unlikely(!rate && !clk->parent))
281 continue;
282
283 seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name,
284 rate / 1000000, (rate % 1000000) / 10000);
285 }
286 331
287 return 0; 332 return 0;
288} 333}
289 334subsys_initcall(clk_proc_init);
290EXPORT_SYMBOL_GPL(clk_register);
291EXPORT_SYMBOL_GPL(clk_unregister);
292EXPORT_SYMBOL_GPL(clk_get);
293EXPORT_SYMBOL_GPL(clk_put);
294EXPORT_SYMBOL_GPL(clk_enable);
295EXPORT_SYMBOL_GPL(clk_disable);
296EXPORT_SYMBOL_GPL(__clk_enable);
297EXPORT_SYMBOL_GPL(__clk_disable);
298EXPORT_SYMBOL_GPL(clk_get_rate);
299EXPORT_SYMBOL_GPL(clk_set_rate);
300EXPORT_SYMBOL_GPL(clk_recalc_rate);
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 726acfcb9b77..6451ad630174 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -41,6 +41,23 @@ __setup("no" __stringify(x), x##_setup);
41onchip_setup(fpu); 41onchip_setup(fpu);
42onchip_setup(dsp); 42onchip_setup(dsp);
43 43
44#ifdef CONFIG_SPECULATIVE_EXECUTION
45#define CPUOPM 0xff2f0000
46#define CPUOPM_RABD (1 << 5)
47
48static void __init speculative_execution_init(void)
49{
50 /* Clear RABD */
51 ctrl_outl(ctrl_inl(CPUOPM) & ~CPUOPM_RABD, CPUOPM);
52
53 /* Flush the update */
54 (void)ctrl_inl(CPUOPM);
55 ctrl_barrier();
56}
57#else
58#define speculative_execution_init() do { } while (0)
59#endif
60
44/* 61/*
45 * Generic first-level cache init 62 * Generic first-level cache init
46 */ 63 */
@@ -261,4 +278,6 @@ asmlinkage void __init sh_cpu_init(void)
261 */ 278 */
262 ubc_wakeup(); 279 ubc_wakeup();
263#endif 280#endif
281
282 speculative_execution_init();
264} 283}
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 0049d217561a..1c23308cfc25 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -4,6 +4,6 @@
4obj-y += imask.o 4obj-y += imask.o
5 5
6obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o 6obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
7obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o 7obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
8obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o 8obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
9obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o 9obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index 74defe76a058..d8e22f4ff0f0 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -18,7 +18,8 @@
18#define INTC2_BASE 0xfe080000 18#define INTC2_BASE 0xfe080000
19#define INTC2_INTMSK (INTC2_BASE + 0x40) 19#define INTC2_INTMSK (INTC2_BASE + 0x40)
20#define INTC2_INTMSKCLR (INTC2_BASE + 0x60) 20#define INTC2_INTMSKCLR (INTC2_BASE + 0x60)
21#elif defined(CONFIG_CPU_SUBTYPE_SH7780) 21#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
22 defined(CONFIG_CPU_SUBTYPE_SH7785)
22#define INTC2_BASE 0xffd40000 23#define INTC2_BASE 0xffd40000
23#define INTC2_INTMSK (INTC2_BASE + 0x38) 24#define INTC2_INTMSK (INTC2_BASE + 0x38)
24#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c) 25#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c)
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
index f60007783a21..67602685df1a 100644
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ b/arch/sh/kernel/cpu/irq/pint.c
@@ -18,6 +18,58 @@
18#include <asm/io.h> 18#include <asm/io.h>
19#include <asm/machvec.h> 19#include <asm/machvec.h>
20 20
21#if defined(CONFIG_CPU_SUBTYPE_SH7705)
22#define INTC_INTER 0xA4000014UL
23#define INTC_IPRD 0xA4000018UL
24#define INTC_ICR2 0xA4000012UL
25
26/* PFC */
27#define PORT_PACR 0xA4000100UL
28#define PORT_PBCR 0xA4000102UL
29#define PORT_PCCR 0xA4000104UL
30#define PORT_PDCR 0xA4000106UL
31#define PORT_PECR 0xA4000108UL
32#define PORT_PFCR 0xA400010AUL
33#define PORT_PGCR 0xA400010CUL
34#define PORT_PHCR 0xA400010EUL
35#define PORT_PJCR 0xA4000110UL
36#define PORT_PKCR 0xA4000112UL
37#define PORT_PLCR 0xA4000114UL
38#define PORT_PMCR 0xA4000118UL
39#define PORT_PNCR 0xA400011AUL
40#define PORT_PECR2 0xA4050148UL
41#define PORT_PFCR2 0xA405014AUL
42#define PORT_PNCR2 0xA405015AUL
43
44/* I/O port */
45#define PORT_PADR 0xA4000120UL
46#define PORT_PBDR 0xA4000122UL
47#define PORT_PCDR 0xA4000124UL
48#define PORT_PDDR 0xA4000126UL
49#define PORT_PEDR 0xA4000128UL
50#define PORT_PFDR 0xA400012AUL
51#define PORT_PGDR 0xA400012CUL
52#define PORT_PHDR 0xA400012EUL
53#define PORT_PJDR 0xA4000130UL
54#define PORT_PKDR 0xA4000132UL
55#define PORT_PLDR 0xA4000134UL
56#define PORT_PMDR 0xA4000138UL
57#define PORT_PNDR 0xA400013AUL
58
59#define PINT0_IRQ 40
60#define PINT8_IRQ 41
61#define PINT_IRQ_BASE 86
62
63#define PINT0_IPR_ADDR INTC_IPRD
64#define PINT0_IPR_POS 3
65#define PINT0_PRIORITY 2
66
67#define PINT8_IPR_ADDR INTC_IPRD
68#define PINT8_IPR_POS 2
69#define PINT8_PRIORITY 2
70
71#endif /* CONFIG_CPU_SUBTYPE_SH7705 */
72
21static unsigned char pint_map[256]; 73static unsigned char pint_map[256];
22static unsigned long portcr_mask; 74static unsigned long portcr_mask;
23 75
@@ -126,7 +178,7 @@ int ipr_irq_demux(int irq)
126 unsigned long creg, dreg, d, sav; 178 unsigned long creg, dreg, d, sav;
127 179
128 if (irq == PINT0_IRQ) { 180 if (irq == PINT0_IRQ) {
129#if defined(CONFIG_CPU_SUBTYPE_SH7707) 181#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
130 creg = PORT_PACR; 182 creg = PORT_PACR;
131 dreg = PORT_PADR; 183 dreg = PORT_PADR;
132#else 184#else
@@ -144,7 +196,7 @@ int ipr_irq_demux(int irq)
144 196
145 return PINT_IRQ_BASE + pint_map[d]; 197 return PINT_IRQ_BASE + pint_map[d];
146 } else if (irq == PINT8_IRQ) { 198 } else if (irq == PINT8_IRQ) {
147#if defined(CONFIG_CPU_SUBTYPE_SH7707) 199#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
148 creg = PORT_PBCR; 200 creg = PORT_PBCR;
149 dreg = PORT_PBDR; 201 dreg = PORT_PBDR;
150#else 202#else
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index 83905e4e4387..09faa056cd43 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
12obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o 12obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
13obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o 13obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o
14obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o 14obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
15obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o
15 16
16# Primary on-chip clocks (common) 17# Primary on-chip clocks (common)
17clock-$(CONFIG_CPU_SH3) := clock-sh3.o 18clock-$(CONFIG_CPU_SH3) := clock-sh3.o
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 821b0ab7b528..647623b22edc 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -78,6 +78,9 @@ int __init detect_cpu_and_cache_system(void)
78#if defined(CONFIG_CPU_SUBTYPE_SH7710) 78#if defined(CONFIG_CPU_SUBTYPE_SH7710)
79 current_cpu_data.type = CPU_SH7710; 79 current_cpu_data.type = CPU_SH7710;
80#endif 80#endif
81#if defined(CONFIG_CPU_SUBTYPE_SH7712)
82 current_cpu_data.type = CPU_SH7712;
83#endif
81#if defined(CONFIG_CPU_SUBTYPE_SH7705) 84#if defined(CONFIG_CPU_SUBTYPE_SH7705)
82 current_cpu_data.type = CPU_SH7705; 85 current_cpu_data.type = CPU_SH7705;
83 86
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index a8e41c5241fa..1983fb7ad6ea 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -2,6 +2,7 @@
2 * SH7705 Setup 2 * SH7705 Setup
3 * 3 *
4 * Copyright (C) 2006 Paul Mundt 4 * Copyright (C) 2006 Paul Mundt
5 * Copyright (C) 2007 Nobuhiro Iwamatsu
5 * 6 *
6 * This file is subject to the terms and conditions of the GNU General Public 7 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive 8 * License. See the file "COPYING" in the main directory of this archive
@@ -14,15 +15,15 @@
14 15
15static struct plat_sci_port sci_platform_data[] = { 16static struct plat_sci_port sci_platform_data[] = {
16 { 17 {
17 .mapbase = 0xa4400000, 18 .mapbase = 0xa4410000,
18 .flags = UPF_BOOT_AUTOCONF, 19 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF, 20 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 }, 21 .irqs = { 56, 57, 59 },
21 }, { 22 }, {
22 .mapbase = 0xa4410000, 23 .mapbase = 0xa4400000,
23 .flags = UPF_BOOT_AUTOCONF, 24 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF, 25 .type = PORT_SCIF,
25 .irqs = { 56, 57, 59, 58 }, 26 .irqs = { 52, 53, 55 },
26 }, { 27 }, {
27 .flags = 0, 28 .flags = 0,
28 } 29 }
@@ -46,3 +47,48 @@ static int __init sh7705_devices_setup(void)
46 ARRAY_SIZE(sh7705_devices)); 47 ARRAY_SIZE(sh7705_devices));
47} 48}
48__initcall(sh7705_devices_setup); 49__initcall(sh7705_devices_setup);
50
51static struct ipr_data sh7705_ipr_map[] = {
52 /* IRQ, IPR-idx, shift, priority */
53 { 16, 0, 12, 2 }, /* TMU0 TUNI*/
54 { 17, 0, 8, 2 }, /* TMU1 TUNI */
55 { 18, 0, 4, 2 }, /* TMU2 TUNI */
56 { 27, 1, 12, 2 }, /* WDT ITI */
57 { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
58 { 21, 0, 0, 2 }, /* RTC PRI (period) */
59 { 22, 0, 0, 2 }, /* RTC CUI (carry) */
60 { 48, 4, 12, 7 }, /* DMAC DMTE0 */
61 { 49, 4, 12, 7 }, /* DMAC DMTE1 */
62 { 50, 4, 12, 7 }, /* DMAC DMTE2 */
63 { 51, 4, 12, 7 }, /* DMAC DMTE3 */
64 { 52, 4, 8, 3 }, /* SCIF0 ERI */
65 { 53, 4, 8, 3 }, /* SCIF0 RXI */
66 { 55, 4, 8, 3 }, /* SCIF0 TXI */
67 { 56, 4, 4, 3 }, /* SCIF1 ERI */
68 { 57, 4, 4, 3 }, /* SCIF1 RXI */
69 { 59, 4, 4, 3 }, /* SCIF1 TXI */
70};
71
72static unsigned long ipr_offsets[] = {
73 0xFFFFFEE2 /* 0: IPRA */
74, 0xFFFFFEE4 /* 1: IPRB */
75, 0xA4000016 /* 2: IPRC */
76, 0xA4000018 /* 3: IPRD */
77, 0xA400001A /* 4: IPRE */
78, 0xA4080000 /* 5: IPRF */
79, 0xA4080002 /* 6: IPRG */
80, 0xA4080004 /* 7: IPRH */
81};
82
83/* given the IPR index return the address of the IPR register */
84unsigned int map_ipridx_to_addr(int idx)
85{
86 if (idx >= ARRAY_SIZE(ipr_offsets))
87 return 0;
88 return ipr_offsets[idx];
89}
90
91void __init init_IRQ_ipr()
92{
93 make_ipr_irq(sh7705_ipr_map, ARRAY_SIZE(sh7705_ipr_map));
94}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
index dc9b211cf87f..c7d7c35fc834 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -48,24 +48,33 @@ static struct platform_device *sh7709_devices[] __initdata = {
48static int __init sh7709_devices_setup(void) 48static int __init sh7709_devices_setup(void)
49{ 49{
50 return platform_add_devices(sh7709_devices, 50 return platform_add_devices(sh7709_devices,
51 ARRAY_SIZE(sh7709_devices)); 51 ARRAY_SIZE(sh7709_devices));
52} 52}
53__initcall(sh7709_devices_setup); 53__initcall(sh7709_devices_setup);
54 54
55#define IPRx(A,N) .addr=A, .shift=0*N*-1 55#define IPRx(A,N) .addr=A, .shift=N
56#define IPRA(N) IPRx(0xfffffee2UL,N) 56#define IPRA(N) IPRx(0xfffffee2UL,N)
57#define IPRB(N) IPRx(0xfffffee4UL,N) 57#define IPRB(N) IPRx(0xfffffee4UL,N)
58#define IPRC(N) IPRx(0xa4000016UL,N)
59#define IPRD(N) IPRx(0xa4000018UL,N)
58#define IPRE(N) IPRx(0xa400001aUL,N) 60#define IPRE(N) IPRx(0xa400001aUL,N)
59 61
60static struct ipr_data sh7709_ipr_map[] = { 62static struct ipr_data sh7709_ipr_map[] = {
61 [16] = { IPRA(15-12), 2 }, /* TMU TUNI0 */ 63 [16] = { IPRA(12), 2 }, /* TMU TUNI0 */
62 [17] = { IPRA(11-8), 4 }, /* TMU TUNI1 */ 64 [17] = { IPRA(8), 4 }, /* TMU TUNI1 */
63 [22] = { IPRA(3-0), 2 }, /* RTC CUI */ 65 [18 ... 19] = { IPRA(4), 1 }, /* TMU TUNI1 */
64 [23 ... 26] = { IPRB(7-4), 3 }, /* SCI */ 66 [20 ... 22] = { IPRA(0), 2 }, /* RTC CUI */
65 [27] = { IPRB(15-12), 2 }, /* WDT ITI */ 67 [23 ... 26] = { IPRB(4), 3 }, /* SCI */
66 [48 ... 51] = { IPRE(15-12), 7 }, /* DMA */ 68 [27] = { IPRB(12), 2 }, /* WDT ITI */
67 [52 ... 55] = { IPRE(11-8), 3 }, /* IRDA */ 69 [32] = { IPRC(0), 1 }, /* IRQ 0 */
68 [56 ... 59] = { IPRE(7-4), 3 }, /* SCIF */ 70 [33] = { IPRC(4), 1 }, /* IRQ 1 */
71 [34] = { IPRC(8), 1 }, /* IRQ 2 APM */
72 [35] = { IPRC(12), 1 }, /* IRQ 3 TOUCHSCREEN */
73 [36] = { IPRD(0), 1 }, /* IRQ 4 */
74 [37] = { IPRD(4), 1 }, /* IRQ 5 */
75 [48 ... 51] = { IPRE(12), 7 }, /* DMA */
76 [52 ... 55] = { IPRE(8), 3 }, /* IRDA */
77 [56 ... 59] = { IPRE(4), 3 }, /* SCIF */
69}; 78};
70 79
71void __init init_IRQ_ipr() 80void __init init_IRQ_ipr()
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 895f99ee6a95..51760a7e7f1c 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -2,6 +2,7 @@
2 * SH7710 Setup 2 * SH7710 Setup
3 * 3 *
4 * Copyright (C) 2006 Paul Mundt 4 * Copyright (C) 2006 Paul Mundt
5 * Copyright (C) 2007 Nobuhiro Iwamatsu
5 * 6 *
6 * This file is subject to the terms and conditions of the GNU General Public 7 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive 8 * License. See the file "COPYING" in the main directory of this archive
@@ -19,6 +20,12 @@ static struct plat_sci_port sci_platform_data[] = {
19 .type = PORT_SCIF, 20 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 }, 21 .irqs = { 52, 53, 55, 54 },
21 }, { 22 }, {
23 .mapbase = 0xa4420000,
24 .flags = UPF_BOOT_AUTOCONF,
25 .type = PORT_SCIF,
26 .irqs = { 56, 57, 59, 58 },
27 }, {
28
22 .flags = 0, 29 .flags = 0,
23 } 30 }
24}; 31};
@@ -41,3 +48,56 @@ static int __init sh7710_devices_setup(void)
41 ARRAY_SIZE(sh7710_devices)); 48 ARRAY_SIZE(sh7710_devices));
42} 49}
43__initcall(sh7710_devices_setup); 50__initcall(sh7710_devices_setup);
51
52static struct ipr_data sh7710_ipr_map[] = {
53 /* IRQ, IPR-idx, shift, priority */
54 { 16, 0, 12, 2 }, /* TMU0 TUNI*/
55 { 17, 0, 8, 2 }, /* TMU1 TUNI */
56 { 18, 0, 4, 2 }, /* TMU2 TUNI */
57 { 27, 1, 12, 2 }, /* WDT ITI */
58 { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
59 { 21, 0, 0, 2 }, /* RTC PRI (period) */
60 { 22, 0, 0, 2 }, /* RTC CUI (carry) */
61 { 48, 4, 12, 7 }, /* DMAC DMTE0 */
62 { 49, 4, 12, 7 }, /* DMAC DMTE1 */
63 { 50, 4, 12, 7 }, /* DMAC DMTE2 */
64 { 51, 4, 12, 7 }, /* DMAC DMTE3 */
65 { 52, 4, 8, 3 }, /* SCIF0 ERI */
66 { 53, 4, 8, 3 }, /* SCIF0 RXI */
67 { 54, 4, 8, 3 }, /* SCIF0 BRI */
68 { 55, 4, 8, 3 }, /* SCIF0 TXI */
69 { 56, 4, 4, 3 }, /* SCIF1 ERI */
70 { 57, 4, 4, 3 }, /* SCIF1 RXI */
71 { 58, 4, 4, 3 }, /* SCIF1 BRI */
72 { 59, 4, 4, 3 }, /* SCIF1 TXI */
73 { 76, 5, 8, 7 }, /* DMAC DMTE4 */
74 { 77, 5, 8, 7 }, /* DMAC DMTE5 */
75 { 80, 6, 12, 5 }, /* EDMAC EINT0 */
76 { 81, 6, 8, 5 }, /* EDMAC EINT1 */
77 { 82, 6, 4, 5 }, /* EDMAC EINT2 */
78};
79
80static unsigned long ipr_offsets[] = {
81 0xA414FEE2 /* 0: IPRA */
82, 0xA414FEE4 /* 1: IPRB */
83, 0xA4140016 /* 2: IPRC */
84, 0xA4140018 /* 3: IPRD */
85, 0xA414001A /* 4: IPRE */
86, 0xA4080000 /* 5: IPRF */
87, 0xA4080002 /* 6: IPRG */
88, 0xA4080004 /* 7: IPRH */
89, 0xA4080006 /* 8: IPRI */
90};
91
92/* given the IPR index return the address of the IPR register */
93unsigned int map_ipridx_to_addr(int idx)
94{
95 if (idx >= ARRAY_SIZE(ipr_offsets))
96 return 0;
97 return ipr_offsets[idx];
98}
99
100void __init init_IRQ_ipr()
101{
102 make_ipr_irq(sh7710_ipr_map, ARRAY_SIZE(sh7710_ipr_map));
103}
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
index fa2019aabd74..fcb2c41bc34e 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
@@ -82,7 +82,8 @@ static void shoc_clk_init(struct clk *clk)
82 for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) { 82 for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
83 int divisor = frqcr3_divisors[i]; 83 int divisor = frqcr3_divisors[i];
84 84
85 if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0) 85 if (clk->ops->set_rate(clk, clk->parent->rate /
86 divisor, 0) == 0)
86 break; 87 break;
87 } 88 }
88 89
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 58950de2696d..8cd04904c77a 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -124,6 +124,14 @@ int __init detect_cpu_and_cache_system(void)
124 current_cpu_data.dcache.ways = 4; 124 current_cpu_data.dcache.ways = 4;
125 current_cpu_data.flags |= CPU_HAS_LLSC; 125 current_cpu_data.flags |= CPU_HAS_LLSC;
126 break; 126 break;
127 case 0x3004:
128 case 0x3007:
129 current_cpu_data.type = CPU_SH7785;
130 current_cpu_data.icache.ways = 4;
131 current_cpu_data.dcache.ways = 4;
132 current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
133 CPU_HAS_LLSC;
134 break;
127 case 0x3008: 135 case 0x3008:
128 if (prr == 0xa0) { 136 if (prr == 0xa0) {
129 current_cpu_data.type = CPU_SH7722; 137 current_cpu_data.type = CPU_SH7722;
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index a8f493f2f21f..ab7422f8f820 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -5,6 +5,7 @@
5# CPU subtype setup 5# CPU subtype setup
6obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o 6obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
7obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o 7obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
8obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
8obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o 9obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
9obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o 10obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
10obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o 11obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
@@ -13,7 +14,8 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
13clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o 14clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
14clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o 15clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
15clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o 16clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
17clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
16clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o 18clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
17clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7343.o 19clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
18 20
19obj-y += $(clock-y) 21obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
new file mode 100644
index 000000000000..29090035bc5b
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -0,0 +1,600 @@
1/*
2 * arch/sh/kernel/cpu/sh4a/clock-sh7722.c
3 *
4 * SH7722 support for the clock framework
5 *
6 * Copyright (c) 2006-2007 Nomad Global Solutions Inc
7 * Based on code for sh7343 by Paul Mundt
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
12 */
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/io.h>
16#include <linux/errno.h>
17#include <asm/clock.h>
18#include <asm/freq.h>
19
20#define SH7722_PLL_FREQ (32000000/8)
21#define N (-1)
22#define NM (-2)
23#define ROUND_NEAREST 0
24#define ROUND_DOWN -1
25#define ROUND_UP +1
26
27static int adjust_algos[][3] = {
28 {}, /* NO_CHANGE */
29 { NM, N, 1 }, /* N:1, N:1 */
30 { 3, 2, 2 }, /* 3:2:2 */
31 { 5, 2, 2 }, /* 5:2:2 */
32 { N, 1, 1 }, /* N:1:1 */
33
34 { N, 1 }, /* N:1 */
35
36 { N, 1 }, /* N:1 */
37 { 3, 2 },
38 { 4, 3 },
39 { 5, 4 },
40
41 { N, 1 }
42};
43
44static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2,
45 int m1, int m2, int round_flag)
46{
47 unsigned long rem, div;
48 int the_one = 0;
49
50 pr_debug( "Actual values: r1 = %ld\n", r1);
51 pr_debug( "...............r2 = %ld\n", r2);
52
53 if (m1 == m2) {
54 r2 = r1;
55 pr_debug( "setting equal rates: r2 now %ld\n", r2);
56 } else if ((m2 == N && m1 == 1) ||
57 (m2 == NM && m1 == N)) { /* N:1 or NM:N */
58 pr_debug( "Setting rates as 1:N (N:N*M)\n");
59 rem = r2 % r1;
60 pr_debug( "...remainder = %ld\n", rem);
61 if (rem) {
62 div = r2 / r1;
63 pr_debug( "...div = %ld\n", div);
64 switch (round_flag) {
65 case ROUND_NEAREST:
66 the_one = rem >= r1/2 ? 1 : 0; break;
67 case ROUND_UP:
68 the_one = 1; break;
69 case ROUND_DOWN:
70 the_one = 0; break;
71 }
72
73 r2 = r1 * (div + the_one);
74 pr_debug( "...setting r2 to %ld\n", r2);
75 }
76 } else if ((m2 == 1 && m1 == N) ||
77 (m2 == N && m1 == NM)) { /* 1:N or N:NM */
78 pr_debug( "Setting rates as N:1 (N*M:N)\n");
79 rem = r1 % r2;
80 pr_debug( "...remainder = %ld\n", rem);
81 if (rem) {
82 div = r1 / r2;
83 pr_debug( "...div = %ld\n", div);
84 switch (round_flag) {
85 case ROUND_NEAREST:
86 the_one = rem > r2/2 ? 1 : 0; break;
87 case ROUND_UP:
88 the_one = 0; break;
89 case ROUND_DOWN:
90 the_one = 1; break;
91 }
92
93 r2 = r1 / (div + the_one);
94 pr_debug( "...setting r2 to %ld\n", r2);
95 }
96 } else { /* value:value */
97 pr_debug( "Setting rates as %d:%d\n", m1, m2);
98 div = r1 / m1;
99 r2 = div * m2;
100 pr_debug( "...div = %ld\n", div);
101 pr_debug( "...setting r2 to %ld\n", r2);
102 }
103
104 return r2;
105}
106
107static void adjust_clocks(int originate, int *l, unsigned long v[],
108 int n_in_line)
109{
110 int x;
111
112 pr_debug( "Go down from %d...\n", originate);
113 /* go up recalculation clocks */
114 for (x = originate; x>0; x -- )
115 v[x-1] = adjust_pair_of_clocks(v[x], v[x-1],
116 l[x], l[x-1],
117 ROUND_UP);
118
119 pr_debug( "Go up from %d...\n", originate);
120 /* go down recalculation clocks */
121 for (x = originate; x<n_in_line - 1; x ++ )
122 v[x+1] = adjust_pair_of_clocks(v[x], v[x+1],
123 l[x], l[x+1],
124 ROUND_UP);
125}
126
127
128/*
129 * SH7722 uses a common set of multipliers and divisors, so this
130 * is quite simple..
131 */
132
133/*
134 * Instead of having two separate multipliers/divisors set, like this:
135 *
136 * static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
137 * static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
138 *
139 * I created the divisors2 array, which is used to calculate rate like
140 * rate = parent * 2 / divisors2[ divisor ];
141*/
142static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
143
144static void master_clk_init(struct clk *clk)
145{
146 clk_set_rate(clk, clk_get_rate(clk));
147}
148
149static void master_clk_recalc(struct clk *clk)
150{
151 unsigned long frqcr = ctrl_inl(FRQCR);
152
153 clk->rate = CONFIG_SH_PCLK_FREQ * (1 + (frqcr >> 24 & 0xF));
154}
155
156static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
157{
158 int div = rate / SH7722_PLL_FREQ;
159 int master_divs[] = { 2, 3, 4, 6, 8, 16 };
160 int index;
161 unsigned long frqcr;
162
163 if (rate < SH7722_PLL_FREQ * 2)
164 return -EINVAL;
165
166 for (index = 1; index < ARRAY_SIZE(master_divs); index++)
167 if (div >= master_divs[index - 1] && div < master_divs[index])
168 break;
169
170 if (index >= ARRAY_SIZE(master_divs))
171 index = ARRAY_SIZE(master_divs);
172 div = master_divs[index - 1];
173
174 frqcr = ctrl_inl(FRQCR);
175 frqcr &= ~(0xF << 24);
176 frqcr |= ( (div-1) << 24);
177 ctrl_outl(frqcr, FRQCR);
178
179 return 0;
180}
181
182static struct clk_ops sh7722_master_clk_ops = {
183 .init = master_clk_init,
184 .recalc = master_clk_recalc,
185 .set_rate = master_clk_setrate,
186};
187
188struct frqcr_context {
189 unsigned mask;
190 unsigned shift;
191};
192
193struct frqcr_context sh7722_get_clk_context(const char *name)
194{
195 struct frqcr_context ctx = { 0, };
196
197 if (!strcmp(name, "peripheral_clk")) {
198 ctx.shift = 0;
199 ctx.mask = 0xF;
200 } else if (!strcmp(name, "sdram_clk")) {
201 ctx.shift = 4;
202 ctx.mask = 0xF;
203 } else if (!strcmp(name, "bus_clk")) {
204 ctx.shift = 8;
205 ctx.mask = 0xF;
206 } else if (!strcmp(name, "sh_clk")) {
207 ctx.shift = 12;
208 ctx.mask = 0xF;
209 } else if (!strcmp(name, "umem_clk")) {
210 ctx.shift = 16;
211 ctx.mask = 0xF;
212 } else if (!strcmp(name, "cpu_clk")) {
213 ctx.shift = 20;
214 ctx.mask = 7;
215 }
216 return ctx;
217}
218
219/**
220 * sh7722_find_divisors - find divisor for setting rate
221 *
222 * All sh7722 clocks use the same set of multipliers/divisors. This function
223 * chooses correct divisor to set the rate of clock with parent clock that
224 * generates frequency of 'parent_rate'
225 *
226 * @parent_rate: rate of parent clock
227 * @rate: requested rate to be set
228 */
229static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate)
230{
231 unsigned div2 = parent_rate * 2 / rate;
232 int index;
233
234 if (rate > parent_rate)
235 return -EINVAL;
236
237 for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
238 if (div2 > divisors2[index] && div2 <= divisors2[index])
239 break;
240 }
241 if (index >= ARRAY_SIZE(divisors2))
242 index = ARRAY_SIZE(divisors2) - 1;
243 return divisors2[index];
244}
245
246static void sh7722_frqcr_recalc(struct clk *clk)
247{
248 struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
249 unsigned long frqcr = ctrl_inl(FRQCR);
250 int index;
251
252 index = (frqcr >> ctx.shift) & ctx.mask;
253 clk->rate = clk->parent->rate * 2 / divisors2[index];
254}
255
256static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
257 int algo_id)
258{
259 struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
260 unsigned long parent_rate = clk->parent->rate;
261 int div;
262 unsigned long frqcr;
263 int err = 0;
264
265 /* pretty invalid */
266 if (parent_rate < rate)
267 return -EINVAL;
268
269 /* look for multiplier/divisor pair */
270 div = sh7722_find_divisors(parent_rate, rate);
271 if (div<0)
272 return div;
273
274 /* calculate new value of clock rate */
275 clk->rate = parent_rate * 2 / div;
276 frqcr = ctrl_inl(FRQCR);
277
278 /* FIXME: adjust as algo_id specifies */
279 if (algo_id != NO_CHANGE) {
280 int originator;
281 char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" };
282 char *algo_group_2[] = { "sh_clk", "bus_clk" };
283 char *algo_group_3[] = { "sh_clk", "sdram_clk" };
284 char *algo_group_4[] = { "bus_clk", "peripheral_clk" };
285 char *algo_group_5[] = { "cpu_clk", "peripheral_clk" };
286 char **algo_current = NULL;
287 /* 3 is the maximum number of clocks in relation */
288 struct clk *ck[3];
289 unsigned long values[3]; /* the same comment as above */
290 int part_length = -1;
291 int i;
292
293 /*
294 * all the steps below only required if adjustion was
295 * requested
296 */
297 if (algo_id == IUS_N1_N1 ||
298 algo_id == IUS_322 ||
299 algo_id == IUS_522 ||
300 algo_id == IUS_N11) {
301 algo_current = algo_group_1;
302 part_length = 3;
303 }
304 if (algo_id == SB_N1) {
305 algo_current = algo_group_2;
306 part_length = 2;
307 }
308 if (algo_id == SB3_N1 ||
309 algo_id == SB3_32 ||
310 algo_id == SB3_43 ||
311 algo_id == SB3_54) {
312 algo_current = algo_group_3;
313 part_length = 2;
314 }
315 if (algo_id == BP_N1) {
316 algo_current = algo_group_4;
317 part_length = 2;
318 }
319 if (algo_id == IP_N1) {
320 algo_current = algo_group_5;
321 part_length = 2;
322 }
323 if (!algo_current)
324 goto incorrect_algo_id;
325
326 originator = -1;
327 for (i = 0; i < part_length; i ++ ) {
328 if (originator >= 0 && !strcmp(clk->name,
329 algo_current[i]))
330 originator = i;
331 ck[i] = clk_get(NULL, algo_current[i]);
332 values[i] = clk_get_rate(ck[i]);
333 }
334
335 if (originator >= 0)
336 adjust_clocks(originator, adjust_algos[algo_id],
337 values, part_length);
338
339 for (i = 0; i < part_length; i ++ ) {
340 struct frqcr_context part_ctx;
341 int part_div;
342
343 if (likely(!err)) {
344 part_div = sh7722_find_divisors(parent_rate,
345 rate);
346 if (part_div > 0) {
347 part_ctx = sh7722_get_clk_context(
348 ck[i]->name);
349 frqcr &= ~(part_ctx.mask <<
350 part_ctx.shift);
351 frqcr |= part_div << part_ctx.shift;
352 } else
353 err = part_div;
354 }
355
356 ck[i]->ops->recalc(ck[i]);
357 clk_put(ck[i]);
358 }
359 }
360
361 /* was there any error during recalculation ? If so, bail out.. */
362 if (unlikely(err!=0))
363 goto out_err;
364
365 /* clear FRQCR bits */
366 frqcr &= ~(ctx.mask << ctx.shift);
367 frqcr |= div << ctx.shift;
368
369 /* ...and perform actual change */
370 ctrl_outl(frqcr, FRQCR);
371 return 0;
372
373incorrect_algo_id:
374 return -EINVAL;
375out_err:
376 return err;
377}
378
379static struct clk_ops sh7722_frqcr_clk_ops = {
380 .recalc = sh7722_frqcr_recalc,
381 .set_rate = sh7722_frqcr_set_rate,
382};
383
384/*
385 * clock ops methods for SIU A/B and IrDA clock
386 *
387 */
388static int sh7722_siu_which(struct clk *clk)
389{
390 if (!strcmp(clk->name, "siu_a_clk"))
391 return 0;
392 if (!strcmp(clk->name, "siu_b_clk"))
393 return 1;
394 if (!strcmp(clk->name, "irda_clk"))
395 return 2;
396 return -EINVAL;
397}
398
399static unsigned long sh7722_siu_regs[] = {
400 [0] = SCLKACR,
401 [1] = SCLKBCR,
402 [2] = IrDACLKCR,
403};
404
405static int sh7722_siu_start_stop(struct clk *clk, int enable)
406{
407 int siu = sh7722_siu_which(clk);
408 unsigned long r;
409
410 if (siu < 0)
411 return siu;
412 BUG_ON(siu > 2);
413 r = ctrl_inl(sh7722_siu_regs[siu]);
414 if (enable)
415 ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]);
416 else
417 ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]);
418 return 0;
419}
420
421static void sh7722_siu_enable(struct clk *clk)
422{
423 sh7722_siu_start_stop(clk, 1);
424}
425
426static void sh7722_siu_disable(struct clk *clk)
427{
428 sh7722_siu_start_stop(clk, 0);
429}
430
431static void sh7722_video_enable(struct clk *clk)
432{
433 unsigned long r;
434
435 r = ctrl_inl(VCLKCR);
436 ctrl_outl( r & ~(1<<8), VCLKCR);
437}
438
439static void sh7722_video_disable(struct clk *clk)
440{
441 unsigned long r;
442
443 r = ctrl_inl(VCLKCR);
444 ctrl_outl( r | (1<<8), VCLKCR);
445}
446
447static int sh7722_video_set_rate(struct clk *clk, unsigned long rate,
448 int algo_id)
449{
450 unsigned long r;
451
452 r = ctrl_inl(VCLKCR);
453 r &= ~0x3F;
454 r |= ((clk->parent->rate / rate - 1) & 0x3F);
455 ctrl_outl(r, VCLKCR);
456 return 0;
457}
458
459static void sh7722_video_recalc(struct clk *clk)
460{
461 unsigned long r;
462
463 r = ctrl_inl(VCLKCR);
464 clk->rate = clk->parent->rate / ((r & 0x3F) + 1);
465}
466
467static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
468{
469 int siu = sh7722_siu_which(clk);
470 unsigned long r;
471 int div;
472
473 if (siu < 0)
474 return siu;
475 BUG_ON(siu > 2);
476 r = ctrl_inl(sh7722_siu_regs[siu]);
477 div = sh7722_find_divisors(clk->parent->rate, rate);
478 if (div < 0)
479 return div;
480 r = (r & ~0xF) | div;
481 ctrl_outl(r, sh7722_siu_regs[siu]);
482 return 0;
483}
484
485static void sh7722_siu_recalc(struct clk *clk)
486{
487 int siu = sh7722_siu_which(clk);
488 unsigned long r;
489
490 if (siu < 0)
491 return /* siu */ ;
492 BUG_ON(siu > 1);
493 r = ctrl_inl(sh7722_siu_regs[siu]);
494 clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
495}
496
497static struct clk_ops sh7722_siu_clk_ops = {
498 .recalc = sh7722_siu_recalc,
499 .set_rate = sh7722_siu_set_rate,
500 .enable = sh7722_siu_enable,
501 .disable = sh7722_siu_disable,
502};
503
504static struct clk_ops sh7722_video_clk_ops = {
505 .recalc = sh7722_video_recalc,
506 .set_rate = sh7722_video_set_rate,
507 .enable = sh7722_video_enable,
508 .disable = sh7722_video_disable,
509};
510/*
511 * and at last, clock definitions themselves
512 */
513static struct clk sh7722_umem_clock = {
514 .name = "umem_clk",
515 .ops = &sh7722_frqcr_clk_ops,
516};
517
518static struct clk sh7722_sh_clock = {
519 .name = "sh_clk",
520 .ops = &sh7722_frqcr_clk_ops,
521};
522
523static struct clk sh7722_peripheral_clock = {
524 .name = "peripheral_clk",
525 .ops = &sh7722_frqcr_clk_ops,
526};
527
528static struct clk sh7722_sdram_clock = {
529 .name = "sdram_clk",
530 .ops = &sh7722_frqcr_clk_ops,
531};
532
533/*
534 * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops
535 * methods of clk_ops determine which register they should access by
536 * examining clk->name field
537 */
538static struct clk sh7722_siu_a_clock = {
539 .name = "siu_a_clk",
540 .ops = &sh7722_siu_clk_ops,
541};
542
543static struct clk sh7722_siu_b_clock = {
544 .name = "siu_b_clk",
545 .ops = &sh7722_siu_clk_ops,
546};
547
548static struct clk sh7722_irda_clock = {
549 .name = "irda_clk",
550 .ops = &sh7722_siu_clk_ops,
551};
552
553static struct clk sh7722_video_clock = {
554 .name = "video_clk",
555 .ops = &sh7722_video_clk_ops,
556};
557
558static struct clk *sh7722_clocks[] = {
559 &sh7722_umem_clock,
560 &sh7722_sh_clock,
561 &sh7722_peripheral_clock,
562 &sh7722_sdram_clock,
563 &sh7722_siu_a_clock,
564 &sh7722_siu_b_clock,
565 &sh7722_irda_clock,
566 &sh7722_video_clock,
567};
568
569/*
570 * init in order: master, module, bus, cpu
571 */
572struct clk_ops *onchip_ops[] = {
573 &sh7722_master_clk_ops,
574 &sh7722_frqcr_clk_ops,
575 &sh7722_frqcr_clk_ops,
576 &sh7722_frqcr_clk_ops,
577};
578
579void __init
580arch_init_clk_ops(struct clk_ops **ops, int type)
581{
582 BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops));
583 *ops = onchip_ops[type];
584}
585
586int __init sh7722_clock_init(void)
587{
588 struct clk *master;
589 int i;
590
591 master = clk_get(NULL, "master_clk");
592 for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) {
593 pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
594 sh7722_clocks[i]->parent = master;
595 clk_register(sh7722_clocks[i]);
596 }
597 clk_put(master);
598 return 0;
599}
600arch_initcall(sh7722_clock_init);
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
new file mode 100644
index 000000000000..805535aa505e
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -0,0 +1,162 @@
1/*
2 * arch/sh/kernel/cpu/sh4a/clock-sh7785.c
3 *
4 * SH7785 support for the clock framework
5 *
6 * Copyright (C) 2007 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
18static int ifc_divisors[] = { 1, 2, 4, 6 };
19static int ufc_divisors[] = { 1, 1, 4, 6 };
20static int sfc_divisors[] = { 1, 1, 4, 6 };
21static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18,
22 24, 32, 36, 48, 1, 1, 1, 1 };
23static int mfc_divisors[] = { 1, 1, 4, 6 };
24static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18,
25 24, 32, 36, 48, 1, 1, 1, 1 };
26
27static void master_clk_init(struct clk *clk)
28{
29 clk->rate *= 36;
30}
31
32static struct clk_ops sh7785_master_clk_ops = {
33 .init = master_clk_init,
34};
35
36static void module_clk_recalc(struct clk *clk)
37{
38 int idx = (ctrl_inl(FRQMR1) & 0x000f);
39 clk->rate = clk->parent->rate / pfc_divisors[idx];
40}
41
42static struct clk_ops sh7785_module_clk_ops = {
43 .recalc = module_clk_recalc,
44};
45
46static void bus_clk_recalc(struct clk *clk)
47{
48 int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
49 clk->rate = clk->parent->rate / bfc_divisors[idx];
50}
51
52static struct clk_ops sh7785_bus_clk_ops = {
53 .recalc = bus_clk_recalc,
54};
55
56static void cpu_clk_recalc(struct clk *clk)
57{
58 int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
59 clk->rate = clk->parent->rate / ifc_divisors[idx];
60}
61
62static struct clk_ops sh7785_cpu_clk_ops = {
63 .recalc = cpu_clk_recalc,
64};
65
66static struct clk_ops *sh7785_clk_ops[] = {
67 &sh7785_master_clk_ops,
68 &sh7785_module_clk_ops,
69 &sh7785_bus_clk_ops,
70 &sh7785_cpu_clk_ops,
71};
72
73void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
74{
75 if (idx < ARRAY_SIZE(sh7785_clk_ops))
76 *ops = sh7785_clk_ops[idx];
77}
78
79static void shyway_clk_recalc(struct clk *clk)
80{
81 int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
82 clk->rate = clk->parent->rate / sfc_divisors[idx];
83}
84
85static struct clk_ops sh7785_shyway_clk_ops = {
86 .recalc = shyway_clk_recalc,
87};
88
89static struct clk sh7785_shyway_clk = {
90 .name = "shyway_clk",
91 .flags = CLK_ALWAYS_ENABLED,
92 .ops = &sh7785_shyway_clk_ops,
93};
94
95static void ddr_clk_recalc(struct clk *clk)
96{
97 int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
98 clk->rate = clk->parent->rate / mfc_divisors[idx];
99}
100
101static struct clk_ops sh7785_ddr_clk_ops = {
102 .recalc = ddr_clk_recalc,
103};
104
105static struct clk sh7785_ddr_clk = {
106 .name = "ddr_clk",
107 .flags = CLK_ALWAYS_ENABLED,
108 .ops = &sh7785_ddr_clk_ops,
109};
110
111static void ram_clk_recalc(struct clk *clk)
112{
113 int idx = ((ctrl_inl(FRQMR1) >> 24) & 0x0003);
114 clk->rate = clk->parent->rate / ufc_divisors[idx];
115}
116
117static struct clk_ops sh7785_ram_clk_ops = {
118 .recalc = ram_clk_recalc,
119};
120
121static struct clk sh7785_ram_clk = {
122 .name = "ram_clk",
123 .flags = CLK_ALWAYS_ENABLED,
124 .ops = &sh7785_ram_clk_ops,
125};
126
127/*
128 * Additional SH7785-specific on-chip clocks that aren't already part of the
129 * clock framework
130 */
131static struct clk *sh7785_onchip_clocks[] = {
132 &sh7785_shyway_clk,
133 &sh7785_ddr_clk,
134 &sh7785_ram_clk,
135};
136
137static int __init sh7785_clk_init(void)
138{
139 struct clk *clk = clk_get(NULL, "master_clk");
140 int i;
141
142 for (i = 0; i < ARRAY_SIZE(sh7785_onchip_clocks); i++) {
143 struct clk *clkp = sh7785_onchip_clocks[i];
144
145 clkp->parent = clk;
146 clk_register(clkp);
147 clk_enable(clkp);
148 }
149
150 /*
151 * Now that we have the rest of the clocks registered, we need to
152 * force the parent clock to propagate so that these clocks will
153 * automatically figure out their rate. We cheat by handing the
154 * parent clock its current rate and forcing child propagation.
155 */
156 clk_set_rate(clk, clk_get_rate(clk));
157
158 clk_put(clk);
159
160 return 0;
161}
162arch_initcall(sh7785_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
new file mode 100644
index 000000000000..07b0de82cfe6
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -0,0 +1,103 @@
1/*
2 * SH7785 Setup
3 *
4 * Copyright (C) 2007 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xffea0000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 40, 41, 43, 42 },
21 }, {
22 .mapbase = 0xffeb0000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 44, 45, 47, 46 },
26 },
27
28 /*
29 * The rest of these all have multiplexed IRQs
30 */
31 {
32 .mapbase = 0xffec0000,
33 .flags = UPF_BOOT_AUTOCONF,
34 .type = PORT_SCIF,
35 .irqs = { 60, 60, 60, 60 },
36 }, {
37 .mapbase = 0xffed0000,
38 .flags = UPF_BOOT_AUTOCONF,
39 .type = PORT_SCIF,
40 .irqs = { 61, 61, 61, 61 },
41 }, {
42 .mapbase = 0xffee0000,
43 .flags = UPF_BOOT_AUTOCONF,
44 .type = PORT_SCIF,
45 .irqs = { 62, 62, 62, 62 },
46 }, {
47 .mapbase = 0xffef0000,
48 .flags = UPF_BOOT_AUTOCONF,
49 .type = PORT_SCIF,
50 .irqs = { 63, 63, 63, 63 },
51 }, {
52 .flags = 0,
53 }
54};
55
56static struct platform_device sci_device = {
57 .name = "sh-sci",
58 .id = -1,
59 .dev = {
60 .platform_data = sci_platform_data,
61 },
62};
63
64static struct platform_device *sh7785_devices[] __initdata = {
65 &sci_device,
66};
67
68static int __init sh7785_devices_setup(void)
69{
70 return platform_add_devices(sh7785_devices,
71 ARRAY_SIZE(sh7785_devices));
72}
73__initcall(sh7785_devices_setup);
74
75static struct intc2_data intc2_irq_table[] = {
76 { 28, 0, 24, 0, 0, 2 }, /* TMU0 */
77
78 { 40, 8, 24, 0, 2, 3 }, /* SCIF0 ERI */
79 { 41, 8, 24, 0, 2, 3 }, /* SCIF0 RXI */
80 { 42, 8, 24, 0, 2, 3 }, /* SCIF0 BRI */
81 { 43, 8, 24, 0, 2, 3 }, /* SCIF0 TXI */
82
83 { 44, 8, 16, 0, 3, 3 }, /* SCIF1 ERI */
84 { 45, 8, 16, 0, 3, 3 }, /* SCIF1 RXI */
85 { 46, 8, 16, 0, 3, 3 }, /* SCIF1 BRI */
86 { 47, 8, 16, 0, 3, 3 }, /* SCIF1 TXI */
87
88 { 64, 0x14, 8, 0, 14, 2 }, /* PCIC0 */
89 { 65, 0x14, 0, 0, 15, 2 }, /* PCIC1 */
90 { 66, 0x18, 24, 0, 16, 2 }, /* PCIC2 */
91 { 67, 0x18, 16, 0, 17, 2 }, /* PCIC3 */
92 { 68, 0x18, 8, 0, 18, 2 }, /* PCIC4 */
93
94 { 60, 8, 8, 0, 4, 3 }, /* SCIF2 ERI, RXI, BRI, TXI */
95 { 60, 8, 0, 0, 5, 3 }, /* SCIF3 ERI, RXI, BRI, TXI */
96 { 60, 12, 24, 0, 6, 3 }, /* SCIF4 ERI, RXI, BRI, TXI */
97 { 60, 12, 16, 0, 7, 3 }, /* SCIF5 ERI, RXI, BRI, TXI */
98};
99
100void __init init_IRQ_intc2(void)
101{
102 make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
103}