aboutsummaryrefslogtreecommitdiff
path: root/arch/sh/kernel/cpu/sh4
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/sh4')
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile10
-rw-r--r--arch/sh/kernel/cpu/sh4/ex.S176
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c138
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh4-202.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh73180.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7343.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c48
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7770.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7780.c79
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c543
11 files changed, 912 insertions, 317 deletions
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 3d5cafc71ae..8dbf3895ece 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
obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
+# CPU subtype setup
+obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
+obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
+obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o
+
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH4) := clock-sh4.o
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 26a27df0650..7146893a6cc 100644
--- a/arch/sh/kernel/cpu/sh4/ex.S
+++ b/arch/sh/kernel/cpu/sh4/ex.S
@@ -72,6 +72,7 @@ ENTRY(interrupt_table)
.long do_IRQ ! 1110
.long exception_error
! Internal hardware
+#ifndef CONFIG_CPU_SUBTYPE_SH7780
.long do_IRQ ! TMU0 tuni0 /* 400 */
.long do_IRQ ! TMU1 tuni1
.long do_IRQ ! TMU2 tuni2
@@ -122,6 +123,13 @@ ENTRY(interrupt_table)
.long do_IRQ ! 45 dmte5
.long do_IRQ ! 46 dmte6
.long do_IRQ ! 47 dmte7 /* 7E0 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+ .long do_IRQ ! 44 IIC1 ali /* 780 */
+ .long do_IRQ ! 45 tacki
+ .long do_IRQ ! 46 waiti
+ .long do_IRQ ! 47 dtei /* 7E0 */
+ .long do_IRQ ! 48 DMAC dei0 /* 800 */
+ .long do_IRQ ! 49 dei1 /* 820 */
#else
.long exception_error ! 44 /* 780 */
.long exception_error ! 45
@@ -131,7 +139,8 @@ ENTRY(interrupt_table)
#if defined(CONFIG_SH_FPU)
.long do_fpu_state_restore ! 48 /* 800 */
.long do_fpu_state_restore ! 49 /* 820 */
-#else
+#elif !defined(CONFIG_CPU_SUBTYPE_SH7343) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH73180)
.long exception_error
.long exception_error
#endif
@@ -224,7 +233,7 @@ ENTRY(interrupt_table)
.long exception_error
.long do_IRQ ! ADC adi
.long do_IRQ ! CMT cmti /* FA0 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
+#elif defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7343)
.long do_IRQ ! 50 0x840
.long do_IRQ ! 51 0x860
.long do_IRQ ! 52 0x880
@@ -379,5 +388,168 @@ ENTRY(interrupt_table)
.long exception_error ! 141 0x13a0
.long exception_error ! 142 0x13c0
.long exception_error ! 143 0x13e0
+#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
+ .long do_IRQ ! 50 0x840
+ .long do_IRQ ! 51 0x860
+ .long do_IRQ ! 52 0x880
+ .long do_IRQ ! 53 0x8a0
+ .long do_IRQ ! 54 0x8c0
+ .long do_IRQ ! 55 0x8e0
+ .long do_IRQ ! 56 0x900
+ .long do_IRQ ! 57 0x920
+ .long do_IRQ ! 58 0x940
+ .long do_IRQ ! 59 0x960
+ .long do_IRQ ! 60 0x980
+ .long do_IRQ ! 61 0x9a0
+ .long do_IRQ ! 62 0x9c0
+ .long do_IRQ ! 63 0x9e0
+ .long do_IRQ ! 64 0xa00
+ .long do_IRQ ! 65 0xa20
+ .long do_IRQ ! 66 0xa4d
+ .long do_IRQ ! 67 0xa60
+ .long do_IRQ ! 68 0xa80
+ .long do_IRQ ! 69 0xaa0
+ .long do_IRQ ! 70 0xac0
+ .long do_IRQ ! 71 0xae0
+ .long do_IRQ ! 72 0xb00
+ .long do_IRQ ! 73 0xb20
+ .long do_IRQ ! 74 0xb40
+ .long do_IRQ ! 75 0xb60
+ .long do_IRQ ! 76 0xb80
+ .long do_IRQ ! 77 0xba0
+ .long do_IRQ ! 78 0xbc0
+ .long do_IRQ ! 79 0xbe0
+ .long do_IRQ ! 80 0xc00
+ .long do_IRQ ! 81 0xc20
+ .long do_IRQ ! 82 0xc40
+ .long do_IRQ ! 83 0xc60
+ .long do_IRQ ! 84 0xc80
+ .long do_IRQ ! 85 0xca0
+ .long do_IRQ ! 86 0xcc0
+ .long do_IRQ ! 87 0xce0
+ .long do_IRQ ! 88 0xd00
+ .long do_IRQ ! 89 0xd20
+ .long do_IRQ ! 90 0xd40
+ .long do_IRQ ! 91 0xd60
+ .long do_IRQ ! 92 0xd80
+ .long do_IRQ ! 93 0xda0
+ .long do_IRQ ! 94 0xdc0
+ .long do_IRQ ! 95 0xde0
+ .long do_IRQ ! 96 0xe00
+ .long do_IRQ ! 97 0xe20
+ .long do_IRQ ! 98 0xe40
+ .long do_IRQ ! 99 0xe60
+ .long do_IRQ ! 100 0xe80
+ .long do_IRQ ! 101 0xea0
+ .long do_IRQ ! 102 0xec0
+ .long do_IRQ ! 103 0xee0
+ .long do_IRQ ! 104 0xf00
+ .long do_IRQ ! 105 0xf20
+ .long do_IRQ ! 106 0xf40
+ .long do_IRQ ! 107 0xf60
+ .long do_IRQ ! 108 0xf80
+#endif
+#else
+ .long exception_error /* 400 */
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! RTC ati
+ .long do_IRQ ! pri
+ .long do_IRQ ! cui
+ .long exception_error
+ .long exception_error /* 500 */
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! WDT iti /* 560 */
+ .long do_IRQ ! TMU-ch0
+ .long do_IRQ ! TMU-ch1
+ .long do_IRQ ! TMU-ch2
+ .long do_IRQ ! ticpi2 /* 5E0 */
+ .long do_IRQ ! 32 Hitachi UDI /* 600 */
+ .long exception_error
+ .long do_IRQ ! 34 DMAC dmte0
+ .long do_IRQ ! 35 dmte1
+ .long do_IRQ ! 36 dmte2
+ .long do_IRQ ! 37 dmte3
+ .long do_IRQ ! 38 dmae
+ .long exception_error ! 39 /* 6E0 */
+ .long do_IRQ ! 40 SCIF-ch0 eri /* 700 */
+ .long do_IRQ ! 41 rxi
+ .long do_IRQ ! 42 bri
+ .long do_IRQ ! 43 txi
+ .long do_IRQ ! 44 DMAC dmte4 /* 780 */
+ .long do_IRQ ! 45 dmte5
+ .long do_IRQ ! 46 dmte6
+ .long do_IRQ ! 47 dmte7 /* 7E0 */
+#if defined(CONFIG_SH_FPU)
+ .long do_fpu_state_restore ! 48 /* 800 */
+ .long do_fpu_state_restore ! 49 /* 820 */
+#else
+ .long exception_error
+ .long exception_error
+#endif
+ .long exception_error /* 840 */
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! 56 CMT /* 900 */
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! 60 HAC
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! PCI serr /* A00 */
+ .long do_IRQ ! INTA
+ .long do_IRQ ! INTB
+ .long do_IRQ ! INTC
+ .long do_IRQ ! INTD
+ .long do_IRQ ! err
+ .long do_IRQ ! pwd3
+ .long do_IRQ ! pwd2
+ .long do_IRQ ! pwd1 /* B00 */
+ .long do_IRQ ! pwd0
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! SCIF-ch1 eri /* B80 */
+ .long do_IRQ ! rxi
+ .long do_IRQ ! bri
+ .long do_IRQ ! txi
+ .long do_IRQ ! SIOF /* C00 */
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! HSPI /* C80 */
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! MMCIF fatat /* D00 */
+ .long do_IRQ ! tran
+ .long do_IRQ ! err
+ .long do_IRQ ! frdy
+ .long do_IRQ ! DMAC dmint8 /* D80 */
+ .long do_IRQ ! dmint9
+ .long do_IRQ ! dmint10
+ .long do_IRQ ! dmint11
+ .long do_IRQ ! TMU-ch3 /* E00 */
+ .long do_IRQ ! TMU-ch4
+ .long do_IRQ ! TMU-ch5
+ .long exception_error
+ .long do_IRQ ! SSI
+ .long exception_error
+ .long exception_error
+ .long exception_error
+ .long do_IRQ ! FLCTL flste /* F00 */
+ .long do_IRQ ! fltend
+ .long do_IRQ ! fltrq0
+ .long do_IRQ ! fltrq1
+ .long do_IRQ ! GPIO gpioi0 /* F80 */
+ .long do_IRQ ! gpioi1
+ .long do_IRQ ! gpioi2
+ .long do_IRQ ! gpioi3
#endif
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 42427b79697..c294de1e14a 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -3,7 +3,7 @@
*
* CPU Subtype Probing for SH-4.
*
- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2001 - 2006 Paul Mundt
* Copyright (C) 2003 Richard Curnow
*
* 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)
[9] = (1 << 16)
};
- pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff;
+ pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffffff;
prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
cvr = (ctrl_inl(CCN_CVR));
@@ -38,7 +38,6 @@ int __init detect_cpu_and_cache_system(void)
*/
cpu_data->icache.way_incr = (1 << 13);
cpu_data->icache.entry_shift = 5;
- cpu_data->icache.entry_mask = 0x1fe0;
cpu_data->icache.sets = 256;
cpu_data->icache.ways = 1;
cpu_data->icache.linesz = L1_CACHE_BYTES;
@@ -48,13 +47,29 @@ int __init detect_cpu_and_cache_system(void)
*/
cpu_data->dcache.way_incr = (1 << 14);
cpu_data->dcache.entry_shift = 5;
- cpu_data->dcache.entry_mask = 0x3fe0;
cpu_data->dcache.sets = 512;
cpu_data->dcache.ways = 1;
cpu_data->dcache.linesz = L1_CACHE_BYTES;
- /* Set the FPU flag, virtually all SH-4's have one */
- cpu_data->flags |= CPU_HAS_FPU;
+ /*
+ * Setup some generic flags we can probe
+ * (L2 and DSP detection only work on SH-4A)
+ */
+ if (((pvr >> 16) & 0xff) == 0x10) {
+ if ((cvr & 0x02000000) == 0)
+ cpu_data->flags |= CPU_HAS_L2_CACHE;
+ if ((cvr & 0x10000000) == 0)
+ cpu_data->flags |= CPU_HAS_DSP;
+
+ cpu_data->flags |= CPU_HAS_LLSC;
+ }
+
+ /* FPU detection works for everyone */
+ if ((cvr & 0x20000000) == 1)
+ cpu_data->flags |= CPU_HAS_FPU;
+
+ /* Mask off the upper chip ID */
+ pvr &= 0xffff;
/*
* Probe the underlying processor version/revision and
@@ -63,56 +78,101 @@ int __init detect_cpu_and_cache_system(void)
switch (pvr) {
case 0x205:
cpu_data->type = CPU_SH7750;
- cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+ cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+ CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
break;
case 0x206:
cpu_data->type = CPU_SH7750S;
- cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+ cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+ CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
break;
case 0x1100:
cpu_data->type = CPU_SH7751;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x2000:
cpu_data->type = CPU_SH73180;
cpu_data->icache.ways = 4;
cpu_data->dcache.ways = 4;
- cpu_data->flags &= ~CPU_HAS_FPU;
+ cpu_data->flags |= CPU_HAS_LLSC;
+ break;
+ case 0x2001:
+ case 0x2004:
+ cpu_data->type = CPU_SH7770;
+ cpu_data->icache.ways = 4;
+ cpu_data->dcache.ways = 4;
+
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
+ break;
+ case 0x2006:
+ case 0x200A:
+ if (prr == 0x61)
+ cpu_data->type = CPU_SH7781;
+ else
+ cpu_data->type = CPU_SH7780;
+
+ cpu_data->icache.ways = 4;
+ cpu_data->dcache.ways = 4;
+
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ CPU_HAS_LLSC;
+ break;
+ case 0x3000:
+ case 0x3003:
+ cpu_data->type = CPU_SH7343;
+ cpu_data->icache.ways = 4;
+ cpu_data->dcache.ways = 4;
+ cpu_data->flags |= CPU_HAS_LLSC;
break;
case 0x8000:
cpu_data->type = CPU_ST40RA;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x8100:
cpu_data->type = CPU_ST40GX1;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x700:
cpu_data->type = CPU_SH4_501;
cpu_data->icache.ways = 2;
cpu_data->dcache.ways = 2;
-
- /* No FPU on the SH4-500 series.. */
- cpu_data->flags &= ~CPU_HAS_FPU;
+ cpu_data->flags |= CPU_HAS_PTEA;
break;
case 0x600:
cpu_data->type = CPU_SH4_202;
cpu_data->icache.ways = 2;
cpu_data->dcache.ways = 2;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x500 ... 0x501:
switch (prr) {
- case 0x10: cpu_data->type = CPU_SH7750R; break;
- case 0x11: cpu_data->type = CPU_SH7751R; break;
- case 0x50: cpu_data->type = CPU_SH7760; break;
+ case 0x10:
+ cpu_data->type = CPU_SH7750R;
+ break;
+ case 0x11:
+ cpu_data->type = CPU_SH7751R;
+ break;
+ case 0x50 ... 0x5f:
+ cpu_data->type = CPU_SH7760;
+ break;
}
cpu_data->icache.ways = 2;
cpu_data->dcache.ways = 2;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
+
break;
default:
cpu_data->type = CPU_SH_NONE;
break;
}
+#ifdef CONFIG_SH_DIRECT_MAPPED
+ cpu_data->icache.ways = 1;
+ cpu_data->dcache.ways = 1;
+#endif
+
/*
* On anything that's not a direct-mapped cache, look to the CVR
* for I/D-cache specifics.
@@ -121,18 +181,56 @@ int __init detect_cpu_and_cache_system(void)
size = sizes[(cvr >> 20) & 0xf];
cpu_data->icache.way_incr = (size >> 1);
cpu_data->icache.sets = (size >> 6);
- cpu_data->icache.entry_mask =
- (cpu_data->icache.way_incr - (1 << 5));
+
}
+ /* Setup the rest of the I-cache info */
+ cpu_data->icache.entry_mask = cpu_data->icache.way_incr -
+ cpu_data->icache.linesz;
+
+ cpu_data->icache.way_size = cpu_data->icache.sets *
+ cpu_data->icache.linesz;
+
+ /* And the rest of the D-cache */
if (cpu_data->dcache.ways > 1) {
size = sizes[(cvr >> 16) & 0xf];
cpu_data->dcache.way_incr = (size >> 1);
cpu_data->dcache.sets = (size >> 6);
- cpu_data->dcache.entry_mask =
- (cpu_data->dcache.way_incr - (1 << 5));
+ }
+
+ cpu_data->dcache.entry_mask = cpu_data->dcache.way_incr -
+ cpu_data->dcache.linesz;
+
+ cpu_data->dcache.way_size = cpu_data->dcache.sets *
+ cpu_data->dcache.linesz;
+
+ /*
+ * Setup the L2 cache desc
+ *
+ * SH-4A's have an optional PIPT L2.
+ */
+ if (cpu_data->flags & CPU_HAS_L2_CACHE) {
+ /*
+ * Size calculation is much more sensible
+ * than it is for the L1.
+ *
+ * Sizes are 128KB, 258KB, 512KB, and 1MB.
+ */
+ size = (cvr & 0xf) << 17;
+
+ BUG_ON(!size);
+
+ cpu_data->scache.way_incr = (1 << 16);
+ cpu_data->scache.entry_shift = 5;
+ cpu_data->scache.ways = 4;
+ cpu_data->scache.linesz = L1_CACHE_BYTES;
+ cpu_data->scache.entry_mask =
+ (cpu_data->scache.way_incr - cpu_data->scache.linesz);
+ cpu_data->scache.sets = size /
+ (cpu_data->scache.linesz * cpu_data->scache.ways);
+ cpu_data->scache.way_size =
+ (cpu_data->scache.sets * cpu_data->scache.linesz);
}
return 0;
}
-
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 00000000000..6e4e9654135
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -0,0 +1,43 @@
+/*
+ * SH4-202 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe80000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh4202_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh4202_devices_setup(void)
+{
+ return platform_add_devices(sh4202_devices,
+ ARRAY_SIZE(sh4202_devices));
+}
+__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 00000000000..cc9ea1e2e5d
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
@@ -0,0 +1,43 @@
+/*
+ * SH73180 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe80000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 80, 81, 83, 82 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh73180_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh73180_devices_setup(void)
+{
+ return platform_add_devices(sh73180_devices,
+ ARRAY_SIZE(sh73180_devices));
+}
+__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 00000000000..91d61cf91ba
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
@@ -0,0 +1,43 @@
+/*
+ * SH7343 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe00000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 80, 81, 83, 82 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7343_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7343_devices_setup(void)
+{
+ return platform_add_devices(sh7343_devices,
+ ARRAY_SIZE(sh7343_devices));
+}
+__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 00000000000..50812d57c1c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -0,0 +1,48 @@
+/*
+ * SH7750/SH7751 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe00000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCI,
+ .irqs = { 23, 24, 25, 0 },
+ }, {
+ .mapbase = 0xffe80000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7750_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7750_devices_setup(void)
+{
+ return platform_add_devices(sh7750_devices,
+ ARRAY_SIZE(sh7750_devices));
+}
+__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 00000000000..97f1c9af35d
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -0,0 +1,53 @@
+/*
+ * SH7760 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xfe600000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 52, 53, 55, 54 },
+ }, {
+ .mapbase = 0xfe610000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 72, 73, 75, 74 },
+ }, {
+ .mapbase = 0xfe620000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 76, 77, 79, 78 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7760_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7760_devices_setup(void)
+{
+ return platform_add_devices(sh7760_devices,
+ ARRAY_SIZE(sh7760_devices));
+}
+__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 00000000000..6a04cc5f5ac
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
@@ -0,0 +1,53 @@
+/*
+ * SH7770 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xff923000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 61, 61, 61, 61 },
+ }, {
+ .mapbase = 0xff924000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 62, 62, 62, 62 },
+ }, {
+ .mapbase = 0xff925000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 63, 63, 63, 63 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7770_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7770_devices_setup(void)
+{
+ return platform_add_devices(sh7770_devices,
+ ARRAY_SIZE(sh7770_devices));
+}
+__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 00000000000..72493f259ed
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
@@ -0,0 +1,79 @@
+/*
+ * SH7780 Setup
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xffe80000,
+ .end = 0xffe80000 + 0x58 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Period IRQ */
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* Carry IRQ */
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ /* Alarm IRQ */
+ .start = 23,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe00000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .mapbase = 0xffe10000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 76, 77, 79, 78 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7780_devices[] __initdata = {
+ &rtc_device,
+ &sci_device,
+};
+
+static int __init sh7780_devices_setup(void)
+{
+ return platform_add_devices(sh7780_devices,
+ ARRAY_SIZE(sh7780_devices));
+}
+__initcall(sh7780_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index b09805f3ee2..7bcc73f9b8d 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -1,49 +1,52 @@
/*
- * arch/sh/kernel/cpu/sq.c
+ * arch/sh/kernel/cpu/sh4/sq.c
*
* General management API for SH-4 integrated Store Queues
*
- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2001 - 2006 Paul Mundt
* Copyright (C) 2001, 2002 M. R. Brown
*
- * Some of this code has been adopted directly from the old arch/sh/mm/sq.c
- * hack that was part of the LinuxDC project. For all intents and purposes,
- * this is a completely new interface that really doesn't have much in common
- * with the old zone-based approach at all. In fact, it's only listed here for
- * general completeness.
- *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/bitmap.h>
+#include <linux/sysdev.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/miscdevice.h>
#include <linux/vmalloc.h>
-
+#include <linux/mm.h>
#include <asm/io.h>
#include <asm/page.h>
-#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
#include <asm/cpu/sq.h>
-static LIST_HEAD(sq_mapping_list);
+struct sq_mapping;
+
+struct sq_mapping {
+ const char *name;
+
+ unsigned long sq_addr;
+ unsigned long addr;
+ unsigned int size;
+
+ struct sq_mapping *next;
+};
+
+static struct sq_mapping *sq_mapping_list;
static DEFINE_SPINLOCK(sq_mapping_lock);
+static kmem_cache_t *sq_cache;
+static unsigned long *sq_bitmap;
-/**
- * sq_flush - Flush (prefetch) the store queue cache
- * @addr: the store queue address to flush
- *
- * Executes a prefetch instruction on the specified store queue cache,
- * so that the cached data is written to physical memory.
- */
-inline void sq_flush(void *addr)
-{
- __asm__ __volatile__ ("pref @%0" : : "r" (addr) : "memory");
-}
+#define store_queue_barrier() \
+do { \
+ (void)ctrl_inl(P4SEG_STORE_QUE); \
+ ctrl_outl(0, P4SEG_STORE_QUE + 0); \
+ ctrl_outl(0, P4SEG_STORE_QUE + 8); \
+} while (0);
/**
* sq_flush_range - Flush (prefetch) a specific SQ range
@@ -56,152 +59,73 @@ inline void sq_flush(void *addr)
void sq_flush_range(unsigned long start, unsigned int len)
{
volatile unsigned long *sq = (unsigned long *)start;
- unsigned long dummy;
/* Flush the queues */
for (len >>= 5; len--; sq += 8)
- sq_flush((void *)sq);
+ prefetchw((void *)sq);
/* Wait for completion */
- dummy = ctrl_inl(P4SEG_STORE_QUE);
-
- ctrl_outl(0, P4SEG_STORE_QUE + 0);
- ctrl_outl(0, P4SEG_STORE_QUE + 8);
+ store_queue_barrier();
}
-static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name)
+static inline void sq_mapping_list_add(struct sq_mapping *map)
{
- struct sq_mapping *map;
-
- if (virt + size > SQ_ADDRMAX)
- return ERR_PTR(-ENOSPC);
-
- map = kmalloc(sizeof(struct sq_mapping), GFP_KERNEL);
- if (!map)
- return ERR_PTR(-ENOMEM);
+ struct sq_mapping **p, *tmp;
- INIT_LIST_HEAD(&map->list);
+ spin_lock_irq(&sq_mapping_lock);
- map->sq_addr = virt;
- map->addr = phys;
- map->size = size + 1;
- map->name = name;
+ p = &sq_mapping_list;
+ while ((tmp = *p) != NULL)
+ p = &tmp->next;
- list_add(&map->list, &sq_mapping_list);
+ map->next = tmp;
+ *p = map;
- return map;
+ spin_unlock_irq(&sq_mapping_lock);
}
-static unsigned long __sq_get_next_addr(void)
+static inline void sq_mapping_list_del(struct sq_mapping *map)
{
- if (!list_empty(&sq_mapping_list)) {
- struct list_head *pos, *tmp;
-
- /*
- * Read one off the list head, as it will have the highest
- * mapped allocation. Set the next one up right above it.
- *
- * This is somewhat sub-optimal, as we don't look at
- * gaps between allocations or anything lower then the
- * highest-level allocation.
- *
- * However, in the interest of performance and the general
- * lack of desire to do constant list rebalancing, we don't
- * worry about it.
- */
- list_for_each_safe(pos, tmp, &sq_mapping_list) {
- struct sq_mapping *entry;
-
- entry = list_entry(pos, typeof(*entry), list);
-
- return entry->sq_addr + entry->size;
+ struct sq_mapping **p, *tmp;
+
+ spin_lock_irq(&sq_mapping_lock);
+
+ for (p = &sq_mapping_list; (tmp = *p); p = &tmp->next)
+ if (tmp == map) {
+ *p = tmp->next;
+ break;
}
- }
- return P4SEG_STORE_QUE;
+ spin_unlock_irq(&sq_mapping_lock);
}
-/**
- * __sq_remap - Perform a translation from the SQ to a phys addr
- * @map: sq mapping containing phys and store queue addresses.
- *
- * Maps the store queue address specified in the mapping to the physical
- * address specified in the mapping.
- */
-static struct sq_mapping *__sq_remap(struct sq_mapping *map)
+static int __sq_remap(struct sq_mapping *map, unsigned long flags)
{
- unsigned long flags, pteh, ptel;
+#if defined(CONFIG_MMU)
struct vm_struct *vma;
- pgprot_t pgprot;
-
- /*
- * Without an MMU (or with it turned off), this is much more
- * straightforward, as we can just load up each queue's QACR with
- * the physical address appropriately masked.
- */
-
- ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
- ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
-#ifdef CONFIG_MMU
- /*
- * With an MMU on the other hand, things are slightly more involved.
- * Namely, we have to have a direct mapping between the SQ addr and
- * the associated physical address in the UTLB by way of setting up
- * a virt<->phys translation by hand. We do this by simply specifying
- * the SQ addr in UTLB.VPN and the associated physical address in
- * UTLB.PPN.
- *
- * Notably, even though this is a special case translation, and some
- * of the configuration bits are meaningless, we're still required
- * to have a valid ASID context in PTEH.
- *
- * We could also probably get by without explicitly setting PTEA, but
- * we do it here just for good measure.
- */
- spin_lock_irqsave(&sq_mapping_lock, flags);
-
- pteh = map->sq_addr;
- ctrl_outl((pteh & MMU_VPN_MASK) | get_asid(), MMU_PTEH);
-
- ptel = map-&