aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorYoshinori Sato <ysato@users.sourceforge.jp>2006-11-05 01:40:13 -0500
committerPaul Mundt <lethal@linux-sh.org>2006-12-05 20:45:36 -0500
commit9d4436a6fbc8c5eccdfcb8f5884e0a7b4a57f6d2 (patch)
treea8b7532fffa76ae526dea547cc87200466e00842 /arch/sh
parente62438630ca37539c8cc1553710bbfaa3cf960a7 (diff)
sh: Add support for SH7206 and SH7619 CPU subtypes.
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>
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/Kconfig43
-rw-r--r--arch/sh/Makefile3
-rw-r--r--arch/sh/boot/compressed/misc.c3
-rw-r--r--arch/sh/kernel/Makefile2
-rw-r--r--arch/sh/kernel/cpu/Makefile11
-rw-r--r--arch/sh/kernel/cpu/init.c2
-rw-r--r--arch/sh/kernel/cpu/irq/imask.c5
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c16
-rw-r--r--arch/sh/kernel/cpu/sh2/Makefile3
-rw-r--r--arch/sh/kernel/cpu/sh2/clock-sh7619.c81
-rw-r--r--arch/sh/kernel/cpu/sh2/probe.c16
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c53
-rw-r--r--arch/sh/kernel/cpu/sh2a/Makefile10
-rw-r--r--arch/sh/kernel/cpu/sh2a/clock-sh7206.c85
-rw-r--r--arch/sh/kernel/cpu/sh2a/probe.c39
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7206.c58
-rw-r--r--arch/sh/kernel/setup.c1
-rw-r--r--arch/sh/kernel/signal.c10
-rw-r--r--arch/sh/kernel/timers/Makefile2
-rw-r--r--arch/sh/kernel/timers/timer-cmt.c256
-rw-r--r--arch/sh/kernel/timers/timer-mtu2.c260
-rw-r--r--arch/sh/kernel/timers/timer.c6
-rw-r--r--arch/sh/mm/Kconfig17
-rw-r--r--arch/sh/mm/cache-sh2.c69
-rw-r--r--arch/sh/tools/mach-types2
25 files changed, 1000 insertions, 53 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index bffc7e176970..ba7a15016307 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -219,6 +219,20 @@ config SH_SHMIN
219 help 219 help
220 Select SHMIN if configuring for the SHMIN board. 220 Select SHMIN if configuring for the SHMIN board.
221 221
222config SH_7206_SOLUTION_ENGINE
223 bool "SolutionEngine7206"
224 select CPU_SUBTYPE_SH7206
225 help
226 Select 7206 SolutionEngine if configuring for a Hitachi SH7206
227 evaluation board.
228
229config SH_7619_SOLUTION_ENGINE
230 bool "SolutionEngine7619"
231 select CPU_SUBTYPE_SH7619
232 help
233 Select 7619 SolutionEngine if configuring for a Hitachi SH7619
234 evaluation board.
235
222config SH_UNKNOWN 236config SH_UNKNOWN
223 bool "BareCPU" 237 bool "BareCPU"
224 help 238 help
@@ -364,10 +378,25 @@ depends on !GENERIC_TIME
364 378
365config SH_TMU 379config SH_TMU
366 bool "TMU timer support" 380 bool "TMU timer support"
381 depends on CPU_SH3 || CPU_SH4
367 default y 382 default y
368 help 383 help
369 This enables the use of the TMU as the system timer. 384 This enables the use of the TMU as the system timer.
370 385
386config SH_CMT
387 bool "CMT timer support"
388 depends on CPU_SH2
389 default y
390 help
391 This enables the use of the CMT as the system timer.
392
393config SH_MTU2
394 bool "MTU2 timer support"
395 depends on CPU_SH2A
396 default n
397 help
398 This enables the use of the MTU2 as the system timer.
399
371endmenu 400endmenu
372 401
373source "arch/sh/boards/renesas/hs7751rvoip/Kconfig" 402source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
@@ -378,17 +407,25 @@ source "arch/sh/boards/renesas/r7780rp/Kconfig"
378 407
379config SH_PCLK_FREQ 408config SH_PCLK_FREQ
380 int "Peripheral clock frequency (in Hz)" 409 int "Peripheral clock frequency (in Hz)"
410 default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
411 default "31250000" if CPU_SUBTYPE_SH7619
412 default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
413 CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
414 CPU_SUBTYPE_SH7206
381 default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780 415 default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780
382 default "60000000" if CPU_SUBTYPE_SH7751 416 default "60000000" if CPU_SUBTYPE_SH7751
383 default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
384 CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705
385 default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
386 default "66000000" if CPU_SUBTYPE_SH4_202 417 default "66000000" if CPU_SUBTYPE_SH4_202
387 help 418 help
388 This option is used to specify the peripheral clock frequency. 419 This option is used to specify the peripheral clock frequency.
389 This is necessary for determining the reference clock value on 420 This is necessary for determining the reference clock value on
390 platforms lacking an RTC. 421 platforms lacking an RTC.
391 422
423config SH_CLK_MD
424 int "CPU Mode Pin Setting"
425 depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206
426 help
427 MD2 - MD0 Setting.
428
392menu "CPU Frequency scaling" 429menu "CPU Frequency scaling"
393 430
394source "drivers/cpufreq/Kconfig" 431source "drivers/cpufreq/Kconfig"
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 26d62ff51a64..dc43984bd4be 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -109,6 +109,8 @@ machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev
109machdir-$(CONFIG_SH_LANDISK) := landisk 109machdir-$(CONFIG_SH_LANDISK) := landisk
110machdir-$(CONFIG_SH_TITAN) := titan 110machdir-$(CONFIG_SH_TITAN) := titan
111machdir-$(CONFIG_SH_SHMIN) := shmin 111machdir-$(CONFIG_SH_SHMIN) := shmin
112machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) := se/7206
113machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) := se/7619
112machdir-$(CONFIG_SH_UNKNOWN) := unknown 114machdir-$(CONFIG_SH_UNKNOWN) := unknown
113 115
114incdir-y := $(notdir $(machdir-y)) 116incdir-y := $(notdir $(machdir-y))
@@ -124,6 +126,7 @@ core-$(CONFIG_HD64465) += arch/sh/cchips/hd6446x/hd64465/
124core-$(CONFIG_VOYAGERGX) += arch/sh/cchips/voyagergx/ 126core-$(CONFIG_VOYAGERGX) += arch/sh/cchips/voyagergx/
125 127
126cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2 128cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2
129cpuincdir-$(CONFIG_CPU_SH2A) := cpu-sh2a
127cpuincdir-$(CONFIG_CPU_SH3) := cpu-sh3 130cpuincdir-$(CONFIG_CPU_SH3) := cpu-sh3
128cpuincdir-$(CONFIG_CPU_SH4) := cpu-sh4 131cpuincdir-$(CONFIG_CPU_SH4) := cpu-sh4
129 132
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
index f2fed5ce5cc3..35452d85b7f7 100644
--- a/arch/sh/boot/compressed/misc.c
+++ b/arch/sh/boot/compressed/misc.c
@@ -12,6 +12,7 @@
12 */ 12 */
13 13
14#include <asm/uaccess.h> 14#include <asm/uaccess.h>
15#include <asm/addrspace.h>
15#ifdef CONFIG_SH_STANDARD_BIOS 16#ifdef CONFIG_SH_STANDARD_BIOS
16#include <asm/sh_bios.h> 17#include <asm/sh_bios.h>
17#endif 18#endif
@@ -228,7 +229,7 @@ long* stack_start = &user_stack[STACK_SIZE];
228void decompress_kernel(void) 229void decompress_kernel(void)
229{ 230{
230 output_data = 0; 231 output_data = 0;
231 output_ptr = (unsigned long)&_text+0x20001000; 232 output_ptr = P2SEGADDR((unsigned long)&_text+0x1000);
232 free_mem_ptr = (unsigned long)&_end; 233 free_mem_ptr = (unsigned long)&_end;
233 free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; 234 free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
234 235
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 5da88a43d350..50d54c24d76a 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -4,7 +4,7 @@
4 4
5extra-y := head.o init_task.o vmlinux.lds 5extra-y := head.o init_task.o vmlinux.lds
6 6
7obj-y := process.o signal.o entry.o traps.o irq.o \ 7obj-y := process.o signal.o traps.o irq.o \
8 ptrace.o setup.o time.o sys_sh.o semaphore.o \ 8 ptrace.o setup.o time.o sys_sh.o semaphore.o \
9 io.o io_generic.o sh_ksyms.o syscalls.o 9 io.o io_generic.o sh_ksyms.o syscalls.o
10 10
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index fb5dac069382..0582e6712b79 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -2,11 +2,12 @@
2# Makefile for the Linux/SuperH CPU-specifc backends. 2# Makefile for the Linux/SuperH CPU-specifc backends.
3# 3#
4 4
5obj-y += irq/ init.o clock.o 5obj-$(CONFIG_CPU_SH2) = sh2/
6 6obj-$(CONFIG_CPU_SH2A) = sh2a/
7obj-$(CONFIG_CPU_SH2) += sh2/ 7obj-$(CONFIG_CPU_SH3) = sh3/
8obj-$(CONFIG_CPU_SH3) += sh3/ 8obj-$(CONFIG_CPU_SH4) = sh4/
9obj-$(CONFIG_CPU_SH4) += sh4/
10 9
11obj-$(CONFIG_UBC_WAKEUP) += ubc.o 10obj-$(CONFIG_UBC_WAKEUP) += ubc.o
12obj-$(CONFIG_SH_ADC) += adc.o 11obj-$(CONFIG_SH_ADC) += adc.o
12
13obj-y += irq/ init.o clock.o
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index bfb90eb0b7a6..48121766e8d2 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -68,12 +68,14 @@ static void __init cache_init(void)
68 68
69 waysize = cpu_data->dcache.sets; 69 waysize = cpu_data->dcache.sets;
70 70
71#ifdef CCR_CACHE_ORA
71 /* 72 /*
72 * If the OC is already in RAM mode, we only have 73 * If the OC is already in RAM mode, we only have
73 * half of the entries to flush.. 74 * half of the entries to flush..
74 */ 75 */
75 if (ccr & CCR_CACHE_ORA) 76 if (ccr & CCR_CACHE_ORA)
76 waysize >>= 1; 77 waysize >>= 1;
78#endif
77 79
78 waysize <<= cpu_data->dcache.entry_shift; 80 waysize <<= cpu_data->dcache.entry_shift;
79 81
diff --git a/arch/sh/kernel/cpu/irq/imask.c b/arch/sh/kernel/cpu/irq/imask.c
index a33ae3e0a5a5..301b505c4278 100644
--- a/arch/sh/kernel/cpu/irq/imask.c
+++ b/arch/sh/kernel/cpu/irq/imask.c
@@ -53,7 +53,10 @@ void static inline set_interrupt_registers(int ip)
53{ 53{
54 unsigned long __dummy; 54 unsigned long __dummy;
55 55
56 asm volatile("ldc %2, r6_bank\n\t" 56 asm volatile(
57#ifdef CONFIG_CPU_HAS_SR_RB
58 "ldc %2, r6_bank\n\t"
59#endif
57 "stc sr, %0\n\t" 60 "stc sr, %0\n\t"
58 "and #0xf0, %0\n\t" 61 "and #0xf0, %0\n\t"
59 "shlr2 %0\n\t" 62 "shlr2 %0\n\t"
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index a0089563cbfc..f7a2bae1df94 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -62,6 +62,10 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs)
62} 62}
63EXPORT_SYMBOL(make_ipr_irq); 63EXPORT_SYMBOL(make_ipr_irq);
64 64
65/*
66 * XXX: Move this garbage in to the drivers, and kill off the ridiculous CPU
67 * subtype checks.
68 */
65static struct ipr_data sys_ipr_map[] = { 69static struct ipr_data sys_ipr_map[] = {
66#ifndef CONFIG_CPU_SUBTYPE_SH7780 70#ifndef CONFIG_CPU_SUBTYPE_SH7780
67 { TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY }, 71 { TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY },
@@ -80,6 +84,18 @@ static struct ipr_data sys_ipr_map[] = {
80 { SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, 84 { SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
81 { SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY }, 85 { SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
82#endif 86#endif
87#ifdef SCIF2_ERI_IRQ
88 { SCIF2_ERI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
89 { SCIF2_RXI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
90 { SCIF2_BRI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
91 { SCIF2_TXI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
92#endif
93#ifdef SCIF3_ERI_IRQ
94 { SCIF3_ERI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
95 { SCIF3_RXI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
96 { SCIF3_BRI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
97 { SCIF3_TXI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
98#endif
83#if defined(CONFIG_CPU_SUBTYPE_SH7300) 99#if defined(CONFIG_CPU_SUBTYPE_SH7300)
84 { SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY }, 100 { SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
85 { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY }, 101 { DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
diff --git a/arch/sh/kernel/cpu/sh2/Makefile b/arch/sh/kernel/cpu/sh2/Makefile
index 389353fba608..f0f059acfcfb 100644
--- a/arch/sh/kernel/cpu/sh2/Makefile
+++ b/arch/sh/kernel/cpu/sh2/Makefile
@@ -2,5 +2,6 @@
2# Makefile for the Linux/SuperH SH-2 backends. 2# Makefile for the Linux/SuperH SH-2 backends.
3# 3#
4 4
5obj-y := probe.o 5obj-y := ex.o probe.o entry.o
6 6
7obj-$(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
index 000000000000..d0440b269702
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c
@@ -0,0 +1,81 @@
1/*
2 * arch/sh/kernel/cpu/sh2/clock-sh7619.c
3 *
4 * SH7619 support for the clock framework
5 *
6 * Copyright (C) 2006 Yoshinori Sato
7 *
8 * Based on clock-sh4.c
9 * Copyright (C) 2005 Paul Mundt
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
21const static int pll1rate[]={1,2};
22const static int pfc_divisors[]={1,2,0,4};
23
24#if (CONFIG_SH_CLK_MD == 1) || (CONFIG_SH_CLK_MD == 2)
25#define PLL2 (4)
26#elif (CONFIG_SH_CLK_MD == 5) || (CONFIG_SH_CLK_MD == 6)
27#define PLL2 (2)
28#else
29#error "Illigal Clock Mode!"
30#endif
31
32static void master_clk_init(struct clk *clk)
33{
34 clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 7];
35}
36
37static struct clk_ops sh7619_master_clk_ops = {
38 .init = master_clk_init,
39};
40
41static void module_clk_recalc(struct clk *clk)
42{
43 int idx = (ctrl_inw(FREQCR) & 0x0007);
44 clk->rate = clk->parent->rate / pfc_divisors[idx];
45}
46
47static struct clk_ops sh7619_module_clk_ops = {
48 .recalc = module_clk_recalc,
49};
50
51static void bus_clk_recalc(struct clk *clk)
52{
53 clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 7];
54}
55
56static struct clk_ops sh7619_bus_clk_ops = {
57 .recalc = bus_clk_recalc,
58};
59
60static void cpu_clk_recalc(struct clk *clk)
61{
62 clk->rate = clk->parent->rate;
63}
64
65static struct clk_ops sh7619_cpu_clk_ops = {
66 .recalc = cpu_clk_recalc,
67};
68
69static struct clk_ops *sh7619_clk_ops[] = {
70 &sh7619_master_clk_ops,
71 &sh7619_module_clk_ops,
72 &sh7619_bus_clk_ops,
73 &sh7619_cpu_clk_ops,
74};
75
76void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
77{
78 if (idx < ARRAY_SIZE(sh7619_clk_ops))
79 *ops = sh7619_clk_ops[idx];
80}
81
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c
index f17a2a0d588e..ba527d9b5024 100644
--- a/arch/sh/kernel/cpu/sh2/probe.c
+++ b/arch/sh/kernel/cpu/sh2/probe.c
@@ -17,17 +17,23 @@
17 17
18int __init detect_cpu_and_cache_system(void) 18int __init detect_cpu_and_cache_system(void)
19{ 19{
20 /* 20#if defined(CONFIG_CPU_SUBTYPE_SH7604)
21 * For now, assume SH7604 .. fix this later.
22 */
23 cpu_data->type = CPU_SH7604; 21 cpu_data->type = CPU_SH7604;
24 cpu_data->dcache.ways = 4; 22 cpu_data->dcache.ways = 4;
25 cpu_data->dcache.way_shift = 6; 23 cpu_data->dcache.way_incr = (1<<10);
26 cpu_data->dcache.sets = 64; 24 cpu_data->dcache.sets = 64;
27 cpu_data->dcache.entry_shift = 4; 25 cpu_data->dcache.entry_shift = 4;
28 cpu_data->dcache.linesz = L1_CACHE_BYTES; 26 cpu_data->dcache.linesz = L1_CACHE_BYTES;
29 cpu_data->dcache.flags = 0; 27 cpu_data->dcache.flags = 0;
30 28#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
29 cpu_data->type = CPU_SH7619;
30 cpu_data->dcache.ways = 4;
31 cpu_data->dcache.way_incr = (1<<12);
32 cpu_data->dcache.sets = 256;
33 cpu_data->dcache.entry_shift = 4;
34 cpu_data->dcache.linesz = L1_CACHE_BYTES;
35 cpu_data->dcache.flags = 0;
36#endif
31 /* 37 /*
32 * SH-2 doesn't have separate caches 38 * SH-2 doesn't have separate caches
33 */ 39 */
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
new file mode 100644
index 000000000000..82c2d905152f
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -0,0 +1,53 @@
1/*
2 * SH7619 Setup
3 *
4 * Copyright (C) 2006 Yoshinori Sato
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xf8400000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 88, 89, 91, 90},
21 }, {
22 .mapbase = 0xf8410000,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 92, 93, 95, 94},
26 }, {
27 .mapbase = 0xf8420000,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_SCIF,
30 .irqs = { 96, 97, 99, 98},
31 }, {
32 .flags = 0,
33 }
34};
35
36static struct platform_device sci_device = {
37 .name = "sh-sci",
38 .id = -1,
39 .dev = {
40 .platform_data = sci_platform_data,
41 },
42};
43
44static struct platform_device *sh7619_devices[] __initdata = {
45 &sci_device,
46};
47
48static int __init sh7619_devices_setup(void)
49{
50 return platform_add_devices(sh7619_devices,
51 ARRAY_SIZE(sh7619_devices));
52}
53__initcall(sh7619_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
new file mode 100644
index 000000000000..350972ae9410
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -0,0 +1,10 @@
1#
2# Makefile for the Linux/SuperH SH-2A backends.
3#
4
5obj-y := common.o probe.o
6
7common-y += $(addprefix ../sh2/, ex.o)
8common-y += $(addprefix ../sh2/, entry.o)
9
10obj-$(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
index 000000000000..a9ad309c6a33
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c
@@ -0,0 +1,85 @@
1/*
2 * arch/sh/kernel/cpu/sh2a/clock-sh7206.c
3 *
4 * SH7206 support for the clock framework
5 *
6 * Copyright (C) 2006 Yoshinori Sato
7 *
8 * Based on clock-sh4.c
9 * Copyright (C) 2005 Paul Mundt
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
21const static int pll1rate[]={1,2,3,4,6,8};
22const static int pfc_divisors[]={1,2,3,4,6,8,12};
23#define ifc_divisors pfc_divisors
24
25#if (CONFIG_SH_CLK_MD == 2)
26#define PLL2 (4)
27#elif (CONFIG_SH_CLK_MD == 6)
28#define PLL2 (2)
29#elif (CONFIG_SH_CLK_MD == 7)
30#define PLL2 (1)
31#else
32#error "Illigal Clock Mode!"
33#endif
34
35static void master_clk_init(struct clk *clk)
36{
37 clk->rate *= PLL2 * pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
38}
39
40static struct clk_ops sh7206_master_clk_ops = {
41 .init = master_clk_init,
42};
43
44static void module_clk_recalc(struct clk *clk)
45{
46 int idx = (ctrl_inw(FREQCR) & 0x0007);
47 clk->rate = clk->parent->rate / pfc_divisors[idx];
48}
49
50static struct clk_ops sh7206_module_clk_ops = {
51 .recalc = module_clk_recalc,
52};
53
54static void bus_clk_recalc(struct clk *clk)
55{
56 clk->rate = clk->parent->rate / pll1rate[(ctrl_inw(FREQCR) >> 8) & 0x0007];
57}
58
59static struct clk_ops sh7206_bus_clk_ops = {
60 .recalc = bus_clk_recalc,
61};
62
63static void cpu_clk_recalc(struct clk *clk)
64{
65 int idx = (ctrl_inw(FREQCR) & 0x0007);
66 clk->rate = clk->parent->rate / ifc_divisors[idx];
67}
68
69static struct clk_ops sh7206_cpu_clk_ops = {
70 .recalc = cpu_clk_recalc,
71};
72
73static struct clk_ops *sh7206_clk_ops[] = {
74 &sh7206_master_clk_ops,
75 &sh7206_module_clk_ops,
76 &sh7206_bus_clk_ops,
77 &sh7206_cpu_clk_ops,
78};
79
80void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
81{
82 if (idx < ARRAY_SIZE(sh7206_clk_ops))
83 *ops = sh7206_clk_ops[idx];
84}
85
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
new file mode 100644
index 000000000000..87c6c0542089
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -0,0 +1,39 @@
1/*
2 * arch/sh/kernel/cpu/sh2a/probe.c
3 *
4 * CPU Subtype Probing for SH-2A.
5 *
6 * Copyright (C) 2004, 2005 Paul Mundt
7 *
8 * 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 * for more details.
11 */
12
13#include <linux/init.h>
14#include <asm/processor.h>
15#include <asm/cache.h>
16
17int __init detect_cpu_and_cache_system(void)
18{
19 /* Just SH7206 for now .. */
20 cpu_data->type = CPU_SH7206;
21
22 cpu_data->dcache.ways = 4;
23 cpu_data->dcache.way_incr = (1 << 11);
24 cpu_data->dcache.sets = 128;
25 cpu_data->dcache.entry_shift = 4;
26 cpu_data->dcache.linesz = L1_CACHE_BYTES;
27 cpu_data->dcache.flags = 0;
28
29 /*
30 * The icache is the same as the dcache as far as this setup is
31 * concerned. The only real difference in hardware is that the icache
32 * lacks the U bit that the dcache has, none of this has any bearing
33 * on the cache info.
34 */
35 cpu_data->icache = cpu_data->dcache;
36
37 return 0;
38}
39
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
new file mode 100644
index 000000000000..cdfeef49e62e
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -0,0 +1,58 @@
1/*
2 * SH7206 Setup
3 *
4 * Copyright (C) 2006 Yoshinori Sato
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/platform_device.h>
11#include <linux/init.h>
12#include <linux/serial.h>
13#include <asm/sci.h>
14
15static struct plat_sci_port sci_platform_data[] = {
16 {
17 .mapbase = 0xfffe8000,
18 .flags = UPF_BOOT_AUTOCONF,
19 .type = PORT_SCIF,
20 .irqs = { 240, 241, 242, 243},
21 }, {
22 .mapbase = 0xfffe8800,
23 .flags = UPF_BOOT_AUTOCONF,
24 .type = PORT_SCIF,
25 .irqs = { 244, 245, 246, 247},
26 }, {
27 .mapbase = 0xfffe9000,
28 .flags = UPF_BOOT_AUTOCONF,
29 .type = PORT_SCIF,
30 .irqs = { 248, 249, 250, 251},
31 }, {
32 .mapbase = 0xfffe9800,
33 .flags = UPF_BOOT_AUTOCONF,
34 .type = PORT_SCIF,
35 .irqs = { 252, 253, 254, 255},
36 }, {
37 .flags = 0,
38 }
39};
40
41static struct platform_device sci_device = {
42 .name = "sh-sci",
43 .id = -1,
44 .dev = {
45 .platform_data = sci_platform_data,
46 },
47};
48
49static struct platform_device *sh7206_devices[] __initdata = {
50 &sci_device,
51};
52
53static int __init sh7206_devices_setup(void)
54{
55 return platform_add_devices(sh7206_devices,
56 ARRAY_SIZE(sh7206_devices));
57}
58__initcall(sh7206_devices_setup);
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 36d86f9ac38a..c24f6390007b 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -404,6 +404,7 @@ static const char *cpu_name[] = {
404 [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", 404 [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501",
405 [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780", 405 [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
406 [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343", 406 [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
407 [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619",
407 [CPU_SH_NONE] = "Unknown" 408 [CPU_SH_NONE] = "Unknown"
408}; 409};
409 410
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index 5213f5bc6ce0..764886b4bcf1 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -98,7 +98,11 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
98 */ 98 */
99 99
100#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ 100#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
101#define TRAP16 0xc310 /* Syscall w/no args (NR in R3) */ 101#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
102#define TRAP_NOARG 0xc320 /* Syscall w/no args (NR in R3) */
103#else
104#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) */
105#endif
102#define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ 106#define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */
103 107
104struct sigframe 108struct sigframe
@@ -350,7 +354,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
350 } else { 354 } else {
351 /* Generate return code (system call to sigreturn) */ 355 /* Generate return code (system call to sigreturn) */
352 err |= __put_user(MOVW(7), &frame->retcode[0]); 356 err |= __put_user(MOVW(7), &frame->retcode[0]);
353 err |= __put_user(TRAP16, &frame->retcode[1]); 357 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
354 err |= __put_user(OR_R0_R0, &frame->retcode[2]); 358 err |= __put_user(OR_R0_R0, &frame->retcode[2]);
355 err |= __put_user(OR_R0_R0, &frame->retcode[3]); 359 err |= __put_user(OR_R0_R0, &frame->retcode[3]);
356 err |= __put_user(OR_R0_R0, &frame->retcode[4]); 360 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,
430 } else { 434 } else {
431 /* Generate return code (system call to rt_sigreturn) */ 435 /* Generate return code (system call to rt_sigreturn) */
432 err |= __put_user(MOVW(7), &frame->retcode[0]); 436 err |= __put_user(MOVW(7), &frame->retcode[0]);
433 err |= __put_user(TRAP16, &frame->retcode[1]); 437 err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
434 err |= __put_user(OR_R0_R0, &frame->retcode[2]); 438 err |= __put_user(OR_R0_R0, &frame->retcode[2]);
435 err |= __put_user(OR_R0_R0, &frame->retcode[3]); 439 err |= __put_user(OR_R0_R0, &frame->retcode[3]);
436 err |= __put_user(OR_R0_R0, &frame->retcode[4]); 440 err |= __put_user(OR_R0_R0, &frame->retcode[4]);
diff --git a/arch/sh/kernel/timers/Makefile b/arch/sh/kernel/timers/Makefile
index 151a6a304cec..bcf244ff6a12 100644
--- a/arch/sh/kernel/timers/Makefile
+++ b/arch/sh/kernel/timers/Makefile
@@ -5,4 +5,6 @@
5obj-y := timer.o 5obj-y := timer.o
6 6
7obj-$(CONFIG_SH_TMU) += timer-tmu.o 7obj-$(CONFIG_SH_TMU) += timer-tmu.o
8obj-$(CONFIG_SH_MTU2) += timer-mtu2.o
9obj-$(CONFIG_SH_CMT) += timer-cmt.o
8 10
diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c
new file mode 100644
index 000000000000..9eab395cd341
--- /dev/null
+++ b/arch/sh/kernel/timers/timer-cmt.c
@@ -0,0 +1,256 @@
1/*
2 * arch/sh/kernel/timers/timer-cmt.c - CMT Timer Support
3 *
4 * Copyright (C) 2005 Yoshinori Sato
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
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/interrupt.h>
14#include <linux/spinlock.h>
15#include <linux/seqlock.h>
16#include <asm/timer.h>
17#include <asm/rtc.h>
18#include <asm/io.h>
19#include <asm/irq.h>
20#include <asm/clock.h>
21
22#if defined(CONFIG_CPU_SUBTYPE_SH7619)
23#define CMT_CMSTR 0xf84a0070
24#define CMT_CMCSR_0 0xf84a0072
25#define CMT_CMCNT_0 0xf84a0074
26#define CMT_CMCOR_0 0xf84a0076
27#define CMT_CMCSR_1 0xf84a0078
28#define CMT_CMCNT_1 0xf84a007a
29#define CMT_CMCOR_1 0xf84a007c
30
31#define STBCR3 0xf80a0000
32#define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0)
33#define CMT_CMCSR_INIT 0x0040
34#define CMT_CMCSR_CALIB 0x0000
35#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
36#define CMT_CMSTR 0xfffec000
37#define CMT_CMCSR_0 0xfffec002
38#define CMT_CMCNT_0 0xfffec004
39#define CMT_CMCOR_0 0xfffec006
40
41#define STBCR4 0xfffe040c
42#define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR4) & ~0x04, STBCR4); } while(0)
43#define CMT_CMCSR_INIT 0x0040
44#define CMT_CMCSR_CALIB 0x0000
45#else
46#error "Unknown CPU SUBTYPE"
47#endif
48
49static DEFINE_SPINLOCK(cmt0_lock);
50
51static unsigned long cmt_timer_get_offset(void)
52{
53 int count;
54 unsigned long flags;
55
56 static unsigned short count_p = 0xffff; /* for the first call after boot */
57 static unsigned long jiffies_p = 0;
58
59 /*
60 * cache volatile jiffies temporarily; we have IRQs turned off.
61 */
62 unsigned long jiffies_t;
63
64 spin_lock_irqsave(&cmt0_lock, flags);
65 /* timer count may underflow right here */
66 count = ctrl_inw(CMT_CMCOR_0);
67 count -= ctrl_inw(CMT_CMCNT_0);
68
69 jiffies_t = jiffies;
70
71 /*
72 * avoiding timer inconsistencies (they are rare, but they happen)...
73 * there is one kind of problem that must be avoided here:
74 * 1. the timer counter underflows
75 */
76
77 if (jiffies_t == jiffies_p) {
78 if (count > count_p) {
79 /* the nutcase */
80 if (ctrl_inw(CMT_CMCSR_0) & 0x80) { /* Check CMF bit */
81 count -= LATCH;
82 } else {
83 printk("%s (): hardware timer problem?\n",
84 __FUNCTION__);
85 }
86 }
87 } else
88 jiffies_p = jiffies_t;
89
90 count_p = count;
91 spin_unlock_irqrestore(&cmt0_lock, flags);
92
93 count = ((LATCH-1) - count) * TICK_SIZE;
94 count = (count + LATCH/2) / LATCH;
95
96 return count;
97}
98
99static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id,
100 struct pt_regs *regs)
101{
102 unsigned long timer_status;
103
104 /* Clear CMF bit */
105 timer_status = ctrl_inw(CMT_CMCSR_0);
106 timer_status &= ~0x80;
107 ctrl_outw(timer_status, CMT_CMCSR_0);
108
109 /*
110 * Here we are in the timer irq handler. We just have irqs locally
111 * disabled but we don't know if the timer_bh is running on the other
112 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
113 * the irq version of write_lock because as just said we have irq
114 * locally disabled. -arca
115 */
116 write_seqlock(&xtime_lock);
117 handle_timer_tick(regs);
118 write_sequnlock(&xtime_lock);
119
120 return IRQ_HANDLED;
121}
122
123static struct irqaction cmt_irq = {
124 .name = "timer",
125 .handler = cmt_timer_interrupt,
126 .flags = SA_INTERRUPT,
127 .mask = CPU_MASK_NONE,
128};
129
130/*
131 * Hah! We'll see if this works (switching from usecs to nsecs).
132 */
133static unsigned long cmt_timer_get_frequency(void)
134{
135 u32 freq;
136 struct timespec ts1, ts2;
137 unsigned long diff_nsec;
138 unsigned long factor;
139
140 /* Setup the timer: We don't want to generate interrupts, just
141 * have it count down at its natural rate.
142 */
143
144 ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR);
145 ctrl_outw(CMT_CMCSR_CALIB, CMT_CMCSR_0);
146 ctrl_outw(0xffff, CMT_CMCOR_0);
147 ctrl_outw(0xffff, CMT_CMCNT_0);
148
149 rtc_sh_get_time(&ts2);
150
151 do {
152 rtc_sh_get_time(&ts1);
153 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
154
155 /* actually start the timer */
156 ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
157
158 do {
159 rtc_sh_get_time(&ts2);
160 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
161
162 freq = 0xffff - ctrl_inw(CMT_CMCNT_0);
163 if (ts2.tv_nsec < ts1.tv_nsec) {
164 ts2.tv_nsec += 1000000000;
165 ts2.tv_sec--;
166 }
167
168 diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
169
170 /* this should work well if the RTC has a precision of n Hz, where
171 * n is an integer. I don't think we have to worry about the other
172 * cases. */
173 factor = (1000000000 + diff_nsec/2) / diff_nsec;
174
175 if (factor * diff_nsec > 1100000000 ||
176 factor * diff_nsec < 900000000)
177 panic("weird RTC (diff_nsec %ld)", diff_nsec);
178
179 return freq * factor;
180}
181
182static void cmt_clk_init(struct clk *clk)
183{
184 u8 divisor = CMT_CMCSR_INIT & 0x3;
185 ctrl_inw(CMT_CMCSR_0);
186 ctrl_outw(CMT_CMCSR_INIT, CMT_CMCSR_0);
187 clk->parent = clk_get("module_clk");
188 clk->rate = clk->parent->rate / (8 << (divisor << 1));
189}
190
191static void cmt_clk_recalc(struct clk *clk)
192{
193 u8 divisor = ctrl_inw(CMT_CMCSR_0) & 0x3;
194 clk->rate = clk->parent->rate / (8 << (divisor << 1));
195}
196
197static struct clk_ops cmt_clk_ops = {
198 .init = cmt_clk_init,
199 .recalc = cmt_clk_recalc,
200};
201
202static struct clk cmt0_clk = {
203 .name = "cmt0_clk",
204 .ops = &cmt_clk_ops,
205};
206
207static int cmt_timer_start(void)
208{
209 ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
210 return 0;
211}
212
213static int cmt_timer_stop(void)
214{
215 ctrl_outw(ctrl_inw(CMT_CMSTR) & ~0x01, CMT_CMSTR);
216 return 0;
217}
218
219static int cmt_timer_init(void)
220{
221 unsigned long interval;
222
223 cmt_clock_enable();
224
225 setup_irq(TIMER_IRQ, &cmt_irq);
226
227 cmt0_clk.parent = clk_get("module_clk");
228
229 cmt_timer_stop();
230
231 interval = cmt0_clk.parent->rate / 8 / HZ;
232 printk(KERN_INFO "Interval = %ld\n", interval);
233
234 ctrl_outw(interval, CMT_CMCOR_0);
235
236 clk_register(&cmt0_clk);
237 clk_enable(&cmt0_clk);
238
239 cmt_timer_start();
240
241 return 0;
242}
243
244struct sys_timer_ops cmt_timer_ops = {
245 .init = cmt_timer_init,
246 .start = cmt_timer_start,
247 .stop = cmt_timer_stop,
248 .get_frequency = cmt_timer_get_frequency,
249 .get_offset = cmt_timer_get_offset,
250};
251
252struct sys_timer cmt_timer = {
253 .name = "cmt",
254 .ops = &cmt_timer_ops,
255};
256
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
new file mode 100644
index 000000000000..73a5ef3c457d
--- /dev/null
+++ b/arch/sh/kernel/timers/timer-mtu2.c
@@ -0,0 +1,260 @@
1/*
2 * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support
3 *
4 * Copyright (C) 2005 Paul Mundt
5 *
6 * Based off of arch/sh/kernel/timers/timer-tmu.c
7 *
8 * 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 * for more details.
11 */
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <linux/spinlock.h>
16#include <linux/seqlock.h>
17#include <asm/timer.h>
18#include <asm/io.h>
19#include <asm/irq.h>
20#include <asm/clock.h>
21
22/*
23 * We use channel 1 for our lowly system timer. Channel 2 would be the other
24 * likely candidate, but we leave it alone as it has higher divisors that
25 * would be of more use to other more interesting applications.
26 *
27 * TODO: Presently we only implement a 16-bit single-channel system timer.
28 * However, we can implement channel cascade if we go the overflow route and
29 * get away with using 2 MTU2 channels as a 32-bit timer.
30 */
31
32static DEFINE_SPINLOCK(mtu2_lock);
33
34#define MTU2_TSTR 0xfffe4280
35#define MTU2_TCR_1 0xfffe4380
36#define MTU2_TMDR_1 0xfffe4381
37#define MTU2_TIOR_1 0xfffe4382
38#define MTU2_TIER_1 0xfffe4384
39#define MTU2_TSR_1 0xfffe4385
40#define MTU2_TCNT_1 0xfffe4386 /* 16-bit counter */
41#define MTU2_TGRA_1 0xfffe438a
42
43#define STBCR3 0xfffe0408
44
45#define MTU2_TSTR_CST1 (1 << 1) /* Counter Start 1 */
46
47#define MTU2_TSR_TGFA (1 << 0) /* GRA compare match */
48
49#define MTU2_TIER_TGIEA (1 << 0) /* GRA compare match interrupt enable */
50
51#define MTU2_TCR_INIT 0x22
52
53#define MTU2_TCR_CALIB 0x00
54
55static unsigned long mtu2_timer_get_offset(void)
56{
57 int count;
58 unsigned long flags;
59
60 static int count_p = 0x7fff; /* for the first call after boot */
61 static unsigned long jiffies_p = 0;
62
63 /*
64 * cache volatile jiffies temporarily; we have IRQs turned off.
65 */
66 unsigned long jiffies_t;
67
68 spin_lock_irqsave(&mtu2_lock, flags);
69 /* timer count may underflow right here */
70 count = ctrl_inw(MTU2_TCNT_1); /* read the latched count */
71
72 jiffies_t = jiffies;
73
74 /*
75 * avoiding timer inconsistencies (they are rare, but they happen)...
76 * there is one kind of problem that must be avoided here:
77 * 1. the timer counter underflows
78 */
79
80 if (jiffies_t == jiffies_p) {
81 if (count > count_p) {
82 if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) {
83 count -= LATCH;
84 } else {
85 printk("%s (): hardware timer problem?\n",
86 __FUNCTION__);
87 }
88 }
89 } else
90 jiffies_p = jiffies_t;
91
92 count_p = count;
93 spin_unlock_irqrestore(&mtu2_lock, flags);
94
95 count = ((LATCH-1) - count) * TICK_SIZE;
96 count = (count + LATCH/2) / LATCH;
97
98 return count;
99}
100
101static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id,
102 struct pt_regs *regs)
103{
104 unsigned long timer_status;
105
106 /* Clear TGFA bit */
107 timer_status = ctrl_inb(MTU2_TSR_1);
108 timer_status &= ~MTU2_TSR_TGFA;
109 ctrl_outb(timer_status, MTU2_TSR_1);
110
111 /* Do timer tick */
112 write_seqlock(&xtime_lock);
113 handle_timer_tick(regs);
114 write_sequnlock(&xtime_lock);
115
116 return IRQ_HANDLED;
117}
118
119static struct irqaction mtu2_irq = {
120 .name = "timer",
121 .handler = mtu2_timer_interrupt,
122 .flags = SA_INTERRUPT,
123 .mask = CPU_MASK_NONE,
124};
125
126/*
127 * Hah! We'll see if this works (switching from usecs to nsecs).
128 */
129static unsigned long mtu2_timer_get_frequency(void)
130{
131 u32 freq;
132 struct timespec ts1, ts2;
133 unsigned long diff_nsec;
134 unsigned long factor;
135
136 /* Setup the timer: We don't want to generate interrupts, just
137 * have it count down at its natural rate.
138 */
139
140 ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR);
141 ctrl_outb(MTU2_TCR_CALIB, MTU2_TCR_1);
142 ctrl_outb(ctrl_inb(MTU2_TIER_1) & ~MTU2_TIER_TGIEA, MTU2_TIER_1);
143 ctrl_outw(0, MTU2_TCNT_1);
144
145 rtc_get_time(&ts2);
146
147 do {
148 rtc_get_time(&ts1);
149 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
150
151 /* actually start the timer */
152 ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
153
154 do {
155 rtc_get_time(&ts2);
156 } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
157
158 freq = ctrl_inw(MTU2_TCNT_0);
159 if (ts2.tv_nsec < ts1.tv_nsec) {
160 ts2.tv_nsec += 1000000000;
161 ts2.tv_sec--;
162 }
163
164 diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
165
166 /* this should work well if the RTC has a precision of n Hz, where
167 * n is an integer. I don't think we have to worry about the other
168 * cases. */
169 factor = (1000000000 + diff_nsec/2) / diff_nsec;
170
171 if (factor * diff_nsec > 1100000000 ||
172 factor * diff_nsec < 900000000)
173 panic("weird RTC (diff_nsec %ld)", diff_nsec);
174
175 return freq * factor;
176}
177
178static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 };
179
180static void mtu2_clk_init(struct clk *clk)
181{
182 u8 idx = MTU2_TCR_INIT & 0x7;
183
184 clk->rate = clk->parent->rate / divisors[idx];
185 /* Start TCNT counting */
186 ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
187
188}
189
190static void mtu2_clk_recalc(struct clk *clk)
191{
192 u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7;
193 clk->rate = clk->parent->rate / divisors[idx];
194}
195
196static struct clk_ops mtu2_clk_ops = {
197 .init = mtu2_clk_init,
198 .recalc = mtu2_clk_recalc,
199};
200
201static struct clk mtu2_clk1 = {
202 .name = "mtu2_clk1",
203 .ops = &mtu2_clk_ops,
204};
205
206static int mtu2_timer_start(void)
207{
208 ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
209 return 0;
210}
211
212static int mtu2_timer_stop(void)
213{
214 ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR);
215 return 0;
216}
217
218static int mtu2_timer_init(void)
219{
220 u8 tmp;
221 unsigned long interval;
222
223 setup_irq(TIMER_IRQ, &mtu2_irq);
224
225 mtu2_clk1.parent = clk_get("module_clk");
226
227 ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3);
228
229 /* Normal operation */
230 ctrl_outb(0, MTU2_TMDR_1);
231 ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1);
232 ctrl_outb(0x01, MTU2_TIOR_1);
233
234 /* Enable underflow interrupt */
235 ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1);
236
237 interval = CONFIG_SH_PCLK_FREQ / 16 / HZ;
238 printk(KERN_INFO "Interval = %ld\n", interval);
239
240 ctrl_outw(interval, MTU2_TGRA_1);
241 ctrl_outw(0, MTU2_TCNT_1);
242
243 clk_register(&mtu2_clk1);
244 clk_enable(&mtu2_clk1);
245
246 return 0;
247}
248
249struct sys_timer_ops mtu2_timer_ops = {
250 .init = mtu2_timer_init,
251 .start = mtu2_timer_start,
252 .stop = mtu2_timer_stop,
253 .get_frequency = mtu2_timer_get_frequency,
254 .get_offset = mtu2_timer_get_offset,
255};
256
257struct sys_timer mtu2_timer = {
258 .name = "mtu2",
259 .ops = &mtu2_timer_ops,
260};
diff --git a/arch/sh/kernel/timers/timer.c b/arch/sh/kernel/timers/timer.c
index dc1f631053a8..a6bcc913d25e 100644
--- a/arch/sh/kernel/timers/timer.c
+++ b/arch/sh/kernel/timers/timer.c
@@ -17,6 +17,12 @@ static struct sys_timer *sys_timers[] __initdata = {
17#ifdef CONFIG_SH_TMU 17#ifdef CONFIG_SH_TMU
18 &tmu_timer, 18 &tmu_timer,
19#endif 19#endif
20#ifdef CONFIG_SH_MTU2
21 &mtu2_timer,
22#endif
23#ifdef CONFIG_SH_CMT
24 &cmt_timer,
25#endif
20 NULL, 26 NULL,
21}; 27};
22 28
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 9dd606464d23..814a17586974 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -4,8 +4,12 @@ menu "Processor selection"
4# Processor families 4# Processor families
5# 5#
6config CPU_SH2 6config CPU_SH2
7 select SH_WRITETHROUGH if !CPU_SH2A
7 bool 8 bool
8 select SH_WRITETHROUGH 9
10config CPU_SH2A
11 bool
12 select CPU_SH2
9 13
10config CPU_SH3 14config CPU_SH3
11 bool 15 bool
@@ -40,6 +44,16 @@ config CPU_SUBTYPE_SH7604
40 bool "Support SH7604 processor" 44 bool "Support SH7604 processor"
41 select CPU_SH2 45 select CPU_SH2
42 46
47config CPU_SUBTYPE_SH7619
48 bool "Support SH7619 processor"
49 select CPU_SH2
50
51comment "SH-2A Processor Support"
52
53config CPU_SUBTYPE_SH7206
54 bool "Support SH7206 processor"
55 select CPU_SH2A
56
43comment "SH-3 Processor Support" 57comment "SH-3 Processor Support"
44 58
45config CPU_SUBTYPE_SH7300 59config CPU_SUBTYPE_SH7300
@@ -274,7 +288,6 @@ config SH_DIRECT_MAPPED
274 288
275config SH_WRITETHROUGH 289config SH_WRITETHROUGH
276 bool "Use write-through caching" 290 bool "Use write-through caching"
277 default y if CPU_SH2
278 help 291 help
279 Selecting this option will configure the caches in write-through 292 Selecting this option will configure the caches in write-through
280 mode, as opposed to the default write-back configuration. 293 mode, as opposed to the default write-back configuration.
diff --git a/arch/sh/mm/cache-sh2.c b/arch/sh/mm/cache-sh2.c
index 2689cb24ea2b..6614033f6be9 100644
--- a/arch/sh/mm/cache-sh2.c
+++ b/arch/sh/mm/cache-sh2.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * Released under the terms of the GNU GPL v2.0. 6 * Released under the terms of the GNU GPL v2.0.
7 */ 7 */
8
8#include <linux/init.h> 9#include <linux/init.h>
9#include <linux/mm.h> 10#include <linux/mm.h>
10 11
@@ -14,37 +15,43 @@
14#include <asm/cacheflush.h> 15#include <asm/cacheflush.h>
15#include <asm/io.h> 16#include <asm/io.h>
16 17
17/* 18void __flush_wback_region(void *start, int size)
18 * Calculate the OC address and set the way bit on the SH-2.
19 *
20 * We must have already jump_to_P2()'ed prior to calling this
21 * function, since we rely on CCR manipulation to do the
22 * Right Thing(tm).
23 */
24unsigned long __get_oc_addr(unsigned long set, unsigned long way)
25{ 19{
26 unsigned long ccr; 20 unsigned long v;
27 21 unsigned long begin, end;
28 /* 22
29 * On SH-2 the way bit isn't tracked in the address field 23 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
30 * if we're doing address array access .. instead, we need 24 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
31 * to manually switch out the way in the CCR. 25 & ~(L1_CACHE_BYTES-1);
32 */ 26 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
33 ccr = ctrl_inl(CCR); 27 /* FIXME cache purge */
34 ccr &= ~0x00c0; 28 ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
35 ccr |= way << cpu_data->dcache.way_shift; 29 }
36 30}
37 /* 31
38 * Despite the number of sets being halved, we end up losing 32void __flush_purge_region(void *start, int size)
39 * the first 2 ways to OCRAM instead of the last 2 (if we're 33{
40 * 4-way). As a result, forcibly setting the W1 bit handily 34 unsigned long v;
41 * bumps us up 2 ways. 35 unsigned long begin, end;
42 */ 36
43 if (ccr & CCR_CACHE_ORA) 37 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
44 ccr |= 1 << (cpu_data->dcache.way_shift + 1); 38 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
45 39 & ~(L1_CACHE_BYTES-1);
46 ctrl_outl(ccr, CCR); 40 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
47 41 ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
48 return CACHE_OC_ADDRESS_ARRAY | (set << cpu_data->dcache.entry_shift); 42 }
43}
44
45void __flush_invalidate_region(void *start, int size)
46{
47 unsigned long v;
48 unsigned long begin, end;
49
50 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
51 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
52 & ~(L1_CACHE_BYTES-1);
53 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
54 ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
55 }
49} 56}
50 57
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index ac57638977ee..0571755e9a84 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -30,3 +30,5 @@ R7780MP SH_R7780MP
30TITAN SH_TITAN 30TITAN SH_TITAN
31SHMIN SH_SHMIN 31SHMIN SH_SHMIN
327710VOIPGW SH_7710VOIPGW 327710VOIPGW SH_7710VOIPGW
337206SE SH_7206_SOLUTION_ENGINE
347619SE SH_7619_SOLUTION_ENGINE