diff options
26 files changed, 1036 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  	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" 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  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 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 @@   */  #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; 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 @@  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 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 @@  # 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 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)  		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; 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)  {  	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" 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)  }  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 }, 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 @@  # 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 index 000000000000..d0440b269702 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c @@ -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]; +} + 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 @@  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 index 000000000000..82c2d905152f --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c @@ -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 index 000000000000..350972ae9410 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/Makefile @@ -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 index 000000000000..a9ad309c6a33 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c @@ -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 index 000000000000..87c6c0542089 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/probe.c @@ -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 index 000000000000..cdfeef49e62e --- /dev/null +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c @@ -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); 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[] = {  	[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"  }; 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,   */  #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]); 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 @@  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 index 000000000000..9eab395cd341 --- /dev/null +++ b/arch/sh/kernel/timers/timer-cmt.c @@ -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 index 000000000000..73a5ef3c457d --- /dev/null +++ b/arch/sh/kernel/timers/timer-mtu2.c @@ -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, +}; 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 = {  #ifdef CONFIG_SH_TMU  	&tmu_timer,  #endif +#ifdef CONFIG_SH_MTU2 +	&mtu2_timer, +#endif +#ifdef CONFIG_SH_CMT +	&cmt_timer, +#endif  	NULL,  }; 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"  # 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. 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 @@   *   * Released under the terms of the GNU GPL v2.0.   */ +  #include <linux/init.h>  #include <linux/mm.h> @@ -14,37 +15,43 @@  #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); +	}  } 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  TITAN			SH_TITAN  SHMIN			SH_SHMIN  7710VOIPGW		SH_7710VOIPGW +7206SE			SH_7206_SOLUTION_ENGINE +7619SE			SH_7619_SOLUTION_ENGINE diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 7ee992146ae9..b2bc0cfb4014 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -133,6 +133,20 @@  # 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  /* | 
