sh: Add support for SH7206 and SH7619 CPU subtypes.
authorYoshinori Sato <ysato@users.sourceforge.jp>
Sun, 5 Nov 2006 06:40:13 +0000 (15:40 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 6 Dec 2006 01:45:36 +0000 (10:45 +0900)
This implements initial support for the SH7206 (SH-2A) and SH7619
(SH-2) MMU-less CPUs.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
26 files changed:
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boot/compressed/misc.c
arch/sh/kernel/Makefile
arch/sh/kernel/cpu/Makefile
arch/sh/kernel/cpu/init.c
arch/sh/kernel/cpu/irq/imask.c
arch/sh/kernel/cpu/irq/ipr.c
arch/sh/kernel/cpu/sh2/Makefile
arch/sh/kernel/cpu/sh2/clock-sh7619.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2/probe.c
arch/sh/kernel/cpu/sh2/setup-sh7619.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/Makefile [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/clock-sh7206.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/probe.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/setup-sh7206.c [new file with mode: 0644]
arch/sh/kernel/setup.c
arch/sh/kernel/signal.c
arch/sh/kernel/timers/Makefile
arch/sh/kernel/timers/timer-cmt.c [new file with mode: 0644]
arch/sh/kernel/timers/timer-mtu2.c [new file with mode: 0644]
arch/sh/kernel/timers/timer.c
arch/sh/mm/Kconfig
arch/sh/mm/cache-sh2.c
arch/sh/tools/mach-types
drivers/serial/sh-sci.h

index bffc7e176970ffa7eb1e6ad20203fd6862ae866b..ba7a15016307c4072be14897c3c32ac3b0a28986 100644 (file)
@@ -219,6 +219,20 @@ config SH_SHMIN
        help
          Select SHMIN if configuring for the SHMIN board.
 
+config SH_7206_SOLUTION_ENGINE
+       bool "SolutionEngine7206"
+       select CPU_SUBTYPE_SH7206
+       help
+         Select 7206 SolutionEngine if configuring for a Hitachi SH7206
+         evaluation board.
+
+config SH_7619_SOLUTION_ENGINE
+       bool "SolutionEngine7619"
+       select CPU_SUBTYPE_SH7619
+       help
+         Select 7619 SolutionEngine if configuring for a Hitachi SH7619
+         evaluation board.
+
 config SH_UNKNOWN
        bool "BareCPU"
        help
@@ -364,10 +378,25 @@ depends on !GENERIC_TIME
 
 config SH_TMU
        bool "TMU timer support"
+       depends on CPU_SH3 || CPU_SH4
        default y
        help
          This enables the use of the TMU as the system timer.
 
+config SH_CMT
+       bool "CMT timer support"
+       depends on CPU_SH2
+       default y
+       help
+         This enables the use of the CMT as the system timer.
+
+config SH_MTU2
+       bool "MTU2 timer support"
+       depends on CPU_SH2A
+       default n
+       help
+         This enables the use of the MTU2 as the system timer.
+
 endmenu
 
 source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
@@ -378,17 +407,25 @@ source "arch/sh/boards/renesas/r7780rp/Kconfig"
 
 config SH_PCLK_FREQ
        int "Peripheral clock frequency (in Hz)"
+       default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
+       default "31250000" if CPU_SUBTYPE_SH7619
+       default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
+                             CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
+                             CPU_SUBTYPE_SH7206
        default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780
        default "60000000" if CPU_SUBTYPE_SH7751
-       default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
-                             CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705
-       default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
        default "66000000" if CPU_SUBTYPE_SH4_202
        help
          This option is used to specify the peripheral clock frequency.
          This is necessary for determining the reference clock value on
          platforms lacking an RTC.
 
+config SH_CLK_MD
+       int "CPU Mode Pin Setting"
+       depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206
+       help
+         MD2 - MD0 Setting.
+
 menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
index 26d62ff51a64e951b96aa90d1620365f15c7a1a1..dc43984bd4be674b08bdb8115c2884478506ac7e 100644 (file)
@@ -109,6 +109,8 @@ machdir-$(CONFIG_SH_SH4202_MICRODEV)                := superh/microdev
 machdir-$(CONFIG_SH_LANDISK)                   := landisk
 machdir-$(CONFIG_SH_TITAN)                     := titan
 machdir-$(CONFIG_SH_SHMIN)                     := shmin
+machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE)      := se/7206
+machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE)      := se/7619
 machdir-$(CONFIG_SH_UNKNOWN)                   := unknown
 
 incdir-y                       := $(notdir $(machdir-y))
@@ -124,6 +126,7 @@ core-$(CONFIG_HD64465)              += arch/sh/cchips/hd6446x/hd64465/
 core-$(CONFIG_VOYAGERGX)       += arch/sh/cchips/voyagergx/
 
 cpuincdir-$(CONFIG_CPU_SH2)    := cpu-sh2
+cpuincdir-$(CONFIG_CPU_SH2A)   := cpu-sh2a
 cpuincdir-$(CONFIG_CPU_SH3)    := cpu-sh3
 cpuincdir-$(CONFIG_CPU_SH4)    := cpu-sh4
 
index f2fed5ce5cc315b0dac14a1ffa6f568a77d6b950..35452d85b7f7f21ccf341ae3af407ed679dfb450 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <asm/uaccess.h>
+#include <asm/addrspace.h>
 #ifdef CONFIG_SH_STANDARD_BIOS
 #include <asm/sh_bios.h>
 #endif
@@ -228,7 +229,7 @@ long* stack_start = &user_stack[STACK_SIZE];
 void decompress_kernel(void)
 {
        output_data = 0;
-       output_ptr = (unsigned long)&_text+0x20001000;
+       output_ptr = P2SEGADDR((unsigned long)&_text+0x1000);
        free_mem_ptr = (unsigned long)&_end;
        free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
 
index 5da88a43d350f4d38d92956090f4dce201e17d6e..50d54c24d76ae76b445894587a3d018c2c78171f 100644 (file)
@@ -4,7 +4,7 @@
 
 extra-y        := head.o init_task.o vmlinux.lds
 
-obj-y  := process.o signal.o entry.o traps.o irq.o \
+obj-y  := process.o signal.o traps.o irq.o \
        ptrace.o setup.o time.o sys_sh.o semaphore.o \
        io.o io_generic.o sh_ksyms.o syscalls.o
 
index fb5dac0693827df8316d15ec253b7005c0349b39..0582e6712b7927aaf6bf3841758e7ba39f5f0329 100644 (file)
@@ -2,11 +2,12 @@
 # Makefile for the Linux/SuperH CPU-specifc backends.
 #
 
-obj-y  += irq/ init.o clock.o
-
-obj-$(CONFIG_CPU_SH2)          += sh2/
-obj-$(CONFIG_CPU_SH3)          += sh3/
-obj-$(CONFIG_CPU_SH4)          += sh4/
+obj-$(CONFIG_CPU_SH2)          = sh2/
+obj-$(CONFIG_CPU_SH2A)         = sh2a/
+obj-$(CONFIG_CPU_SH3)          = sh3/
+obj-$(CONFIG_CPU_SH4)          = sh4/
 
 obj-$(CONFIG_UBC_WAKEUP)       += ubc.o
 obj-$(CONFIG_SH_ADC)           += adc.o
+
+obj-y  += irq/ init.o clock.o
index bfb90eb0b7a6caabc529f33e49c5371a74f62208..48121766e8d243e07065e3f3797da7376092cc9b 100644 (file)
@@ -68,12 +68,14 @@ static void __init cache_init(void)
 
                waysize = cpu_data->dcache.sets;
 
+#ifdef CCR_CACHE_ORA
                /*
                 * If the OC is already in RAM mode, we only have
                 * half of the entries to flush..
                 */
                if (ccr & CCR_CACHE_ORA)
                        waysize >>= 1;
+#endif
 
                waysize <<= cpu_data->dcache.entry_shift;
 
index a33ae3e0a5a5dc808f72c425d69afca96d4ed531..301b505c4278929668bceeee5b2b4b09a4eca06f 100644 (file)
@@ -53,7 +53,10 @@ void static inline set_interrupt_registers(int ip)
 {
        unsigned long __dummy;
 
-       asm volatile("ldc       %2, r6_bank\n\t"
+       asm volatile(
+#ifdef CONFIG_CPU_HAS_SR_RB
+                    "ldc       %2, r6_bank\n\t"
+#endif
                     "stc       sr, %0\n\t"
                     "and       #0xf0, %0\n\t"
                     "shlr2     %0\n\t"
index a0089563cbfcfef2d7618a45c97e401185e0d86c..f7a2bae1df948ec27b97b58ab4df7f53db5faadc 100644 (file)
@@ -62,6 +62,10 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs)
 }
 EXPORT_SYMBOL(make_ipr_irq);
 
+/*
+ * XXX: Move this garbage in to the drivers, and kill off the ridiculous CPU
+ * subtype checks.
+ */
 static struct ipr_data sys_ipr_map[] = {
 #ifndef CONFIG_CPU_SUBTYPE_SH7780
        { TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY },
@@ -80,6 +84,18 @@ static struct ipr_data sys_ipr_map[] = {
        { SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
        { SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
 #endif
+#ifdef SCIF2_ERI_IRQ
+       { SCIF2_ERI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
+       { SCIF2_RXI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
+       { SCIF2_BRI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
+       { SCIF2_TXI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
+#endif
+#ifdef SCIF3_ERI_IRQ
+       { SCIF3_ERI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
+       { SCIF3_RXI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
+       { SCIF3_BRI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
+       { SCIF3_TXI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
+#endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7300)
        { SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
        { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
index 389353fba608f7aecf9a6e606f8f28892fbdeaf5..f0f059acfcfbd5707766eea4c8c15064bfd437cf 100644 (file)
@@ -2,5 +2,6 @@
 # Makefile for the Linux/SuperH SH-2 backends.
 #
 
-obj-y  := probe.o
+obj-y  := ex.o probe.o entry.o
 
+obj-$(CONFIG_CPU_SUBTYPE_SH7619) += setup-sh7619.o clock-sh7619.o
diff --git a/arch/sh/kernel/cpu/sh2/clock-sh7619.c b/arch/sh/kernel/cpu/sh2/clock-sh7619.c
new file mode 100644 (file)
index 0000000..d0440b2
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * arch/sh/kernel/cpu/sh2/clock-sh7619.c
+ *
+ * SH7619 support for the clock framework
+ *
+ *  Copyright (C) 2006  Yoshinori Sato
+ *
+ * Based on clock-sh4.c
+ *  Copyright (C) 2005  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>
+
+const static int pll1rate[]={1,2};
+const static int pfc_divisors[]={1,2,0,4};
+
+#if (CONFIG_SH_CLK_MD == 1) || (CONFIG_SH_CLK_MD == 2)
+#define PLL2 (4)
+#elif (CONFIG_SH_CLK_MD == 5) || (CONFIG_SH_CLK_MD == 6)
+#define PLL2 (2)
+#else
+#error "Illigal Clock Mode!"
+#endif
+
+static void master_clk_init(struct clk *clk)
+{
+       clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 7];
+}
+
+static struct clk_ops sh7619_master_clk_ops = {
+       .init           = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+       int idx = (ctrl_inw(FREQCR) & 0x0007);
+       clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7619_module_clk_ops = {
+       .recalc         = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+       clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 7];
+}
+
+static struct clk_ops sh7619_bus_clk_ops = {
+       .recalc         = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+       clk->rate = clk->parent->rate;
+}
+
+static struct clk_ops sh7619_cpu_clk_ops = {
+       .recalc         = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7619_clk_ops[] = {
+       &sh7619_master_clk_ops,
+       &sh7619_module_clk_ops,
+       &sh7619_bus_clk_ops,
+       &sh7619_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+       if (idx < ARRAY_SIZE(sh7619_clk_ops))
+               *ops = sh7619_clk_ops[idx];
+}
+
index f17a2a0d588edf52985018241c333374d7da03da..ba527d9b502411a56db05cb9b840688f8e4ba4fb 100644 (file)
 
 int __init detect_cpu_and_cache_system(void)
 {
-       /*
-        * For now, assume SH7604 .. fix this later.
-        */
+#if defined(CONFIG_CPU_SUBTYPE_SH7604)
        cpu_data->type                  = CPU_SH7604;
        cpu_data->dcache.ways           = 4;
-       cpu_data->dcache.way_shift      = 6;
+       cpu_data->dcache.way_incr       = (1<<10);
        cpu_data->dcache.sets           = 64;
        cpu_data->dcache.entry_shift    = 4;
        cpu_data->dcache.linesz         = L1_CACHE_BYTES;
        cpu_data->dcache.flags          = 0;
-
+#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+       cpu_data->type                  = CPU_SH7619;
+       cpu_data->dcache.ways           = 4;
+       cpu_data->dcache.way_incr       = (1<<12);
+       cpu_data->dcache.sets           = 256;
+       cpu_data->dcache.entry_shift    = 4;
+       cpu_data->dcache.linesz         = L1_CACHE_BYTES;
+       cpu_data->dcache.flags          = 0;
+#endif
        /*
         * SH-2 doesn't have separate caches
         */
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
new file mode 100644 (file)
index 0000000..82c2d90
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SH7619 Setup
+ *
+ *  Copyright (C) 2006  Yoshinori Sato
+ *
+ * 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        = 0xf8400000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           =  { 88, 89, 91, 90},
+       }, {
+               .mapbase        = 0xf8410000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           =  { 92, 93, 95, 94},
+       }, {
+               .mapbase        = 0xf8420000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           =  { 96, 97, 99, 98},
+       }, {
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+static struct platform_device *sh7619_devices[] __initdata = {
+       &sci_device,
+};
+
+static int __init sh7619_devices_setup(void)
+{
+       return platform_add_devices(sh7619_devices,
+                                   ARRAY_SIZE(sh7619_devices));
+}
+__initcall(sh7619_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
new file mode 100644 (file)
index 0000000..350972a
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the Linux/SuperH SH-2A backends.
+#
+
+obj-y  := common.o probe.o
+
+common-y       += $(addprefix ../sh2/, ex.o)
+common-y       += $(addprefix ../sh2/, entry.o)
+
+obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c
new file mode 100644 (file)
index 0000000..a9ad309
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7206.c
+ *
+ * SH7206 support for the clock framework
+ *
+ *  Copyright (C) 2006  Yoshinori Sato
+ *
+ * Based on clock-sh4.c
+ *  Copyright (C) 2005  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>
+
+const static int pll1rate[]={1,2,3,4,6,8};
+const static int pfc_divisors[]={1,2,3,4,6,8,12};
+#define ifc_divisors pfc_divisors
+
+#if (CONFIG_SH_CLK_MD == 2)
+#define PLL2 (4)
+#elif (CONFIG_SH_CLK_MD == 6)
+#define PLL2 (2)
+#elif (CONFIG_SH_CLK_MD == 7)
+#define PLL2 (1)
+#else
+#error "Illigal Clock Mode!"
+#endif
+
+static void master_clk_init(struct clk *clk)
+{
+       clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
+}
+
+static struct clk_ops sh7206_master_clk_ops = {
+       .init           = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+       int idx = (ctrl_inw(FREQCR) & 0x0007);
+       clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7206_module_clk_ops = {
+       .recalc         = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+       clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
+}
+
+static struct clk_ops sh7206_bus_clk_ops = {
+       .recalc         = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+       int idx = (ctrl_inw(FREQCR) & 0x0007);
+       clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops sh7206_cpu_clk_ops = {
+       .recalc         = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7206_clk_ops[] = {
+       &sh7206_master_clk_ops,
+       &sh7206_module_clk_ops,
+       &sh7206_bus_clk_ops,
+       &sh7206_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+       if (idx < ARRAY_SIZE(sh7206_clk_ops))
+               *ops = sh7206_clk_ops[idx];
+}
+
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
new file mode 100644 (file)
index 0000000..87c6c05
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/probe.c
+ *
+ * CPU Subtype Probing for SH-2A.
+ *
+ * Copyright (C) 2004, 2005 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 <asm/processor.h>
+#include <asm/cache.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+       /* Just SH7206 for now .. */
+       cpu_data->type                  = CPU_SH7206;
+
+       cpu_data->dcache.ways           = 4;
+       cpu_data->dcache.way_incr       = (1 << 11);
+       cpu_data->dcache.sets           = 128;
+       cpu_data->dcache.entry_shift    = 4;
+       cpu_data->dcache.linesz         = L1_CACHE_BYTES;
+       cpu_data->dcache.flags          = 0;
+
+       /*
+        * The icache is the same as the dcache as far as this setup is
+        * concerned. The only real difference in hardware is that the icache
+        * lacks the U bit that the dcache has, none of this has any bearing
+        * on the cache info.
+        */
+       cpu_data->icache                = cpu_data->dcache;
+
+       return 0;
+}
+
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
new file mode 100644 (file)
index 0000000..cdfeef4
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SH7206 Setup
+ *
+ *  Copyright (C) 2006  Yoshinori Sato
+ *
+ * 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        = 0xfffe8000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           =  { 240, 241, 242, 243},
+       }, {
+               .mapbase        = 0xfffe8800,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           =  { 244, 245, 246, 247},
+       }, {
+               .mapbase        = 0xfffe9000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           =  { 248, 249, 250, 251},
+       }, {
+               .mapbase        = 0xfffe9800,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           =  { 252, 253, 254, 255},
+       }, {
+               .flags = 0,
+       }
+};
+
+static struct platform_device sci_device = {
+       .name           = "sh-sci",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = sci_platform_data,
+       },
+};
+
+static struct platform_device *sh7206_devices[] __initdata = {
+       &sci_device,
+};
+
+static int __init sh7206_devices_setup(void)
+{
+       return platform_add_devices(sh7206_devices,
+                                   ARRAY_SIZE(sh7206_devices));
+}
+__initcall(sh7206_devices_setup);
index 36d86f9ac38a78b2834c6ba6551c1a6053ac76ef..c24f6390007b78e8ea8c79ef44fef3cd6c5737ec 100644 (file)
@@ -404,6 +404,7 @@ static const char *cpu_name[] = {
        [CPU_SH4_202]   = "SH4-202",    [CPU_SH4_501]   = "SH4-501",
        [CPU_SH7770]    = "SH7770",     [CPU_SH7780]    = "SH7780",
        [CPU_SH7781]    = "SH7781",     [CPU_SH7343]    = "SH7343",
+       [CPU_SH7206]    = "SH7206",     [CPU_SH7619]    = "SH7619",
        [CPU_SH_NONE]   = "Unknown"
 };
 
index 5213f5bc6ce0832c395f5b69f4eeacf407a41479..764886b4bcf18f0f999f80ddb00e19b0b8325c32 100644 (file)
@@ -98,7 +98,11 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
  */
 
 #define MOVW(n)         (0x9300|((n)-2))       /* Move mem word at PC+n to R3 */
-#define TRAP16  0xc310                 /* Syscall w/no args (NR in R3) */
+#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
+#define TRAP_NOARG 0xc320              /* Syscall w/no args (NR in R3) */
+#else
+#define TRAP_NOARG 0xc310              /* Syscall w/no args (NR in R3) */
+#endif
 #define OR_R0_R0 0x200b                        /* or r0,r0 (insert to avoid hardware bug) */
 
 struct sigframe
@@ -350,7 +354,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
        } else {
                /* Generate return code (system call to sigreturn) */
                err |= __put_user(MOVW(7), &frame->retcode[0]);
-               err |= __put_user(TRAP16, &frame->retcode[1]);
+               err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
                err |= __put_user(OR_R0_R0, &frame->retcode[2]);
                err |= __put_user(OR_R0_R0, &frame->retcode[3]);
                err |= __put_user(OR_R0_R0, &frame->retcode[4]);
@@ -430,7 +434,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        } else {
                /* Generate return code (system call to rt_sigreturn) */
                err |= __put_user(MOVW(7), &frame->retcode[0]);
-               err |= __put_user(TRAP16, &frame->retcode[1]);
+               err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
                err |= __put_user(OR_R0_R0, &frame->retcode[2]);
                err |= __put_user(OR_R0_R0, &frame->retcode[3]);
                err |= __put_user(OR_R0_R0, &frame->retcode[4]);
index 151a6a304ceca4ca484223d1707d799c184be300..bcf244ff6a128a90698257804490f9d6c3d4be97 100644 (file)
@@ -5,4 +5,6 @@
 obj-y  := timer.o
 
 obj-$(CONFIG_SH_TMU)           += timer-tmu.o
+obj-$(CONFIG_SH_MTU2)          += timer-mtu2.o
+obj-$(CONFIG_SH_CMT)           += timer-cmt.o
 
diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c
new file mode 100644 (file)
index 0000000..9eab395
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * arch/sh/kernel/timers/timer-cmt.c - CMT Timer Support
+ *
+ *  Copyright (C) 2005  Yoshinori Sato
+ *
+ * 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 <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/seqlock.h>
+#include <asm/timer.h>
+#include <asm/rtc.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/clock.h>
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7619)
+#define CMT_CMSTR      0xf84a0070
+#define CMT_CMCSR_0    0xf84a0072
+#define CMT_CMCNT_0    0xf84a0074
+#define CMT_CMCOR_0    0xf84a0076
+#define CMT_CMCSR_1    0xf84a0078
+#define CMT_CMCNT_1    0xf84a007a
+#define CMT_CMCOR_1    0xf84a007c
+
+#define STBCR3         0xf80a0000
+#define cmt_clock_enable() do {        ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0)
+#define CMT_CMCSR_INIT 0x0040
+#define CMT_CMCSR_CALIB        0x0000
+#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
+#define CMT_CMSTR      0xfffec000
+#define CMT_CMCSR_0    0xfffec002
+#define CMT_CMCNT_0    0xfffec004
+#define CMT_CMCOR_0    0xfffec006
+
+#define STBCR4         0xfffe040c
+#define cmt_clock_enable() do {        ctrl_outb(ctrl_inb(STBCR4) & ~0x04, STBCR4); } while(0)
+#define CMT_CMCSR_INIT 0x0040
+#define CMT_CMCSR_CALIB        0x0000
+#else
+#error "Unknown CPU SUBTYPE"
+#endif
+
+static DEFINE_SPINLOCK(cmt0_lock);
+
+static unsigned long cmt_timer_get_offset(void)
+{
+       int count;
+       unsigned long flags;
+
+       static unsigned short count_p = 0xffff;    /* for the first call after boot */
+       static unsigned long jiffies_p = 0;
+
+       /*
+        * cache volatile jiffies temporarily; we have IRQs turned off.
+        */
+       unsigned long jiffies_t;
+
+       spin_lock_irqsave(&cmt0_lock, flags);
+       /* timer count may underflow right here */
+       count =  ctrl_inw(CMT_CMCOR_0);
+       count -= ctrl_inw(CMT_CMCNT_0);
+
+       jiffies_t = jiffies;
+
+       /*
+        * avoiding timer inconsistencies (they are rare, but they happen)...
+        * there is one kind of problem that must be avoided here:
+        *  1. the timer counter underflows
+        */
+
+       if (jiffies_t == jiffies_p) {
+               if (count > count_p) {
+                       /* the nutcase */
+                       if (ctrl_inw(CMT_CMCSR_0) & 0x80) { /* Check CMF bit */
+                               count -= LATCH;
+                       } else {
+                               printk("%s (): hardware timer problem?\n",
+                                      __FUNCTION__);
+                       }
+               }
+       } else
+               jiffies_p = jiffies_t;
+
+       count_p = count;
+       spin_unlock_irqrestore(&cmt0_lock, flags);
+
+       count = ((LATCH-1) - count) * TICK_SIZE;
+       count = (count + LATCH/2) / LATCH;
+
+       return count;
+}
+
+static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id,
+                                      struct pt_regs *regs)
+{
+       unsigned long timer_status;
+
+       /* Clear CMF bit */
+       timer_status = ctrl_inw(CMT_CMCSR_0);
+       timer_status &= ~0x80;
+       ctrl_outw(timer_status, CMT_CMCSR_0);
+
+       /*
+        * Here we are in the timer irq handler. We just have irqs locally
+        * disabled but we don't know if the timer_bh is running on the other
+        * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+        * the irq version of write_lock because as just said we have irq
+        * locally disabled. -arca
+        */
+       write_seqlock(&xtime_lock);
+       handle_timer_tick(regs);
+       write_sequnlock(&xtime_lock);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction cmt_irq = {
+       .name           = "timer",
+       .handler        = cmt_timer_interrupt,
+       .flags          = SA_INTERRUPT,
+       .mask           = CPU_MASK_NONE,
+};
+
+/*
+ * Hah!  We'll see if this works (switching from usecs to nsecs).
+ */
+static unsigned long cmt_timer_get_frequency(void)
+{
+       u32 freq;
+       struct timespec ts1, ts2;
+       unsigned long diff_nsec;
+       unsigned long factor;
+
+       /* Setup the timer:  We don't want to generate interrupts, just
+        * have it count down at its natural rate.
+        */
+       
+       ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR);
+       ctrl_outw(CMT_CMCSR_CALIB, CMT_CMCSR_0);
+       ctrl_outw(0xffff, CMT_CMCOR_0);
+       ctrl_outw(0xffff, CMT_CMCNT_0);
+
+       rtc_sh_get_time(&ts2);
+
+       do {
+               rtc_sh_get_time(&ts1);
+       } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+       /* actually start the timer */
+       ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
+
+       do {
+               rtc_sh_get_time(&ts2);
+       } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+       freq = 0xffff - ctrl_inw(CMT_CMCNT_0);
+       if (ts2.tv_nsec < ts1.tv_nsec) {
+               ts2.tv_nsec += 1000000000;
+               ts2.tv_sec--;
+       }
+
+       diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
+
+       /* this should work well if the RTC has a precision of n Hz, where
+        * n is an integer.  I don't think we have to worry about the other
+        * cases. */
+       factor = (1000000000 + diff_nsec/2) / diff_nsec;
+
+       if (factor * diff_nsec > 1100000000 ||
+           factor * diff_nsec <  900000000)
+               panic("weird RTC (diff_nsec %ld)", diff_nsec);
+
+       return freq * factor;
+}
+
+static void cmt_clk_init(struct clk *clk)
+{
+       u8 divisor = CMT_CMCSR_INIT & 0x3;
+       ctrl_inw(CMT_CMCSR_0);
+       ctrl_outw(CMT_CMCSR_INIT, CMT_CMCSR_0);
+       clk->parent = clk_get("module_clk");
+       clk->rate = clk->parent->rate / (8 << (divisor << 1));
+}
+
+static void cmt_clk_recalc(struct clk *clk)
+{
+       u8 divisor = ctrl_inw(CMT_CMCSR_0) & 0x3;
+       clk->rate = clk->parent->rate / (8 << (divisor << 1));
+}
+
+static struct clk_ops cmt_clk_ops = {
+       .init           = cmt_clk_init,
+       .recalc         = cmt_clk_recalc,
+};
+
+static struct clk cmt0_clk = {
+       .name           = "cmt0_clk",
+       .ops            = &cmt_clk_ops,
+};
+
+static int cmt_timer_start(void)
+{
+       ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
+       return 0;
+}
+
+static int cmt_timer_stop(void)
+{
+       ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR);
+       return 0;
+}
+
+static int cmt_timer_init(void)
+{
+       unsigned long interval;
+
+       cmt_clock_enable();
+
+       setup_irq(TIMER_IRQ, &cmt_irq);
+
+       cmt0_clk.parent = clk_get("module_clk");
+
+       cmt_timer_stop();
+
+       interval = cmt0_clk.parent->rate / 8 / HZ;
+       printk(KERN_INFO "Interval = %ld\n", interval);
+
+       ctrl_outw(interval, CMT_CMCOR_0);
+
+       clk_register(&cmt0_clk);
+       clk_enable(&cmt0_clk);
+
+       cmt_timer_start();
+
+       return 0;
+}
+
+struct sys_timer_ops cmt_timer_ops = {
+       .init           = cmt_timer_init,
+       .start          = cmt_timer_start,
+       .stop           = cmt_timer_stop,
+       .get_frequency  = cmt_timer_get_frequency,
+       .get_offset     = cmt_timer_get_offset,
+};
+
+struct sys_timer cmt_timer = {
+       .name   = "cmt",
+       .ops    = &cmt_timer_ops,
+};
+
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
new file mode 100644 (file)
index 0000000..73a5ef3
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support
+ *
+ *  Copyright (C) 2005  Paul Mundt
+ *
+ * Based off of arch/sh/kernel/timers/timer-tmu.c
+ *
+ * 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 <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/seqlock.h>
+#include <asm/timer.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/clock.h>
+
+/*
+ * We use channel 1 for our lowly system timer. Channel 2 would be the other
+ * likely candidate, but we leave it alone as it has higher divisors that
+ * would be of more use to other more interesting applications.
+ *
+ * TODO: Presently we only implement a 16-bit single-channel system timer.
+ * However, we can implement channel cascade if we go the overflow route and
+ * get away with using 2 MTU2 channels as a 32-bit timer.
+ */
+
+static DEFINE_SPINLOCK(mtu2_lock);
+
+#define MTU2_TSTR      0xfffe4280
+#define MTU2_TCR_1     0xfffe4380
+#define MTU2_TMDR_1    0xfffe4381
+#define MTU2_TIOR_1    0xfffe4382
+#define MTU2_TIER_1    0xfffe4384
+#define MTU2_TSR_1     0xfffe4385
+#define MTU2_TCNT_1    0xfffe4386      /* 16-bit counter */
+#define MTU2_TGRA_1    0xfffe438a
+
+#define STBCR3         0xfffe0408
+
+#define MTU2_TSTR_CST1 (1 << 1)        /* Counter Start 1 */
+
+#define MTU2_TSR_TGFA  (1 << 0)        /* GRA compare match */
+
+#define MTU2_TIER_TGIEA        (1 << 0)        /* GRA compare match  interrupt enable */
+
+#define MTU2_TCR_INIT  0x22
+
+#define MTU2_TCR_CALIB  0x00
+
+static unsigned long mtu2_timer_get_offset(void)
+{
+       int count;
+       unsigned long flags;
+
+       static int count_p = 0x7fff;    /* for the first call after boot */
+       static unsigned long jiffies_p = 0;
+
+       /*
+        * cache volatile jiffies temporarily; we have IRQs turned off.
+        */
+       unsigned long jiffies_t;
+
+       spin_lock_irqsave(&mtu2_lock, flags);
+       /* timer count may underflow right here */
+       count = ctrl_inw(MTU2_TCNT_1);  /* read the latched count */
+
+       jiffies_t = jiffies;
+
+       /*
+        * avoiding timer inconsistencies (they are rare, but they happen)...
+        * there is one kind of problem that must be avoided here:
+        *  1. the timer counter underflows
+        */
+
+       if (jiffies_t == jiffies_p) {
+               if (count > count_p) {
+                       if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) {
+                               count -= LATCH;
+                       } else {
+                               printk("%s (): hardware timer problem?\n",
+                                      __FUNCTION__);
+                       }
+               }
+       } else
+               jiffies_p = jiffies_t;
+
+       count_p = count;
+       spin_unlock_irqrestore(&mtu2_lock, flags);
+
+       count = ((LATCH-1) - count) * TICK_SIZE;
+       count = (count + LATCH/2) / LATCH;
+
+       return count;
+}
+
+static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id,
+                                      struct pt_regs *regs)
+{
+       unsigned long timer_status;
+
+       /* Clear TGFA bit */
+       timer_status = ctrl_inb(MTU2_TSR_1);
+       timer_status &= ~MTU2_TSR_TGFA;
+       ctrl_outb(timer_status, MTU2_TSR_1);
+
+       /* Do timer tick */
+       write_seqlock(&xtime_lock);
+       handle_timer_tick(regs);
+       write_sequnlock(&xtime_lock);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction mtu2_irq = {
+       .name           = "timer",
+       .handler        = mtu2_timer_interrupt,
+       .flags          = SA_INTERRUPT,
+       .mask           = CPU_MASK_NONE,
+};
+
+/*
+ * Hah!  We'll see if this works (switching from usecs to nsecs).
+ */
+static unsigned long mtu2_timer_get_frequency(void)
+{
+       u32 freq;
+       struct timespec ts1, ts2;
+       unsigned long diff_nsec;
+       unsigned long factor;
+
+       /* Setup the timer:  We don't want to generate interrupts, just
+        * have it count down at its natural rate.
+        */
+       
+       ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR);
+       ctrl_outb(MTU2_TCR_CALIB, MTU2_TCR_1);
+       ctrl_outb(ctrl_inb(MTU2_TIER_1) & ~MTU2_TIER_TGIEA, MTU2_TIER_1);
+       ctrl_outw(0, MTU2_TCNT_1);
+
+       rtc_get_time(&ts2);
+
+       do {
+               rtc_get_time(&ts1);
+       } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+       /* actually start the timer */
+       ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
+
+       do {
+               rtc_get_time(&ts2);
+       } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+       freq = ctrl_inw(MTU2_TCNT_0);
+       if (ts2.tv_nsec < ts1.tv_nsec) {
+               ts2.tv_nsec += 1000000000;
+               ts2.tv_sec--;
+       }
+
+       diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
+
+       /* this should work well if the RTC has a precision of n Hz, where
+        * n is an integer.  I don't think we have to worry about the other
+        * cases. */
+       factor = (1000000000 + diff_nsec/2) / diff_nsec;
+
+       if (factor * diff_nsec > 1100000000 ||
+           factor * diff_nsec <  900000000)
+               panic("weird RTC (diff_nsec %ld)", diff_nsec);
+
+       return freq * factor;
+}
+
+static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 };
+
+static void mtu2_clk_init(struct clk *clk)
+{
+       u8 idx = MTU2_TCR_INIT & 0x7;
+
+       clk->rate = clk->parent->rate / divisors[idx];
+       /* Start TCNT counting */
+       ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
+
+}
+
+static void mtu2_clk_recalc(struct clk *clk)
+{
+       u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7;
+       clk->rate = clk->parent->rate / divisors[idx];
+}
+
+static struct clk_ops mtu2_clk_ops = {
+       .init           = mtu2_clk_init,
+       .recalc         = mtu2_clk_recalc,
+};
+
+static struct clk mtu2_clk1 = {
+       .name           = "mtu2_clk1",
+       .ops            = &mtu2_clk_ops,
+};
+
+static int mtu2_timer_start(void)
+{
+       ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
+       return 0;
+}
+
+static int mtu2_timer_stop(void)
+{
+       ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR);
+       return 0;
+}
+
+static int mtu2_timer_init(void)
+{
+       u8 tmp;
+       unsigned long interval;
+
+       setup_irq(TIMER_IRQ, &mtu2_irq);
+
+       mtu2_clk1.parent = clk_get("module_clk");
+
+       ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3);
+
+       /* Normal operation */
+       ctrl_outb(0, MTU2_TMDR_1);
+       ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1);
+       ctrl_outb(0x01, MTU2_TIOR_1);
+
+       /* Enable underflow interrupt */
+       ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1);
+
+       interval = CONFIG_SH_PCLK_FREQ / 16 / HZ;
+       printk(KERN_INFO "Interval = %ld\n", interval);
+
+       ctrl_outw(interval, MTU2_TGRA_1);
+       ctrl_outw(0, MTU2_TCNT_1);
+
+       clk_register(&mtu2_clk1);
+       clk_enable(&mtu2_clk1);
+
+       return 0;
+}
+
+struct sys_timer_ops mtu2_timer_ops = {
+       .init           = mtu2_timer_init,
+       .start          = mtu2_timer_start,
+       .stop           = mtu2_timer_stop,
+       .get_frequency  = mtu2_timer_get_frequency,
+       .get_offset     = mtu2_timer_get_offset,
+};
+
+struct sys_timer mtu2_timer = {
+       .name   = "mtu2",
+       .ops    = &mtu2_timer_ops,
+};
index dc1f631053a8175744e03e63979a9cf67618d77e..a6bcc913d25e8687f96ad783220fbdfaa64f111b 100644 (file)
 static struct sys_timer *sys_timers[] __initdata = {
 #ifdef CONFIG_SH_TMU
        &tmu_timer,
+#endif
+#ifdef CONFIG_SH_MTU2
+       &mtu2_timer,
+#endif
+#ifdef CONFIG_SH_CMT
+       &cmt_timer,
 #endif
        NULL,
 };
index 9dd606464d234347d4e0f94bec69b34f129e2a42..814a17586974e709e9b21473a950c6a7ab1059d0 100644 (file)
@@ -4,8 +4,12 @@ menu "Processor selection"
 # Processor families
 #
 config CPU_SH2
+       select SH_WRITETHROUGH if !CPU_SH2A
        bool
-       select SH_WRITETHROUGH
+
+config CPU_SH2A
+       bool
+       select CPU_SH2
 
 config CPU_SH3
        bool
@@ -40,6 +44,16 @@ config CPU_SUBTYPE_SH7604
        bool "Support SH7604 processor"
        select CPU_SH2
 
+config CPU_SUBTYPE_SH7619
+       bool "Support SH7619 processor"
+       select CPU_SH2
+
+comment "SH-2A Processor Support"
+
+config CPU_SUBTYPE_SH7206
+       bool "Support SH7206 processor"
+       select CPU_SH2A
+
 comment "SH-3 Processor Support"
 
 config CPU_SUBTYPE_SH7300
@@ -274,7 +288,6 @@ config SH_DIRECT_MAPPED
 
 config SH_WRITETHROUGH
        bool "Use write-through caching"
-       default y if CPU_SH2
        help
          Selecting this option will configure the caches in write-through
          mode, as opposed to the default write-back configuration.
index 2689cb24ea2b996aafe7a794af64e84380cf9323..6614033f6be93133a419f262d9091536cc05492e 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Released under the terms of the GNU GPL v2.0.
  */
+
 #include <linux/init.h>
 #include <linux/mm.h>
 
 #include <asm/cacheflush.h>
 #include <asm/io.h>
 
-/*
- * Calculate the OC address and set the way bit on the SH-2.
- *
- * We must have already jump_to_P2()'ed prior to calling this
- * function, since we rely on CCR manipulation to do the
- * Right Thing(tm).
- */
-unsigned long __get_oc_addr(unsigned long set, unsigned long way)
+void __flush_wback_region(void *start, int size)
 {
-       unsigned long ccr;
-
-       /*
-        * On SH-2 the way bit isn't tracked in the address field
-        * if we're doing address array access .. instead, we need
-        * to manually switch out the way in the CCR.
-        */
-       ccr = ctrl_inl(CCR);
-       ccr &= ~0x00c0;
-       ccr |= way << cpu_data->dcache.way_shift;
-
-       /*
-        * Despite the number of sets being halved, we end up losing
-        * the first 2 ways to OCRAM instead of the last 2 (if we're
-        * 4-way). As a result, forcibly setting the W1 bit handily
-        * bumps us up 2 ways.
-        */
-       if (ccr & CCR_CACHE_ORA)
-               ccr |= 1 << (cpu_data->dcache.way_shift + 1);
-
-       ctrl_outl(ccr, CCR);
-
-       return CACHE_OC_ADDRESS_ARRAY | (set << cpu_data->dcache.entry_shift);
+       unsigned long v;
+       unsigned long begin, end;
+
+       begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
+       end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
+               & ~(L1_CACHE_BYTES-1);
+       for (v = begin; v < end; v+=L1_CACHE_BYTES) {
+               /* FIXME cache purge */
+               ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
+       }
+}
+
+void __flush_purge_region(void *start, int size)
+{
+       unsigned long v;
+       unsigned long begin, end;
+
+       begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
+       end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
+               & ~(L1_CACHE_BYTES-1);
+       for (v = begin; v < end; v+=L1_CACHE_BYTES) {
+               ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
+       }
+}
+
+void __flush_invalidate_region(void *start, int size)
+{
+       unsigned long v;
+       unsigned long begin, end;
+
+       begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
+       end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
+               & ~(L1_CACHE_BYTES-1);
+       for (v = begin; v < end; v+=L1_CACHE_BYTES) {
+               ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
+       }
 }
 
index ac57638977ee639f332b541a9b2624a233a81d6d..0571755e9a84e8e6b2ae55e266043923f03423e8 100644 (file)
@@ -30,3 +30,5 @@ R7780MP                       SH_R7780MP
 TITAN                  SH_TITAN
 SHMIN                  SH_SHMIN
 7710VOIPGW             SH_7710VOIPGW
+7206SE                 SH_7206_SOLUTION_ENGINE
+7619SE                 SH_7619_SOLUTION_ENGINE
index 7ee992146ae9453c47667a7f8c505d5848644ff0..b2bc0cfb40141c4a814bd319653cba5c2e7c7446 100644 (file)
 # define SCIF_ORER     0x0001          /* Overrun error bit */
 # define SCSCR_INIT(port)      0x3a    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
 # define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
+# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
+# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
+# define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
+# define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
+# define SCSCR_INIT(port)      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
+# define SCSPTR1 0xf8410020 /* 16 bit SCIF */
+# define SCSPTR2 0xf8420020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
 #else
 # error CPU subtype not defined
 #endif
@@ -544,6 +558,28 @@ static inline int sci_rxd_in(struct uart_port *port)
        if (port->mapbase == 0xffe10000)
                return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xfffe8000)
+               return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+       if (port->mapbase == 0xfffe8800)
+               return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+       if (port->mapbase == 0xfffe9000)
+               return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+       if (port->mapbase == 0xfffe9800)
+               return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+       if (port->mapbase == 0xf8400000)
+               return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+       if (port->mapbase == 0xf8410000)
+               return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+       if (port->mapbase == 0xf8420000)
+               return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+}
 #endif
 
 /*