diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh2')
-rw-r--r-- | arch/sh/kernel/cpu/sh2/Makefile | 7 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/clock-sh7619.c | 77 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/entry.S | 321 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/ex.S | 47 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/probe.c | 33 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh2/setup-sh7619.c | 211 |
6 files changed, 696 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/sh2/Makefile b/arch/sh/kernel/cpu/sh2/Makefile new file mode 100644 index 000000000..f0f059acf --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Linux/SuperH SH-2 backends. +# + +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 index 000000000..e80252ae5 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c @@ -0,0 +1,77 @@ +/* + * 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 <linux/io.h> +#include <asm/clock.h> +#include <asm/freq.h> +#include <asm/processor.h> + +static const int pll1rate[] = {1,2}; +static const int pfc_divisors[] = {1,2,0,4}; +static unsigned int pll2_mult; + +static void master_clk_init(struct clk *clk) +{ + clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 7]; +} + +static struct sh_clk_ops sh7619_master_clk_ops = { + .init = master_clk_init, +}; + +static unsigned long module_clk_recalc(struct clk *clk) +{ + int idx = (__raw_readw(FREQCR) & 0x0007); + return clk->parent->rate / pfc_divisors[idx]; +} + +static struct sh_clk_ops sh7619_module_clk_ops = { + .recalc = module_clk_recalc, +}; + +static unsigned long bus_clk_recalc(struct clk *clk) +{ + return clk->parent->rate / pll1rate[(__raw_readw(FREQCR) >> 8) & 7]; +} + +static struct sh_clk_ops sh7619_bus_clk_ops = { + .recalc = bus_clk_recalc, +}; + +static struct sh_clk_ops sh7619_cpu_clk_ops = { + .recalc = followparent_recalc, +}; + +static struct sh_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 sh_clk_ops **ops, int idx) +{ + if (test_mode_pin(MODE_PIN2 | MODE_PIN0) || + test_mode_pin(MODE_PIN2 | MODE_PIN1)) + pll2_mult = 2; + else if (test_mode_pin(MODE_PIN0) || test_mode_pin(MODE_PIN1)) + pll2_mult = 4; + + BUG_ON(!pll2_mult); + + if (idx < ARRAY_SIZE(sh7619_clk_ops)) + *ops = sh7619_clk_ops[idx]; +} diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S new file mode 100644 index 000000000..c8a4331d9 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/entry.S @@ -0,0 +1,321 @@ +/* + * arch/sh/kernel/cpu/sh2/entry.S + * + * The SH-2 exception entry + * + * Copyright (C) 2005-2008 Yoshinori Sato + * Copyright (C) 2005 AXE,Inc. + * + * 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/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <cpu/mmu_context.h> +#include <asm/unistd.h> +#include <asm/errno.h> +#include <asm/page.h> + +/* Offsets to the stack */ +OFF_R0 = 0 /* Return value. New ABI also arg4 */ +OFF_R1 = 4 /* New ABI: arg5 */ +OFF_R2 = 8 /* New ABI: arg6 */ +OFF_R3 = 12 /* New ABI: syscall_nr */ +OFF_R4 = 16 /* New ABI: arg0 */ +OFF_R5 = 20 /* New ABI: arg1 */ +OFF_R6 = 24 /* New ABI: arg2 */ +OFF_R7 = 28 /* New ABI: arg3 */ +OFF_SP = (15*4) +OFF_PC = (16*4) +OFF_SR = (16*4+2*4) +OFF_TRA = (16*4+6*4) + +#include <asm/entry-macros.S> + +ENTRY(exception_handler) + ! stack + ! r0 <- point sp + ! r1 + ! pc + ! sr + ! r0 = temporary + ! r1 = vector (pseudo EXPEVT / INTEVT / TRA) + mov.l r2,@-sp + mov.l r3,@-sp + cli + mov.l $cpu_mode,r2 + mov.l @r2,r0 + mov.l @(5*4,r15),r3 ! previous SR + or r0,r3 ! set MD + tst r0,r0 + bf/s 1f ! previous mode check + mov.l r3,@(5*4,r15) ! update SR + ! switch to kernel mode + mov.l __md_bit,r0 + mov.l r0,@r2 ! enter kernel mode + mov.l $current_thread_info,r2 + mov.l @r2,r2 + mov #(THREAD_SIZE >> 8),r0 + shll8 r0 + add r2,r0 + mov r15,r2 ! r2 = user stack top + mov r0,r15 ! switch kernel stack + mov.l r1,@-r15 ! TRA + sts.l macl, @-r15 + sts.l mach, @-r15 + stc.l gbr, @-r15 + mov.l @(5*4,r2),r0 + mov.l r0,@-r15 ! original SR + sts.l pr,@-r15 + mov.l @(4*4,r2),r0 + mov.l r0,@-r15 ! original PC + mov r2,r3 + add #(4+2)*4,r3 ! rewind r0 - r3 + exception frame + mov.l r3,@-r15 ! original SP + mov.l r14,@-r15 + mov.l r13,@-r15 + mov.l r12,@-r15 + mov.l r11,@-r15 + mov.l r10,@-r15 + mov.l r9,@-r15 + mov.l r8,@-r15 + mov.l r7,@-r15 + mov.l r6,@-r15 + mov.l r5,@-r15 + mov.l r4,@-r15 + mov r1,r9 ! save TRA + mov r2,r8 ! copy user -> kernel stack + mov.l @(0,r8),r3 + mov.l r3,@-r15 + mov.l @(4,r8),r2 + mov.l r2,@-r15 + mov.l @(12,r8),r1 + mov.l r1,@-r15 + mov.l @(8,r8),r0 + bra 2f + mov.l r0,@-r15 +1: + ! in kernel exception + mov #(22-4-4-1)*4+4,r0 + mov r15,r2 + sub r0,r15 + mov.l @r2+,r0 ! old R3 + mov.l r0,@-r15 + mov.l @r2+,r0 ! old R2 + mov.l r0,@-r15 + mov.l @(4,r2),r0 ! old R1 + mov.l r0,@-r15 + mov.l @r2,r0 ! old R0 + mov.l r0,@-r15 + add #8,r2 + mov.l @r2+,r3 ! old PC + mov.l @r2+,r0 ! old SR + add #-4,r2 ! exception frame stub (sr) + mov.l r1,@-r2 ! TRA + sts.l macl, @-r2 + sts.l mach, @-r2 + stc.l gbr, @-r2 + mov.l r0,@-r2 ! save old SR + sts.l pr,@-r2 + mov.l r3,@-r2 ! save old PC + mov r2,r0 + add #8*4,r0 + mov.l r0,@-r2 ! save old SP + mov.l r14,@-r2 + mov.l r13,@-r2 + mov.l r12,@-r2 + mov.l r11,@-r2 + mov.l r10,@-r2 + mov.l r9,@-r2 + mov.l r8,@-r2 + mov.l r7,@-r2 + mov.l r6,@-r2 + mov.l r5,@-r2 + mov.l r4,@-r2 + mov r1,r9 + mov.l @(OFF_R0,r15),r0 + mov.l @(OFF_R1,r15),r1 + mov.l @(OFF_R2,r15),r2 + mov.l @(OFF_R3,r15),r3 +2: + mov #64,r8 + cmp/hs r8,r9 + bt interrupt_entry ! vec >= 64 is interrupt + mov #32,r8 + cmp/hs r8,r9 + bt trap_entry ! 64 > vec >= 32 is trap + + mov.l 4f,r8 + mov r9,r4 + shll2 r9 + add r9,r8 + mov.l @r8,r8 ! exception handler address + tst r8,r8 + bf 3f + mov.l 8f,r8 ! unhandled exception +3: + mov.l 5f,r10 + jmp @r8 + lds r10,pr + +interrupt_entry: + mov r9,r4 + mov r15,r5 + mov.l 6f,r9 + mov.l 7f,r8 + jmp @r8 + lds r9,pr + + .align 2 +4: .long exception_handling_table +5: .long ret_from_exception +6: .long ret_from_irq +7: .long do_IRQ +8: .long exception_error + +trap_entry: + mov #0x30,r8 + cmp/ge r8,r9 ! vector 0x20-0x2f is systemcall + bt 1f + add #-0x10,r9 ! convert SH2 to SH3/4 ABI +1: + shll2 r9 ! TRA + bra system_call ! jump common systemcall entry + mov r9,r8 + +#if defined(CONFIG_SH_STANDARD_BIOS) + /* Unwind the stack and jmp to the debug entry */ +ENTRY(sh_bios_handler) + mov r15,r0 + add #(22-4)*4-4,r0 + ldc.l @r0+,gbr + lds.l @r0+,mach + lds.l @r0+,macl + mov r15,r0 + mov.l @(OFF_SP,r0),r1 + mov #OFF_SR,r2 + mov.l @(r0,r2),r3 + mov.l r3,@-r1 + mov #OFF_SP,r2 + mov.l @(r0,r2),r3 + mov.l r3,@-r1 + mov r15,r0 + add #(22-4)*4-8,r0 + mov.l 1f,r2 + mov.l @r2,r2 + stc sr,r3 + mov.l r2,@r0 + mov.l r3,@(4,r0) + mov.l r1,@(8,r0) + mov.l @r15+, r0 + mov.l @r15+, r1 + mov.l @r15+, r2 + mov.l @r15+, r3 + mov.l @r15+, r4 + mov.l @r15+, r5 + mov.l @r15+, r6 + mov.l @r15+, r7 + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r10 + mov.l @r15+, r11 + mov.l @r15+, r12 + mov.l @r15+, r13 + mov.l @r15+, r14 + add #8,r15 + lds.l @r15+, pr + mov.l @r15+,r15 + rte + nop + .align 2 +1: .long gdb_vbr_vector +#endif /* CONFIG_SH_STANDARD_BIOS */ + +ENTRY(address_error_trap_handler) + mov r15,r4 ! regs + mov #OFF_PC,r0 + mov.l @(r0,r15),r6 ! pc + mov.l 1f,r0 + jmp @r0 + mov #0,r5 ! writeaccess is unknown + + .align 2 +1: .long do_address_error + +restore_all: + stc sr,r0 + or #0xf0,r0 + ldc r0,sr ! all interrupt block (same BL = 1) + ! restore special register + ! overlap exception frame + mov r15,r0 + add #17*4,r0 + lds.l @r0+,pr + add #4,r0 + ldc.l @r0+,gbr + lds.l @r0+,mach + lds.l @r0+,macl + mov r15,r0 + mov.l $cpu_mode,r2 + mov #OFF_SR,r3 + mov.l @(r0,r3),r1 + mov.l __md_bit,r3 + and r1,r3 ! copy MD bit + mov.l r3,@r2 + shll2 r1 ! clear MD bit + shlr2 r1 + mov.l @(OFF_SP,r0),r2 + add #-8,r2 + mov.l r2,@(OFF_SP,r0) ! point exception frame top + mov.l r1,@(4,r2) ! set sr + mov #OFF_PC,r3 + mov.l @(r0,r3),r1 + mov.l r1,@r2 ! set pc + get_current_thread_info r0, r1 + mov.l $current_thread_info,r1 + mov.l r0,@r1 + mov.l @r15+,r0 + mov.l @r15+,r1 + mov.l @r15+,r2 + mov.l @r15+,r3 + mov.l @r15+,r4 + mov.l @r15+,r5 + mov.l @r15+,r6 + mov.l @r15+,r7 + mov.l @r15+,r8 + mov.l @r15+,r9 + mov.l @r15+,r10 + mov.l @r15+,r11 + mov.l @r15+,r12 + mov.l @r15+,r13 + mov.l @r15+,r14 + mov.l @r15,r15 + rte + nop + + .align 2 +__md_bit: + .long 0x40000000 +$current_thread_info: + .long __current_thread_info +$cpu_mode: + .long __cpu_mode + +! common exception handler +#include "../../entry-common.S" + + .data +! cpu operation mode +! bit30 = MD (compatible SH3/4) +__cpu_mode: + .long 0x40000000 + + .section .bss +__current_thread_info: + .long 0 + +ENTRY(exception_handling_table) + .space 4*32 diff --git a/arch/sh/kernel/cpu/sh2/ex.S b/arch/sh/kernel/cpu/sh2/ex.S new file mode 100644 index 000000000..85b0bf81f --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/ex.S @@ -0,0 +1,47 @@ +/* + * arch/sh/kernel/cpu/sh2/ex.S + * + * The SH-2 exception vector table + * + * 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/linkage.h> + +! +! convert Exception Vector to Exception Number +! +exception_entry: +no = 0 + .rept 256 + mov.l r1,@-sp + bra exception_trampoline + mov #no,r1 +no = no + 1 + .endr +exception_trampoline: + mov.l r0,@-sp + mov.l $exception_handler,r0 + extu.b r1,r1 + jmp @r0 + extu.w r1,r1 + + .align 2 +$exception_entry: + .long exception_entry +$exception_handler: + .long exception_handler +! +! Exception Vector Base +! + .align 2 +ENTRY(vbr_base) +vector = 0 + .rept 256 + .long exception_entry + vector * 6 +vector = vector + 1 + .endr diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c new file mode 100644 index 000000000..6c687ae81 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/probe.c @@ -0,0 +1,33 @@ +/* + * arch/sh/kernel/cpu/sh2/probe.c + * + * CPU Subtype Probing for SH-2. + * + * Copyright (C) 2002 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> + +void cpu_probe(void) +{ +#if defined(CONFIG_CPU_SUBTYPE_SH7619) + boot_cpu_data.type = CPU_SH7619; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.dcache.way_incr = (1<<12); + boot_cpu_data.dcache.sets = 256; + boot_cpu_data.dcache.entry_shift = 4; + boot_cpu_data.dcache.linesz = L1_CACHE_BYTES; + boot_cpu_data.dcache.flags = 0; +#endif + /* + * SH-2 doesn't have separate caches + */ + boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED; + boot_cpu_data.icache = boot_cpu_data.dcache; + boot_cpu_data.family = CPU_FAMILY_SH2; +} 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 000000000..58c19adae --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c @@ -0,0 +1,211 @@ +/* + * SH7619 Setup + * + * Copyright (C) 2006 Yoshinori Sato + * Copyright (C) 2009 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/serial_sci.h> +#include <linux/sh_eth.h> +#include <linux/sh_timer.h> +#include <linux/io.h> + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, + WDT, EDMAC, CMT0, CMT1, + SCIF0, SCIF1, SCIF2, + HIF_HIFI, HIF_HIFBI, + DMAC0, DMAC1, DMAC2, DMAC3, + SIOF, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65), + INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67), + INTC_IRQ(IRQ4, 80), INTC_IRQ(IRQ5, 81), + INTC_IRQ(IRQ6, 82), INTC_IRQ(IRQ7, 83), + INTC_IRQ(WDT, 84), INTC_IRQ(EDMAC, 85), + INTC_IRQ(CMT0, 86), INTC_IRQ(CMT1, 87), + INTC_IRQ(SCIF0, 88), INTC_IRQ(SCIF0, 89), + INTC_IRQ(SCIF0, 90), INTC_IRQ(SCIF0, 91), + INTC_IRQ(SCIF1, 92), INTC_IRQ(SCIF1, 93), + INTC_IRQ(SCIF1, 94), INTC_IRQ(SCIF1, 95), + INTC_IRQ(SCIF2, 96), INTC_IRQ(SCIF2, 97), + INTC_IRQ(SCIF2, 98), INTC_IRQ(SCIF2, 99), + INTC_IRQ(HIF_HIFI, 100), INTC_IRQ(HIF_HIFBI, 101), + INTC_IRQ(DMAC0, 104), INTC_IRQ(DMAC1, 105), + INTC_IRQ(DMAC2, 106), INTC_IRQ(DMAC3, 107), + INTC_IRQ(SIOF, 108), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xf8140006, 0, 16, 4, /* IPRA */ { IRQ0, IRQ1, IRQ2, IRQ3 } }, + { 0xf8140008, 0, 16, 4, /* IPRB */ { IRQ4, IRQ5, IRQ6, IRQ7 } }, + { 0xf8080000, 0, 16, 4, /* IPRC */ { WDT, EDMAC, CMT0, CMT1 } }, + { 0xf8080002, 0, 16, 4, /* IPRD */ { SCIF0, SCIF1, SCIF2 } }, + { 0xf8080004, 0, 16, 4, /* IPRE */ { HIF_HIFI, HIF_HIFBI } }, + { 0xf8080006, 0, 16, 4, /* IPRF */ { DMAC0, DMAC1, DMAC2, DMAC3 } }, + { 0xf8080008, 0, 16, 4, /* IPRG */ { SIOF } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7619", vectors, NULL, + NULL, prio_registers, NULL); + +static struct plat_sci_port scif0_platform_data = { + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .type = PORT_SCIF, +}; + +static struct resource scif0_resources[] = { + DEFINE_RES_MEM(0xf8400000, 0x100), + DEFINE_RES_IRQ(88), +}; + +static struct platform_device scif0_device = { + .name = "sh-sci", + .id = 0, + .resource = scif0_resources, + .num_resources = ARRAY_SIZE(scif0_resources), + .dev = { + .platform_data = &scif0_platform_data, + }, +}; + +static struct plat_sci_port scif1_platform_data = { + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .type = PORT_SCIF, +}; + +static struct resource scif1_resources[] = { + DEFINE_RES_MEM(0xf8410000, 0x100), + DEFINE_RES_IRQ(92), +}; + +static struct platform_device scif1_device = { + .name = "sh-sci", + .id = 1, + .resource = scif1_resources, + .num_resources = ARRAY_SIZE(scif1_resources), + .dev = { + .platform_data = &scif1_platform_data, + }, +}; + +static struct plat_sci_port scif2_platform_data = { + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE, + .type = PORT_SCIF, +}; + +static struct resource scif2_resources[] = { + DEFINE_RES_MEM(0xf8420000, 0x100), + DEFINE_RES_IRQ(96), +}; + +static struct platform_device scif2_device = { + .name = "sh-sci", + .id = 2, + .resource = scif2_resources, + .num_resources = ARRAY_SIZE(scif2_resources), + .dev = { + .platform_data = &scif2_platform_data, + }, +}; + +static struct sh_eth_plat_data eth_platform_data = { + .phy = 1, + .edmac_endian = EDMAC_LITTLE_ENDIAN, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +static struct resource eth_resources[] = { + [0] = { + .start = 0xfb000000, + .end = 0xfb0001c7, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 85, + .end = 85, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device eth_device = { + .name = "sh7619-ether", + .id = -1, + .dev = { + .platform_data = ð_platform_data, + }, + .num_resources = ARRAY_SIZE(eth_resources), + .resource = eth_resources, +}; + +static struct sh_timer_config cmt_platform_data = { + .channels_mask = 3, +}; + +static struct resource cmt_resources[] = { + DEFINE_RES_MEM(0xf84a0070, 0x10), + DEFINE_RES_IRQ(86), + DEFINE_RES_IRQ(87), +}; + +static struct platform_device cmt_device = { + .name = "sh-cmt-16", + .id = 0, + .dev = { + .platform_data = &cmt_platform_data, + }, + .resource = cmt_resources, + .num_resources = ARRAY_SIZE(cmt_resources), +}; + +static struct platform_device *sh7619_devices[] __initdata = { + &scif0_device, + &scif1_device, + &scif2_device, + ð_device, + &cmt_device, +}; + +static int __init sh7619_devices_setup(void) +{ + return platform_add_devices(sh7619_devices, + ARRAY_SIZE(sh7619_devices)); +} +arch_initcall(sh7619_devices_setup); + +void __init plat_irq_setup(void) +{ + register_intc_controller(&intc_desc); +} + +static struct platform_device *sh7619_early_devices[] __initdata = { + &scif0_device, + &scif1_device, + &scif2_device, + &cmt_device, +}; + +#define STBCR3 0xf80a0000 + +void __init plat_early_device_setup(void) +{ + /* enable CMT clock */ + __raw_writeb(__raw_readb(STBCR3) & ~0x10, STBCR3); + + early_platform_add_devices(sh7619_early_devices, + ARRAY_SIZE(sh7619_early_devices)); +} |