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/Makefile1
-rw-r--r--arch/sh/kernel/cpu/clock.c19
-rw-r--r--arch/sh/kernel/cpu/init.c21
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile5
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c6
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c14
-rw-r--r--arch/sh/kernel/cpu/irq/maskreg.c93
-rw-r--r--arch/sh/kernel/cpu/irq/pint.c8
-rw-r--r--arch/sh/kernel/cpu/rtc.c128
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile13
-rw-r--r--arch/sh/kernel/cpu/sh3/clock-sh7706.c84
-rw-r--r--arch/sh/kernel/cpu/sh3/ex.S54
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c6
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7300.c43
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c48
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7708.c43
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c53
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile10
-rw-r--r--arch/sh/kernel/cpu/sh4/ex.S176
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c138
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh4-202.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh73180.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7343.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c48
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7770.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7780.c79
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c543
29 files changed, 1433 insertions, 478 deletions
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 59d5b748752f..fb5dac069382 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -8,6 +8,5 @@ obj-$(CONFIG_CPU_SH2) += sh2/
8obj-$(CONFIG_CPU_SH3) += sh3/ 8obj-$(CONFIG_CPU_SH3) += sh3/
9obj-$(CONFIG_CPU_SH4) += sh4/ 9obj-$(CONFIG_CPU_SH4) += sh4/
10 10
11obj-$(CONFIG_SH_RTC) += rtc.o
12obj-$(CONFIG_UBC_WAKEUP) += ubc.o 11obj-$(CONFIG_UBC_WAKEUP) += ubc.o
13obj-$(CONFIG_SH_ADC) += adc.o 12obj-$(CONFIG_SH_ADC) += adc.o
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 97fa37f42b84..51ec64cdf348 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 Paul Mundt 4 * Copyright (C) 2005, 2006 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 *
@@ -15,6 +15,7 @@
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/mutex.h>
18#include <linux/list.h> 19#include <linux/list.h>
19#include <linux/kref.h> 20#include <linux/kref.h>
20#include <linux/seq_file.h> 21#include <linux/seq_file.h>
@@ -24,7 +25,7 @@
24 25
25static LIST_HEAD(clock_list); 26static LIST_HEAD(clock_list);
26static DEFINE_SPINLOCK(clock_lock); 27static DEFINE_SPINLOCK(clock_lock);
27static DECLARE_MUTEX(clock_list_sem); 28static DEFINE_MUTEX(clock_list_sem);
28 29
29/* 30/*
30 * Each subtype is expected to define the init routines for these clocks, 31 * Each subtype is expected to define the init routines for these clocks,
@@ -140,21 +141,21 @@ void clk_disable(struct clk *clk)
140 141
141int clk_register(struct clk *clk) 142int clk_register(struct clk *clk)
142{ 143{
143 down(&clock_list_sem); 144 mutex_lock(&clock_list_sem);
144 145
145 list_add(&clk->node, &clock_list); 146 list_add(&clk->node, &clock_list);
146 kref_init(&clk->kref); 147 kref_init(&clk->kref);
147 148
148 up(&clock_list_sem); 149 mutex_unlock(&clock_list_sem);
149 150
150 return 0; 151 return 0;
151} 152}
152 153
153void clk_unregister(struct clk *clk) 154void clk_unregister(struct clk *clk)
154{ 155{
155 down(&clock_list_sem); 156 mutex_lock(&clock_list_sem);
156 list_del(&clk->node); 157 list_del(&clk->node);
157 up(&clock_list_sem); 158 mutex_unlock(&clock_list_sem);
158} 159}
159 160
160inline unsigned long clk_get_rate(struct clk *clk) 161inline unsigned long clk_get_rate(struct clk *clk)
@@ -198,14 +199,14 @@ struct clk *clk_get(const char *id)
198{ 199{
199 struct clk *p, *clk = ERR_PTR(-ENOENT); 200 struct clk *p, *clk = ERR_PTR(-ENOENT);
200 201
201 down(&clock_list_sem); 202 mutex_lock(&clock_list_sem);
202 list_for_each_entry(p, &clock_list, node) { 203 list_for_each_entry(p, &clock_list, node) {
203 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { 204 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
204 clk = p; 205 clk = p;
205 break; 206 break;
206 } 207 }
207 } 208 }
208 up(&clock_list_sem); 209 mutex_unlock(&clock_list_sem);
209 210
210 return clk; 211 return clk;
211} 212}
@@ -225,7 +226,7 @@ int __init clk_init(void)
225{ 226{
226 int i, ret = 0; 227 int i, ret = 0;
227 228
228 BUG_ON(unlikely(!master_clk.rate)); 229 BUG_ON(!master_clk.rate);
229 230
230 for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) { 231 for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
231 struct clk *clk = onchip_clocks[i]; 232 struct clk *clk = onchip_clocks[i];
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 868e68b28880..bfb90eb0b7a6 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -4,6 +4,7 @@
4 * CPU init code 4 * CPU init code
5 * 5 *
6 * Copyright (C) 2002, 2003 Paul Mundt 6 * Copyright (C) 2002, 2003 Paul Mundt
7 * Copyright (C) 2003 Richard Curnow
7 * 8 *
8 * This file is subject to the terms and conditions of the GNU General Public 9 * 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 * License. See the file "COPYING" in the main directory of this archive
@@ -13,6 +14,7 @@
13#include <linux/kernel.h> 14#include <linux/kernel.h>
14#include <asm/processor.h> 15#include <asm/processor.h>
15#include <asm/uaccess.h> 16#include <asm/uaccess.h>
17#include <asm/page.h>
16#include <asm/system.h> 18#include <asm/system.h>
17#include <asm/cacheflush.h> 19#include <asm/cacheflush.h>
18#include <asm/cache.h> 20#include <asm/cache.h>
@@ -51,7 +53,15 @@ static void __init cache_init(void)
51 ccr = ctrl_inl(CCR); 53 ccr = ctrl_inl(CCR);
52 54
53 /* 55 /*
54 * If the cache is already enabled .. flush it. 56 * At this point we don't know whether the cache is enabled or not - a
57 * bootloader may have enabled it. There are at least 2 things that
58 * could be dirty in the cache at this point:
59 * 1. kernel command line set up by boot loader
60 * 2. spilled registers from the prolog of this function
61 * => before re-initialising the cache, we must do a purge of the whole
62 * cache out to memory for safety. As long as nothing is spilled
63 * during the loop to lines that have already been done, this is safe.
64 * - RPC
55 */ 65 */
56 if (ccr & CCR_CACHE_ENABLE) { 66 if (ccr & CCR_CACHE_ENABLE) {
57 unsigned long ways, waysize, addrstart; 67 unsigned long ways, waysize, addrstart;
@@ -98,6 +108,8 @@ static void __init cache_init(void)
98 /* Force EMODE if possible */ 108 /* Force EMODE if possible */
99 if (cpu_data->dcache.ways > 1) 109 if (cpu_data->dcache.ways > 1)
100 flags |= CCR_CACHE_EMODE; 110 flags |= CCR_CACHE_EMODE;
111 else
112 flags &= ~CCR_CACHE_EMODE;
101#endif 113#endif
102 114
103#ifdef CONFIG_SH_WRITETHROUGH 115#ifdef CONFIG_SH_WRITETHROUGH
@@ -112,6 +124,9 @@ static void __init cache_init(void)
112 /* Turn on OCRAM -- halve the OC */ 124 /* Turn on OCRAM -- halve the OC */
113 flags |= CCR_CACHE_ORA; 125 flags |= CCR_CACHE_ORA;
114 cpu_data->dcache.sets >>= 1; 126 cpu_data->dcache.sets >>= 1;
127
128 cpu_data->dcache.way_size = cpu_data->dcache.sets *
129 cpu_data->dcache.linesz;
115#endif 130#endif
116 131
117 ctrl_outl(flags, CCR); 132 ctrl_outl(flags, CCR);
@@ -184,6 +199,10 @@ asmlinkage void __init sh_cpu_init(void)
184 /* Init the cache */ 199 /* Init the cache */
185 cache_init(); 200 cache_init();
186 201
202 shm_align_mask = max_t(unsigned long,
203 cpu_data->dcache.way_size - 1,
204 PAGE_SIZE - 1);
205
187 /* Disable the FPU */ 206 /* Disable the FPU */
188 if (fpu_disabled) { 207 if (fpu_disabled) {
189 printk("FPU Disabled\n"); 208 printk("FPU Disabled\n");
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index e3cccea15e1d..1c034c283f59 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -3,5 +3,6 @@
3# 3#
4obj-y += ipr.o imask.o 4obj-y += ipr.o imask.o
5 5
6obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o 6obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
7obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o 7obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
8obj-$(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 30064bf6e154..e30e4b7aa70e 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -241,9 +241,9 @@ static struct intc2_init {
241 /* 110-111 reserved/unused */ 241 /* 110-111 reserved/unused */
242#elif defined(CONFIG_CPU_SUBTYPE_SH7780) 242#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
243 { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2}, 243 { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2},
244#ifdef CONFIG_SH_RTC 244 { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY },
245 { RTC_IRQ, 4, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY }, 245 { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY },
246#endif 246 { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY },
247 { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, 247 { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
248 { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, 248 { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
249 { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY }, 249 { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 0f545941fb4f..f785822cd5de 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -57,31 +57,27 @@ static struct hw_interrupt_type ipr_irq_type = {
57 57
58static void disable_ipr_irq(unsigned int irq) 58static void disable_ipr_irq(unsigned int irq)
59{ 59{
60 unsigned long val, flags; 60 unsigned long val;
61 unsigned int addr = ipr_data[irq].addr; 61 unsigned int addr = ipr_data[irq].addr;
62 unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift); 62 unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
63 63
64 /* Set the priority in IPR to 0 */ 64 /* Set the priority in IPR to 0 */
65 local_irq_save(flags);
66 val = ctrl_inw(addr); 65 val = ctrl_inw(addr);
67 val &= mask; 66 val &= mask;
68 ctrl_outw(val, addr); 67 ctrl_outw(val, addr);
69 local_irq_restore(flags);
70} 68}
71 69
72static void enable_ipr_irq(unsigned int irq) 70static void enable_ipr_irq(unsigned int irq)
73{ 71{
74 unsigned long val, flags; 72 unsigned long val;
75 unsigned int addr = ipr_data[irq].addr; 73 unsigned int addr = ipr_data[irq].addr;
76 int priority = ipr_data[irq].priority; 74 int priority = ipr_data[irq].priority;
77 unsigned short value = (priority << ipr_data[irq].shift); 75 unsigned short value = (priority << ipr_data[irq].shift);
78 76
79 /* Set priority in IPR back to original value */ 77 /* Set priority in IPR back to original value */
80 local_irq_save(flags);
81 val = ctrl_inw(addr); 78 val = ctrl_inw(addr);
82 val |= value; 79 val |= value;
83 ctrl_outw(val, addr); 80 ctrl_outw(val, addr);
84 local_irq_restore(flags);
85} 81}
86 82
87static void mask_and_ack_ipr(unsigned int irq) 83static void mask_and_ack_ipr(unsigned int irq)
@@ -89,6 +85,7 @@ static void mask_and_ack_ipr(unsigned int irq)
89 disable_ipr_irq(irq); 85 disable_ipr_irq(irq);
90 86
91#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ 87#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
88 defined(CONFIG_CPU_SUBTYPE_SH7706) || \
92 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) 89 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
93 /* This is needed when we use edge triggered setting */ 90 /* This is needed when we use edge triggered setting */
94 /* XXX: Is it really needed? */ 91 /* XXX: Is it really needed? */
@@ -123,7 +120,7 @@ void __init init_IRQ(void)
123#ifndef CONFIG_CPU_SUBTYPE_SH7780 120#ifndef CONFIG_CPU_SUBTYPE_SH7780
124 make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); 121 make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
125 make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); 122 make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY);
126#if defined(CONFIG_SH_RTC) 123#ifdef RTC_IRQ
127 make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); 124 make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
128#endif 125#endif
129 126
@@ -162,6 +159,7 @@ void __init init_IRQ(void)
162#endif 159#endif
163 160
164#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ 161#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
162 defined(CONFIG_CPU_SUBTYPE_SH7706) || \
165 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) 163 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
166 /* 164 /*
167 * Initialize the Interrupt Controller (INTC) 165 * Initialize the Interrupt Controller (INTC)
@@ -192,6 +190,8 @@ void __init init_IRQ(void)
192 /* Perform the machine specific initialisation */ 190 /* Perform the machine specific initialisation */
193 if (sh_mv.mv_init_irq != NULL) 191 if (sh_mv.mv_init_irq != NULL)
194 sh_mv.mv_init_irq(); 192 sh_mv.mv_init_irq();
193
194 irq_ctx_init(smp_processor_id());
195} 195}
196 196
197#if !defined(CONFIG_CPU_HAS_PINT_IRQ) 197#if !defined(CONFIG_CPU_HAS_PINT_IRQ)
diff --git a/arch/sh/kernel/cpu/irq/maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c
new file mode 100644
index 000000000000..492db31b3cab
--- /dev/null
+++ b/arch/sh/kernel/cpu/irq/maskreg.c
@@ -0,0 +1,93 @@
1/*
2 * Interrupt handling for Simple external interrupt mask register
3 *
4 * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp>
5 *
6 * This is for the machine which have single 16 bit register
7 * for masking external IRQ individually.
8 * Each bit of the register is for masking each interrupt.
9 *
10 * This file may be copied or modified under the terms of the GNU
11 * General Public License. See linux/COPYING for more information.
12 */
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/irq.h>
16#include <asm/system.h>
17#include <asm/io.h>
18
19/* address of external interrupt mask register */
20unsigned long irq_mask_register;
21
22/* forward declaration */
23static unsigned int startup_maskreg_irq(unsigned int irq);
24static void shutdown_maskreg_irq(unsigned int irq);
25static void enable_maskreg_irq(unsigned int irq);
26static void disable_maskreg_irq(unsigned int irq);
27static void mask_and_ack_maskreg(unsigned int);
28static void end_maskreg_irq(unsigned int irq);
29
30/* hw_interrupt_type */
31static struct hw_interrupt_type maskreg_irq_type = {
32 .typename = "Mask Register",
33 .startup = startup_maskreg_irq,
34 .shutdown = shutdown_maskreg_irq,
35 .enable = enable_maskreg_irq,
36 .disable = disable_maskreg_irq,
37 .ack = mask_and_ack_maskreg,
38 .end = end_maskreg_irq
39};
40
41/* actual implementatin */
42static unsigned int startup_maskreg_irq(unsigned int irq)
43{
44 enable_maskreg_irq(irq);
45 return 0; /* never anything pending */
46}
47
48static void shutdown_maskreg_irq(unsigned int irq)
49{
50 disable_maskreg_irq(irq);
51}
52
53static void disable_maskreg_irq(unsigned int irq)
54{
55 unsigned short val, mask = 0x01 << irq;
56
57 BUG_ON(!irq_mask_register);
58
59 /* Set "irq"th bit */
60 val = ctrl_inw(irq_mask_register);
61 val |= mask;
62 ctrl_outw(val, irq_mask_register);
63}
64
65static void enable_maskreg_irq(unsigned int irq)
66{
67 unsigned short val, mask = ~(0x01 << irq);
68
69 BUG_ON(!irq_mask_register);
70
71 /* Clear "irq"th bit */
72 val = ctrl_inw(irq_mask_register);
73 val &= mask;
74 ctrl_outw(val, irq_mask_register);
75}
76
77static void mask_and_ack_maskreg(unsigned int irq)
78{
79 disable_maskreg_irq(irq);
80}
81
82static void end_maskreg_irq(unsigned int irq)
83{
84 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
85 enable_maskreg_irq(irq);
86}
87
88void make_maskreg_irq(unsigned int irq)
89{
90 disable_irq_nosync(irq);
91 irq_desc[irq].handler = &maskreg_irq_type;
92 disable_maskreg_irq(irq);
93}
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
index 80cd8108d36a..17f47b373d6e 100644
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ b/arch/sh/kernel/cpu/irq/pint.c
@@ -48,26 +48,22 @@ static struct hw_interrupt_type pint_irq_type = {
48 48
49static void disable_pint_irq(unsigned int irq) 49static void disable_pint_irq(unsigned int irq)
50{ 50{
51 unsigned long val, flags; 51 unsigned long val;
52 52
53 local_irq_save(flags);
54 val = ctrl_inw(INTC_INTER); 53 val = ctrl_inw(INTC_INTER);
55 val &= ~(1 << (irq - PINT_IRQ_BASE)); 54 val &= ~(1 << (irq - PINT_IRQ_BASE));
56 ctrl_outw(val, INTC_INTER); /* disable PINTn */ 55 ctrl_outw(val, INTC_INTER); /* disable PINTn */
57 portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2); 56 portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
58 local_irq_restore(flags);
59} 57}
60 58
61static void enable_pint_irq(unsigned int irq) 59static void enable_pint_irq(unsigned int irq)
62{ 60{
63 unsigned long val, flags; 61 unsigned long val;
64 62
65 local_irq_save(flags);
66 val = ctrl_inw(INTC_INTER); 63 val = ctrl_inw(INTC_INTER);
67 val |= 1 << (irq - PINT_IRQ_BASE); 64 val |= 1 << (irq - PINT_IRQ_BASE);
68 ctrl_outw(val, INTC_INTER); /* enable PINTn */ 65 ctrl_outw(val, INTC_INTER); /* enable PINTn */
69 portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2; 66 portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
70 local_irq_restore(flags);
71} 67}
72 68
73static void mask_and_ack_pint(unsigned int irq) 69static void mask_and_ack_pint(unsigned int irq)
diff --git a/arch/sh/kernel/cpu/rtc.c b/arch/sh/kernel/cpu/rtc.c
deleted file mode 100644
index 4304cf75cfa2..000000000000
--- a/arch/sh/kernel/cpu/rtc.c
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support
3 *
4 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
5 * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
6 */
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/time.h>
12#include <linux/bcd.h>
13#include <asm/io.h>
14#include <asm/rtc.h>
15
16void sh_rtc_gettimeofday(struct timespec *ts)
17{
18 unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit;
19 unsigned long flags;
20
21 again:
22 do {
23 local_irq_save(flags);
24 ctrl_outb(0, RCR1); /* Clear CF-bit */
25 sec128 = ctrl_inb(R64CNT);
26 sec = ctrl_inb(RSECCNT);
27 min = ctrl_inb(RMINCNT);
28 hr = ctrl_inb(RHRCNT);
29 wk = ctrl_inb(RWKCNT);
30 day = ctrl_inb(RDAYCNT);
31 mon = ctrl_inb(RMONCNT);
32#if defined(CONFIG_CPU_SH4)
33 yr = ctrl_inw(RYRCNT);
34 yr100 = (yr >> 8);
35 yr &= 0xff;
36#else
37 yr = ctrl_inb(RYRCNT);
38 yr100 = (yr == 0x99) ? 0x19 : 0x20;
39#endif
40 sec2 = ctrl_inb(R64CNT);
41 cf_bit = ctrl_inb(RCR1) & RCR1_CF;
42 local_irq_restore(flags);
43 } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
44
45 BCD_TO_BIN(yr100);
46 BCD_TO_BIN(yr);
47 BCD_TO_BIN(mon);
48 BCD_TO_BIN(day);
49 BCD_TO_BIN(hr);
50 BCD_TO_BIN(min);
51 BCD_TO_BIN(sec);
52
53 if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
54 hr > 23 || min > 59 || sec > 59) {
55 printk(KERN_ERR
56 "SH RTC: invalid value, resetting to 1 Jan 2000\n");
57 local_irq_save(flags);
58 ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */
59 ctrl_outb(0, RSECCNT);
60 ctrl_outb(0, RMINCNT);
61 ctrl_outb(0, RHRCNT);
62 ctrl_outb(6, RWKCNT);
63 ctrl_outb(1, RDAYCNT);
64 ctrl_outb(1, RMONCNT);
65#if defined(CONFIG_CPU_SH4)
66 ctrl_outw(0x2000, RYRCNT);
67#else
68 ctrl_outb(0, RYRCNT);
69#endif
70 ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */
71 goto again;
72 }
73
74#if RTC_BIT_INVERTED != 0
75 if ((sec128 & RTC_BIT_INVERTED))
76 sec--;
77#endif
78
79 ts->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
80 ts->tv_nsec = ((sec128 * 1000000) / 128) * 1000;
81}
82
83/*
84 * Changed to only care about tv_sec, and not the full timespec struct
85 * (i.e. tv_nsec). It can easily be switched to timespec for future cpus
86 * that support setting usec or nsec RTC values.
87 */
88int sh_rtc_settimeofday(const time_t secs)
89{
90 int retval = 0;
91 int real_seconds, real_minutes, cmos_minutes;
92 unsigned long flags;
93
94 local_irq_save(flags);
95 ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */
96
97 cmos_minutes = ctrl_inb(RMINCNT);
98 BCD_TO_BIN(cmos_minutes);
99
100 /*
101 * since we're only adjusting minutes and seconds,
102 * don't interfere with hour overflow. This avoids
103 * messing with unknown time zones but requires your
104 * RTC not to be off by more than 15 minutes
105 */
106 real_seconds = secs % 60;
107 real_minutes = secs / 60;
108 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
109 real_minutes += 30; /* correct for half hour time zone */
110 real_minutes %= 60;
111
112 if (abs(real_minutes - cmos_minutes) < 30) {
113 BIN_TO_BCD(real_seconds);
114 BIN_TO_BCD(real_minutes);
115 ctrl_outb(real_seconds, RSECCNT);
116 ctrl_outb(real_minutes, RMINCNT);
117 } else {
118 printk(KERN_WARNING
119 "set_rtc_time: can't update from %d to %d\n",
120 cmos_minutes, real_minutes);
121 retval = -1;
122 }
123
124 ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */
125 local_irq_restore(flags);
126
127 return retval;
128}
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index b54dbb9a0c86..58d3815695ff 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -4,10 +4,21 @@
4 4
5obj-y := ex.o probe.o 5obj-y := ex.o probe.o
6 6
7# CPU subtype setup
8obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o
9obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o
10obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o
11obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
12obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
13obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o
14obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
15
16# Primary on-chip clocks (common)
7clock-$(CONFIG_CPU_SH3) := clock-sh3.o 17clock-$(CONFIG_CPU_SH3) := clock-sh3.o
8clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o 18clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o
9clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o 19clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o
20clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o
10clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o 21clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o
22clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7300.o
11 23
12obj-y += $(clock-y) 24obj-y += $(clock-y)
13
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7706.c b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
new file mode 100644
index 000000000000..0cf96f9833bc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
@@ -0,0 +1,84 @@
1/*
2 * arch/sh/kernel/cpu/sh3/clock-sh7706.c
3 *
4 * SH7706 support for the clock framework
5 *
6 * Copyright (C) 2006 Takashi YOSHII
7 *
8 * Based on arch/sh/kernel/cpu/sh3/clock-sh7709.c
9 * Copyright (C) 2005 Andriy Skulysh
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
21static int stc_multipliers[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
22static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
23static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
24
25static void master_clk_init(struct clk *clk)
26{
27 int frqcr = ctrl_inw(FRQCR);
28 int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
29
30 clk->rate *= pfc_divisors[idx];
31}
32
33static struct clk_ops sh7706_master_clk_ops = {
34 .init = master_clk_init,
35};
36
37static void module_clk_recalc(struct clk *clk)
38{
39 int frqcr = ctrl_inw(FRQCR);
40 int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
41
42 clk->rate = clk->parent->rate / pfc_divisors[idx];
43}
44
45static struct clk_ops sh7706_module_clk_ops = {
46 .recalc = module_clk_recalc,
47};
48
49static void bus_clk_recalc(struct clk *clk)
50{
51 int frqcr = ctrl_inw(FRQCR);
52 int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
53
54 clk->rate = clk->parent->rate / stc_multipliers[idx];
55}
56
57static struct clk_ops sh7706_bus_clk_ops = {
58 .recalc = bus_clk_recalc,
59};
60
61static void cpu_clk_recalc(struct clk *clk)
62{
63 int frqcr = ctrl_inw(FRQCR);
64 int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
65
66 clk->rate = clk->parent->rate / ifc_divisors[idx];
67}
68
69static struct clk_ops sh7706_cpu_clk_ops = {
70 .recalc = cpu_clk_recalc,
71};
72
73static struct clk_ops *sh7706_clk_ops[] = {
74 &sh7706_master_clk_ops,
75 &sh7706_module_clk_ops,
76 &sh7706_bus_clk_ops,
77 &sh7706_cpu_clk_ops,
78};
79
80void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
81{
82 if (idx < ARRAY_SIZE(sh7706_clk_ops))
83 *ops = sh7706_clk_ops[idx];
84}
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index cc04e9e239ff..44daf44833f9 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -84,8 +84,12 @@ ENTRY(interrupt_table)
84 .long do_IRQ ! rovi 84 .long do_IRQ ! rovi
85 .long do_IRQ 85 .long do_IRQ
86 .long do_IRQ /* 5E0 */ 86 .long do_IRQ /* 5E0 */
87#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ 87#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
88 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) 88 defined(CONFIG_CPU_SUBTYPE_SH7709) || \
89 defined(CONFIG_CPU_SUBTYPE_SH7706) || \
90 defined(CONFIG_CPU_SUBTYPE_SH7300) || \
91 defined(CONFIG_CPU_SUBTYPE_SH7705) || \
92 defined(CONFIG_CPU_SUBTYPE_SH7710)
89 .long do_IRQ ! 32 IRQ irq0 /* 600 */ 93 .long do_IRQ ! 32 IRQ irq0 /* 600 */
90 .long do_IRQ ! 33 irq1 94 .long do_IRQ ! 33 irq1
91 .long do_IRQ ! 34 irq2 95 .long do_IRQ ! 34 irq2
@@ -147,6 +151,51 @@ ENTRY(interrupt_table)
147 .long do_IRQ ! 62 PCC pcc0i 151 .long do_IRQ ! 62 PCC pcc0i
148 .long do_IRQ ! 63 pcc1i /* 9E0 */ 152 .long do_IRQ ! 63 pcc1i /* 9E0 */
149#endif 153#endif
154#if defined(CONFIG_CPU_SUBTYPE_SH7710)
155 .long exception_none ! 61 /* 9A0 */
156 .long exception_none ! 62
157 .long exception_none ! 63
158 .long exception_none ! 64 /* A00 */
159 .long exception_none ! 65
160 .long exception_none ! 66
161 .long exception_none ! 67
162 .long exception_none ! 68
163 .long exception_none ! 69
164 .long exception_none ! 70
165 .long exception_none ! 71
166 .long exception_none ! 72 /* B00 */
167 .long exception_none ! 73
168 .long exception_none ! 74
169 .long exception_none ! 75
170 .long do_IRQ ! 76 DMAC2 dei4 /* B80 */
171 .long do_IRQ ! 77 DMAC2 dei5
172 .long exception_none ! 78
173 .long do_IRQ ! 79 IPSEC ipseci /* BE0 */
174 .long do_IRQ ! 80 EDMAC eint0 /* C00 */
175 .long do_IRQ ! 81 EDMAC eint1
176 .long do_IRQ ! 82 EDMAC eint2
177 .long exception_none ! 83 /* C60 */
178 .long exception_none ! 84
179 .long exception_none ! 85
180 .long exception_none ! 86
181 .long exception_none ! 87
182 .long exception_none ! 88 /* D00 */
183 .long exception_none ! 89
184 .long exception_none ! 90
185 .long exception_none ! 91
186 .long exception_none ! 92
187 .long exception_none ! 93
188 .long exception_none ! 94
189 .long exception_none ! 95
190 .long do_IRQ ! 96 SIOF eri0 /* E00 */
191 .long do_IRQ ! 97 txi0
192 .long do_IRQ ! 98 rxi0
193 .long do_IRQ ! 99 cci0
194 .long do_IRQ ! 100 eri1 /* E80 */
195 .long do_IRQ ! 101 txi1
196 .long do_IRQ ! 102 rxi2
197 .long do_IRQ ! 103 cci3
198#endif
150#if defined(CONFIG_CPU_SUBTYPE_SH7300) 199#if defined(CONFIG_CPU_SUBTYPE_SH7300)
151 .long do_IRQ ! 64 200 .long do_IRQ ! 64
152 .long do_IRQ ! 65 201 .long do_IRQ ! 65
@@ -195,4 +244,3 @@ ENTRY(interrupt_table)
195 .long do_IRQ ! 108 244 .long do_IRQ ! 108
196#endif 245#endif
197#endif 246#endif
198
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 5cdc88638601..e67098836290 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -72,6 +72,12 @@ int __init detect_cpu_and_cache_system(void)
72 cpu_data->dcache.sets = 256; 72 cpu_data->dcache.sets = 256;
73 cpu_data->type = CPU_SH7729; 73 cpu_data->type = CPU_SH7729;
74 74
75#if defined(CONFIG_CPU_SUBTYPE_SH7706)
76 cpu_data->type = CPU_SH7706;
77#endif
78#if defined(CONFIG_CPU_SUBTYPE_SH7710)
79 cpu_data->type = CPU_SH7710;
80#endif
75#if defined(CONFIG_CPU_SUBTYPE_SH7705) 81#if defined(CONFIG_CPU_SUBTYPE_SH7705)
76 cpu_data->type = CPU_SH7705; 82 cpu_data->type = CPU_SH7705;
77 83
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7300.c b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
new file mode 100644
index 000000000000..ab4d204bfba5
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
@@ -0,0 +1,43 @@
1/*
2 * SH7300 Setup
3 *
4 * Copyright (C) 2006 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 = 0xa4430000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 80, 80, 80, 80 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7300_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7300_devices_setup(void)
39{
40 return platform_add_devices(sh7300_devices,
41 ARRAY_SIZE(sh7300_devices));
42}
43__initcall(sh7300_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
new file mode 100644
index 000000000000..a8e41c5241fa
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -0,0 +1,48 @@
1/*
2 * SH7705 Setup
3 *
4 * Copyright (C) 2006 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 = 0xa4400000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 },
21 }, {
22 .mapbase = 0xa4410000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 56, 57, 59, 58 },
26 }, {
27 .flags = 0,
28 }
29};
30
31static struct platform_device sci_device = {
32 .name = "sh-sci",
33 .id = -1,
34 .dev = {
35 .platform_data = sci_platform_data,
36 },
37};
38
39static struct platform_device *sh7705_devices[] __initdata = {
40 &sci_device,
41};
42
43static int __init sh7705_devices_setup(void)
44{
45 return platform_add_devices(sh7705_devices,
46 ARRAY_SIZE(sh7705_devices));
47}
48__initcall(sh7705_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7708.c b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
new file mode 100644
index 000000000000..f933723911ca
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
@@ -0,0 +1,43 @@
1/*
2 * SH7708 Setup
3 *
4 * Copyright (C) 2006 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 = 0xfffffe80,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 23, 24, 25, 0 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7708_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7708_devices_setup(void)
39{
40 return platform_add_devices(sh7708_devices,
41 ARRAY_SIZE(sh7708_devices));
42}
43__initcall(sh7708_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
new file mode 100644
index 000000000000..ff43ef2a1f0c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -0,0 +1,53 @@
1/*
2 * SH7707/SH7709 Setup
3 *
4 * Copyright (C) 2006 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 = 0xfffffe80,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 23, 24, 25, 0 },
21 }, {
22 .mapbase = 0xa4000150,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 56, 57, 59, 58 },
26 }, {
27 .mapbase = 0xa4000140,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_IRDA,
30 .irqs = { 52, 53, 55, 54 },
31 }, {
32 .flags = 0,
33 }
34};
35
36static struct platform_device sci_device = {
37 .name = "sh-sci",
38 .id = -1,
39 .dev = {
40 .platform_data = sci_platform_data,
41 },
42};
43
44static struct platform_device *sh7709_devices[] __initdata = {
45 &sci_device,
46};
47
48static int __init sh7709_devices_setup(void)
49{
50 return platform_add_devices(sh7709_devices,
51 ARRAY_SIZE(sh7709_devices));
52}
53__initcall(sh7709_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
new file mode 100644
index 000000000000..895f99ee6a95
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -0,0 +1,43 @@
1/*
2 * SH7710 Setup
3 *
4 * Copyright (C) 2006 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 = 0xa4400000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7710_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7710_devices_setup(void)
39{
40 return platform_add_devices(sh7710_devices,
41 ARRAY_SIZE(sh7710_devices));
42}
43__initcall(sh7710_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 3d5cafc71ae3..8dbf3895ece7 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -7,6 +7,16 @@ obj-y := ex.o probe.o
7obj-$(CONFIG_SH_FPU) += fpu.o 7obj-$(CONFIG_SH_FPU) += fpu.o
8obj-$(CONFIG_SH_STORE_QUEUES) += sq.o 8obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
9 9
10# CPU subtype setup
11obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
12obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o
13obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o
14obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
15obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
16obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
17obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
18obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o
19
10# Primary on-chip clocks (common) 20# Primary on-chip clocks (common)
11clock-$(CONFIG_CPU_SH4) := clock-sh4.o 21clock-$(CONFIG_CPU_SH4) := clock-sh4.o
12clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o 22clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
index 26a27df06505..7146893a6cca 100644
--- a/arch/sh/kernel/cpu/sh4/ex.S
+++ b/arch/sh/kernel/cpu/sh4/ex.S
@@ -72,6 +72,7 @@ ENTRY(interrupt_table)
72 .long do_IRQ ! 1110 72 .long do_IRQ ! 1110
73 .long exception_error 73 .long exception_error
74 ! Internal hardware 74 ! Internal hardware
75#ifndef CONFIG_CPU_SUBTYPE_SH7780
75 .long do_IRQ ! TMU0 tuni0 /* 400 */ 76 .long do_IRQ ! TMU0 tuni0 /* 400 */
76 .long do_IRQ ! TMU1 tuni1 77 .long do_IRQ ! TMU1 tuni1
77 .long do_IRQ ! TMU2 tuni2 78 .long do_IRQ ! TMU2 tuni2
@@ -122,6 +123,13 @@ ENTRY(interrupt_table)
122 .long do_IRQ ! 45 dmte5 123 .long do_IRQ ! 45 dmte5
123 .long do_IRQ ! 46 dmte6 124 .long do_IRQ ! 46 dmte6
124 .long do_IRQ ! 47 dmte7 /* 7E0 */ 125 .long do_IRQ ! 47 dmte7 /* 7E0 */
126#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
127 .long do_IRQ ! 44 IIC1 ali /* 780 */
128 .long do_IRQ ! 45 tacki
129 .long do_IRQ ! 46 waiti
130 .long do_IRQ ! 47 dtei /* 7E0 */
131 .long do_IRQ ! 48 DMAC dei0 /* 800 */
132 .long do_IRQ ! 49 dei1 /* 820 */
125#else 133#else
126 .long exception_error ! 44 /* 780 */ 134 .long exception_error ! 44 /* 780 */
127 .long exception_error ! 45 135 .long exception_error ! 45
@@ -131,7 +139,8 @@ ENTRY(interrupt_table)
131#if defined(CONFIG_SH_FPU) 139#if defined(CONFIG_SH_FPU)
132 .long do_fpu_state_restore ! 48 /* 800 */ 140 .long do_fpu_state_restore ! 48 /* 800 */
133 .long do_fpu_state_restore ! 49 /* 820 */ 141 .long do_fpu_state_restore ! 49 /* 820 */
134#else 142#elif !defined(CONFIG_CPU_SUBTYPE_SH7343) && \
143 !defined(CONFIG_CPU_SUBTYPE_SH73180)
135 .long exception_error 144 .long exception_error
136 .long exception_error 145 .long exception_error
137#endif 146#endif
@@ -224,7 +233,7 @@ ENTRY(interrupt_table)
224 .long exception_error 233 .long exception_error
225 .long do_IRQ ! ADC adi 234 .long do_IRQ ! ADC adi
226 .long do_IRQ ! CMT cmti /* FA0 */ 235 .long do_IRQ ! CMT cmti /* FA0 */
227#elif defined(CONFIG_CPU_SUBTYPE_SH73180) 236#elif defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7343)
228 .long do_IRQ ! 50 0x840 237 .long do_IRQ ! 50 0x840
229 .long do_IRQ ! 51 0x860 238 .long do_IRQ ! 51 0x860
230 .long do_IRQ ! 52 0x880 239 .long do_IRQ ! 52 0x880
@@ -379,5 +388,168 @@ ENTRY(interrupt_table)
379 .long exception_error ! 141 0x13a0 388 .long exception_error ! 141 0x13a0
380 .long exception_error ! 142 0x13c0 389 .long exception_error ! 142 0x13c0
381 .long exception_error ! 143 0x13e0 390 .long exception_error ! 143 0x13e0
391#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
392 .long do_IRQ ! 50 0x840
393 .long do_IRQ ! 51 0x860
394 .long do_IRQ ! 52 0x880
395 .long do_IRQ ! 53 0x8a0
396 .long do_IRQ ! 54 0x8c0
397 .long do_IRQ ! 55 0x8e0
398 .long do_IRQ ! 56 0x900
399 .long do_IRQ ! 57 0x920
400 .long do_IRQ ! 58 0x940
401 .long do_IRQ ! 59 0x960
402 .long do_IRQ ! 60 0x980
403 .long do_IRQ ! 61 0x9a0
404 .long do_IRQ ! 62 0x9c0
405 .long do_IRQ ! 63 0x9e0
406 .long do_IRQ ! 64 0xa00
407 .long do_IRQ ! 65 0xa20
408 .long do_IRQ ! 66 0xa4d
409 .long do_IRQ ! 67 0xa60
410 .long do_IRQ ! 68 0xa80
411 .long do_IRQ ! 69 0xaa0
412 .long do_IRQ ! 70 0xac0
413 .long do_IRQ ! 71 0xae0
414 .long do_IRQ ! 72 0xb00
415 .long do_IRQ ! 73 0xb20
416 .long do_IRQ ! 74 0xb40
417 .long do_IRQ ! 75 0xb60
418 .long do_IRQ ! 76 0xb80
419 .long do_IRQ ! 77 0xba0
420 .long do_IRQ ! 78 0xbc0
421 .long do_IRQ ! 79 0xbe0
422 .long do_IRQ ! 80 0xc00
423 .long do_IRQ ! 81 0xc20
424 .long do_IRQ ! 82 0xc40
425 .long do_IRQ ! 83 0xc60
426 .long do_IRQ ! 84 0xc80
427 .long do_IRQ ! 85 0xca0
428 .long do_IRQ ! 86 0xcc0
429 .long do_IRQ ! 87 0xce0
430 .long do_IRQ ! 88 0xd00
431 .long do_IRQ ! 89 0xd20
432 .long do_IRQ ! 90 0xd40
433 .long do_IRQ ! 91 0xd60
434 .long do_IRQ ! 92 0xd80
435 .long do_IRQ ! 93 0xda0
436 .long do_IRQ ! 94 0xdc0
437 .long do_IRQ ! 95 0xde0
438 .long do_IRQ ! 96 0xe00
439 .long do_IRQ ! 97 0xe20
440 .long do_IRQ ! 98 0xe40
441 .long do_IRQ ! 99 0xe60
442 .long do_IRQ ! 100 0xe80
443 .long do_IRQ ! 101 0xea0
444 .long do_IRQ ! 102 0xec0
445 .long do_IRQ ! 103 0xee0
446 .long do_IRQ ! 104 0xf00
447 .long do_IRQ ! 105 0xf20
448 .long do_IRQ ! 106 0xf40
449 .long do_IRQ ! 107 0xf60
450 .long do_IRQ ! 108 0xf80
451#endif
452#else
453 .long exception_error /* 400 */
454 .long exception_error
455 .long exception_error
456 .long exception_error
457 .long do_IRQ ! RTC ati
458 .long do_IRQ ! pri
459 .long do_IRQ ! cui
460 .long exception_error
461 .long exception_error /* 500 */
462 .long exception_error
463 .long exception_error
464 .long do_IRQ ! WDT iti /* 560 */
465 .long do_IRQ ! TMU-ch0
466 .long do_IRQ ! TMU-ch1
467 .long do_IRQ ! TMU-ch2
468 .long do_IRQ ! ticpi2 /* 5E0 */
469 .long do_IRQ ! 32 Hitachi UDI /* 600 */
470 .long exception_error
471 .long do_IRQ ! 34 DMAC dmte0
472 .long do_IRQ ! 35 dmte1
473 .long do_IRQ ! 36 dmte2
474 .long do_IRQ ! 37 dmte3
475 .long do_IRQ ! 38 dmae
476 .long exception_error ! 39 /* 6E0 */
477 .long do_IRQ ! 40 SCIF-ch0 eri /* 700 */
478 .long do_IRQ ! 41 rxi
479 .long do_IRQ ! 42 bri
480 .long do_IRQ ! 43 txi
481 .long do_IRQ ! 44 DMAC dmte4 /* 780 */
482 .long do_IRQ ! 45 dmte5
483 .long do_IRQ ! 46 dmte6
484 .long do_IRQ ! 47 dmte7 /* 7E0 */
485#if defined(CONFIG_SH_FPU)
486 .long do_fpu_state_restore ! 48 /* 800 */
487 .long do_fpu_state_restore ! 49 /* 820 */
488#else
489 .long exception_error
490 .long exception_error
491#endif
492 .long exception_error /* 840 */
493 .long exception_error
494 .long exception_error
495 .long exception_error
496 .long exception_error
497 .long exception_error
498 .long do_IRQ ! 56 CMT /* 900 */
499 .long exception_error
500 .long exception_error
501 .long exception_error
502 .long do_IRQ ! 60 HAC
503 .long exception_error
504 .long exception_error
505 .long exception_error
506 .long do_IRQ ! PCI serr /* A00 */
507 .long do_IRQ ! INTA
508 .long do_IRQ ! INTB
509 .long do_IRQ ! INTC
510 .long do_IRQ ! INTD
511 .long do_IRQ ! err
512 .long do_IRQ ! pwd3
513 .long do_IRQ ! pwd2
514 .long do_IRQ ! pwd1 /* B00 */
515 .long do_IRQ ! pwd0
516 .long exception_error
517 .long exception_error
518 .long do_IRQ ! SCIF-ch1 eri /* B80 */
519 .long do_IRQ ! rxi
520 .long do_IRQ ! bri
521 .long do_IRQ ! txi
522 .long do_IRQ ! SIOF /* C00 */
523 .long exception_error
524 .long exception_error
525 .long exception_error
526 .long do_IRQ ! HSPI /* C80 */
527 .long exception_error
528 .long exception_error
529 .long exception_error
530 .long do_IRQ ! MMCIF fatat /* D00 */
531 .long do_IRQ ! tran
532 .long do_IRQ ! err
533 .long do_IRQ ! frdy
534 .long do_IRQ ! DMAC dmint8 /* D80 */
535 .long do_IRQ ! dmint9
536 .long do_IRQ ! dmint10
537 .long do_IRQ ! dmint11
538 .long do_IRQ ! TMU-ch3 /* E00 */
539 .long do_IRQ ! TMU-ch4
540 .long do_IRQ ! TMU-ch5
541 .long exception_error
542 .long do_IRQ ! SSI
543 .long exception_error
544 .long exception_error
545 .long exception_error
546 .long do_IRQ ! FLCTL flste /* F00 */
547 .long do_IRQ ! fltend
548 .long do_IRQ ! fltrq0
549 .long do_IRQ ! fltrq1
550 .long do_IRQ ! GPIO gpioi0 /* F80 */
551 .long do_IRQ ! gpioi1
552 .long do_IRQ ! gpioi2
553 .long do_IRQ ! gpioi3
382#endif 554#endif
383 555
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 42427b79697b..c294de1e14a3 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * CPU Subtype Probing for SH-4. 4 * CPU Subtype Probing for SH-4.
5 * 5 *
6 * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt 6 * Copyright (C) 2001 - 2006 Paul Mundt
7 * Copyright (C) 2003 Richard Curnow 7 * Copyright (C) 2003 Richard Curnow
8 * 8 *
9 * This file is subject to the terms and conditions of the GNU General Public 9 * This file is subject to the terms and conditions of the GNU General Public
@@ -29,7 +29,7 @@ int __init detect_cpu_and_cache_system(void)
29 [9] = (1 << 16) 29 [9] = (1 << 16)
30 }; 30 };
31 31
32 pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff; 32 pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffffff;
33 prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff; 33 prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
34 cvr = (ctrl_inl(CCN_CVR)); 34 cvr = (ctrl_inl(CCN_CVR));
35 35
@@ -38,7 +38,6 @@ int __init detect_cpu_and_cache_system(void)
38 */ 38 */
39 cpu_data->icache.way_incr = (1 << 13); 39 cpu_data->icache.way_incr = (1 << 13);
40 cpu_data->icache.entry_shift = 5; 40 cpu_data->icache.entry_shift = 5;
41 cpu_data->icache.entry_mask = 0x1fe0;
42 cpu_data->icache.sets = 256; 41 cpu_data->icache.sets = 256;
43 cpu_data->icache.ways = 1; 42 cpu_data->icache.ways = 1;
44 cpu_data->icache.linesz = L1_CACHE_BYTES; 43 cpu_data->icache.linesz = L1_CACHE_BYTES;
@@ -48,13 +47,29 @@ int __init detect_cpu_and_cache_system(void)
48 */ 47 */
49 cpu_data->dcache.way_incr = (1 << 14); 48 cpu_data->dcache.way_incr = (1 << 14);
50 cpu_data->dcache.entry_shift = 5; 49 cpu_data->dcache.entry_shift = 5;
51 cpu_data->dcache.entry_mask = 0x3fe0;
52 cpu_data->dcache.sets = 512; 50 cpu_data->dcache.sets = 512;
53 cpu_data->dcache.ways = 1; 51 cpu_data->dcache.ways = 1;
54 cpu_data->dcache.linesz = L1_CACHE_BYTES; 52 cpu_data->dcache.linesz = L1_CACHE_BYTES;
55 53
56 /* Set the FPU flag, virtually all SH-4's have one */ 54 /*
57 cpu_data->flags |= CPU_HAS_FPU; 55 * Setup some generic flags we can probe
56 * (L2 and DSP detection only work on SH-4A)
57 */
58 if (((pvr >> 16) & 0xff) == 0x10) {
59 if ((cvr & 0x02000000) == 0)
60 cpu_data->flags |= CPU_HAS_L2_CACHE;
61 if ((cvr & 0x10000000) == 0)
62 cpu_data->flags |= CPU_HAS_DSP;
63
64 cpu_data->flags |= CPU_HAS_LLSC;
65 }
66
67 /* FPU detection works for everyone */
68 if ((cvr & 0x20000000) == 1)
69 cpu_data->flags |= CPU_HAS_FPU;
70
71 /* Mask off the upper chip ID */
72 pvr &= 0xffff;
58 73
59 /* 74 /*
60 * Probe the underlying processor version/revision and 75 * Probe the underlying processor version/revision and
@@ -63,56 +78,101 @@ int __init detect_cpu_and_cache_system(void)
63 switch (pvr) { 78 switch (pvr) {
64 case 0x205: 79 case 0x205:
65 cpu_data->type = CPU_SH7750; 80 cpu_data->type = CPU_SH7750;
66 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER; 81 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
82 CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
67 break; 83 break;
68 case 0x206: 84 case 0x206:
69 cpu_data->type = CPU_SH7750S; 85 cpu_data->type = CPU_SH7750S;
70 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER; 86 cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
87 CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
71 break; 88 break;
72 case 0x1100: 89 case 0x1100:
73 cpu_data->type = CPU_SH7751; 90 cpu_data->type = CPU_SH7751;
91 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
74 break; 92 break;
75 case 0x2000: 93 case 0x2000:
76 cpu_data->type = CPU_SH73180; 94 cpu_data->type = CPU_SH73180;
77 cpu_data->icache.ways = 4; 95 cpu_data->icache.ways = 4;
78 cpu_data->dcache.ways = 4; 96 cpu_data->dcache.ways = 4;
79 cpu_data->flags &= ~CPU_HAS_FPU; 97 cpu_data->flags |= CPU_HAS_LLSC;
98 break;
99 case 0x2001:
100 case 0x2004:
101 cpu_data->type = CPU_SH7770;
102 cpu_data->icache.ways = 4;
103 cpu_data->dcache.ways = 4;
104
105 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
106 break;
107 case 0x2006:
108 case 0x200A:
109 if (prr == 0x61)
110 cpu_data->type = CPU_SH7781;
111 else
112 cpu_data->type = CPU_SH7780;
113
114 cpu_data->icache.ways = 4;
115 cpu_data->dcache.ways = 4;
116
117 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
118 CPU_HAS_LLSC;
119 break;
120 case 0x3000:
121 case 0x3003:
122 cpu_data->type = CPU_SH7343;
123 cpu_data->icache.ways = 4;
124 cpu_data->dcache.ways = 4;
125 cpu_data->flags |= CPU_HAS_LLSC;
80 break; 126 break;
81 case 0x8000: 127 case 0x8000:
82 cpu_data->type = CPU_ST40RA; 128 cpu_data->type = CPU_ST40RA;
129 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
83 break; 130 break;
84 case 0x8100: 131 case 0x8100:
85 cpu_data->type = CPU_ST40GX1; 132 cpu_data->type = CPU_ST40GX1;
133 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
86 break; 134 break;
87 case 0x700: 135 case 0x700:
88 cpu_data->type = CPU_SH4_501; 136 cpu_data->type = CPU_SH4_501;
89 cpu_data->icache.ways = 2; 137 cpu_data->icache.ways = 2;
90 cpu_data->dcache.ways = 2; 138 cpu_data->dcache.ways = 2;
91 139 cpu_data->flags |= CPU_HAS_PTEA;
92 /* No FPU on the SH4-500 series.. */
93 cpu_data->flags &= ~CPU_HAS_FPU;
94 break; 140 break;
95 case 0x600: 141 case 0x600:
96 cpu_data->type = CPU_SH4_202; 142 cpu_data->type = CPU_SH4_202;
97 cpu_data->icache.ways = 2; 143 cpu_data->icache.ways = 2;
98 cpu_data->dcache.ways = 2; 144 cpu_data->dcache.ways = 2;
145 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
99 break; 146 break;
100 case 0x500 ... 0x501: 147 case 0x500 ... 0x501:
101 switch (prr) { 148 switch (prr) {
102 case 0x10: cpu_data->type = CPU_SH7750R; break; 149 case 0x10:
103 case 0x11: cpu_data->type = CPU_SH7751R; break; 150 cpu_data->type = CPU_SH7750R;
104 case 0x50: cpu_data->type = CPU_SH7760; break; 151 break;
152 case 0x11:
153 cpu_data->type = CPU_SH7751R;
154 break;
155 case 0x50 ... 0x5f:
156 cpu_data->type = CPU_SH7760;
157 break;
105 } 158 }
106 159
107 cpu_data->icache.ways = 2; 160 cpu_data->icache.ways = 2;
108 cpu_data->dcache.ways = 2; 161 cpu_data->dcache.ways = 2;
109 162
163 cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
164
110 break; 165 break;
111 default: 166 default:
112 cpu_data->type = CPU_SH_NONE; 167 cpu_data->type = CPU_SH_NONE;
113 break; 168 break;
114 } 169 }
115 170
171#ifdef CONFIG_SH_DIRECT_MAPPED
172 cpu_data->icache.ways = 1;
173 cpu_data->dcache.ways = 1;
174#endif
175
116 /* 176 /*
117 * On anything that's not a direct-mapped cache, look to the CVR 177 * On anything that's not a direct-mapped cache, look to the CVR
118 * for I/D-cache specifics. 178 * for I/D-cache specifics.
@@ -121,18 +181,56 @@ int __init detect_cpu_and_cache_system(void)
121 size = sizes[(cvr >> 20) & 0xf]; 181 size = sizes[(cvr >> 20) & 0xf];
122 cpu_data->icache.way_incr = (size >> 1); 182 cpu_data->icache.way_incr = (size >> 1);
123 cpu_data->icache.sets = (size >> 6); 183 cpu_data->icache.sets = (size >> 6);
124 cpu_data->icache.entry_mask = 184
125 (cpu_data->icache.way_incr - (1 << 5));
126 } 185 }
127 186
187 /* Setup the rest of the I-cache info */
188 cpu_data->icache.entry_mask = cpu_data->icache.way_incr -
189 cpu_data->icache.linesz;
190
191 cpu_data->icache.way_size = cpu_data->icache.sets *
192 cpu_data->icache.linesz;
193
194 /* And the rest of the D-cache */
128 if (cpu_data->dcache.ways > 1) { 195 if (cpu_data->dcache.ways > 1) {
129 size = sizes[(cvr >> 16) & 0xf]; 196 size = sizes[(cvr >> 16) & 0xf];
130 cpu_data->dcache.way_incr = (size >> 1); 197 cpu_data->dcache.way_incr = (size >> 1);
131 cpu_data->dcache.sets = (size >> 6); 198 cpu_data->dcache.sets = (size >> 6);
132 cpu_data->dcache.entry_mask = 199 }
133 (cpu_data->dcache.way_incr - (1 << 5)); 200
201 cpu_data->dcache.entry_mask = cpu_data->dcache.way_incr -
202 cpu_data->dcache.linesz;
203
204 cpu_data->dcache.way_size = cpu_data->dcache.sets *
205 cpu_data->dcache.linesz;
206
207 /*
208 * Setup the L2 cache desc
209 *
210 * SH-4A's have an optional PIPT L2.
211 */
212 if (cpu_data->flags & CPU_HAS_L2_CACHE) {
213 /*
214 * Size calculation is much more sensible
215 * than it is for the L1.
216 *
217 * Sizes are 128KB, 258KB, 512KB, and 1MB.
218 */
219 size = (cvr & 0xf) << 17;
220
221 BUG_ON(!size);
222
223 cpu_data->scache.way_incr = (1 << 16);
224 cpu_data->scache.entry_shift = 5;
225 cpu_data->scache.ways = 4;
226 cpu_data->scache.linesz = L1_CACHE_BYTES;
227 cpu_data->scache.entry_mask =
228 (cpu_data->scache.way_incr - cpu_data->scache.linesz);
229 cpu_data->scache.sets = size /
230 (cpu_data->scache.linesz * cpu_data->scache.ways);
231 cpu_data->scache.way_size =
232 (cpu_data->scache.sets * cpu_data->scache.linesz);
134 } 233 }
135 234
136 return 0; 235 return 0;
137} 236}
138
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
new file mode 100644
index 000000000000..6e4e96541358
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -0,0 +1,43 @@
1/*
2 * SH4-202 Setup
3 *
4 * Copyright (C) 2006 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 = 0xffe80000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 40, 41, 43, 42 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh4202_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh4202_devices_setup(void)
39{
40 return platform_add_devices(sh4202_devices,
41 ARRAY_SIZE(sh4202_devices));
42}
43__initcall(sh4202_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh73180.c b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
new file mode 100644
index 000000000000..cc9ea1e2e5df
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
@@ -0,0 +1,43 @@
1/*
2 * SH73180 Setup
3 *
4 * Copyright (C) 2006 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 = 0xffe80000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 80, 81, 83, 82 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh73180_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh73180_devices_setup(void)
39{
40 return platform_add_devices(sh73180_devices,
41 ARRAY_SIZE(sh73180_devices));
42}
43__initcall(sh73180_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7343.c b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
new file mode 100644
index 000000000000..91d61cf91ba1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
@@ -0,0 +1,43 @@
1/*
2 * SH7343 Setup
3 *
4 * Copyright (C) 2006 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 = 0xffe00000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 80, 81, 83, 82 },
21 }, {
22 .flags = 0,
23 }
24};
25
26static struct platform_device sci_device = {
27 .name = "sh-sci",
28 .id = -1,
29 .dev = {
30 .platform_data = sci_platform_data,
31 },
32};
33
34static struct platform_device *sh7343_devices[] __initdata = {
35 &sci_device,
36};
37
38static int __init sh7343_devices_setup(void)
39{
40 return platform_add_devices(sh7343_devices,
41 ARRAY_SIZE(sh7343_devices));
42}
43__initcall(sh7343_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
new file mode 100644
index 000000000000..50812d57c1c1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -0,0 +1,48 @@
1/*
2 * SH7750/SH7751 Setup
3 *
4 * Copyright (C) 2006 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 = 0xffe00000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCI,
20 .irqs = { 23, 24, 25, 0 },
21 }, {
22 .mapbase = 0xffe80000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 40, 41, 43, 42 },
26 }, {
27 .flags = 0,
28 }
29};
30
31static struct platform_device sci_device = {
32 .name = "sh-sci",
33 .id = -1,
34 .dev = {
35 .platform_data = sci_platform_data,
36 },
37};
38
39static struct platform_device *sh7750_devices[] __initdata = {
40 &sci_device,
41};
42
43static int __init sh7750_devices_setup(void)
44{
45 return platform_add_devices(sh7750_devices,
46 ARRAY_SIZE(sh7750_devices));
47}
48__initcall(sh7750_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
new file mode 100644
index 000000000000..97f1c9af35d6
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -0,0 +1,53 @@
1/*
2 * SH7760 Setup
3 *
4 * Copyright (C) 2006 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 = 0xfe600000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 52, 53, 55, 54 },
21 }, {
22 .mapbase = 0xfe610000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 72, 73, 75, 74 },
26 }, {
27 .mapbase = 0xfe620000,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_SCIF,
30 .irqs = { 76, 77, 79, 78 },
31 }, {
32 .flags = 0,
33 }
34};
35
36static struct platform_device sci_device = {
37 .name = "sh-sci",
38 .id = -1,
39 .dev = {
40 .platform_data = sci_platform_data,
41 },
42};
43
44static struct platform_device *sh7760_devices[] __initdata = {
45 &sci_device,
46};
47
48static int __init sh7760_devices_setup(void)
49{
50 return platform_add_devices(sh7760_devices,
51 ARRAY_SIZE(sh7760_devices));
52}
53__initcall(sh7760_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7770.c b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
new file mode 100644
index 000000000000..6a04cc5f5aca
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
@@ -0,0 +1,53 @@
1/*
2 * SH7770 Setup
3 *
4 * Copyright (C) 2006 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 = 0xff923000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 61, 61, 61, 61 },
21 }, {
22 .mapbase = 0xff924000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 62, 62, 62, 62 },
26 }, {
27 .mapbase = 0xff925000,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_SCIF,
30 .irqs = { 63, 63, 63, 63 },
31 }, {
32 .flags = 0,
33 }
34};
35
36static struct platform_device sci_device = {
37 .name = "sh-sci",
38 .id = -1,
39 .dev = {
40 .platform_data = sci_platform_data,
41 },
42};
43
44static struct platform_device *sh7770_devices[] __initdata = {
45 &sci_device,
46};
47
48static int __init sh7770_devices_setup(void)
49{
50 return platform_add_devices(sh7770_devices,
51 ARRAY_SIZE(sh7770_devices));
52}
53__initcall(sh7770_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
new file mode 100644
index 000000000000..72493f259edc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
@@ -0,0 +1,79 @@
1/*
2 * SH7780 Setup
3 *
4 * Copyright (C) 2006 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 resource rtc_resources[] = {
16 [0] = {
17 .start = 0xffe80000,
18 .end = 0xffe80000 + 0x58 - 1,
19 .flags = IORESOURCE_IO,
20 },
21 [1] = {
22 /* Period IRQ */
23 .start = 21,
24 .flags = IORESOURCE_IRQ,
25 },
26 [2] = {
27 /* Carry IRQ */
28 .start = 22,
29 .flags = IORESOURCE_IRQ,
30 },
31 [3] = {
32 /* Alarm IRQ */
33 .start = 23,
34 .flags = IORESOURCE_IRQ,
35 },
36};
37
38static struct platform_device rtc_device = {
39 .name = "sh-rtc",
40 .id = -1,
41 .num_resources = ARRAY_SIZE(rtc_resources),
42 .resource = rtc_resources,
43};
44
45static struct plat_sci_port sci_platform_data[] = {
46 {
47 .mapbase = 0xffe00000,
48 .flags = UPF_BOOT_AUTOCONF,
49 .type = PORT_SCIF,
50 .irqs = { 40, 41, 43, 42 },
51 }, {
52 .mapbase = 0xffe10000,
53 .flags = UPF_BOOT_AUTOCONF,
54 .type = PORT_SCIF,
55 .irqs = { 76, 77, 79, 78 },
56 }, {
57 .flags = 0,
58 }
59};
60
61static struct platform_device sci_device = {
62 .name = "sh-sci",
63 .id = -1,
64 .dev = {
65 .platform_data = sci_platform_data,
66 },
67};
68
69static struct platform_device *sh7780_devices[] __initdata = {
70 &rtc_device,
71 &sci_device,
72};
73
74static int __init sh7780_devices_setup(void)
75{
76 return platform_add_devices(sh7780_devices,
77 ARRAY_SIZE(sh7780_devices));
78}
79__initcall(sh7780_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index b09805f3ee23..7bcc73f9b8df 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -1,49 +1,52 @@
1/* 1/*
2 * arch/sh/kernel/cpu/sq.c 2 * arch/sh/kernel/cpu/sh4/sq.c
3 * 3 *
4 * General management API for SH-4 integrated Store Queues 4 * General management API for SH-4 integrated Store Queues
5 * 5 *
6 * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt 6 * Copyright (C) 2001 - 2006 Paul Mundt
7 * Copyright (C) 2001, 2002 M. R. Brown 7 * Copyright (C) 2001, 2002 M. R. Brown
8 * 8 *
9 * Some of this code has been adopted directly from the old arch/sh/mm/sq.c
10 * hack that was part of the LinuxDC project. For all intents and purposes,
11 * this is a completely new interface that really doesn't have much in common
12 * with the old zone-based approach at all. In fact, it's only listed here for
13 * general completeness.
14 *
15 * This file is subject to the terms and conditions of the GNU General Public 9 * 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 10 * License. See the file "COPYING" in the main directory of this archive
17 * for more details. 11 * for more details.
18 */ 12 */
19#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/cpu.h>
15#include <linux/bitmap.h>
16#include <linux/sysdev.h>
20#include <linux/kernel.h> 17#include <linux/kernel.h>
21#include <linux/module.h> 18#include <linux/module.h>
22#include <linux/slab.h> 19#include <linux/slab.h>
23#include <linux/list.h>
24#include <linux/proc_fs.h>
25#include <linux/miscdevice.h>
26#include <linux/vmalloc.h> 20#include <linux/vmalloc.h>
27 21#include <linux/mm.h>
28#include <asm/io.h> 22#include <asm/io.h>
29#include <asm/page.h> 23#include <asm/page.h>
30#include <asm/mmu_context.h> 24#include <asm/cacheflush.h>
31#include <asm/cpu/sq.h> 25#include <asm/cpu/sq.h>
32 26
33static LIST_HEAD(sq_mapping_list); 27struct sq_mapping;
28
29struct sq_mapping {
30 const char *name;
31
32 unsigned long sq_addr;
33 unsigned long addr;
34 unsigned int size;
35
36 struct sq_mapping *next;
37};
38
39static struct sq_mapping *sq_mapping_list;
34static DEFINE_SPINLOCK(sq_mapping_lock); 40static DEFINE_SPINLOCK(sq_mapping_lock);
41static kmem_cache_t *sq_cache;
42static unsigned long *sq_bitmap;
35 43
36/** 44#define store_queue_barrier() \
37 * sq_flush - Flush (prefetch) the store queue cache 45do { \
38 * @addr: the store queue address to flush 46 (void)ctrl_inl(P4SEG_STORE_QUE); \
39 * 47 ctrl_outl(0, P4SEG_STORE_QUE + 0); \
40 * Executes a prefetch instruction on the specified store queue cache, 48 ctrl_outl(0, P4SEG_STORE_QUE + 8); \
41 * so that the cached data is written to physical memory. 49} while (0);
42 */
43inline void sq_flush(void *addr)
44{
45 __asm__ __volatile__ ("pref @%0" : : "r" (addr) : "memory");
46}
47 50
48/** 51/**
49 * sq_flush_range - Flush (prefetch) a specific SQ range 52 * sq_flush_range - Flush (prefetch) a specific SQ range
@@ -56,152 +59,73 @@ inline void sq_flush(void *addr)
56void sq_flush_range(unsigned long start, unsigned int len) 59void sq_flush_range(unsigned long start, unsigned int len)
57{ 60{
58 volatile unsigned long *sq = (unsigned long *)start; 61 volatile unsigned long *sq = (unsigned long *)start;
59 unsigned long dummy;
60 62
61 /* Flush the queues */ 63 /* Flush the queues */
62 for (len >>= 5; len--; sq += 8) 64 for (len >>= 5; len--; sq += 8)
63 sq_flush((void *)sq); 65 prefetchw((void *)sq);
64 66
65 /* Wait for completion */ 67 /* Wait for completion */
66 dummy = ctrl_inl(P4SEG_STORE_QUE); 68 store_queue_barrier();
67
68 ctrl_outl(0, P4SEG_STORE_QUE + 0);
69 ctrl_outl(0, P4SEG_STORE_QUE + 8);
70} 69}
71 70
72static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name) 71static inline void sq_mapping_list_add(struct sq_mapping *map)
73{ 72{
74 struct sq_mapping *map; 73 struct sq_mapping **p, *tmp;
75
76 if (virt + size > SQ_ADDRMAX)
77 return ERR_PTR(-ENOSPC);
78
79 map = kmalloc(sizeof(struct sq_mapping), GFP_KERNEL);
80 if (!map)
81 return ERR_PTR(-ENOMEM);
82 74
83 INIT_LIST_HEAD(&map->list); 75 spin_lock_irq(&sq_mapping_lock);
84 76
85 map->sq_addr = virt; 77 p = &sq_mapping_list;
86 map->addr = phys; 78 while ((tmp = *p) != NULL)
87 map->size = size + 1; 79 p = &tmp->next;
88 map->name = name;
89 80
90 list_add(&map->list, &sq_mapping_list); 81 map->next = tmp;
82 *p = map;
91 83
92 return map; 84 spin_unlock_irq(&sq_mapping_lock);
93} 85}
94 86
95static unsigned long __sq_get_next_addr(void) 87static inline void sq_mapping_list_del(struct sq_mapping *map)
96{ 88{
97 if (!list_empty(&sq_mapping_list)) { 89 struct sq_mapping **p, *tmp;
98 struct list_head *pos, *tmp; 90
99 91 spin_lock_irq(&sq_mapping_lock);
100 /* 92
101 * Read one off the list head, as it will have the highest 93 for (p = &sq_mapping_list; (tmp = *p); p = &tmp->next)
102 * mapped allocation. Set the next one up right above it. 94 if (tmp == map) {
103 * 95 *p = tmp->next;
104 * This is somewhat sub-optimal, as we don't look at 96 break;
105 * gaps between allocations or anything lower then the
106 * highest-level allocation.
107 *
108 * However, in the interest of performance and the general
109 * lack of desire to do constant list rebalancing, we don't
110 * worry about it.
111 */
112 list_for_each_safe(pos, tmp, &sq_mapping_list) {
113 struct sq_mapping *entry;
114
115 entry = list_entry(pos, typeof(*entry), list);
116
117 return entry->sq_addr + entry->size;
118 } 97 }
119 }
120 98
121 return P4SEG_STORE_QUE; 99 spin_unlock_irq(&sq_mapping_lock);
122} 100}
123 101
124/** 102static int __sq_remap(struct sq_mapping *map, unsigned long flags)
125 * __sq_remap - Perform a translation from the SQ to a phys addr
126 * @map: sq mapping containing phys and store queue addresses.
127 *
128 * Maps the store queue address specified in the mapping to the physical
129 * address specified in the mapping.
130 */
131static struct sq_mapping *__sq_remap(struct sq_mapping *map)
132{ 103{
133 unsigned long flags, pteh, ptel; 104#if defined(CONFIG_MMU)
134 struct vm_struct *vma; 105 struct vm_struct *vma;
135 pgprot_t pgprot;
136
137 /*
138 * Without an MMU (or with it turned off), this is much more
139 * straightforward, as we can just load up each queue's QACR with
140 * the physical address appropriately masked.
141 */
142
143 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
144 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
145 106
146#ifdef CONFIG_MMU
147 /*
148 * With an MMU on the other hand, things are slightly more involved.
149 * Namely, we have to have a direct mapping between the SQ addr and
150 * the associated physical address in the UTLB by way of setting up
151 * a virt<->phys translation by hand. We do this by simply specifying
152 * the SQ addr in UTLB.VPN and the associated physical address in
153 * UTLB.PPN.
154 *
155 * Notably, even though this is a special case translation, and some
156 * of the configuration bits are meaningless, we're still required
157 * to have a valid ASID context in PTEH.
158 *
159 * We could also probably get by without explicitly setting PTEA, but
160 * we do it here just for good measure.
161 */
162 spin_lock_irqsave(&sq_mapping_lock, flags);
163
164 pteh = map->sq_addr;
165 ctrl_outl((pteh & MMU_VPN_MASK) | get_asid(), MMU_PTEH);
166
167 ptel = map->addr & PAGE_MASK;
168 ctrl_outl(((ptel >> 28) & 0xe) | (ptel & 0x1), MMU_PTEA);
169
170 pgprot = pgprot_noncached(PAGE_KERNEL);
171
172 ptel &= _PAGE_FLAGS_HARDWARE_MASK;
173 ptel |= pgprot_val(pgprot);
174 ctrl_outl(ptel, MMU_PTEL);
175
176 __asm__ __volatile__ ("ldtlb" : : : "memory");
177
178 spin_unlock_irqrestore(&sq_mapping_lock, flags);
179
180 /*
181 * Next, we need to map ourselves in the kernel page table, so that
182 * future accesses after a TLB flush will be handled when we take a
183 * page fault.
184 *
185 * Theoretically we could just do this directly and not worry about
186 * setting up the translation by hand ahead of time, but for the
187 * cases where we want a one-shot SQ mapping followed by a quick
188 * writeout before we hit the TLB flush, we do it anyways. This way
189 * we at least save ourselves the initial page fault overhead.
190 */
191 vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX); 107 vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
192 if (!vma) 108 if (!vma)
193 return ERR_PTR(-ENOMEM); 109 return -ENOMEM;
194 110
195 vma->phys_addr = map->addr; 111 vma->phys_addr = map->addr;
196 112
197 if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr, 113 if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
198 map->size, pgprot_val(pgprot))) { 114 map->size, flags)) {
199 vunmap(vma->addr); 115 vunmap(vma->addr);
200 return NULL; 116 return -EAGAIN;
201 } 117 }
202#endif /* CONFIG_MMU */ 118#else
119 /*
120 * Without an MMU (or with it turned off), this is much more
121 * straightforward, as we can just load up each queue's QACR with
122 * the physical address appropriately masked.
123 */
124 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
125 ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
126#endif
203 127
204 return map; 128 return 0;
205} 129}
206 130
207/** 131/**
@@ -209,42 +133,65 @@ static struct sq_mapping *__sq_remap(struct sq_mapping *map)
209 * @phys: Physical address of mapping. 133 * @phys: Physical address of mapping.
210 * @size: Length of mapping. 134 * @size: Length of mapping.
211 * @name: User invoking mapping. 135 * @name: User invoking mapping.
136 * @flags: Protection flags.
212 * 137 *
213 * Remaps the physical address @phys through the next available store queue 138 * Remaps the physical address @phys through the next available store queue
214 * address of @size length. @name is logged at boot time as well as through 139 * address of @size length. @name is logged at boot time as well as through
215 * the procfs interface. 140 * the sysfs interface.
216 *
217 * A pre-allocated and filled sq_mapping pointer is returned, and must be
218 * cleaned up with a call to sq_unmap() when the user is done with the
219 * mapping.
220 */ 141 */
221struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name) 142unsigned long sq_remap(unsigned long phys, unsigned int size,
143 const char *name, unsigned long flags)
222{ 144{
223 struct sq_mapping *map; 145 struct sq_mapping *map;
224 unsigned long virt, end; 146 unsigned long end;
225 unsigned int psz; 147 unsigned int psz;
148 int ret, page;
226 149
227 /* Don't allow wraparound or zero size */ 150 /* Don't allow wraparound or zero size */
228 end = phys + size - 1; 151 end = phys + size - 1;
229 if (!size || end < phys) 152 if (unlikely(!size || end < phys))
230 return NULL; 153 return -EINVAL;
231 /* Don't allow anyone to remap normal memory.. */ 154 /* Don't allow anyone to remap normal memory.. */
232 if (phys < virt_to_phys(high_memory)) 155 if (unlikely(phys < virt_to_phys(high_memory)))
233 return NULL; 156 return -EINVAL;
234 157
235 phys &= PAGE_MASK; 158 phys &= PAGE_MASK;
159 size = PAGE_ALIGN(end + 1) - phys;
160
161 map = kmem_cache_alloc(sq_cache, GFP_KERNEL);
162 if (unlikely(!map))
163 return -ENOMEM;
164
165 map->addr = phys;
166 map->size = size;
167 map->name = name;
168
169 page = bitmap_find_free_region(sq_bitmap, 0x04000000,
170 get_order(map->size));
171 if (unlikely(page < 0)) {
172 ret = -ENOSPC;
173 goto out;
174 }
175
176 map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT);
177
178 ret = __sq_remap(map, flags);
179 if (unlikely(ret != 0))
180 goto out;
181
182 psz = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
183 pr_info("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n",
184 likely(map->name) ? map->name : "???",
185 psz, psz == 1 ? " " : "s",
186 map->sq_addr, map->addr);
236 187
237 size = PAGE_ALIGN(end + 1) - phys; 188 sq_mapping_list_add(map);
238 virt = __sq_get_next_addr();
239 psz = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
240 map = __sq_alloc_mapping(virt, phys, size, name);
241 189
242 printk("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n", 190 return map->sq_addr;
243 map->name ? map->name : "???",
244 psz, psz == 1 ? " " : "s",
245 map->sq_addr, map->addr);
246 191
247 return __sq_remap(map); 192out:
193 kmem_cache_free(sq_cache, map);
194 return ret;
248} 195}
249 196
250/** 197/**
@@ -255,188 +202,198 @@ struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *n
255 * sq_remap(). Also frees up the pte that was previously inserted into 202 * sq_remap(). Also frees up the pte that was previously inserted into
256 * the kernel page table and discards the UTLB translation. 203 * the kernel page table and discards the UTLB translation.
257 */ 204 */
258void sq_unmap(struct sq_mapping *map) 205void sq_unmap(unsigned long vaddr)
259{ 206{
260 if (map->sq_addr > (unsigned long)high_memory) 207 struct sq_mapping **p, *map;
261 vfree((void *)(map->sq_addr & PAGE_MASK)); 208 struct vm_struct *vma;
209 int page;
262 210
263 list_del(&map->list); 211 for (p = &sq_mapping_list; (map = *p); p = &map->next)
264 kfree(map); 212 if (map->sq_addr == vaddr)
265} 213 break;
266 214
267/** 215 if (unlikely(!map)) {
268 * sq_clear - Clear a store queue range 216 printk("%s: bad store queue address 0x%08lx\n",
269 * @addr: Address to start clearing from. 217 __FUNCTION__, vaddr);
270 * @len: Length to clear. 218 return;
271 * 219 }
272 * A quick zero-fill implementation for clearing out memory that has been
273 * remapped through the store queues.
274 */
275void sq_clear(unsigned long addr, unsigned int len)
276{
277 int i;
278 220
279 /* Clear out both queues linearly */ 221 page = (map->sq_addr - P4SEG_STORE_QUE) >> PAGE_SHIFT;
280 for (i = 0; i < 8; i++) { 222 bitmap_release_region(sq_bitmap, page, get_order(map->size));
281 ctrl_outl(0, addr + i + 0); 223
282 ctrl_outl(0, addr + i + 8); 224#ifdef CONFIG_MMU
225 vma = remove_vm_area((void *)(map->sq_addr & PAGE_MASK));
226 if (!vma) {
227 printk(KERN_ERR "%s: bad address 0x%08lx\n",
228 __FUNCTION__, map->sq_addr);
229 return;
283 } 230 }
231#endif
232
233 sq_mapping_list_del(map);
284 234
285 sq_flush_range(addr, len); 235 kmem_cache_free(sq_cache, map);
286} 236}
287 237
288/** 238/*
289 * sq_vma_unmap - Unmap a VMA range 239 * Needlessly complex sysfs interface. Unfortunately it doesn't seem like
290 * @area: VMA containing range. 240 * there is any other easy way to add things on a per-cpu basis without
291 * @addr: Start of range. 241 * putting the directory entries somewhere stupid and having to create
292 * @len: Length of range. 242 * links in sysfs by hand back in to the per-cpu directories.
293 * 243 *
294 * Searches the sq_mapping_list for a mapping matching the sq addr @addr, 244 * Some day we may want to have an additional abstraction per store
295 * and subsequently frees up the entry. Further cleanup is done by generic 245 * queue, but considering the kobject hell we already have to deal with,
296 * code. 246 * it's simply not worth the trouble.
297 */ 247 */
298static void sq_vma_unmap(struct vm_area_struct *area, 248static struct kobject *sq_kobject[NR_CPUS];
299 unsigned long addr, size_t len)
300{
301 struct list_head *pos, *tmp;
302 249
303 list_for_each_safe(pos, tmp, &sq_mapping_list) { 250struct sq_sysfs_attr {
304 struct sq_mapping *entry; 251 struct attribute attr;
252 ssize_t (*show)(char *buf);
253 ssize_t (*store)(const char *buf, size_t count);
254};
305 255
306 entry = list_entry(pos, typeof(*entry), list); 256#define to_sq_sysfs_attr(attr) container_of(attr, struct sq_sysfs_attr, attr)
307 257
308 if (entry->sq_addr == addr) { 258static ssize_t sq_sysfs_show(struct kobject *kobj, struct attribute *attr,
309 /* 259 char *buf)
310 * We could probably get away without doing the tlb flush 260{
311 * here, as generic code should take care of most of this 261 struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
312 * when unmapping the rest of the VMA range for us. Leave
313 * it in for added sanity for the time being..
314 */
315 __flush_tlb_page(get_asid(), entry->sq_addr & PAGE_MASK);
316 262
317 list_del(&entry->list); 263 if (likely(sattr->show))
318 kfree(entry); 264 return sattr->show(buf);
319 265
320 return; 266 return -EIO;
321 }
322 }
323} 267}
324 268
325/** 269static ssize_t sq_sysfs_store(struct kobject *kobj, struct attribute *attr,
326 * sq_vma_sync - Sync a VMA range 270 const char *buf, size_t count)
327 * @area: VMA containing range.
328 * @start: Start of range.
329 * @len: Length of range.
330 * @flags: Additional flags.
331 *
332 * Synchronizes an sq mapped range by flushing the store queue cache for
333 * the duration of the mapping.
334 *
335 * Used internally for user mappings, which must use msync() to prefetch
336 * the store queue cache.
337 */
338static int sq_vma_sync(struct vm_area_struct *area,
339 unsigned long start, size_t len, unsigned int flags)
340{ 271{
341 sq_flush_range(start, len); 272 struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
342 273
343 return 0; 274 if (likely(sattr->store))
275 return sattr->store(buf, count);
276
277 return -EIO;
344} 278}
345 279
346static struct vm_operations_struct sq_vma_ops = { 280static ssize_t mapping_show(char *buf)
347 .unmap = sq_vma_unmap, 281{
348 .sync = sq_vma_sync, 282 struct sq_mapping **list, *entry;
349}; 283 char *p = buf;
350 284
351/** 285 for (list = &sq_mapping_list; (entry = *list); list = &entry->next)
352 * sq_mmap - mmap() for /dev/cpu/sq 286 p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n",
353 * @file: unused. 287 entry->sq_addr, entry->sq_addr + entry->size,
354 * @vma: VMA to remap. 288 entry->addr, entry->name);
355 * 289
356 * Remap the specified vma @vma through the store queues, and setup associated 290 return p - buf;
357 * information for the new mapping. Also build up the page tables for the new 291}
358 * area. 292
359 */ 293static ssize_t mapping_store(const char *buf, size_t count)
360static int sq_mmap(struct file *file, struct vm_area_struct *vma)
361{ 294{
362 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 295 unsigned long base = 0, len = 0;
363 unsigned long size = vma->vm_end - vma->vm_start;
364 struct sq_mapping *map;
365 296
366 /* 297 sscanf(buf, "%lx %lx", &base, &len);
367 * We're not interested in any arbitrary virtual address that has 298 if (!base)
368 * been stuck in the VMA, as we already know what addresses we 299 return -EIO;
369 * want. Save off the size, and reposition the VMA to begin at
370 * the next available sq address.
371 */
372 vma->vm_start = __sq_get_next_addr();
373 vma->vm_end = vma->vm_start + size;
374 300
375 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 301 if (likely(len)) {
302 int ret = sq_remap(base, len, "Userspace",
303 pgprot_val(PAGE_SHARED));
304 if (ret < 0)
305 return ret;
306 } else
307 sq_unmap(base);
376 308
377 vma->vm_flags |= VM_IO | VM_RESERVED; 309 return count;
310}
378 311
379 map = __sq_alloc_mapping(vma->vm_start, offset, size, "Userspace"); 312static struct sq_sysfs_attr mapping_attr =
313 __ATTR(mapping, 0644, mapping_show, mapping_store);
380 314
381 if (io_remap_pfn_range(vma, map->sq_addr, map->addr >> PAGE_SHIFT, 315static struct attribute *sq_sysfs_attrs[] = {
382 size, vma->vm_page_prot)) 316 &mapping_attr.attr,
383 return -EAGAIN; 317 NULL,
318};
384 319
385 vma->vm_ops = &sq_vma_ops; 320static struct sysfs_ops sq_sysfs_ops = {
321 .show = sq_sysfs_show,
322 .store = sq_sysfs_store,
323};
386 324
387 return 0; 325static struct kobj_type ktype_percpu_entry = {
388} 326 .sysfs_ops = &sq_sysfs_ops,
327 .default_attrs = sq_sysfs_attrs,
328};
389 329
390#ifdef CONFIG_PROC_FS 330static int __devinit sq_sysdev_add(struct sys_device *sysdev)
391static int sq_mapping_read_proc(char *buf, char **start, off_t off,
392 int len, int *eof, void *data)
393{ 331{
394 struct list_head *pos; 332 unsigned int cpu = sysdev->id;
395 char *p = buf; 333 struct kobject *kobj;
396 334
397 list_for_each_prev(pos, &sq_mapping_list) { 335 sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
398 struct sq_mapping *entry; 336 if (unlikely(!sq_kobject[cpu]))
337 return -ENOMEM;
399 338
400 entry = list_entry(pos, typeof(*entry), list); 339 kobj = sq_kobject[cpu];
340 kobj->parent = &sysdev->kobj;
341 kobject_set_name(kobj, "%s", "sq");
342 kobj->ktype = &ktype_percpu_entry;
401 343
402 p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n", entry->sq_addr, 344 return kobject_register(kobj);
403 entry->sq_addr + entry->size - 1, entry->addr,
404 entry->name);
405 }
406
407 return p - buf;
408} 345}
409#endif
410 346
411static struct file_operations sq_fops = { 347static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
412 .owner = THIS_MODULE, 348{
413 .mmap = sq_mmap, 349 unsigned int cpu = sysdev->id;
414}; 350 struct kobject *kobj = sq_kobject[cpu];
415 351
416static struct miscdevice sq_dev = { 352 kobject_unregister(kobj);
417 .minor = STORE_QUEUE_MINOR, 353 return 0;
418 .name = "sq", 354}
419 .fops = &sq_fops, 355
356static struct sysdev_driver sq_sysdev_driver = {
357 .add = sq_sysdev_add,
358 .remove = __devexit_p(sq_sysdev_remove),
420}; 359};
421 360
422static int __init sq_api_init(void) 361static int __init sq_api_init(void)
423{ 362{
424 int ret; 363 unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT;
364 unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
365 int ret = -ENOMEM;
366
425 printk(KERN_NOTICE "sq: Registering store queue API.\n"); 367 printk(KERN_NOTICE "sq: Registering store queue API.\n");
426 368
427 create_proc_read_entry("sq_mapping", 0, 0, sq_mapping_read_proc, 0); 369 sq_cache = kmem_cache_create("store_queue_cache",
370 sizeof(struct sq_mapping), 0, 0,
371 NULL, NULL);
372 if (unlikely(!sq_cache))
373 return ret;
428 374
429 ret = misc_register(&sq_dev); 375 sq_bitmap = kzalloc(size, GFP_KERNEL);
430 if (ret) 376 if (unlikely(!sq_bitmap))
431 remove_proc_entry("sq_mapping", NULL); 377 goto out;
378
379 ret = sysdev_driver_register(&cpu_sysdev_class, &sq_sysdev_driver);
380 if (unlikely(ret != 0))
381 goto out;
382
383 return 0;
384
385out:
386 kfree(sq_bitmap);
387 kmem_cache_destroy(sq_cache);
432 388
433 return ret; 389 return ret;
434} 390}
435 391
436static void __exit sq_api_exit(void) 392static void __exit sq_api_exit(void)
437{ 393{
438 misc_deregister(&sq_dev); 394 sysdev_driver_unregister(&cpu_sysdev_class, &sq_sysdev_driver);
439 remove_proc_entry("sq_mapping", NULL); 395 kfree(sq_bitmap);
396 kmem_cache_destroy(sq_cache);
440} 397}
441 398
442module_init(sq_api_init); 399module_init(sq_api_init);
@@ -445,11 +402,7 @@ module_exit(sq_api_exit);
445MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); 402MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
446MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); 403MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues");
447MODULE_LICENSE("GPL"); 404MODULE_LICENSE("GPL");
448MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR);
449 405
450EXPORT_SYMBOL(sq_remap); 406EXPORT_SYMBOL(sq_remap);
451EXPORT_SYMBOL(sq_unmap); 407EXPORT_SYMBOL(sq_unmap);
452EXPORT_SYMBOL(sq_clear);
453EXPORT_SYMBOL(sq_flush);
454EXPORT_SYMBOL(sq_flush_range); 408EXPORT_SYMBOL(sq_flush_range);
455