diff options
Diffstat (limited to 'arch/sh/kernel/cpu')
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/ | |||
8 | obj-$(CONFIG_CPU_SH3) += sh3/ | 8 | obj-$(CONFIG_CPU_SH3) += sh3/ |
9 | obj-$(CONFIG_CPU_SH4) += sh4/ | 9 | obj-$(CONFIG_CPU_SH4) += sh4/ |
10 | 10 | ||
11 | obj-$(CONFIG_SH_RTC) += rtc.o | ||
12 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o | 11 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o |
13 | obj-$(CONFIG_SH_ADC) += adc.o | 12 | obj-$(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 | ||
25 | static LIST_HEAD(clock_list); | 26 | static LIST_HEAD(clock_list); |
26 | static DEFINE_SPINLOCK(clock_lock); | 27 | static DEFINE_SPINLOCK(clock_lock); |
27 | static DECLARE_MUTEX(clock_list_sem); | 28 | static 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 | ||
141 | int clk_register(struct clk *clk) | 142 | int 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 | ||
153 | void clk_unregister(struct clk *clk) | 154 | void 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 | ||
160 | inline unsigned long clk_get_rate(struct clk *clk) | 161 | inline 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 | # |
4 | obj-y += ipr.o imask.o | 4 | obj-y += ipr.o imask.o |
5 | 5 | ||
6 | obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o | 6 | obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o |
7 | obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o | 7 | obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o |
8 | obj-$(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 | ||
58 | static void disable_ipr_irq(unsigned int irq) | 58 | static 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 | ||
72 | static void enable_ipr_irq(unsigned int irq) | 70 | static 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 | ||
87 | static void mask_and_ack_ipr(unsigned int irq) | 83 | static 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 */ | ||
20 | unsigned long irq_mask_register; | ||
21 | |||
22 | /* forward declaration */ | ||
23 | static unsigned int startup_maskreg_irq(unsigned int irq); | ||
24 | static void shutdown_maskreg_irq(unsigned int irq); | ||
25 | static void enable_maskreg_irq(unsigned int irq); | ||
26 | static void disable_maskreg_irq(unsigned int irq); | ||
27 | static void mask_and_ack_maskreg(unsigned int); | ||
28 | static void end_maskreg_irq(unsigned int irq); | ||
29 | |||
30 | /* hw_interrupt_type */ | ||
31 | static 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 */ | ||
42 | static unsigned int startup_maskreg_irq(unsigned int irq) | ||
43 | { | ||
44 | enable_maskreg_irq(irq); | ||
45 | return 0; /* never anything pending */ | ||
46 | } | ||
47 | |||
48 | static void shutdown_maskreg_irq(unsigned int irq) | ||
49 | { | ||
50 | disable_maskreg_irq(irq); | ||
51 | } | ||
52 | |||
53 | static 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 | |||
65 | static 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 | |||
77 | static void mask_and_ack_maskreg(unsigned int irq) | ||
78 | { | ||
79 | disable_maskreg_irq(irq); | ||
80 | } | ||
81 | |||
82 | static 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 | |||
88 | void 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 | ||
49 | static void disable_pint_irq(unsigned int irq) | 49 | static 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 | ||
61 | static void enable_pint_irq(unsigned int irq) | 59 | static 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 | ||
73 | static void mask_and_ack_pint(unsigned int irq) | 69 | static 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 | |||
16 | void 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 | */ | ||
88 | int 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 | ||
5 | obj-y := ex.o probe.o | 5 | obj-y := ex.o probe.o |
6 | 6 | ||
7 | # CPU subtype setup | ||
8 | obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o | ||
9 | obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o | ||
10 | obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o | ||
11 | obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o | ||
12 | obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o | ||
13 | obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o | ||
14 | obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o | ||
15 | |||
16 | # Primary on-chip clocks (common) | ||
7 | clock-$(CONFIG_CPU_SH3) := clock-sh3.o | 17 | clock-$(CONFIG_CPU_SH3) := clock-sh3.o |
8 | clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o | 18 | clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o |
9 | clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o | 19 | clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o |
20 | clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o | ||
10 | clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o | 21 | clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o |
22 | clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7300.o | ||
11 | 23 | ||
12 | obj-y += $(clock-y) | 24 | obj-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 | |||
21 | static int stc_multipliers[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; | ||
22 | static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 }; | ||
23 | static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; | ||
24 | |||
25 | static void 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 | |||
33 | static struct clk_ops sh7706_master_clk_ops = { | ||
34 | .init = master_clk_init, | ||
35 | }; | ||
36 | |||
37 | static 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 | |||
45 | static struct clk_ops sh7706_module_clk_ops = { | ||
46 | .recalc = module_clk_recalc, | ||
47 | }; | ||
48 | |||
49 | static 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 | |||
57 | static struct clk_ops sh7706_bus_clk_ops = { | ||
58 | .recalc = bus_clk_recalc, | ||
59 | }; | ||
60 | |||
61 | static 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 | |||
69 | static struct clk_ops sh7706_cpu_clk_ops = { | ||
70 | .recalc = cpu_clk_recalc, | ||
71 | }; | ||
72 | |||
73 | static 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 | |||
80 | void __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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7300_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
31 | static struct platform_device sci_device = { | ||
32 | .name = "sh-sci", | ||
33 | .id = -1, | ||
34 | .dev = { | ||
35 | .platform_data = sci_platform_data, | ||
36 | }, | ||
37 | }; | ||
38 | |||
39 | static struct platform_device *sh7705_devices[] __initdata = { | ||
40 | &sci_device, | ||
41 | }; | ||
42 | |||
43 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7708_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
36 | static struct platform_device sci_device = { | ||
37 | .name = "sh-sci", | ||
38 | .id = -1, | ||
39 | .dev = { | ||
40 | .platform_data = sci_platform_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct platform_device *sh7709_devices[] __initdata = { | ||
45 | &sci_device, | ||
46 | }; | ||
47 | |||
48 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7710_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
7 | obj-$(CONFIG_SH_FPU) += fpu.o | 7 | obj-$(CONFIG_SH_FPU) += fpu.o |
8 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o | 8 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o |
9 | 9 | ||
10 | # CPU subtype setup | ||
11 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o | ||
12 | obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o | ||
13 | obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o | ||
14 | obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o | ||
15 | obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o | ||
16 | obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o | ||
17 | obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o | ||
18 | obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o | ||
19 | |||
10 | # Primary on-chip clocks (common) | 20 | # Primary on-chip clocks (common) |
11 | clock-$(CONFIG_CPU_SH4) := clock-sh4.o | 21 | clock-$(CONFIG_CPU_SH4) := clock-sh4.o |
12 | clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o | 22 | clock-$(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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh4202_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh73180_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
26 | static struct platform_device sci_device = { | ||
27 | .name = "sh-sci", | ||
28 | .id = -1, | ||
29 | .dev = { | ||
30 | .platform_data = sci_platform_data, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct platform_device *sh7343_devices[] __initdata = { | ||
35 | &sci_device, | ||
36 | }; | ||
37 | |||
38 | static 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 | |||
15 | static 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 | |||
31 | static struct platform_device sci_device = { | ||
32 | .name = "sh-sci", | ||
33 | .id = -1, | ||
34 | .dev = { | ||
35 | .platform_data = sci_platform_data, | ||
36 | }, | ||
37 | }; | ||
38 | |||
39 | static struct platform_device *sh7750_devices[] __initdata = { | ||
40 | &sci_device, | ||
41 | }; | ||
42 | |||
43 | static 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 | |||
15 | static 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 | |||
36 | static struct platform_device sci_device = { | ||
37 | .name = "sh-sci", | ||
38 | .id = -1, | ||
39 | .dev = { | ||
40 | .platform_data = sci_platform_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct platform_device *sh7760_devices[] __initdata = { | ||
45 | &sci_device, | ||
46 | }; | ||
47 | |||
48 | static 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 | |||
15 | static 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 | |||
36 | static struct platform_device sci_device = { | ||
37 | .name = "sh-sci", | ||
38 | .id = -1, | ||
39 | .dev = { | ||
40 | .platform_data = sci_platform_data, | ||
41 | }, | ||
42 | }; | ||
43 | |||
44 | static struct platform_device *sh7770_devices[] __initdata = { | ||
45 | &sci_device, | ||
46 | }; | ||
47 | |||
48 | static 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 | |||
15 | static 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 | |||
38 | static 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 | |||
45 | static 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 | |||
61 | static struct platform_device sci_device = { | ||
62 | .name = "sh-sci", | ||
63 | .id = -1, | ||
64 | .dev = { | ||
65 | .platform_data = sci_platform_data, | ||
66 | }, | ||
67 | }; | ||
68 | |||
69 | static struct platform_device *sh7780_devices[] __initdata = { | ||
70 | &rtc_device, | ||
71 | &sci_device, | ||
72 | }; | ||
73 | |||
74 | static 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 | ||
33 | static LIST_HEAD(sq_mapping_list); | 27 | struct sq_mapping; |
28 | |||
29 | struct 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 | |||
39 | static struct sq_mapping *sq_mapping_list; | ||
34 | static DEFINE_SPINLOCK(sq_mapping_lock); | 40 | static DEFINE_SPINLOCK(sq_mapping_lock); |
41 | static kmem_cache_t *sq_cache; | ||
42 | static unsigned long *sq_bitmap; | ||
35 | 43 | ||
36 | /** | 44 | #define store_queue_barrier() \ |
37 | * sq_flush - Flush (prefetch) the store queue cache | 45 | do { \ |
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 | */ | ||
43 | inline 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) | |||
56 | void sq_flush_range(unsigned long start, unsigned int len) | 59 | void 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 | ||
72 | static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name) | 71 | static 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 | ||
95 | static unsigned long __sq_get_next_addr(void) | 87 | static 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 | /** | 102 | static 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 | */ | ||
131 | static 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 | */ |
221 | struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name) | 142 | unsigned 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); | 192 | out: |
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 | */ |
258 | void sq_unmap(struct sq_mapping *map) | 205 | void 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 | */ | ||
275 | void 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 | */ |
298 | static void sq_vma_unmap(struct vm_area_struct *area, | 248 | static 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) { | 250 | struct 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) { | 258 | static 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 | /** | 269 | static 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 | */ | ||
338 | static 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 | ||
346 | static struct vm_operations_struct sq_vma_ops = { | 280 | static 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 | */ | 293 | static ssize_t mapping_store(const char *buf, size_t count) |
360 | static 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"); | 312 | static 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, | 315 | static 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; | 320 | static struct sysfs_ops sq_sysfs_ops = { |
321 | .show = sq_sysfs_show, | ||
322 | .store = sq_sysfs_store, | ||
323 | }; | ||
386 | 324 | ||
387 | return 0; | 325 | static 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 | 330 | static int __devinit sq_sysdev_add(struct sys_device *sysdev) |
391 | static 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 | ||
411 | static struct file_operations sq_fops = { | 347 | static 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 | ||
416 | static 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 | |
356 | static struct sysdev_driver sq_sysdev_driver = { | ||
357 | .add = sq_sysdev_add, | ||
358 | .remove = __devexit_p(sq_sysdev_remove), | ||
420 | }; | 359 | }; |
421 | 360 | ||
422 | static int __init sq_api_init(void) | 361 | static 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 | |||
385 | out: | ||
386 | kfree(sq_bitmap); | ||
387 | kmem_cache_destroy(sq_cache); | ||
432 | 388 | ||
433 | return ret; | 389 | return ret; |
434 | } | 390 | } |
435 | 391 | ||
436 | static void __exit sq_api_exit(void) | 392 | static 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 | ||
442 | module_init(sq_api_init); | 399 | module_init(sq_api_init); |
@@ -445,11 +402,7 @@ module_exit(sq_api_exit); | |||
445 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); | 402 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); |
446 | MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); | 403 | MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); |
447 | MODULE_LICENSE("GPL"); | 404 | MODULE_LICENSE("GPL"); |
448 | MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR); | ||
449 | 405 | ||
450 | EXPORT_SYMBOL(sq_remap); | 406 | EXPORT_SYMBOL(sq_remap); |
451 | EXPORT_SYMBOL(sq_unmap); | 407 | EXPORT_SYMBOL(sq_unmap); |
452 | EXPORT_SYMBOL(sq_clear); | ||
453 | EXPORT_SYMBOL(sq_flush); | ||
454 | EXPORT_SYMBOL(sq_flush_range); | 408 | EXPORT_SYMBOL(sq_flush_range); |
455 | |||