mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
e62438630c
commit
9d4436a6fb
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
|
@ -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
|
|
@ -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];
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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"
|
||||
};
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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,
|
||||
};
|
|
@ -16,6 +16,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,
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
unsigned long v;
|
||||
unsigned long begin, end;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue