aboutsummaryrefslogtreecommitdiff
path: root/arch/sh/kernel/cpu
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-06-20 18:27:10 +0900
committerPaul Mundt <lethal@linux-sh.org>2007-06-20 18:27:10 +0900
commit2b1bd1ac5d4bffe3fd542bfe1784a583bd7df4fa (patch)
tree9c9840807d84cb4d9ca981fbae5093eef1c9ed12 /arch/sh/kernel/cpu
parent027e56e68543780870fda74360ca45e392c50e1c (diff)
sh: Preliminary support for the SH-X3 CPU.
This adds basic support for UP SH-X3. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu')
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S19
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c8
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-shx3.c135
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c85
5 files changed, 249 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index b0b59d4a33c..d8e122971c3 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -340,8 +340,27 @@ ENTRY(vbr_base)
general_exception:
mov.l 1f, k2
mov.l 2f, k3
+#ifdef CONFIG_CPU_SUBTYPE_SHX3
+ mov.l @k2, k2
+
+ ! Is EXPEVT larger than 0x800?
+ mov #0x8, k0
+ shll8 k0
+ cmp/hs k0, k2
+ bf 0f
+
+ ! then add 0x580 (k2 is 0xd80 or 0xda0)
+ mov #0x58, k0
+ shll2 k0
+ shll2 k0
+ add k0, k2
+0:
+ bra handle_exception
+ nop
+#else
bra handle_exception
mov.l @k2, k2
+#endif
.align 2
1: .long EXPEVT
2: .long ret_from_exception
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index fab2eb07196..66c3f75647b 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -141,6 +141,14 @@ int __init detect_cpu_and_cache_system(void)
current_cpu_data.flags |= CPU_HAS_LLSC;
}
break;
+ case 0x4000: /* 1st cut */
+ case 0x4001: /* 2nd cut */
+ current_cpu_data.type = CPU_SHX3;
+ current_cpu_data.icache.ways = 4;
+ current_cpu_data.dcache.ways = 4;
+ current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ CPU_HAS_LLSC;
+ break;
case 0x8000:
current_cpu_data.type = CPU_ST40RA;
current_cpu_data.flags |= CPU_HAS_FPU;
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index ab7422f8f82..40062328648 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
+obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
@@ -17,5 +18,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
new file mode 100644
index 00000000000..c630b29e06a
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
@@ -0,0 +1,135 @@
+/*
+ * arch/sh/kernel/cpu/sh4/clock-shx3.c
+ *
+ * SH-X3 support for the clock framework
+ *
+ * Copyright (C) 2006-2007 Renesas Technology Corp.
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ * Copyright (C) 2006-2007 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/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int ifc_divisors[] = { 1, 2, 4 ,6 };
+static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 };
+static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 };
+static int cfc_divisors[] = { 1, 1, 4, 6 };
+
+#define IFC_POS 28
+#define IFC_MSK 0x0003
+#define BFC_MSK 0x000f
+#define PFC_MSK 0x000f
+#define CFC_MSK 0x0003
+#define BFC_POS 16
+#define PFC_POS 0
+#define CFC_POS 20
+
+static void master_clk_init(struct clk *clk)
+{
+ clk->rate *= pfc_divisors[(ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK];
+}
+
+static struct clk_ops shx3_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK);
+ clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops shx3_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> BFC_POS) & BFC_MSK);
+ clk->rate = clk->parent->rate / bfc_divisors[idx];
+}
+
+static struct clk_ops shx3_bus_clk_ops = {
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> IFC_POS) & IFC_MSK);
+ clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops shx3_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *shx3_clk_ops[] = {
+ &shx3_master_clk_ops,
+ &shx3_module_clk_ops,
+ &shx3_bus_clk_ops,
+ &shx3_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(shx3_clk_ops))
+ *ops = shx3_clk_ops[idx];
+}
+
+static void shyway_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> CFC_POS) & CFC_MSK);
+ clk->rate = clk->parent->rate / cfc_divisors[idx];
+}
+
+static struct clk_ops shx3_shyway_clk_ops = {
+ .recalc = shyway_clk_recalc,
+};
+
+static struct clk shx3_shyway_clk = {
+ .name = "shyway_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &shx3_shyway_clk_ops,
+};
+
+/*
+ * Additional SHx3-specific on-chip clocks that aren't already part of the
+ * clock framework
+ */
+static struct clk *shx3_onchip_clocks[] = {
+ &shx3_shyway_clk,
+};
+
+static int __init shx3_clk_init(void)
+{
+ struct clk *clk = clk_get(NULL, "master_clk");
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
+ struct clk *clkp = shx3_onchip_clocks[i];
+
+ clkp->parent = clk;
+ clk_register(clkp);
+ clk_enable(clkp);
+ }
+
+ /*
+ * Now that we have the rest of the clocks registered, we need to
+ * force the parent clock to propagate so that these clocks will
+ * automatically figure out their rate. We cheat by handing the
+ * parent clock its current rate and forcing child propagation.
+ */
+ clk_set_rate(clk, clk_get_rate(clk));
+
+ clk_put(clk);
+
+ return 0;
+}
+arch_initcall(shx3_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
new file mode 100644
index 00000000000..70683ea12b8
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -0,0 +1,85 @@
+/*
+ * SH-X3 Setup
+ *
+ * Copyright (C) 2007 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 <linux/io.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffc30000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .mapbase = 0xffc40000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 44, 45, 47, 46 },
+ }, {
+ .mapbase = 0xffc50000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 48, 49, 51, 50 },
+ }, {
+ .mapbase = 0xffc60000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 52, 53, 55, 54 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *shx3_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init shx3_devices_setup(void)
+{
+ return platform_add_devices(shx3_devices,
+ ARRAY_SIZE(shx3_devices));
+}
+__initcall(shx3_devices_setup);
+
+static struct intc2_data intc2_irq_table[] = {
+ { 16, 0, 0, 0, 1, 2 }, /* TMU0 */
+ { 40, 4, 0, 0x20, 0, 3 }, /* SCIF0 ERI */
+ { 41, 4, 0, 0x20, 1, 3 }, /* SCIF0 RXI */
+ { 42, 4, 0, 0x20, 2, 3 }, /* SCIF0 BRI */
+ { 43, 4, 0, 0x20, 3, 3 }, /* SCIF0 TXI */
+};
+
+static struct intc2_desc intc2_irq_desc __read_mostly = {
+ .prio_base = 0xfe410000,
+ .msk_base = 0xfe410820,
+ .mskclr_base = 0xfe410850,
+
+ .intc2_data = intc2_irq_table,
+ .nr_irqs = ARRAY_SIZE(intc2_irq_table),
+
+ .chip = {
+ .name = "INTC2-SHX3",
+ },
+};
+
+void __init init_IRQ_intc2(void)
+{
+ register_intc2_controller(&intc2_irq_desc);
+}