Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

51
arch/sh/kernel/Makefile Normal file
View file

@ -0,0 +1,51 @@
#
# Makefile for the Linux/SuperH kernel.
#
extra-y := head_$(BITS).o vmlinux.lds
ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_ftrace.o = -pg
endif
CFLAGS_REMOVE_return_address.o = -pg
obj-y := debugtraps.o dma-nommu.o dumpstack.o \
idle.o io.o irq.o irq_$(BITS).o kdebugfs.o \
machvec.o nmi_debug.o process.o \
process_$(BITS).o ptrace.o ptrace_$(BITS).o \
reboot.o return_address.o \
setup.o signal_$(BITS).o sys_sh.o \
syscalls_$(BITS).o time.o topology.o traps.o \
traps_$(BITS).o unwinder.o
ifndef CONFIG_GENERIC_IOMAP
obj-y += iomap.o
obj-$(CONFIG_HAS_IOPORT_MAP) += ioport.o
endif
obj-$(CONFIG_SUPERH32) += sys_sh32.o
obj-y += cpu/
obj-$(CONFIG_VSYSCALL) += vsyscall/
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_IO_TRAPPED) += io_trapped.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_DUMP_CODE) += disassemble.o
obj-$(CONFIG_HIBERNATION) += swsusp.o
obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o
ccflags-y := -Werror

View file

@ -0,0 +1,61 @@
/*
* This program is used to generate definitions needed by
* assembly language modules.
*
* We use the technique used in the OSF Mach kernel code:
* generate asm statements containing #defines,
* compile this file to assembler, and then extract the
* #defines from the assembly-language output.
*/
#include <linux/stddef.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/kbuild.h>
#include <linux/suspend.h>
#include <asm/thread_info.h>
#include <asm/suspend.h>
int main(void)
{
/* offsets into the thread_info struct */
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block));
DEFINE(TI_SIZE, sizeof(struct thread_info));
#ifdef CONFIG_HIBERNATION
DEFINE(PBE_ADDRESS, offsetof(struct pbe, address));
DEFINE(PBE_ORIG_ADDRESS, offsetof(struct pbe, orig_address));
DEFINE(PBE_NEXT, offsetof(struct pbe, next));
DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs));
#endif
DEFINE(SH_SLEEP_MODE, offsetof(struct sh_sleep_data, mode));
DEFINE(SH_SLEEP_SF_PRE, offsetof(struct sh_sleep_data, sf_pre));
DEFINE(SH_SLEEP_SF_POST, offsetof(struct sh_sleep_data, sf_post));
DEFINE(SH_SLEEP_RESUME, offsetof(struct sh_sleep_data, resume));
DEFINE(SH_SLEEP_VBR, offsetof(struct sh_sleep_data, vbr));
DEFINE(SH_SLEEP_SPC, offsetof(struct sh_sleep_data, spc));
DEFINE(SH_SLEEP_SR, offsetof(struct sh_sleep_data, sr));
DEFINE(SH_SLEEP_SP, offsetof(struct sh_sleep_data, sp));
DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr));
DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data));
DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr));
DEFINE(SH_SLEEP_REG_BAR, offsetof(struct sh_sleep_regs, bar));
DEFINE(SH_SLEEP_REG_PTEH, offsetof(struct sh_sleep_regs, pteh));
DEFINE(SH_SLEEP_REG_PTEL, offsetof(struct sh_sleep_regs, ptel));
DEFINE(SH_SLEEP_REG_TTB, offsetof(struct sh_sleep_regs, ttb));
DEFINE(SH_SLEEP_REG_TEA, offsetof(struct sh_sleep_regs, tea));
DEFINE(SH_SLEEP_REG_MMUCR, offsetof(struct sh_sleep_regs, mmucr));
DEFINE(SH_SLEEP_REG_PTEA, offsetof(struct sh_sleep_regs, ptea));
DEFINE(SH_SLEEP_REG_PASCR, offsetof(struct sh_sleep_regs, pascr));
DEFINE(SH_SLEEP_REG_IRMCR, offsetof(struct sh_sleep_regs, irmcr));
DEFINE(SH_SLEEP_REG_CCR, offsetof(struct sh_sleep_regs, ccr));
DEFINE(SH_SLEEP_REG_RAMCR, offsetof(struct sh_sleep_regs, ramcr));
return 0;
}

View file

@ -0,0 +1,21 @@
#
# Makefile for the Linux/SuperH CPU-specifc backends.
#
obj-$(CONFIG_CPU_SH2) = sh2/
obj-$(CONFIG_CPU_SH2A) = sh2a/
obj-$(CONFIG_CPU_SH3) = sh3/
obj-$(CONFIG_CPU_SH4) = sh4/
obj-$(CONFIG_CPU_SH5) = sh5/
# Special cases for family ancestry.
obj-$(CONFIG_CPU_SH4A) += sh4a/
obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
# Common interfaces.
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
obj-y += irq/ init.o clock.o fpu.o pfc.o proc.o

36
arch/sh/kernel/cpu/adc.c Normal file
View file

@ -0,0 +1,36 @@
/*
* linux/arch/sh/kernel/adc.c -- SH3 on-chip ADC support
*
* Copyright (C) 2004 Andriy Skulysh <askulysh@image.kiev.ua>
*/
#include <linux/module.h>
#include <asm/adc.h>
#include <asm/io.h>
int adc_single(unsigned int channel)
{
int off;
unsigned char csr;
if (channel >= 8) return -1;
off = (channel & 0x03) << 2;
csr = __raw_readb(ADCSR);
csr = channel | ADCSR_ADST | ADCSR_CKS;
__raw_writeb(csr, ADCSR);
do {
csr = __raw_readb(ADCSR);
} while ((csr & ADCSR_ADF) == 0);
csr &= ~(ADCSR_ADF | ADCSR_ADST);
__raw_writeb(csr, ADCSR);
return (((__raw_readb(ADDRAH + off) << 8) |
__raw_readb(ADDRAL + off)) >> 6);
}
EXPORT_SYMBOL(adc_single);

View file

@ -0,0 +1,78 @@
#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/clkdev.h>
#include <asm/clock.h>
static struct clk master_clk = {
.flags = CLK_ENABLE_ON_INIT,
.rate = CONFIG_SH_PCLK_FREQ,
};
static struct clk peripheral_clk = {
.parent = &master_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static struct clk bus_clk = {
.parent = &master_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static struct clk cpu_clk = {
.parent = &master_clk,
.flags = CLK_ENABLE_ON_INIT,
};
/*
* The ordering of these clocks matters, do not change it.
*/
static struct clk *onchip_clocks[] = {
&master_clk,
&peripheral_clk,
&bus_clk,
&cpu_clk,
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("master_clk", &master_clk),
CLKDEV_CON_ID("peripheral_clk", &peripheral_clk),
CLKDEV_CON_ID("bus_clk", &bus_clk),
CLKDEV_CON_ID("cpu_clk", &cpu_clk),
};
int __init __deprecated cpg_clk_init(void)
{
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
struct clk *clk = onchip_clocks[i];
arch_init_clk_ops(&clk->ops, i);
if (clk->ops)
ret |= clk_register(clk);
}
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
clk_add_alias("fck", "sh-tmu-sh3.0", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-tmu.0", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-tmu.1", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-tmu.2", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-mtu2", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-cmt-16.0", "peripheral_clk", NULL);
clk_add_alias("fck", "sh-cmt-32.0", "peripheral_clk", NULL);
clk_add_alias("sci_ick", NULL, "peripheral_clk", NULL);
return ret;
}
/*
* Placeholder for compatibility, until the lazy CPUs do this
* on their own.
*/
int __init __weak arch_clk_init(void)
{
return cpg_clk_init();
}

View file

@ -0,0 +1,51 @@
/*
* arch/sh/kernel/cpu/clock.c - SuperH clock framework
*
* Copyright (C) 2005 - 2009 Paul Mundt
*
* This clock framework is derived from the OMAP version by:
*
* Copyright (C) 2004 - 2008 Nokia Corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
*
* Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <asm/clock.h>
#include <asm/machvec.h>
int __init clk_init(void)
{
int ret;
ret = arch_clk_init();
if (unlikely(ret)) {
pr_err("%s: CPU clock registration failed.\n", __func__);
return ret;
}
if (sh_mv.mv_clk_init) {
ret = sh_mv.mv_clk_init();
if (unlikely(ret)) {
pr_err("%s: machvec clock initialization failed.\n",
__func__);
return ret;
}
}
/* Kick the child clocks.. */
recalculate_root_clocks();
/* Enable the necessary init clocks */
clk_enable_init_clocks();
return ret;
}

86
arch/sh/kernel/cpu/fpu.c Normal file
View file

@ -0,0 +1,86 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/processor.h>
#include <asm/fpu.h>
#include <asm/traps.h>
int init_fpu(struct task_struct *tsk)
{
if (tsk_used_math(tsk)) {
if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current)
unlazy_fpu(tsk, task_pt_regs(tsk));
return 0;
}
/*
* Memory allocation at the first usage of the FPU and other state.
*/
if (!tsk->thread.xstate) {
tsk->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
GFP_KERNEL);
if (!tsk->thread.xstate)
return -ENOMEM;
}
if (boot_cpu_data.flags & CPU_HAS_FPU) {
struct sh_fpu_hard_struct *fp = &tsk->thread.xstate->hardfpu;
memset(fp, 0, xstate_size);
fp->fpscr = FPSCR_INIT;
} else {
struct sh_fpu_soft_struct *fp = &tsk->thread.xstate->softfpu;
memset(fp, 0, xstate_size);
fp->fpscr = FPSCR_INIT;
}
set_stopped_child_used_math(tsk);
return 0;
}
#ifdef CONFIG_SH_FPU
void __fpu_state_restore(void)
{
struct task_struct *tsk = current;
restore_fpu(tsk);
task_thread_info(tsk)->status |= TS_USEDFPU;
tsk->thread.fpu_counter++;
}
void fpu_state_restore(struct pt_regs *regs)
{
struct task_struct *tsk = current;
if (unlikely(!user_mode(regs))) {
printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
BUG();
return;
}
if (!tsk_used_math(tsk)) {
local_irq_enable();
/*
* does a slab alloc which can sleep
*/
if (init_fpu(tsk)) {
/*
* ran out of memory!
*/
do_group_exit(SIGKILL);
return;
}
local_irq_disable();
}
grab_fpu(regs);
__fpu_state_restore();
}
BUILD_TRAP_HANDLER(fpu_state_restore)
{
TRAP_HANDLER_DECL;
fpu_state_restore(regs);
}
#endif /* CONFIG_SH_FPU */

365
arch/sh/kernel/cpu/init.c Normal file
View file

@ -0,0 +1,365 @@
/*
* arch/sh/kernel/cpu/init.c
*
* CPU init code
*
* Copyright (C) 2002 - 2009 Paul Mundt
* Copyright (C) 2003 Richard Curnow
*
* 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/mm.h>
#include <linux/log2.h>
#include <asm/mmu_context.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/cacheflush.h>
#include <asm/cache.h>
#include <asm/elf.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/sh_bios.h>
#include <asm/setup.h>
#ifdef CONFIG_SH_FPU
#define cpu_has_fpu 1
#else
#define cpu_has_fpu 0
#endif
#ifdef CONFIG_SH_DSP
#define cpu_has_dsp 1
#else
#define cpu_has_dsp 0
#endif
/*
* Generic wrapper for command line arguments to disable on-chip
* peripherals (nofpu, nodsp, and so forth).
*/
#define onchip_setup(x) \
static int x##_disabled = !cpu_has_##x; \
\
static int x##_setup(char *opts) \
{ \
x##_disabled = 1; \
return 1; \
} \
__setup("no" __stringify(x), x##_setup);
onchip_setup(fpu);
onchip_setup(dsp);
#ifdef CONFIG_SPECULATIVE_EXECUTION
#define CPUOPM 0xff2f0000
#define CPUOPM_RABD (1 << 5)
static void speculative_execution_init(void)
{
/* Clear RABD */
__raw_writel(__raw_readl(CPUOPM) & ~CPUOPM_RABD, CPUOPM);
/* Flush the update */
(void)__raw_readl(CPUOPM);
ctrl_barrier();
}
#else
#define speculative_execution_init() do { } while (0)
#endif
#ifdef CONFIG_CPU_SH4A
#define EXPMASK 0xff2f0004
#define EXPMASK_RTEDS (1 << 0)
#define EXPMASK_BRDSSLP (1 << 1)
#define EXPMASK_MMCAW (1 << 4)
static void expmask_init(void)
{
unsigned long expmask = __raw_readl(EXPMASK);
/*
* Future proofing.
*
* Disable support for slottable sleep instruction, non-nop
* instructions in the rte delay slot, and associative writes to
* the memory-mapped cache array.
*/
expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP | EXPMASK_MMCAW);
__raw_writel(expmask, EXPMASK);
ctrl_barrier();
}
#else
#define expmask_init() do { } while (0)
#endif
/* 2nd-level cache init */
void __attribute__ ((weak)) l2_cache_init(void)
{
}
/*
* Generic first-level cache init
*/
#ifdef CONFIG_SUPERH32
static void cache_init(void)
{
unsigned long ccr, flags;
jump_to_uncached();
ccr = __raw_readl(SH_CCR);
/*
* At this point we don't know whether the cache is enabled or not - a
* bootloader may have enabled it. There are at least 2 things that
* could be dirty in the cache at this point:
* 1. kernel command line set up by boot loader
* 2. spilled registers from the prolog of this function
* => before re-initialising the cache, we must do a purge of the whole
* cache out to memory for safety. As long as nothing is spilled
* during the loop to lines that have already been done, this is safe.
* - RPC
*/
if (ccr & CCR_CACHE_ENABLE) {
unsigned long ways, waysize, addrstart;
waysize = current_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 <<= current_cpu_data.dcache.entry_shift;
#ifdef CCR_CACHE_EMODE
/* If EMODE is not set, we only have 1 way to flush. */
if (!(ccr & CCR_CACHE_EMODE))
ways = 1;
else
#endif
ways = current_cpu_data.dcache.ways;
addrstart = CACHE_OC_ADDRESS_ARRAY;
do {
unsigned long addr;
for (addr = addrstart;
addr < addrstart + waysize;
addr += current_cpu_data.dcache.linesz)
__raw_writel(0, addr);
addrstart += current_cpu_data.dcache.way_incr;
} while (--ways);
}
/*
* Default CCR values .. enable the caches
* and invalidate them immediately..
*/
flags = CCR_CACHE_ENABLE | CCR_CACHE_INVALIDATE;
#ifdef CCR_CACHE_EMODE
/* Force EMODE if possible */
if (current_cpu_data.dcache.ways > 1)
flags |= CCR_CACHE_EMODE;
else
flags &= ~CCR_CACHE_EMODE;
#endif
#if defined(CONFIG_CACHE_WRITETHROUGH)
/* Write-through */
flags |= CCR_CACHE_WT;
#elif defined(CONFIG_CACHE_WRITEBACK)
/* Write-back */
flags |= CCR_CACHE_CB;
#else
/* Off */
flags &= ~CCR_CACHE_ENABLE;
#endif
l2_cache_init();
__raw_writel(flags, SH_CCR);
back_to_cached();
}
#else
#define cache_init() do { } while (0)
#endif
#define CSHAPE(totalsize, linesize, assoc) \
((totalsize & ~0xff) | (linesize << 4) | assoc)
#define CACHE_DESC_SHAPE(desc) \
CSHAPE((desc).way_size * (desc).ways, ilog2((desc).linesz), (desc).ways)
static void detect_cache_shape(void)
{
l1d_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.dcache);
if (current_cpu_data.dcache.flags & SH_CACHE_COMBINED)
l1i_cache_shape = l1d_cache_shape;
else
l1i_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.icache);
if (current_cpu_data.flags & CPU_HAS_L2_CACHE)
l2_cache_shape = CACHE_DESC_SHAPE(current_cpu_data.scache);
else
l2_cache_shape = -1; /* No S-cache */
}
static void fpu_init(void)
{
/* Disable the FPU */
if (fpu_disabled && (current_cpu_data.flags & CPU_HAS_FPU)) {
printk("FPU Disabled\n");
current_cpu_data.flags &= ~CPU_HAS_FPU;
}
disable_fpu();
clear_used_math();
}
#ifdef CONFIG_SH_DSP
static void release_dsp(void)
{
unsigned long sr;
/* Clear SR.DSP bit */
__asm__ __volatile__ (
"stc\tsr, %0\n\t"
"and\t%1, %0\n\t"
"ldc\t%0, sr\n\t"
: "=&r" (sr)
: "r" (~SR_DSP)
);
}
static void dsp_init(void)
{
unsigned long sr;
/*
* Set the SR.DSP bit, wait for one instruction, and then read
* back the SR value.
*/
__asm__ __volatile__ (
"stc\tsr, %0\n\t"
"or\t%1, %0\n\t"
"ldc\t%0, sr\n\t"
"nop\n\t"
"stc\tsr, %0\n\t"
: "=&r" (sr)
: "r" (SR_DSP)
);
/* If the DSP bit is still set, this CPU has a DSP */
if (sr & SR_DSP)
current_cpu_data.flags |= CPU_HAS_DSP;
/* Disable the DSP */
if (dsp_disabled && (current_cpu_data.flags & CPU_HAS_DSP)) {
printk("DSP Disabled\n");
current_cpu_data.flags &= ~CPU_HAS_DSP;
}
/* Now that we've determined the DSP status, clear the DSP bit. */
release_dsp();
}
#else
static inline void dsp_init(void) { }
#endif /* CONFIG_SH_DSP */
/**
* cpu_init
*
* This is our initial entry point for each CPU, and is invoked on the
* boot CPU prior to calling start_kernel(). For SMP, a combination of
* this and start_secondary() will bring up each processor to a ready
* state prior to hand forking the idle loop.
*
* We do all of the basic processor init here, including setting up
* the caches, FPU, DSP, etc. By the time start_kernel() is hit (and
* subsequently platform_setup()) things like determining the CPU
* subtype and initial configuration will all be done.
*
* Each processor family is still responsible for doing its own probing
* and cache configuration in cpu_probe().
*/
asmlinkage void cpu_init(void)
{
current_thread_info()->cpu = hard_smp_processor_id();
/* First, probe the CPU */
cpu_probe();
if (current_cpu_data.type == CPU_SH_NONE)
panic("Unknown CPU");
/* First setup the rest of the I-cache info */
current_cpu_data.icache.entry_mask = current_cpu_data.icache.way_incr -
current_cpu_data.icache.linesz;
current_cpu_data.icache.way_size = current_cpu_data.icache.sets *
current_cpu_data.icache.linesz;
/* And the D-cache too */
current_cpu_data.dcache.entry_mask = current_cpu_data.dcache.way_incr -
current_cpu_data.dcache.linesz;
current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets *
current_cpu_data.dcache.linesz;
/* Init the cache */
cache_init();
if (raw_smp_processor_id() == 0) {
shm_align_mask = max_t(unsigned long,
current_cpu_data.dcache.way_size - 1,
PAGE_SIZE - 1);
/* Boot CPU sets the cache shape */
detect_cache_shape();
}
fpu_init();
dsp_init();
/*
* Initialize the per-CPU ASID cache very early, since the
* TLB flushing routines depend on this being setup.
*/
current_cpu_data.asid_cache = NO_CONTEXT;
current_cpu_data.phys_bits = __in_29bit_mode() ? 29 : 32;
speculative_execution_init();
expmask_init();
/* Do the rest of the boot processor setup */
if (raw_smp_processor_id() == 0) {
/* Save off the BIOS VBR, if there is one */
sh_bios_vbr_init();
/*
* Setup VBR for boot CPU. Secondary CPUs do this through
* start_secondary().
*/
per_cpu_trap_init();
/*
* Boot processor to setup the FP and extended state
* context info.
*/
init_thread_xstate();
}
}

View file

@ -0,0 +1,6 @@
#
# Makefile for the Linux/SuperH CPU-specifc IRQ handlers.
#
obj-$(CONFIG_SUPERH32) += imask.o
obj-$(CONFIG_CPU_SH5) += intc-sh5.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o

View file

@ -0,0 +1,84 @@
/*
* arch/sh/kernel/cpu/irq/imask.c
*
* Copyright (C) 1999, 2000 Niibe Yutaka
*
* Simple interrupt handling using IMASK of SR register.
*
*/
/* NOTE: Will not work on level 15 */
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/cache.h>
#include <linux/irq.h>
#include <linux/bitmap.h>
#include <asm/irq.h>
/* Bitmap of IRQ masked */
#define IMASK_PRIORITY 15
static DECLARE_BITMAP(imask_mask, IMASK_PRIORITY);
static int interrupt_priority;
static inline void set_interrupt_registers(int ip)
{
unsigned long __dummy;
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"
"cmp/eq #0x3c, %0\n\t"
"bt/s 1f ! CLI-ed\n\t"
" stc sr, %0\n\t"
"and %1, %0\n\t"
"or %2, %0\n\t"
"ldc %0, sr\n"
"1:"
: "=&z" (__dummy)
: "r" (~0xf0), "r" (ip << 4)
: "t");
}
static void mask_imask_irq(struct irq_data *data)
{
unsigned int irq = data->irq;
clear_bit(irq, imask_mask);
if (interrupt_priority < IMASK_PRIORITY - irq)
interrupt_priority = IMASK_PRIORITY - irq;
set_interrupt_registers(interrupt_priority);
}
static void unmask_imask_irq(struct irq_data *data)
{
unsigned int irq = data->irq;
set_bit(irq, imask_mask);
interrupt_priority = IMASK_PRIORITY -
find_first_zero_bit(imask_mask, IMASK_PRIORITY);
set_interrupt_registers(interrupt_priority);
}
static struct irq_chip imask_irq_chip = {
.name = "SR.IMASK",
.irq_mask = mask_imask_irq,
.irq_unmask = unmask_imask_irq,
.irq_mask_ack = mask_imask_irq,
};
void make_imask_irq(unsigned int irq)
{
irq_set_chip_and_handler_name(irq, &imask_irq_chip, handle_level_irq,
"level");
}

View file

@ -0,0 +1,197 @@
/*
* arch/sh/kernel/cpu/irq/intc-sh5.c
*
* Interrupt Controller support for SH5 INTC.
*
* Copyright (C) 2000, 2001 Paolo Alberelli
* Copyright (C) 2003 Paul Mundt
*
* Per-interrupt selective. IRLM=0 (Fixed priority) is not
* supported being useless without a cascaded interrupt
* controller.
*
* 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/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <cpu/irq.h>
#include <asm/page.h>
/*
* Maybe the generic Peripheral block could move to a more
* generic include file. INTC Block will be defined here
* and only here to make INTC self-contained in a single
* file.
*/
#define INTC_BLOCK_OFFSET 0x01000000
/* Base */
#define INTC_BASE PHYS_PERIPHERAL_BLOCK + \
INTC_BLOCK_OFFSET
/* Address */
#define INTC_ICR_SET (intc_virt + 0x0)
#define INTC_ICR_CLEAR (intc_virt + 0x8)
#define INTC_INTPRI_0 (intc_virt + 0x10)
#define INTC_INTSRC_0 (intc_virt + 0x50)
#define INTC_INTSRC_1 (intc_virt + 0x58)
#define INTC_INTREQ_0 (intc_virt + 0x60)
#define INTC_INTREQ_1 (intc_virt + 0x68)
#define INTC_INTENB_0 (intc_virt + 0x70)
#define INTC_INTENB_1 (intc_virt + 0x78)
#define INTC_INTDSB_0 (intc_virt + 0x80)
#define INTC_INTDSB_1 (intc_virt + 0x88)
#define INTC_ICR_IRLM 0x1
#define INTC_INTPRI_PREGS 8 /* 8 Priority Registers */
#define INTC_INTPRI_PPREG 8 /* 8 Priorities per Register */
/*
* Mapper between the vector ordinal and the IRQ number
* passed to kernel/device drivers.
*/
int intc_evt_to_irq[(0xE20/0x20)+1] = {
-1, -1, -1, -1, -1, -1, -1, -1, /* 0x000 - 0x0E0 */
-1, -1, -1, -1, -1, -1, -1, -1, /* 0x100 - 0x1E0 */
0, 0, 0, 0, 0, 1, 0, 0, /* 0x200 - 0x2E0 */
2, 0, 0, 3, 0, 0, 0, -1, /* 0x300 - 0x3E0 */
32, 33, 34, 35, 36, 37, 38, -1, /* 0x400 - 0x4E0 */
-1, -1, -1, 63, -1, -1, -1, -1, /* 0x500 - 0x5E0 */
-1, -1, 18, 19, 20, 21, 22, -1, /* 0x600 - 0x6E0 */
39, 40, 41, 42, -1, -1, -1, -1, /* 0x700 - 0x7E0 */
4, 5, 6, 7, -1, -1, -1, -1, /* 0x800 - 0x8E0 */
-1, -1, -1, -1, -1, -1, -1, -1, /* 0x900 - 0x9E0 */
12, 13, 14, 15, 16, 17, -1, -1, /* 0xA00 - 0xAE0 */
-1, -1, -1, -1, -1, -1, -1, -1, /* 0xB00 - 0xBE0 */
-1, -1, -1, -1, -1, -1, -1, -1, /* 0xC00 - 0xCE0 */
-1, -1, -1, -1, -1, -1, -1, -1, /* 0xD00 - 0xDE0 */
-1, -1 /* 0xE00 - 0xE20 */
};
static unsigned long intc_virt;
static int irlm; /* IRL mode */
static void enable_intc_irq(struct irq_data *data)
{
unsigned int irq = data->irq;
unsigned long reg;
unsigned long bitmask;
if ((irq <= IRQ_IRL3) && (irlm == NO_PRIORITY))
printk("Trying to use straight IRL0-3 with an encoding platform.\n");
if (irq < 32) {
reg = INTC_INTENB_0;
bitmask = 1 << irq;
} else {
reg = INTC_INTENB_1;
bitmask = 1 << (irq - 32);
}
__raw_writel(bitmask, reg);
}
static void disable_intc_irq(struct irq_data *data)
{
unsigned int irq = data->irq;
unsigned long reg;
unsigned long bitmask;
if (irq < 32) {
reg = INTC_INTDSB_0;
bitmask = 1 << irq;
} else {
reg = INTC_INTDSB_1;
bitmask = 1 << (irq - 32);
}
__raw_writel(bitmask, reg);
}
static struct irq_chip intc_irq_type = {
.name = "INTC",
.irq_enable = enable_intc_irq,
.irq_disable = disable_intc_irq,
};
void __init plat_irq_setup(void)
{
unsigned long long __dummy0, __dummy1=~0x00000000100000f0;
unsigned long reg;
int i;
intc_virt = (unsigned long)ioremap_nocache(INTC_BASE, 1024);
if (!intc_virt) {
panic("Unable to remap INTC\n");
}
/* Set default: per-line enable/disable, priority driven ack/eoi */
for (i = 0; i < NR_INTC_IRQS; i++)
irq_set_chip_and_handler(i, &intc_irq_type, handle_level_irq);
/* Disable all interrupts and set all priorities to 0 to avoid trouble */
__raw_writel(-1, INTC_INTDSB_0);
__raw_writel(-1, INTC_INTDSB_1);
for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8)
__raw_writel( NO_PRIORITY, reg);
#ifdef CONFIG_SH_CAYMAN
{
unsigned long data;
/* Set IRLM */
/* If all the priorities are set to 'no priority', then
* assume we are using encoded mode.
*/
irlm = platform_int_priority[IRQ_IRL0] +
platform_int_priority[IRQ_IRL1] +
platform_int_priority[IRQ_IRL2] +
platform_int_priority[IRQ_IRL3];
if (irlm == NO_PRIORITY) {
/* IRLM = 0 */
reg = INTC_ICR_CLEAR;
i = IRQ_INTA;
printk("Trying to use encoded IRL0-3. IRLs unsupported.\n");
} else {
/* IRLM = 1 */
reg = INTC_ICR_SET;
i = IRQ_IRL0;
}
__raw_writel(INTC_ICR_IRLM, reg);
/* Set interrupt priorities according to platform description */
for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) {
data |= platform_int_priority[i] <<
((i % INTC_INTPRI_PPREG) * 4);
if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) {
/* Upon the 7th, set Priority Register */
__raw_writel(data, reg);
data = 0;
reg += 8;
}
}
}
#endif
/*
* And now let interrupts come in.
* sti() is not enough, we need to
* lower priority, too.
*/
__asm__ __volatile__("getcon " __SR ", %0\n\t"
"and %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy0)
: "r" (__dummy1));
}

View file

@ -0,0 +1,83 @@
/*
* Interrupt handling for IPR-based IRQ.
*
* Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
* Copyright (C) 2000 Kazumoto Kojima
* Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
* Copyright (C) 2006 Paul Mundt
*
* Supported system:
* On-chip supporting modules (TMU, RTC, etc.).
* On-chip supporting modules for SH7709/SH7709A/SH7729.
* Hitachi SolutionEngine external I/O:
* MS7709SE01, MS7709ASE01, and MS7750SE01
*
* 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/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/topology.h>
static inline struct ipr_desc *get_ipr_desc(struct irq_data *data)
{
struct irq_chip *chip = irq_data_get_irq_chip(data);
return container_of(chip, struct ipr_desc, chip);
}
static void disable_ipr_irq(struct irq_data *data)
{
struct ipr_data *p = irq_data_get_irq_chip_data(data);
unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
/* Set the priority in IPR to 0 */
__raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr);
(void)__raw_readw(addr); /* Read back to flush write posting */
}
static void enable_ipr_irq(struct irq_data *data)
{
struct ipr_data *p = irq_data_get_irq_chip_data(data);
unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
/* Set priority in IPR back to original value */
__raw_writew(__raw_readw(addr) | (p->priority << p->shift), addr);
}
/*
* The shift value is now the number of bits to shift, not the number of
* bits/4. This is to make it easier to read the value directly from the
* datasheets. The IPR address is calculated using the ipr_offset table.
*/
void register_ipr_controller(struct ipr_desc *desc)
{
int i;
desc->chip.irq_mask = disable_ipr_irq;
desc->chip.irq_unmask = enable_ipr_irq;
for (i = 0; i < desc->nr_irqs; i++) {
struct ipr_data *p = desc->ipr_data + i;
int res;
BUG_ON(p->ipr_idx >= desc->nr_offsets);
BUG_ON(!desc->ipr_offsets[p->ipr_idx]);
res = irq_alloc_desc_at(p->irq, numa_node_id());
if (unlikely(res != p->irq && res != -EEXIST)) {
printk(KERN_INFO "can not get irq_desc for %d\n",
p->irq);
continue;
}
disable_irq_nosync(p->irq);
irq_set_chip_and_handler_name(p->irq, &desc->chip,
handle_level_irq, "level");
irq_set_chip_data(p->irq, p);
disable_ipr_irq(irq_get_irq_data(p->irq));
}
}
EXPORT_SYMBOL(register_ipr_controller);

33
arch/sh/kernel/cpu/pfc.c Normal file
View file

@ -0,0 +1,33 @@
/*
* SH Pin Function Control Initialization
*
* Copyright (C) 2012 Renesas Solutions Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <cpu/pfc.h>
static struct platform_device sh_pfc_device = {
.id = -1,
};
int __init sh_pfc_register(const char *name,
struct resource *resource, u32 num_resources)
{
sh_pfc_device.name = name;
sh_pfc_device.num_resources = num_resources;
sh_pfc_device.resource = resource;
return platform_device_register(&sh_pfc_device);
}

150
arch/sh/kernel/cpu/proc.c Normal file
View file

@ -0,0 +1,150 @@
#include <linux/seq_file.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/machvec.h>
#include <asm/processor.h>
static const char *cpu_name[] = {
[CPU_SH7201] = "SH7201",
[CPU_SH7203] = "SH7203", [CPU_SH7263] = "SH7263",
[CPU_SH7264] = "SH7264", [CPU_SH7269] = "SH7269",
[CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619",
[CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
[CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
[CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
[CPU_SH7712] = "SH7712", [CPU_SH7720] = "SH7720",
[CPU_SH7721] = "SH7721", [CPU_SH7729] = "SH7729",
[CPU_SH7750] = "SH7750", [CPU_SH7750S] = "SH7750S",
[CPU_SH7750R] = "SH7750R", [CPU_SH7751] = "SH7751",
[CPU_SH7751R] = "SH7751R", [CPU_SH7760] = "SH7760",
[CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501",
[CPU_SH7763] = "SH7763", [CPU_SH7770] = "SH7770",
[CPU_SH7780] = "SH7780", [CPU_SH7781] = "SH7781",
[CPU_SH7343] = "SH7343", [CPU_SH7785] = "SH7785",
[CPU_SH7786] = "SH7786", [CPU_SH7757] = "SH7757",
[CPU_SH7722] = "SH7722", [CPU_SHX3] = "SH-X3",
[CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103",
[CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723",
[CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724",
[CPU_SH7372] = "SH7372", [CPU_SH7734] = "SH7734",
[CPU_SH_NONE] = "Unknown"
};
const char *get_cpu_subtype(struct sh_cpuinfo *c)
{
return cpu_name[c->type];
}
EXPORT_SYMBOL(get_cpu_subtype);
#ifdef CONFIG_PROC_FS
/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
static const char *cpu_flags[] = {
"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
"ptea", "llsc", "l2", "op32", "pteaex", NULL
};
static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
{
unsigned long i;
seq_printf(m, "cpu flags\t:");
if (!c->flags) {
seq_printf(m, " %s\n", cpu_flags[0]);
return;
}
for (i = 0; cpu_flags[i]; i++)
if ((c->flags & (1 << i)))
seq_printf(m, " %s", cpu_flags[i+1]);
seq_printf(m, "\n");
}
static void show_cacheinfo(struct seq_file *m, const char *type,
struct cache_info info)
{
unsigned int cache_size;
cache_size = info.ways * info.sets * info.linesz;
seq_printf(m, "%s size\t: %2dKiB (%d-way)\n",
type, cache_size >> 10, info.ways);
}
/*
* Get CPU information for use by the procfs.
*/
static int show_cpuinfo(struct seq_file *m, void *v)
{
struct sh_cpuinfo *c = v;
unsigned int cpu = c - cpu_data;
if (!cpu_online(cpu))
return 0;
if (cpu == 0)
seq_printf(m, "machine\t\t: %s\n", get_system_type());
else
seq_printf(m, "\n");
seq_printf(m, "processor\t: %d\n", cpu);
seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine);
seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype(c));
if (c->cut_major == -1)
seq_printf(m, "cut\t\t: unknown\n");
else if (c->cut_minor == -1)
seq_printf(m, "cut\t\t: %d.x\n", c->cut_major);
else
seq_printf(m, "cut\t\t: %d.%d\n", c->cut_major, c->cut_minor);
show_cpuflags(m, c);
seq_printf(m, "cache type\t: ");
/*
* Check for what type of cache we have, we support both the
* unified cache on the SH-2 and SH-3, as well as the harvard
* style cache on the SH-4.
*/
if (c->icache.flags & SH_CACHE_COMBINED) {
seq_printf(m, "unified\n");
show_cacheinfo(m, "cache", c->icache);
} else {
seq_printf(m, "split (harvard)\n");
show_cacheinfo(m, "icache", c->icache);
show_cacheinfo(m, "dcache", c->dcache);
}
/* Optional secondary cache */
if (c->flags & CPU_HAS_L2_CACHE)
show_cacheinfo(m, "scache", c->scache);
seq_printf(m, "address sizes\t: %u bits physical\n", c->phys_bits);
seq_printf(m, "bogomips\t: %lu.%02lu\n",
c->loops_per_jiffy/(500000/HZ),
(c->loops_per_jiffy/(5000/HZ)) % 100);
return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
{
return *pos < NR_CPUS ? cpu_data + *pos : NULL;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
return c_start(m, pos);
}
static void c_stop(struct seq_file *m, void *v)
{
}
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = show_cpuinfo,
};
#endif /* CONFIG_PROC_FS */

View file

@ -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

View file

@ -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];
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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 = &eth_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,
&eth_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));
}

View file

@ -0,0 +1,24 @@
#
# Makefile for the Linux/SuperH SH-2A backends.
#
obj-y := common.o probe.o opcode_helper.o
common-y += ex.o entry.o
obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_CPU_SUBTYPE_SH7201) += setup-sh7201.o clock-sh7201.o
obj-$(CONFIG_CPU_SUBTYPE_SH7203) += setup-sh7203.o clock-sh7203.o
obj-$(CONFIG_CPU_SUBTYPE_SH7263) += setup-sh7203.o clock-sh7203.o
obj-$(CONFIG_CPU_SUBTYPE_SH7264) += setup-sh7264.o clock-sh7264.o
obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
obj-$(CONFIG_CPU_SUBTYPE_SH7269) += setup-sh7269.o clock-sh7269.o
obj-$(CONFIG_CPU_SUBTYPE_MXG) += setup-mxg.o clock-sh7206.o
# Pinmux setup
pinmux-$(CONFIG_CPU_SUBTYPE_SH7203) := pinmux-sh7203.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7264) := pinmux-sh7264.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7269) := pinmux-sh7269.o
obj-$(CONFIG_GPIOLIB) += $(pinmux-y)

View file

@ -0,0 +1,85 @@
/*
* arch/sh/kernel/cpu/sh2a/clock-sh7201.c
*
* SH7201 support for the clock framework
*
* Copyright (C) 2008 Peter Griffin <pgriffin@mpc-data.co.uk>
*
* 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>
static const int pll1rate[]={1,2,3,4,6,8};
static const int pfc_divisors[]={1,2,3,4,6,8,12};
#define ifc_divisors pfc_divisors
static unsigned int pll2_mult;
static void master_clk_init(struct clk *clk)
{
clk->rate = 10000000 * pll2_mult *
pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
}
static struct sh_clk_ops sh7201_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 sh7201_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FREQCR) & 0x0007);
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh7201_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readw(FREQCR) >> 4) & 0x0007);
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh7201_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7201_clk_ops[] = {
&sh7201_master_clk_ops,
&sh7201_module_clk_ops,
&sh7201_bus_clk_ops,
&sh7201_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (test_mode_pin(MODE_PIN1 | MODE_PIN0))
pll2_mult = 1;
else if (test_mode_pin(MODE_PIN1))
pll2_mult = 2;
else
pll2_mult = 4;
if (idx < ARRAY_SIZE(sh7201_clk_ops))
*ops = sh7201_clk_ops[idx];
}

View file

@ -0,0 +1,81 @@
/*
* arch/sh/kernel/cpu/sh2a/clock-sh7203.c
*
* SH7203 support for the clock framework
*
* Copyright (C) 2007 Kieran Bingham (MPC-Data Ltd)
*
* Based on clock-sh7263.c
* 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>
static const int pll1rate[]={8,12,16,0};
static const int pfc_divisors[]={1,2,3,4,6,8,12};
#define ifc_divisors pfc_divisors
static unsigned int pll2_mult;
static void master_clk_init(struct clk *clk)
{
clk->rate *= pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0003] * pll2_mult;
}
static struct sh_clk_ops sh7203_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 sh7203_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FREQCR) & 0x0007);
return clk->parent->rate / pfc_divisors[idx-2];
}
static struct sh_clk_ops sh7203_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static struct sh_clk_ops sh7203_cpu_clk_ops = {
.recalc = followparent_recalc,
};
static struct sh_clk_ops *sh7203_clk_ops[] = {
&sh7203_master_clk_ops,
&sh7203_module_clk_ops,
&sh7203_bus_clk_ops,
&sh7203_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (test_mode_pin(MODE_PIN1))
pll2_mult = 4;
else if (test_mode_pin(MODE_PIN0))
pll2_mult = 2;
else
pll2_mult = 1;
if (idx < ARRAY_SIZE(sh7203_clk_ops))
*ops = sh7203_clk_ops[idx];
}

View file

@ -0,0 +1,83 @@
/*
* 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>
static const int pll1rate[]={1,2,3,4,6,8};
static const int pfc_divisors[]={1,2,3,4,6,8,12};
#define ifc_divisors pfc_divisors
static unsigned int pll2_mult;
static void master_clk_init(struct clk *clk)
{
clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
}
static struct sh_clk_ops sh7206_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 sh7206_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) & 0x0007];
}
static struct sh_clk_ops sh7206_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FREQCR) & 0x0007);
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh7206_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_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 sh_clk_ops **ops, int idx)
{
if (test_mode_pin(MODE_PIN2 | MODE_PIN1 | MODE_PIN0))
pll2_mult = 1;
else if (test_mode_pin(MODE_PIN2 | MODE_PIN1))
pll2_mult = 2;
else if (test_mode_pin(MODE_PIN1))
pll2_mult = 4;
if (idx < ARRAY_SIZE(sh7206_clk_ops))
*ops = sh7206_clk_ops[idx];
}

View file

@ -0,0 +1,153 @@
/*
* arch/sh/kernel/cpu/sh2a/clock-sh7264.c
*
* SH7264 clock framework support
*
* Copyright (C) 2012 Phil Edworthy
*
* 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 <linux/clkdev.h>
#include <asm/clock.h>
/* SH7264 registers */
#define FRQCR 0xfffe0010
#define STBCR3 0xfffe0408
#define STBCR4 0xfffe040c
#define STBCR5 0xfffe0410
#define STBCR6 0xfffe0414
#define STBCR7 0xfffe0418
#define STBCR8 0xfffe041c
static const unsigned int pll1rate[] = {8, 12};
static unsigned int pll1_div;
/* Fixed 32 KHz root clock for RTC */
static struct clk r_clk = {
.rate = 32768,
};
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
static struct clk extal_clk = {
.rate = 18000000,
};
static unsigned long pll_recalc(struct clk *clk)
{
unsigned long rate = clk->parent->rate / pll1_div;
return rate * pll1rate[(__raw_readw(FRQCR) >> 8) & 1];
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.parent = &extal_clk,
.flags = CLK_ENABLE_ON_INIT,
};
struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&pll_clk,
};
static int div2[] = { 1, 2, 3, 4, 6, 8, 12 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = div2,
.nr_divisors = ARRAY_SIZE(div2),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_P,
DIV4_NR };
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
/* The mask field specifies the div2 entries that are valid */
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQCR, 4, 0x7, CLK_ENABLE_REG_16BIT
| CLK_ENABLE_ON_INIT),
[DIV4_P] = DIV4(FRQCR, 0, 0x78, CLK_ENABLE_REG_16BIT),
};
enum { MSTP77, MSTP74, MSTP72,
MSTP60,
MSTP35, MSTP34, MSTP33, MSTP32, MSTP30,
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
[MSTP77] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 7, 0), /* SCIF */
[MSTP74] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 4, 0), /* VDC */
[MSTP72] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 2, 0), /* CMT */
[MSTP60] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR6, 0, 0), /* USB */
[MSTP35] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 6, 0), /* MTU2 */
[MSTP34] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 4, 0), /* SDHI0 */
[MSTP33] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 3, 0), /* SDHI1 */
[MSTP32] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 2, 0), /* ADC */
[MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0), /* RTC */
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("rclk", &r_clk),
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
/* MSTP clocks */
CLKDEV_CON_ID("sci_ick", &mstp_clks[MSTP77]),
CLKDEV_CON_ID("vdc3", &mstp_clks[MSTP74]),
CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
CLKDEV_ICK_ID("fck", "sh-mtu2", &mstp_clks[MSTP35]),
CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP34]),
CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP33]),
CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
};
int __init arch_clk_init(void)
{
int k, ret = 0;
if (test_mode_pin(MODE_PIN0)) {
if (test_mode_pin(MODE_PIN1))
pll1_div = 3;
else
pll1_div = 4;
} else
pll1_div = 1;
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,184 @@
/*
* arch/sh/kernel/cpu/sh2a/clock-sh7269.c
*
* SH7269 clock framework support
*
* Copyright (C) 2012 Phil Edworthy
*
* 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 <linux/clkdev.h>
#include <asm/clock.h>
/* SH7269 registers */
#define FRQCR 0xfffe0010
#define STBCR3 0xfffe0408
#define STBCR4 0xfffe040c
#define STBCR5 0xfffe0410
#define STBCR6 0xfffe0414
#define STBCR7 0xfffe0418
#define PLL_RATE 20
/* Fixed 32 KHz root clock for RTC */
static struct clk r_clk = {
.rate = 32768,
};
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
static struct clk extal_clk = {
.rate = 13340000,
};
static unsigned long pll_recalc(struct clk *clk)
{
return clk->parent->rate * PLL_RATE;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.parent = &extal_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static unsigned long peripheral0_recalc(struct clk *clk)
{
return clk->parent->rate / 8;
}
static struct sh_clk_ops peripheral0_clk_ops = {
.recalc = peripheral0_recalc,
};
static struct clk peripheral0_clk = {
.ops = &peripheral0_clk_ops,
.parent = &pll_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static unsigned long peripheral1_recalc(struct clk *clk)
{
return clk->parent->rate / 4;
}
static struct sh_clk_ops peripheral1_clk_ops = {
.recalc = peripheral1_recalc,
};
static struct clk peripheral1_clk = {
.ops = &peripheral1_clk_ops,
.parent = &pll_clk,
.flags = CLK_ENABLE_ON_INIT,
};
struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&pll_clk,
&peripheral0_clk,
&peripheral1_clk,
};
static int div2[] = { 1, 2, 0, 4 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = div2,
.nr_divisors = ARRAY_SIZE(div2),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_B,
DIV4_NR };
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
/* The mask field specifies the div2 entries that are valid */
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQCR, 8, 0xB, CLK_ENABLE_REG_16BIT
| CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(FRQCR, 4, 0xA, CLK_ENABLE_REG_16BIT
| CLK_ENABLE_ON_INIT),
};
enum { MSTP72,
MSTP60,
MSTP47, MSTP46, MSTP45, MSTP44, MSTP43, MSTP42, MSTP41, MSTP40,
MSTP35, MSTP32, MSTP30,
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
[MSTP72] = SH_CLK_MSTP8(&peripheral0_clk, STBCR7, 2, 0), /* CMT */
[MSTP60] = SH_CLK_MSTP8(&peripheral1_clk, STBCR6, 0, 0), /* USB */
[MSTP47] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 7, 0), /* SCIF0 */
[MSTP46] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 6, 0), /* SCIF1 */
[MSTP45] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 5, 0), /* SCIF2 */
[MSTP44] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 4, 0), /* SCIF3 */
[MSTP43] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 3, 0), /* SCIF4 */
[MSTP42] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 2, 0), /* SCIF5 */
[MSTP41] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 1, 0), /* SCIF6 */
[MSTP40] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 0, 0), /* SCIF7 */
[MSTP35] = SH_CLK_MSTP8(&peripheral0_clk, STBCR3, 5, 0), /* MTU2 */
[MSTP32] = SH_CLK_MSTP8(&peripheral1_clk, STBCR3, 2, 0), /* ADC */
[MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0), /* RTC */
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("rclk", &r_clk),
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
CLKDEV_CON_ID("peripheral_clk", &peripheral1_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
/* MSTP clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP44]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP43]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP42]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.6", &mstp_clks[MSTP41]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.7", &mstp_clks[MSTP40]),
CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
CLKDEV_ICK_ID("fck", "sh-mtu2", &mstp_clks[MSTP35]),
CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
};
int __init arch_clk_init(void)
{
int k, ret = 0;
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,250 @@
/*
* arch/sh/kernel/cpu/sh2a/entry.S
*
* The SH-2A exception entry
*
* Copyright (C) 2008 Yoshinori Sato
* Based on arch/sh/kernel/cpu/sh2/entry.S
*
* 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
cli
mov.l $cpu_mode,r2
bld.b #6,@(0,r2) !previus SR.MD
bst.b #6,@(4*4,r15) !set cpu mode to SR.MD
bt 1f
! switch to kernel mode
bset.b #6,@(0,r2) !set SR.MD
mov.l $current_thread_info,r2
mov.l @r2,r2
mov #(THREAD_SIZE >> 8),r0
shll8 r0
add r2,r0 ! r0 = kernel stack tail
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 @(4*4,r2),r0
mov.l r0,@-r15 ! original SR
sts.l pr,@-r15
mov.l @(3*4,r2),r0
mov.l r0,@-r15 ! original PC
mov r2,r0
add #(3+2)*4,r0 ! rewind r0 - r3 + exception frame
lds r0,pr ! pr = original SP
movmu.l r3,@-r15 ! save regs
mov r2,r8 ! r8 = previus stack top
mov r1,r9 ! r9 = interrupt vector
! restore previous stack
mov.l @r8+,r2
mov.l @r8+,r0
mov.l @r8+,r1
bra 2f
movml.l r2,@-r15
1:
! in kernel exception
mov r15,r2
add #-((OFF_TRA + 4) - OFF_PC) + 5*4,r15
movmu.l r3,@-r15
mov r2,r8 ! r8 = previous stack top
mov r1,r9 ! r9 = interrupt vector
! restore exception frame & regs
mov.l @r8+,r2 ! old R2
mov.l @r8+,r0 ! old R0
mov.l @r8+,r1 ! old R1
mov.l @r8+,r10 ! old PC
mov.l @r8+,r11 ! old SR
movml.l r2,@-r15
mov.l r10,@(OFF_PC,r15)
mov.l r11,@(OFF_SR,r15)
mov.l r8,@(OFF_SP,r15) ! save old sp
mov r15,r8
add #OFF_TRA + 4,r8
mov.l r9,@-r8
sts.l macl,@-r8
sts.l mach,@-r8
stc.l gbr,@-r8
add #-4,r8
sts.l pr,@-r8
2:
! dispatch exception / interrupt
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 7f,r8
mov.l 6f,r9
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.l @(OFF_SR,r2),r3
mov.l r3,@-r1
mov.l @(OFF_SP,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)
movml.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.l @(OFF_PC,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
bld.b #6,@(OFF_SR,r15)
bst.b #6,@(0,r2) ! save CPU mode
mov.l @(OFF_SR,r0),r1
shll2 r1
shlr2 r1 ! clear MD bit
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.l @(OFF_PC,r0),r1
mov.l r1,@r2 ! set pc
get_current_thread_info r0, r1
mov.l $current_thread_info,r1
mov.l r0,@r1
movml.l @r15+,r14
mov.l @r15,r15
rte
nop
.align 2
$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

View file

@ -0,0 +1,73 @@
/*
* arch/sh/kernel/cpu/sh2a/ex.S
*
* The SH-2A exception vector table
*
* Copyright (C) 2008 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 no 0 to 255
exception_entry0:
no = 0
.rept 256
mov.l r1,@-sp
bra exception_trampoline0
mov #no,r1
no = no + 1
.endr
exception_trampoline0:
mov.l r0,@-sp
mov.l 1f,r0
extu.b r1,r1
jmp @r0
extu.w r1,r1
.align 2
1: .long exception_handler
! exception no 256 to 511
exception_entry1:
no = 0
.rept 256
mov.l r1,@-sp
bra exception_trampoline1
mov #no,r1
no = no + 1
.endr
exception_trampoline1:
mov.l r0,@-sp
extu.b r1,r1
movi20 #0x100,r0
add r0,r1
mov.l 1f,r0
jmp @r0
extu.w r1,r1
.align 2
1: .long exception_handler
!
! Exception Vector Base
!
.align 2
ENTRY(vbr_base)
vector = 0
.rept 256
.long exception_entry0 + vector * 6
vector = vector + 1
.endr
vector = 0
.rept 256
.long exception_entry1 + vector * 6
vector = vector + 1
.endr

View file

@ -0,0 +1,575 @@
/*
* Save/restore floating point context for signal handlers.
*
* Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
*
* 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.
*
* FIXME! These routines can be optimized in big endian case.
*/
#include <linux/sched.h>
#include <linux/signal.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/fpu.h>
#include <asm/traps.h>
/* The PR (precision) bit in the FP Status Register must be clear when
* an frchg instruction is executed, otherwise the instruction is undefined.
* Executing frchg with PR set causes a trap on some SH4 implementations.
*/
#define FPSCR_RCHG 0x00000000
/*
* Save FPU registers onto task structure.
*/
void save_fpu(struct task_struct *tsk)
{
unsigned long dummy;
enable_fpu();
asm volatile("sts.l fpul, @-%0\n\t"
"sts.l fpscr, @-%0\n\t"
"fmov.s fr15, @-%0\n\t"
"fmov.s fr14, @-%0\n\t"
"fmov.s fr13, @-%0\n\t"
"fmov.s fr12, @-%0\n\t"
"fmov.s fr11, @-%0\n\t"
"fmov.s fr10, @-%0\n\t"
"fmov.s fr9, @-%0\n\t"
"fmov.s fr8, @-%0\n\t"
"fmov.s fr7, @-%0\n\t"
"fmov.s fr6, @-%0\n\t"
"fmov.s fr5, @-%0\n\t"
"fmov.s fr4, @-%0\n\t"
"fmov.s fr3, @-%0\n\t"
"fmov.s fr2, @-%0\n\t"
"fmov.s fr1, @-%0\n\t"
"fmov.s fr0, @-%0\n\t"
"lds %3, fpscr\n\t"
: "=r" (dummy)
: "0" ((char *)(&tsk->thread.xstate->hardfpu.status)),
"r" (FPSCR_RCHG),
"r" (FPSCR_INIT)
: "memory");
disable_fpu();
}
void restore_fpu(struct task_struct *tsk)
{
unsigned long dummy;
enable_fpu();
asm volatile("fmov.s @%0+, fr0\n\t"
"fmov.s @%0+, fr1\n\t"
"fmov.s @%0+, fr2\n\t"
"fmov.s @%0+, fr3\n\t"
"fmov.s @%0+, fr4\n\t"
"fmov.s @%0+, fr5\n\t"
"fmov.s @%0+, fr6\n\t"
"fmov.s @%0+, fr7\n\t"
"fmov.s @%0+, fr8\n\t"
"fmov.s @%0+, fr9\n\t"
"fmov.s @%0+, fr10\n\t"
"fmov.s @%0+, fr11\n\t"
"fmov.s @%0+, fr12\n\t"
"fmov.s @%0+, fr13\n\t"
"fmov.s @%0+, fr14\n\t"
"fmov.s @%0+, fr15\n\t"
"lds.l @%0+, fpscr\n\t"
"lds.l @%0+, fpul\n\t"
: "=r" (dummy)
: "0" (tsk->thread.xstate), "r" (FPSCR_RCHG)
: "memory");
disable_fpu();
}
/*
* Emulate arithmetic ops on denormalized number for some FPU insns.
*/
/* denormalized float * float */
static int denormal_mulf(int hx, int hy)
{
unsigned int ix, iy;
unsigned long long m, n;
int exp, w;
ix = hx & 0x7fffffff;
iy = hy & 0x7fffffff;
if (iy < 0x00800000 || ix == 0)
return ((hx ^ hy) & 0x80000000);
exp = (iy & 0x7f800000) >> 23;
ix &= 0x007fffff;
iy = (iy & 0x007fffff) | 0x00800000;
m = (unsigned long long)ix * iy;
n = m;
w = -1;
while (n) { n >>= 1; w++; }
/* FIXME: use guard bits */
exp += w - 126 - 46;
if (exp > 0)
ix = ((int) (m >> (w - 23)) & 0x007fffff) | (exp << 23);
else if (exp + 22 >= 0)
ix = (int) (m >> (w - 22 - exp)) & 0x007fffff;
else
ix = 0;
ix |= (hx ^ hy) & 0x80000000;
return ix;
}
/* denormalized double * double */
static void mult64(unsigned long long x, unsigned long long y,
unsigned long long *highp, unsigned long long *lowp)
{
unsigned long long sub0, sub1, sub2, sub3;
unsigned long long high, low;
sub0 = (x >> 32) * (unsigned long) (y >> 32);
sub1 = (x & 0xffffffffLL) * (unsigned long) (y >> 32);
sub2 = (x >> 32) * (unsigned long) (y & 0xffffffffLL);
sub3 = (x & 0xffffffffLL) * (unsigned long) (y & 0xffffffffLL);
low = sub3;
high = 0LL;
sub3 += (sub1 << 32);
if (low > sub3)
high++;
low = sub3;
sub3 += (sub2 << 32);
if (low > sub3)
high++;
low = sub3;
high += (sub1 >> 32) + (sub2 >> 32);
high += sub0;
*lowp = low;
*highp = high;
}
static inline long long rshift64(unsigned long long mh,
unsigned long long ml, int n)
{
if (n >= 64)
return mh >> (n - 64);
return (mh << (64 - n)) | (ml >> n);
}
static long long denormal_muld(long long hx, long long hy)
{
unsigned long long ix, iy;
unsigned long long mh, ml, nh, nl;
int exp, w;
ix = hx & 0x7fffffffffffffffLL;
iy = hy & 0x7fffffffffffffffLL;
if (iy < 0x0010000000000000LL || ix == 0)
return ((hx ^ hy) & 0x8000000000000000LL);
exp = (iy & 0x7ff0000000000000LL) >> 52;
ix &= 0x000fffffffffffffLL;
iy = (iy & 0x000fffffffffffffLL) | 0x0010000000000000LL;
mult64(ix, iy, &mh, &ml);
nh = mh;
nl = ml;
w = -1;
if (nh) {
while (nh) { nh >>= 1; w++;}
w += 64;
} else
while (nl) { nl >>= 1; w++;}
/* FIXME: use guard bits */
exp += w - 1022 - 52 * 2;
if (exp > 0)
ix = (rshift64(mh, ml, w - 52) & 0x000fffffffffffffLL)
| ((long long)exp << 52);
else if (exp + 51 >= 0)
ix = rshift64(mh, ml, w - 51 - exp) & 0x000fffffffffffffLL;
else
ix = 0;
ix |= (hx ^ hy) & 0x8000000000000000LL;
return ix;
}
/* ix - iy where iy: denormal and ix, iy >= 0 */
static int denormal_subf1(unsigned int ix, unsigned int iy)
{
int frac;
int exp;
if (ix < 0x00800000)
return ix - iy;
exp = (ix & 0x7f800000) >> 23;
if (exp - 1 > 31)
return ix;
iy >>= exp - 1;
if (iy == 0)
return ix;
frac = (ix & 0x007fffff) | 0x00800000;
frac -= iy;
while (frac < 0x00800000) {
if (--exp == 0)
return frac;
frac <<= 1;
}
return (exp << 23) | (frac & 0x007fffff);
}
/* ix + iy where iy: denormal and ix, iy >= 0 */
static int denormal_addf1(unsigned int ix, unsigned int iy)
{
int frac;
int exp;
if (ix < 0x00800000)
return ix + iy;
exp = (ix & 0x7f800000) >> 23;
if (exp - 1 > 31)
return ix;
iy >>= exp - 1;
if (iy == 0)
return ix;
frac = (ix & 0x007fffff) | 0x00800000;
frac += iy;
if (frac >= 0x01000000) {
frac >>= 1;
++exp;
}
return (exp << 23) | (frac & 0x007fffff);
}
static int denormal_addf(int hx, int hy)
{
unsigned int ix, iy;
int sign;
if ((hx ^ hy) & 0x80000000) {
sign = hx & 0x80000000;
ix = hx & 0x7fffffff;
iy = hy & 0x7fffffff;
if (iy < 0x00800000) {
ix = denormal_subf1(ix, iy);
if ((int) ix < 0) {
ix = -ix;
sign ^= 0x80000000;
}
} else {
ix = denormal_subf1(iy, ix);
sign ^= 0x80000000;
}
} else {
sign = hx & 0x80000000;
ix = hx & 0x7fffffff;
iy = hy & 0x7fffffff;
if (iy < 0x00800000)
ix = denormal_addf1(ix, iy);
else
ix = denormal_addf1(iy, ix);
}
return sign | ix;
}
/* ix - iy where iy: denormal and ix, iy >= 0 */
static long long denormal_subd1(unsigned long long ix, unsigned long long iy)
{
long long frac;
int exp;
if (ix < 0x0010000000000000LL)
return ix - iy;
exp = (ix & 0x7ff0000000000000LL) >> 52;
if (exp - 1 > 63)
return ix;
iy >>= exp - 1;
if (iy == 0)
return ix;
frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL;
frac -= iy;
while (frac < 0x0010000000000000LL) {
if (--exp == 0)
return frac;
frac <<= 1;
}
return ((long long)exp << 52) | (frac & 0x000fffffffffffffLL);
}
/* ix + iy where iy: denormal and ix, iy >= 0 */
static long long denormal_addd1(unsigned long long ix, unsigned long long iy)
{
long long frac;
long long exp;
if (ix < 0x0010000000000000LL)
return ix + iy;
exp = (ix & 0x7ff0000000000000LL) >> 52;
if (exp - 1 > 63)
return ix;
iy >>= exp - 1;
if (iy == 0)
return ix;
frac = (ix & 0x000fffffffffffffLL) | 0x0010000000000000LL;
frac += iy;
if (frac >= 0x0020000000000000LL) {
frac >>= 1;
++exp;
}
return (exp << 52) | (frac & 0x000fffffffffffffLL);
}
static long long denormal_addd(long long hx, long long hy)
{
unsigned long long ix, iy;
long long sign;
if ((hx ^ hy) & 0x8000000000000000LL) {
sign = hx & 0x8000000000000000LL;
ix = hx & 0x7fffffffffffffffLL;
iy = hy & 0x7fffffffffffffffLL;
if (iy < 0x0010000000000000LL) {
ix = denormal_subd1(ix, iy);
if ((int) ix < 0) {
ix = -ix;
sign ^= 0x8000000000000000LL;
}
} else {
ix = denormal_subd1(iy, ix);
sign ^= 0x8000000000000000LL;
}
} else {
sign = hx & 0x8000000000000000LL;
ix = hx & 0x7fffffffffffffffLL;
iy = hy & 0x7fffffffffffffffLL;
if (iy < 0x0010000000000000LL)
ix = denormal_addd1(ix, iy);
else
ix = denormal_addd1(iy, ix);
}
return sign | ix;
}
/**
* denormal_to_double - Given denormalized float number,
* store double float
*
* @fpu: Pointer to sh_fpu_hard structure
* @n: Index to FP register
*/
static void
denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
{
unsigned long du, dl;
unsigned long x = fpu->fpul;
int exp = 1023 - 126;
if (x != 0 && (x & 0x7f800000) == 0) {
du = (x & 0x80000000);
while ((x & 0x00800000) == 0) {
x <<= 1;
exp--;
}
x &= 0x007fffff;
du |= (exp << 20) | (x >> 3);
dl = x << 29;
fpu->fp_regs[n] = du;
fpu->fp_regs[n+1] = dl;
}
}
/**
* ieee_fpe_handler - Handle denormalized number exception
*
* @regs: Pointer to register structure
*
* Returns 1 when it's handled (should not cause exception).
*/
static int
ieee_fpe_handler (struct pt_regs *regs)
{
unsigned short insn = *(unsigned short *) regs->pc;
unsigned short finsn;
unsigned long nextpc;
int nib[4] = {
(insn >> 12) & 0xf,
(insn >> 8) & 0xf,
(insn >> 4) & 0xf,
insn & 0xf};
if (nib[0] == 0xb ||
(nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
regs->pr = regs->pc + 4;
if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
finsn = *(unsigned short *) (regs->pc + 2);
} else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
if (regs->sr & 1)
nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
else
nextpc = regs->pc + 4;
finsn = *(unsigned short *) (regs->pc + 2);
} else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
if (regs->sr & 1)
nextpc = regs->pc + 4;
else
nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
finsn = *(unsigned short *) (regs->pc + 2);
} else if (nib[0] == 0x4 && nib[3] == 0xb &&
(nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
nextpc = regs->regs[nib[1]];
finsn = *(unsigned short *) (regs->pc + 2);
} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
(nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
nextpc = regs->pc + 4 + regs->regs[nib[1]];
finsn = *(unsigned short *) (regs->pc + 2);
} else if (insn == 0x000b) { /* rts */
nextpc = regs->pr;
finsn = *(unsigned short *) (regs->pc + 2);
} else {
nextpc = regs->pc + 2;
finsn = insn;
}
#define FPSCR_FPU_ERROR (1 << 17)
if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
struct task_struct *tsk = current;
if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_FPU_ERROR)) {
/* FPU error */
denormal_to_double (&tsk->thread.xstate->hardfpu,
(finsn >> 8) & 0xf);
} else
return 0;
regs->pc = nextpc;
return 1;
} else if ((finsn & 0xf00f) == 0xf002) { /* fmul */
struct task_struct *tsk = current;
int fpscr;
int n, m, prec;
unsigned int hx, hy;
n = (finsn >> 8) & 0xf;
m = (finsn >> 4) & 0xf;
hx = tsk->thread.xstate->hardfpu.fp_regs[n];
hy = tsk->thread.xstate->hardfpu.fp_regs[m];
fpscr = tsk->thread.xstate->hardfpu.fpscr;
prec = fpscr & (1 << 19);
if ((fpscr & FPSCR_FPU_ERROR)
&& (prec && ((hx & 0x7fffffff) < 0x00100000
|| (hy & 0x7fffffff) < 0x00100000))) {
long long llx, lly;
/* FPU error because of denormal */
llx = ((long long) hx << 32)
| tsk->thread.xstate->hardfpu.fp_regs[n+1];
lly = ((long long) hy << 32)
| tsk->thread.xstate->hardfpu.fp_regs[m+1];
if ((hx & 0x7fffffff) >= 0x00100000)
llx = denormal_muld(lly, llx);
else
llx = denormal_muld(llx, lly);
tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff;
} else if ((fpscr & FPSCR_FPU_ERROR)
&& (!prec && ((hx & 0x7fffffff) < 0x00800000
|| (hy & 0x7fffffff) < 0x00800000))) {
/* FPU error because of denormal */
if ((hx & 0x7fffffff) >= 0x00800000)
hx = denormal_mulf(hy, hx);
else
hx = denormal_mulf(hx, hy);
tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
} else
return 0;
regs->pc = nextpc;
return 1;
} else if ((finsn & 0xf00e) == 0xf000) { /* fadd, fsub */
struct task_struct *tsk = current;
int fpscr;
int n, m, prec;
unsigned int hx, hy;
n = (finsn >> 8) & 0xf;
m = (finsn >> 4) & 0xf;
hx = tsk->thread.xstate->hardfpu.fp_regs[n];
hy = tsk->thread.xstate->hardfpu.fp_regs[m];
fpscr = tsk->thread.xstate->hardfpu.fpscr;
prec = fpscr & (1 << 19);
if ((fpscr & FPSCR_FPU_ERROR)
&& (prec && ((hx & 0x7fffffff) < 0x00100000
|| (hy & 0x7fffffff) < 0x00100000))) {
long long llx, lly;
/* FPU error because of denormal */
llx = ((long long) hx << 32)
| tsk->thread.xstate->hardfpu.fp_regs[n+1];
lly = ((long long) hy << 32)
| tsk->thread.xstate->hardfpu.fp_regs[m+1];
if ((finsn & 0xf00f) == 0xf000)
llx = denormal_addd(llx, lly);
else
llx = denormal_addd(llx, lly ^ (1LL << 63));
tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff;
} else if ((fpscr & FPSCR_FPU_ERROR)
&& (!prec && ((hx & 0x7fffffff) < 0x00800000
|| (hy & 0x7fffffff) < 0x00800000))) {
/* FPU error because of denormal */
if ((finsn & 0xf00f) == 0xf000)
hx = denormal_addf(hx, hy);
else
hx = denormal_addf(hx, hy ^ 0x80000000);
tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
} else
return 0;
regs->pc = nextpc;
return 1;
}
return 0;
}
BUILD_TRAP_HANDLER(fpu_error)
{
struct task_struct *tsk = current;
TRAP_HANDLER_DECL;
__unlazy_fpu(tsk, regs);
if (ieee_fpe_handler(regs)) {
tsk->thread.xstate->hardfpu.fpscr &=
~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
grab_fpu(regs);
restore_fpu(tsk);
task_thread_info(tsk)->status |= TS_USEDFPU;
return;
}
force_sig(SIGFPE, tsk);
}

View file

@ -0,0 +1,54 @@
/*
* arch/sh/kernel/cpu/sh2a/opcode_helper.c
*
* Helper for the SH-2A 32-bit opcodes.
*
* Copyright (C) 2007 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/kernel.h>
/*
* Instructions on SH are generally fixed at 16-bits, however, SH-2A
* introduces some 32-bit instructions. Since there are no real
* constraints on their use (and they can be mixed and matched), we need
* to check the instruction encoding to work out if it's a true 32-bit
* instruction or not.
*
* Presently, 32-bit opcodes have only slight variations in what the
* actual encoding looks like in the first-half of the instruction, which
* makes it fairly straightforward to differentiate from the 16-bit ones.
*
* First 16-bits of encoding Used by
*
* 0011nnnnmmmm0001 mov.b, mov.w, mov.l, fmov.d,
* fmov.s, movu.b, movu.w
*
* 0011nnnn0iii1001 bclr.b, bld.b, bset.b, bst.b, band.b,
* bandnot.b, bldnot.b, bor.b, bornot.b,
* bxor.b
*
* 0000nnnniiii0000 movi20
* 0000nnnniiii0001 movi20s
*/
unsigned int instruction_size(unsigned int insn)
{
/* Look for the common cases */
switch ((insn & 0xf00f)) {
case 0x0000: /* movi20 */
case 0x0001: /* movi20s */
case 0x3001: /* 32-bit mov/fmov/movu variants */
return 4;
}
/* And the special cases.. */
switch ((insn & 0xf08f)) {
case 0x3009: /* 32-bit b*.b bit operations */
return 4;
}
return 2;
}

View file

@ -0,0 +1,30 @@
/*
* SH7203 Pinmux
*
* Copyright (C) 2008 Magnus Damm
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7203_pfc_resources[] = {
[0] = {
.start = 0xfffe3800,
.end = 0xfffe3a9f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7203", sh7203_pfc_resources,
ARRAY_SIZE(sh7203_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,30 @@
/*
* SH7264 Pinmux
*
* Copyright (C) 2012 Renesas Electronics Europe Ltd
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7264_pfc_resources[] = {
[0] = {
.start = 0xfffe3800,
.end = 0xfffe393f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7264", sh7264_pfc_resources,
ARRAY_SIZE(sh7264_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,31 @@
/*
* SH7269 Pinmux
*
* Copyright (C) 2012 Renesas Electronics Europe Ltd
* Copyright (C) 2012 Phil Edworthy
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <cpu/pfc.h>
static struct resource sh7269_pfc_resources[] = {
[0] = {
.start = 0xfffe3800,
.end = 0xfffe391f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7269", sh7269_pfc_resources,
ARRAY_SIZE(sh7269_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,60 @@
/*
* arch/sh/kernel/cpu/sh2a/probe.c
*
* CPU Subtype Probing for SH-2A.
*
* Copyright (C) 2004 - 2007 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)
{
boot_cpu_data.family = CPU_FAMILY_SH2A;
/* All SH-2A CPUs have support for 16 and 32-bit opcodes.. */
boot_cpu_data.flags |= CPU_HAS_OP32;
#if defined(CONFIG_CPU_SUBTYPE_SH7201)
boot_cpu_data.type = CPU_SH7201;
boot_cpu_data.flags |= CPU_HAS_FPU;
#elif defined(CONFIG_CPU_SUBTYPE_SH7203)
boot_cpu_data.type = CPU_SH7203;
boot_cpu_data.flags |= CPU_HAS_FPU;
#elif defined(CONFIG_CPU_SUBTYPE_SH7263)
boot_cpu_data.type = CPU_SH7263;
boot_cpu_data.flags |= CPU_HAS_FPU;
#elif defined(CONFIG_CPU_SUBTYPE_SH7264)
boot_cpu_data.type = CPU_SH7264;
boot_cpu_data.flags |= CPU_HAS_FPU;
#elif defined(CONFIG_CPU_SUBTYPE_SH7269)
boot_cpu_data.type = CPU_SH7269;
boot_cpu_data.flags |= CPU_HAS_FPU;
#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
boot_cpu_data.type = CPU_SH7206;
boot_cpu_data.flags |= CPU_HAS_DSP;
#elif defined(CONFIG_CPU_SUBTYPE_MXG)
boot_cpu_data.type = CPU_MXG;
boot_cpu_data.flags |= CPU_HAS_DSP;
#endif
boot_cpu_data.dcache.ways = 4;
boot_cpu_data.dcache.way_incr = (1 << 11);
boot_cpu_data.dcache.sets = 128;
boot_cpu_data.dcache.entry_shift = 4;
boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
boot_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.
*/
boot_cpu_data.icache = boot_cpu_data.dcache;
}

View file

@ -0,0 +1,178 @@
/*
* Renesas MX-G (R8A03022BG) Setup
*
* Copyright (C) 2008, 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_timer.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
IRQ8, IRQ9, IRQ10, IRQ11, IRQ12, IRQ13, IRQ14, IRQ15,
PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
SINT8, SINT7, SINT6, SINT5, SINT4, SINT3, SINT2, SINT1,
SCIF0, SCIF1,
MTU2_GROUP1, MTU2_GROUP2, MTU2_GROUP3, MTU2_GROUP4, MTU2_GROUP5,
MTU2_TGI3B, MTU2_TGI3C,
/* interrupt groups */
PINT,
};
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, 68), INTC_IRQ(IRQ5, 69),
INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
INTC_IRQ(IRQ8, 72), INTC_IRQ(IRQ9, 73),
INTC_IRQ(IRQ10, 74), INTC_IRQ(IRQ11, 75),
INTC_IRQ(IRQ12, 76), INTC_IRQ(IRQ13, 77),
INTC_IRQ(IRQ14, 78), INTC_IRQ(IRQ15, 79),
INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
INTC_IRQ(SINT8, 94), INTC_IRQ(SINT7, 95),
INTC_IRQ(SINT6, 96), INTC_IRQ(SINT5, 97),
INTC_IRQ(SINT4, 98), INTC_IRQ(SINT3, 99),
INTC_IRQ(SINT2, 100), INTC_IRQ(SINT1, 101),
INTC_IRQ(SCIF0, 220), INTC_IRQ(SCIF0, 221),
INTC_IRQ(SCIF0, 222), INTC_IRQ(SCIF0, 223),
INTC_IRQ(SCIF1, 224), INTC_IRQ(SCIF1, 225),
INTC_IRQ(SCIF1, 226), INTC_IRQ(SCIF1, 227),
INTC_IRQ(MTU2_GROUP1, 228), INTC_IRQ(MTU2_GROUP1, 229),
INTC_IRQ(MTU2_GROUP1, 230), INTC_IRQ(MTU2_GROUP1, 231),
INTC_IRQ(MTU2_GROUP1, 232), INTC_IRQ(MTU2_GROUP1, 233),
INTC_IRQ(MTU2_GROUP2, 234), INTC_IRQ(MTU2_GROUP2, 235),
INTC_IRQ(MTU2_GROUP2, 236), INTC_IRQ(MTU2_GROUP2, 237),
INTC_IRQ(MTU2_GROUP2, 238), INTC_IRQ(MTU2_GROUP2, 239),
INTC_IRQ(MTU2_GROUP3, 240), INTC_IRQ(MTU2_GROUP3, 241),
INTC_IRQ(MTU2_GROUP3, 242), INTC_IRQ(MTU2_GROUP3, 243),
INTC_IRQ(MTU2_TGI3B, 244),
INTC_IRQ(MTU2_TGI3C, 245),
INTC_IRQ(MTU2_GROUP4, 246), INTC_IRQ(MTU2_GROUP4, 247),
INTC_IRQ(MTU2_GROUP4, 248), INTC_IRQ(MTU2_GROUP4, 249),
INTC_IRQ(MTU2_GROUP4, 250), INTC_IRQ(MTU2_GROUP4, 251),
INTC_IRQ(MTU2_GROUP5, 252), INTC_IRQ(MTU2_GROUP5, 253),
INTC_IRQ(MTU2_GROUP5, 254), INTC_IRQ(MTU2_GROUP5, 255),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
PINT4, PINT5, PINT6, PINT7),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffd9418, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
{ 0xfffd941a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfffd941c, 0, 16, 4, /* IPR03 */ { IRQ8, IRQ9, IRQ10, IRQ11 } },
{ 0xfffd941e, 0, 16, 4, /* IPR04 */ { IRQ12, IRQ13, IRQ14, IRQ15 } },
{ 0xfffd9420, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
{ 0xfffd9800, 0, 16, 4, /* IPR06 */ { } },
{ 0xfffd9802, 0, 16, 4, /* IPR07 */ { } },
{ 0xfffd9804, 0, 16, 4, /* IPR08 */ { } },
{ 0xfffd9806, 0, 16, 4, /* IPR09 */ { } },
{ 0xfffd9808, 0, 16, 4, /* IPR10 */ { } },
{ 0xfffd980a, 0, 16, 4, /* IPR11 */ { } },
{ 0xfffd980c, 0, 16, 4, /* IPR12 */ { } },
{ 0xfffd980e, 0, 16, 4, /* IPR13 */ { } },
{ 0xfffd9810, 0, 16, 4, /* IPR14 */ { 0, 0, 0, SCIF0 } },
{ 0xfffd9812, 0, 16, 4, /* IPR15 */
{ SCIF1, MTU2_GROUP1, MTU2_GROUP2, MTU2_GROUP3 } },
{ 0xfffd9814, 0, 16, 4, /* IPR16 */
{ MTU2_TGI3B, MTU2_TGI3C, MTU2_GROUP4, MTU2_GROUP5 } },
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfffd9408, 0, 16, /* PINTER */
{ 0, 0, 0, 0, 0, 0, 0, 0,
PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
};
static DECLARE_INTC_DESC(intc_desc, "mxg", vectors, groups,
mask_registers, prio_registers, NULL);
static struct resource mtu2_resources[] = {
DEFINE_RES_MEM(0xff801000, 0x400),
DEFINE_RES_IRQ_NAMED(228, "tgi0a"),
DEFINE_RES_IRQ_NAMED(234, "tgi1a"),
DEFINE_RES_IRQ_NAMED(240, "tgi2a"),
};
static struct platform_device mtu2_device = {
.name = "sh-mtu2",
.id = -1,
.resource = mtu2_resources,
.num_resources = ARRAY_SIZE(mtu2_resources),
};
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(0xff804000, 0x100),
DEFINE_RES_IRQ(220),
};
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 platform_device *mxg_devices[] __initdata = {
&scif0_device,
&mtu2_device,
};
static int __init mxg_devices_setup(void)
{
return platform_add_devices(mxg_devices,
ARRAY_SIZE(mxg_devices));
}
arch_initcall(mxg_devices_setup);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
static struct platform_device *mxg_early_devices[] __initdata = {
&scif0_device,
&mtu2_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(mxg_early_devices,
ARRAY_SIZE(mxg_early_devices));
}

View file

@ -0,0 +1,428 @@
/*
* SH7201 setup
*
* Copyright (C) 2008 Peter Griffin pgriffin@mpc-data.co.uk
* 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_timer.h>
#include <linux/io.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
ADC_ADI,
MTU20_ABCD, MTU20_VEF, MTU21_AB, MTU21_VU, MTU22_AB, MTU22_VU,
MTU23_ABCD, MTU24_ABCD, MTU25_UVW, MTU2_TCI3V, MTU2_TCI4V,
RTC, WDT,
IIC30, IIC31, IIC32,
DMAC0_DMINT0, DMAC1_DMINT1,
DMAC2_DMINT2, DMAC3_DMINT3,
SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
DMAC0_DMINTA, DMAC4_DMINT4, DMAC5_DMINT5, DMAC6_DMINT6,
DMAC7_DMINT7,
RCAN0, RCAN1,
SSI0_SSII, SSI1_SSII,
TMR0, TMR1,
/* interrupt groups */
PINT,
};
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, 68), INTC_IRQ(IRQ5, 69),
INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
INTC_IRQ(ADC_ADI, 92),
INTC_IRQ(MTU20_ABCD, 108), INTC_IRQ(MTU20_ABCD, 109),
INTC_IRQ(MTU20_ABCD, 110), INTC_IRQ(MTU20_ABCD, 111),
INTC_IRQ(MTU20_VEF, 112), INTC_IRQ(MTU20_VEF, 113),
INTC_IRQ(MTU20_VEF, 114),
INTC_IRQ(MTU21_AB, 116), INTC_IRQ(MTU21_AB, 117),
INTC_IRQ(MTU21_VU, 120), INTC_IRQ(MTU21_VU, 121),
INTC_IRQ(MTU22_AB, 124), INTC_IRQ(MTU22_AB, 125),
INTC_IRQ(MTU22_VU, 128), INTC_IRQ(MTU22_VU, 129),
INTC_IRQ(MTU23_ABCD, 132), INTC_IRQ(MTU23_ABCD, 133),
INTC_IRQ(MTU23_ABCD, 134), INTC_IRQ(MTU23_ABCD, 135),
INTC_IRQ(MTU2_TCI3V, 136),
INTC_IRQ(MTU24_ABCD, 140), INTC_IRQ(MTU24_ABCD, 141),
INTC_IRQ(MTU24_ABCD, 142), INTC_IRQ(MTU24_ABCD, 143),
INTC_IRQ(MTU2_TCI4V, 144),
INTC_IRQ(MTU25_UVW, 148), INTC_IRQ(MTU25_UVW, 149),
INTC_IRQ(MTU25_UVW, 150),
INTC_IRQ(RTC, 152), INTC_IRQ(RTC, 153),
INTC_IRQ(RTC, 154),
INTC_IRQ(WDT, 156),
INTC_IRQ(IIC30, 157), INTC_IRQ(IIC30, 158),
INTC_IRQ(IIC30, 159), INTC_IRQ(IIC30, 160),
INTC_IRQ(IIC30, 161),
INTC_IRQ(IIC31, 164), INTC_IRQ(IIC31, 165),
INTC_IRQ(IIC31, 166), INTC_IRQ(IIC31, 167),
INTC_IRQ(IIC31, 168),
INTC_IRQ(IIC32, 170), INTC_IRQ(IIC32, 171),
INTC_IRQ(IIC32, 172), INTC_IRQ(IIC32, 173),
INTC_IRQ(IIC32, 174),
INTC_IRQ(DMAC0_DMINT0, 176), INTC_IRQ(DMAC1_DMINT1, 177),
INTC_IRQ(DMAC2_DMINT2, 178), INTC_IRQ(DMAC3_DMINT3, 179),
INTC_IRQ(SCIF0, 180), INTC_IRQ(SCIF0, 181),
INTC_IRQ(SCIF0, 182), INTC_IRQ(SCIF0, 183),
INTC_IRQ(SCIF1, 184), INTC_IRQ(SCIF1, 185),
INTC_IRQ(SCIF1, 186), INTC_IRQ(SCIF1, 187),
INTC_IRQ(SCIF2, 188), INTC_IRQ(SCIF2, 189),
INTC_IRQ(SCIF2, 190), INTC_IRQ(SCIF2, 191),
INTC_IRQ(SCIF3, 192), INTC_IRQ(SCIF3, 193),
INTC_IRQ(SCIF3, 194), INTC_IRQ(SCIF3, 195),
INTC_IRQ(SCIF4, 196), INTC_IRQ(SCIF4, 197),
INTC_IRQ(SCIF4, 198), INTC_IRQ(SCIF4, 199),
INTC_IRQ(SCIF5, 200), INTC_IRQ(SCIF5, 201),
INTC_IRQ(SCIF5, 202), INTC_IRQ(SCIF5, 203),
INTC_IRQ(SCIF6, 204), INTC_IRQ(SCIF6, 205),
INTC_IRQ(SCIF6, 206), INTC_IRQ(SCIF6, 207),
INTC_IRQ(SCIF7, 208), INTC_IRQ(SCIF7, 209),
INTC_IRQ(SCIF7, 210), INTC_IRQ(SCIF7, 211),
INTC_IRQ(DMAC0_DMINTA, 212), INTC_IRQ(DMAC4_DMINT4, 216),
INTC_IRQ(DMAC5_DMINT5, 217), INTC_IRQ(DMAC6_DMINT6, 218),
INTC_IRQ(DMAC7_DMINT7, 219),
INTC_IRQ(RCAN0, 228), INTC_IRQ(RCAN0, 229),
INTC_IRQ(RCAN0, 230),
INTC_IRQ(RCAN0, 231), INTC_IRQ(RCAN0, 232),
INTC_IRQ(RCAN1, 234), INTC_IRQ(RCAN1, 235),
INTC_IRQ(RCAN1, 236),
INTC_IRQ(RCAN1, 237), INTC_IRQ(RCAN1, 238),
INTC_IRQ(SSI0_SSII, 244), INTC_IRQ(SSI1_SSII, 245),
INTC_IRQ(TMR0, 246), INTC_IRQ(TMR0, 247),
INTC_IRQ(TMR0, 248),
INTC_IRQ(TMR1, 252), INTC_IRQ(TMR1, 253),
INTC_IRQ(TMR1, 254),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
PINT4, PINT5, PINT6, PINT7),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffe9418, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
{ 0xfffe941a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfffe9420, 0, 16, 4, /* IPR05 */ { PINT, 0, ADC_ADI, 0 } },
{ 0xfffe9800, 0, 16, 4, /* IPR06 */ { 0, MTU20_ABCD, MTU20_VEF, MTU21_AB } },
{ 0xfffe9802, 0, 16, 4, /* IPR07 */ { MTU21_VU, MTU22_AB, MTU22_VU, MTU23_ABCD } },
{ 0xfffe9804, 0, 16, 4, /* IPR08 */ { MTU2_TCI3V, MTU24_ABCD, MTU2_TCI4V, MTU25_UVW } },
{ 0xfffe9806, 0, 16, 4, /* IPR09 */ { RTC, WDT, IIC30, 0 } },
{ 0xfffe9808, 0, 16, 4, /* IPR10 */ { IIC31, IIC32, DMAC0_DMINT0, DMAC1_DMINT1 } },
{ 0xfffe980a, 0, 16, 4, /* IPR11 */ { DMAC2_DMINT2, DMAC3_DMINT3, SCIF0, SCIF1 } },
{ 0xfffe980c, 0, 16, 4, /* IPR12 */ { SCIF2, SCIF3, SCIF4, SCIF5 } },
{ 0xfffe980e, 0, 16, 4, /* IPR13 */ { SCIF6, SCIF7, DMAC0_DMINTA, DMAC4_DMINT4 } },
{ 0xfffe9810, 0, 16, 4, /* IPR14 */ { DMAC5_DMINT5, DMAC6_DMINT6, DMAC7_DMINT7, 0 } },
{ 0xfffe9812, 0, 16, 4, /* IPR15 */ { 0, RCAN0, RCAN1, 0 } },
{ 0xfffe9814, 0, 16, 4, /* IPR16 */ { SSI0_SSII, SSI1_SSII, TMR0, TMR1 } },
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfffe9408, 0, 16, /* PINTER */
{ 0, 0, 0, 0, 0, 0, 0, 0,
PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7201", vectors, groups,
mask_registers, 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(0xfffe8000, 0x100),
DEFINE_RES_IRQ(180),
};
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(0xfffe8800, 0x100),
DEFINE_RES_IRQ(184),
};
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(0xfffe9000, 0x100),
DEFINE_RES_IRQ(188),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xfffe9800, 0x100),
DEFINE_RES_IRQ(192),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct plat_sci_port scif4_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif4_resources[] = {
DEFINE_RES_MEM(0xfffea000, 0x100),
DEFINE_RES_IRQ(196),
};
static struct platform_device scif4_device = {
.name = "sh-sci",
.id = 4,
.resource = scif4_resources,
.num_resources = ARRAY_SIZE(scif4_resources),
.dev = {
.platform_data = &scif4_platform_data,
},
};
static struct plat_sci_port scif5_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif5_resources[] = {
DEFINE_RES_MEM(0xfffea800, 0x100),
DEFINE_RES_IRQ(200),
};
static struct platform_device scif5_device = {
.name = "sh-sci",
.id = 5,
.resource = scif5_resources,
.num_resources = ARRAY_SIZE(scif5_resources),
.dev = {
.platform_data = &scif5_platform_data,
},
};
static struct plat_sci_port scif6_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif6_resources[] = {
DEFINE_RES_MEM(0xfffeb000, 0x100),
DEFINE_RES_IRQ(204),
};
static struct platform_device scif6_device = {
.name = "sh-sci",
.id = 6,
.resource = scif6_resources,
.num_resources = ARRAY_SIZE(scif6_resources),
.dev = {
.platform_data = &scif6_platform_data,
},
};
static struct plat_sci_port scif7_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif7_resources[] = {
DEFINE_RES_MEM(0xfffeb800, 0x100),
DEFINE_RES_IRQ(208),
};
static struct platform_device scif7_device = {
.name = "sh-sci",
.id = 7,
.resource = scif7_resources,
.num_resources = ARRAY_SIZE(scif7_resources),
.dev = {
.platform_data = &scif7_platform_data,
},
};
static struct resource rtc_resources[] = {
[0] = {
.start = 0xffff0800,
.end = 0xffff2000 + 0x58 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
.start = 152,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
static struct resource mtu2_resources[] = {
DEFINE_RES_MEM(0xfffe4000, 0x400),
DEFINE_RES_IRQ_NAMED(108, "tgi0a"),
DEFINE_RES_IRQ_NAMED(116, "tgi1a"),
DEFINE_RES_IRQ_NAMED(124, "tgi1b"),
};
static struct platform_device mtu2_device = {
.name = "sh-mtu2",
.id = -1,
.resource = mtu2_resources,
.num_resources = ARRAY_SIZE(mtu2_resources),
};
static struct platform_device *sh7201_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&scif6_device,
&scif7_device,
&rtc_device,
&mtu2_device,
};
static int __init sh7201_devices_setup(void)
{
return platform_add_devices(sh7201_devices,
ARRAY_SIZE(sh7201_devices));
}
arch_initcall(sh7201_devices_setup);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
static struct platform_device *sh7201_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&scif6_device,
&scif7_device,
&mtu2_device,
};
#define STBCR3 0xfffe0408
void __init plat_early_device_setup(void)
{
/* enable MTU2 clock */
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
early_platform_add_devices(sh7201_early_devices,
ARRAY_SIZE(sh7201_early_devices));
}

View file

@ -0,0 +1,365 @@
/*
* SH7203 and SH7263 Setup
*
* Copyright (C) 2007 - 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_timer.h>
#include <linux/io.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
USB, LCDC, CMT0, CMT1, BSC, WDT,
MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
MTU3_ABCD, MTU4_ABCD, MTU2_TCI3V, MTU2_TCI4V,
ADC_ADI,
IIC30, IIC31, IIC32, IIC33,
SCIF0, SCIF1, SCIF2, SCIF3,
SSU0, SSU1,
SSI0_SSII, SSI1_SSII, SSI2_SSII, SSI3_SSII,
/* ROM-DEC, SDHI, SRC, and IEB are SH7263 specific */
ROMDEC, FLCTL, SDHI, RTC, RCAN0, RCAN1,
SRC, IEBI,
/* interrupt groups */
PINT,
};
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, 68), INTC_IRQ(IRQ5, 69),
INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
INTC_IRQ(USB, 140), INTC_IRQ(LCDC, 141),
INTC_IRQ(CMT0, 142), INTC_IRQ(CMT1, 143),
INTC_IRQ(BSC, 144), INTC_IRQ(WDT, 145),
INTC_IRQ(MTU0_ABCD, 146), INTC_IRQ(MTU0_ABCD, 147),
INTC_IRQ(MTU0_ABCD, 148), INTC_IRQ(MTU0_ABCD, 149),
INTC_IRQ(MTU0_VEF, 150),
INTC_IRQ(MTU0_VEF, 151), INTC_IRQ(MTU0_VEF, 152),
INTC_IRQ(MTU1_AB, 153), INTC_IRQ(MTU1_AB, 154),
INTC_IRQ(MTU1_VU, 155), INTC_IRQ(MTU1_VU, 156),
INTC_IRQ(MTU2_AB, 157), INTC_IRQ(MTU2_AB, 158),
INTC_IRQ(MTU2_VU, 159), INTC_IRQ(MTU2_VU, 160),
INTC_IRQ(MTU3_ABCD, 161), INTC_IRQ(MTU3_ABCD, 162),
INTC_IRQ(MTU3_ABCD, 163), INTC_IRQ(MTU3_ABCD, 164),
INTC_IRQ(MTU2_TCI3V, 165),
INTC_IRQ(MTU4_ABCD, 166), INTC_IRQ(MTU4_ABCD, 167),
INTC_IRQ(MTU4_ABCD, 168), INTC_IRQ(MTU4_ABCD, 169),
INTC_IRQ(MTU2_TCI4V, 170),
INTC_IRQ(ADC_ADI, 171),
INTC_IRQ(IIC30, 172), INTC_IRQ(IIC30, 173),
INTC_IRQ(IIC30, 174), INTC_IRQ(IIC30, 175),
INTC_IRQ(IIC30, 176),
INTC_IRQ(IIC31, 177), INTC_IRQ(IIC31, 178),
INTC_IRQ(IIC31, 179), INTC_IRQ(IIC31, 180),
INTC_IRQ(IIC31, 181),
INTC_IRQ(IIC32, 182), INTC_IRQ(IIC32, 183),
INTC_IRQ(IIC32, 184), INTC_IRQ(IIC32, 185),
INTC_IRQ(IIC32, 186),
INTC_IRQ(IIC33, 187), INTC_IRQ(IIC33, 188),
INTC_IRQ(IIC33, 189), INTC_IRQ(IIC33, 190),
INTC_IRQ(IIC33, 191),
INTC_IRQ(SCIF0, 192), INTC_IRQ(SCIF0, 193),
INTC_IRQ(SCIF0, 194), INTC_IRQ(SCIF0, 195),
INTC_IRQ(SCIF1, 196), INTC_IRQ(SCIF1, 197),
INTC_IRQ(SCIF1, 198), INTC_IRQ(SCIF1, 199),
INTC_IRQ(SCIF2, 200), INTC_IRQ(SCIF2, 201),
INTC_IRQ(SCIF2, 202), INTC_IRQ(SCIF2, 203),
INTC_IRQ(SCIF3, 204), INTC_IRQ(SCIF3, 205),
INTC_IRQ(SCIF3, 206), INTC_IRQ(SCIF3, 207),
INTC_IRQ(SSU0, 208), INTC_IRQ(SSU0, 209),
INTC_IRQ(SSU0, 210),
INTC_IRQ(SSU1, 211), INTC_IRQ(SSU1, 212),
INTC_IRQ(SSU1, 213),
INTC_IRQ(SSI0_SSII, 214), INTC_IRQ(SSI1_SSII, 215),
INTC_IRQ(SSI2_SSII, 216), INTC_IRQ(SSI3_SSII, 217),
INTC_IRQ(FLCTL, 224), INTC_IRQ(FLCTL, 225),
INTC_IRQ(FLCTL, 226), INTC_IRQ(FLCTL, 227),
INTC_IRQ(RTC, 231), INTC_IRQ(RTC, 232),
INTC_IRQ(RTC, 233),
INTC_IRQ(RCAN0, 234), INTC_IRQ(RCAN0, 235),
INTC_IRQ(RCAN0, 236), INTC_IRQ(RCAN0, 237),
INTC_IRQ(RCAN0, 238),
INTC_IRQ(RCAN1, 239), INTC_IRQ(RCAN1, 240),
INTC_IRQ(RCAN1, 241), INTC_IRQ(RCAN1, 242),
INTC_IRQ(RCAN1, 243),
/* SH7263-specific trash */
#ifdef CONFIG_CPU_SUBTYPE_SH7263
INTC_IRQ(ROMDEC, 218), INTC_IRQ(ROMDEC, 219),
INTC_IRQ(ROMDEC, 220), INTC_IRQ(ROMDEC, 221),
INTC_IRQ(ROMDEC, 222), INTC_IRQ(ROMDEC, 223),
INTC_IRQ(SDHI, 228), INTC_IRQ(SDHI, 229),
INTC_IRQ(SDHI, 230),
INTC_IRQ(SRC, 244), INTC_IRQ(SRC, 245),
INTC_IRQ(SRC, 246),
INTC_IRQ(IEBI, 247),
#endif
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
PINT4, PINT5, PINT6, PINT7),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
{ 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
{ 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
{ 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
{ 0xfffe0c04, 0, 16, 4, /* IPR08 */ { USB, LCDC, CMT0, CMT1 } },
{ 0xfffe0c06, 0, 16, 4, /* IPR09 */ { BSC, WDT, MTU0_ABCD, MTU0_VEF } },
{ 0xfffe0c08, 0, 16, 4, /* IPR10 */ { MTU1_AB, MTU1_VU, MTU2_AB,
MTU2_VU } },
{ 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { MTU3_ABCD, MTU2_TCI3V, MTU4_ABCD,
MTU2_TCI4V } },
{ 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { ADC_ADI, IIC30, IIC31, IIC32 } },
{ 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { IIC33, SCIF0, SCIF1, SCIF2 } },
{ 0xfffe0c10, 0, 16, 4, /* IPR14 */ { SCIF3, SSU0, SSU1, SSI0_SSII } },
#ifdef CONFIG_CPU_SUBTYPE_SH7203
{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSI1_SSII, SSI2_SSII,
SSI3_SSII, 0 } },
{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { FLCTL, 0, RTC, RCAN0 } },
{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { RCAN1, 0, 0, 0 } },
#else
{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSI1_SSII, SSI2_SSII,
SSI3_SSII, ROMDEC } },
{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { FLCTL, SDHI, RTC, RCAN0 } },
{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { RCAN1, SRC, IEBI, 0 } },
#endif
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfffe0808, 0, 16, /* PINTER */
{ 0, 0, 0, 0, 0, 0, 0, 0,
PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7203", vectors, groups,
mask_registers, prio_registers, NULL);
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xfffe8000, 0x100),
DEFINE_RES_IRQ(192),
};
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_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xfffe8800, 0x100),
DEFINE_RES_IRQ(196),
};
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_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xfffe9000, 0x100),
DEFINE_RES_IRQ(200),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xfffe9800, 0x100),
DEFINE_RES_IRQ(204),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 3,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0xfffec000, 0x10),
DEFINE_RES_IRQ(142),
DEFINE_RES_IRQ(143),
};
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 resource mtu2_resources[] = {
DEFINE_RES_MEM(0xfffe4000, 0x400),
DEFINE_RES_IRQ_NAMED(146, "tgi0a"),
DEFINE_RES_IRQ_NAMED(153, "tgi1a"),
};
static struct platform_device mtu2_device = {
.name = "sh-mtu2",
.id = -1,
.resource = mtu2_resources,
.num_resources = ARRAY_SIZE(mtu2_resources),
};
static struct resource rtc_resources[] = {
[0] = {
.start = 0xffff2000,
.end = 0xffff2000 + 0x58 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
.start = 231,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
static struct platform_device *sh7203_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&cmt_device,
&mtu2_device,
&rtc_device,
};
static int __init sh7203_devices_setup(void)
{
return platform_add_devices(sh7203_devices,
ARRAY_SIZE(sh7203_devices));
}
arch_initcall(sh7203_devices_setup);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
static struct platform_device *sh7203_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&cmt_device,
&mtu2_device,
};
#define STBCR3 0xfffe0408
#define STBCR4 0xfffe040c
void __init plat_early_device_setup(void)
{
/* enable CMT clock */
__raw_writeb(__raw_readb(STBCR4) & ~0x04, STBCR4);
/* enable MTU2 clock */
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
early_platform_add_devices(sh7203_early_devices,
ARRAY_SIZE(sh7203_early_devices));
}

View file

@ -0,0 +1,297 @@
/*
* SH7206 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_timer.h>
#include <linux/io.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
ADC_ADI0, ADC_ADI1,
DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
MTU3_ABCD, MTU4_ABCD, MTU5, POE2_12, MTU3S_ABCD, MTU4S_ABCD, MTU5S,
IIC3,
CMT0, CMT1, BSC, WDT,
MTU2_TCI3V, MTU2_TCI4V, MTU2S_TCI3V, MTU2S_TCI4V,
POE2_OEI3,
SCIF0, SCIF1, SCIF2, SCIF3,
/* interrupt groups */
PINT,
};
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, 68), INTC_IRQ(IRQ5, 69),
INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
INTC_IRQ(ADC_ADI0, 92), INTC_IRQ(ADC_ADI1, 96),
INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
INTC_IRQ(CMT0, 140), INTC_IRQ(CMT1, 144),
INTC_IRQ(BSC, 148), INTC_IRQ(WDT, 152),
INTC_IRQ(MTU0_ABCD, 156), INTC_IRQ(MTU0_ABCD, 157),
INTC_IRQ(MTU0_ABCD, 158), INTC_IRQ(MTU0_ABCD, 159),
INTC_IRQ(MTU0_VEF, 160), INTC_IRQ(MTU0_VEF, 161),
INTC_IRQ(MTU0_VEF, 162),
INTC_IRQ(MTU1_AB, 164), INTC_IRQ(MTU1_AB, 165),
INTC_IRQ(MTU1_VU, 168), INTC_IRQ(MTU1_VU, 169),
INTC_IRQ(MTU2_AB, 172), INTC_IRQ(MTU2_AB, 173),
INTC_IRQ(MTU2_VU, 176), INTC_IRQ(MTU2_VU, 177),
INTC_IRQ(MTU3_ABCD, 180), INTC_IRQ(MTU3_ABCD, 181),
INTC_IRQ(MTU3_ABCD, 182), INTC_IRQ(MTU3_ABCD, 183),
INTC_IRQ(MTU2_TCI3V, 184),
INTC_IRQ(MTU4_ABCD, 188), INTC_IRQ(MTU4_ABCD, 189),
INTC_IRQ(MTU4_ABCD, 190), INTC_IRQ(MTU4_ABCD, 191),
INTC_IRQ(MTU2_TCI4V, 192),
INTC_IRQ(MTU5, 196), INTC_IRQ(MTU5, 197),
INTC_IRQ(MTU5, 198),
INTC_IRQ(POE2_12, 200), INTC_IRQ(POE2_12, 201),
INTC_IRQ(MTU3S_ABCD, 204), INTC_IRQ(MTU3S_ABCD, 205),
INTC_IRQ(MTU3S_ABCD, 206), INTC_IRQ(MTU3S_ABCD, 207),
INTC_IRQ(MTU2S_TCI3V, 208),
INTC_IRQ(MTU4S_ABCD, 212), INTC_IRQ(MTU4S_ABCD, 213),
INTC_IRQ(MTU4S_ABCD, 214), INTC_IRQ(MTU4S_ABCD, 215),
INTC_IRQ(MTU2S_TCI4V, 216),
INTC_IRQ(MTU5S, 220), INTC_IRQ(MTU5S, 221),
INTC_IRQ(MTU5S, 222),
INTC_IRQ(POE2_OEI3, 224),
INTC_IRQ(IIC3, 228), INTC_IRQ(IIC3, 229),
INTC_IRQ(IIC3, 230), INTC_IRQ(IIC3, 231),
INTC_IRQ(IIC3, 232),
INTC_IRQ(SCIF0, 240), INTC_IRQ(SCIF0, 241),
INTC_IRQ(SCIF0, 242), INTC_IRQ(SCIF0, 243),
INTC_IRQ(SCIF1, 244), INTC_IRQ(SCIF1, 245),
INTC_IRQ(SCIF1, 246), INTC_IRQ(SCIF1, 247),
INTC_IRQ(SCIF2, 248), INTC_IRQ(SCIF2, 249),
INTC_IRQ(SCIF2, 250), INTC_IRQ(SCIF2, 251),
INTC_IRQ(SCIF3, 252), INTC_IRQ(SCIF3, 253),
INTC_IRQ(SCIF3, 254), INTC_IRQ(SCIF3, 255),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
PINT4, PINT5, PINT6, PINT7),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
{ 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, ADC_ADI0, ADC_ADI1 } },
{ 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
{ 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
{ 0xfffe0c04, 0, 16, 4, /* IPR08 */ { CMT0, CMT1, BSC, WDT } },
{ 0xfffe0c06, 0, 16, 4, /* IPR09 */ { MTU0_ABCD, MTU0_VEF,
MTU1_AB, MTU1_VU } },
{ 0xfffe0c08, 0, 16, 4, /* IPR10 */ { MTU2_AB, MTU2_VU,
MTU3_ABCD, MTU2_TCI3V } },
{ 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { MTU4_ABCD, MTU2_TCI4V,
MTU5, POE2_12 } },
{ 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU3S_ABCD, MTU2S_TCI3V,
MTU4S_ABCD, MTU2S_TCI4V } },
{ 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU5S, POE2_OEI3, IIC3, 0 } },
{ 0xfffe0c10, 0, 16, 4, /* IPR14 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfffe0808, 0, 16, /* PINTER */
{ 0, 0, 0, 0, 0, 0, 0, 0,
PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7206", vectors, groups,
mask_registers, 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(0xfffe8000, 0x100),
DEFINE_RES_IRQ(240),
};
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(0xfffe8800, 0x100),
DEFINE_RES_IRQ(244),
};
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(0xfffe9000, 0x100),
DEFINE_RES_IRQ(248),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xfffe9800, 0x100),
DEFINE_RES_IRQ(252),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 3,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0xfffec000, 0x10),
DEFINE_RES_IRQ(140),
DEFINE_RES_IRQ(144),
};
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 resource mtu2_resources[] = {
DEFINE_RES_MEM(0xfffe4000, 0x400),
DEFINE_RES_IRQ_NAMED(156, "tgi0a"),
DEFINE_RES_IRQ_NAMED(164, "tgi1a"),
DEFINE_RES_IRQ_NAMED(180, "tgi2a"),
};
static struct platform_device mtu2_device = {
.name = "sh-mtu2s",
.id = -1,
.resource = mtu2_resources,
.num_resources = ARRAY_SIZE(mtu2_resources),
};
static struct platform_device *sh7206_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&cmt_device,
&mtu2_device,
};
static int __init sh7206_devices_setup(void)
{
return platform_add_devices(sh7206_devices,
ARRAY_SIZE(sh7206_devices));
}
arch_initcall(sh7206_devices_setup);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
static struct platform_device *sh7206_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&cmt_device,
&mtu2_device,
};
#define STBCR3 0xfffe0408
#define STBCR4 0xfffe040c
void __init plat_early_device_setup(void)
{
/* enable CMT clock */
__raw_writeb(__raw_readb(STBCR4) & ~0x04, STBCR4);
/* enable MTU2 clock */
__raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
early_platform_add_devices(sh7206_early_devices,
ARRAY_SIZE(sh7206_early_devices));
}

View file

@ -0,0 +1,570 @@
/*
* SH7264 Setup
*
* Copyright (C) 2012 Renesas Electronics Europe Ltd
*
* 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/usb/r8a66597.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
USB, VDC3, CMT0, CMT1, BSC, WDT,
MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
PWMT1, PWMT2, ADC_ADI,
SSIF0, SSII1, SSII2, SSII3,
RSPDIF,
IIC30, IIC31, IIC32, IIC33,
SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
SIO_FIFO, RSPIC0, RSPIC1,
RCAN0, RCAN1, IEBC, CD_ROMD,
NFMC, SDHI, RTC,
SRCC0, SRCC1, DCOMU, OFFI, IFEI,
/* interrupt groups */
PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
};
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, 68), INTC_IRQ(IRQ5, 69),
INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
INTC_IRQ(USB, 170),
INTC_IRQ(VDC3, 171), INTC_IRQ(VDC3, 172),
INTC_IRQ(VDC3, 173), INTC_IRQ(VDC3, 174),
INTC_IRQ(CMT0, 175), INTC_IRQ(CMT1, 176),
INTC_IRQ(BSC, 177), INTC_IRQ(WDT, 178),
INTC_IRQ(MTU0_ABCD, 179), INTC_IRQ(MTU0_ABCD, 180),
INTC_IRQ(MTU0_ABCD, 181), INTC_IRQ(MTU0_ABCD, 182),
INTC_IRQ(MTU0_VEF, 183),
INTC_IRQ(MTU0_VEF, 184), INTC_IRQ(MTU0_VEF, 185),
INTC_IRQ(MTU1_AB, 186), INTC_IRQ(MTU1_AB, 187),
INTC_IRQ(MTU1_VU, 188), INTC_IRQ(MTU1_VU, 189),
INTC_IRQ(MTU2_AB, 190), INTC_IRQ(MTU2_AB, 191),
INTC_IRQ(MTU2_VU, 192), INTC_IRQ(MTU2_VU, 193),
INTC_IRQ(MTU3_ABCD, 194), INTC_IRQ(MTU3_ABCD, 195),
INTC_IRQ(MTU3_ABCD, 196), INTC_IRQ(MTU3_ABCD, 197),
INTC_IRQ(MTU3_TCI3V, 198),
INTC_IRQ(MTU4_ABCD, 199), INTC_IRQ(MTU4_ABCD, 200),
INTC_IRQ(MTU4_ABCD, 201), INTC_IRQ(MTU4_ABCD, 202),
INTC_IRQ(MTU4_TCI4V, 203),
INTC_IRQ(PWMT1, 204), INTC_IRQ(PWMT2, 205),
INTC_IRQ(ADC_ADI, 206),
INTC_IRQ(SSIF0, 207), INTC_IRQ(SSIF0, 208),
INTC_IRQ(SSIF0, 209),
INTC_IRQ(SSII1, 210), INTC_IRQ(SSII1, 211),
INTC_IRQ(SSII2, 212), INTC_IRQ(SSII2, 213),
INTC_IRQ(SSII3, 214), INTC_IRQ(SSII3, 215),
INTC_IRQ(RSPDIF, 216),
INTC_IRQ(IIC30, 217), INTC_IRQ(IIC30, 218),
INTC_IRQ(IIC30, 219), INTC_IRQ(IIC30, 220),
INTC_IRQ(IIC30, 221),
INTC_IRQ(IIC31, 222), INTC_IRQ(IIC31, 223),
INTC_IRQ(IIC31, 224), INTC_IRQ(IIC31, 225),
INTC_IRQ(IIC31, 226),
INTC_IRQ(IIC32, 227), INTC_IRQ(IIC32, 228),
INTC_IRQ(IIC32, 229), INTC_IRQ(IIC32, 230),
INTC_IRQ(IIC32, 231),
INTC_IRQ(SCIF0_BRI, 232), INTC_IRQ(SCIF0_ERI, 233),
INTC_IRQ(SCIF0_RXI, 234), INTC_IRQ(SCIF0_TXI, 235),
INTC_IRQ(SCIF1_BRI, 236), INTC_IRQ(SCIF1_ERI, 237),
INTC_IRQ(SCIF1_RXI, 238), INTC_IRQ(SCIF1_TXI, 239),
INTC_IRQ(SCIF2_BRI, 240), INTC_IRQ(SCIF2_ERI, 241),
INTC_IRQ(SCIF2_RXI, 242), INTC_IRQ(SCIF2_TXI, 243),
INTC_IRQ(SCIF3_BRI, 244), INTC_IRQ(SCIF3_ERI, 245),
INTC_IRQ(SCIF3_RXI, 246), INTC_IRQ(SCIF3_TXI, 247),
INTC_IRQ(SCIF4_BRI, 248), INTC_IRQ(SCIF4_ERI, 249),
INTC_IRQ(SCIF4_RXI, 250), INTC_IRQ(SCIF4_TXI, 251),
INTC_IRQ(SCIF5_BRI, 252), INTC_IRQ(SCIF5_ERI, 253),
INTC_IRQ(SCIF5_RXI, 254), INTC_IRQ(SCIF5_TXI, 255),
INTC_IRQ(SCIF6_BRI, 256), INTC_IRQ(SCIF6_ERI, 257),
INTC_IRQ(SCIF6_RXI, 258), INTC_IRQ(SCIF6_TXI, 259),
INTC_IRQ(SCIF7_BRI, 260), INTC_IRQ(SCIF7_ERI, 261),
INTC_IRQ(SCIF7_RXI, 262), INTC_IRQ(SCIF7_TXI, 263),
INTC_IRQ(SIO_FIFO, 264),
INTC_IRQ(RSPIC0, 265), INTC_IRQ(RSPIC0, 266),
INTC_IRQ(RSPIC0, 267),
INTC_IRQ(RSPIC1, 268), INTC_IRQ(RSPIC1, 269),
INTC_IRQ(RSPIC1, 270),
INTC_IRQ(RCAN0, 271), INTC_IRQ(RCAN0, 272),
INTC_IRQ(RCAN0, 273), INTC_IRQ(RCAN0, 274),
INTC_IRQ(RCAN0, 275),
INTC_IRQ(RCAN1, 276), INTC_IRQ(RCAN1, 277),
INTC_IRQ(RCAN1, 278), INTC_IRQ(RCAN1, 279),
INTC_IRQ(RCAN1, 280),
INTC_IRQ(IEBC, 281),
INTC_IRQ(CD_ROMD, 282), INTC_IRQ(CD_ROMD, 283),
INTC_IRQ(CD_ROMD, 284), INTC_IRQ(CD_ROMD, 285),
INTC_IRQ(CD_ROMD, 286), INTC_IRQ(CD_ROMD, 287),
INTC_IRQ(NFMC, 288), INTC_IRQ(NFMC, 289),
INTC_IRQ(NFMC, 290), INTC_IRQ(NFMC, 291),
INTC_IRQ(SDHI, 292), INTC_IRQ(SDHI, 293),
INTC_IRQ(SDHI, 294),
INTC_IRQ(RTC, 296), INTC_IRQ(RTC, 297),
INTC_IRQ(RTC, 298),
INTC_IRQ(SRCC0, 299), INTC_IRQ(SRCC0, 300),
INTC_IRQ(SRCC0, 301), INTC_IRQ(SRCC0, 302),
INTC_IRQ(SRCC0, 303),
INTC_IRQ(SRCC1, 304), INTC_IRQ(SRCC1, 305),
INTC_IRQ(SRCC1, 306), INTC_IRQ(SRCC1, 307),
INTC_IRQ(SRCC1, 308),
INTC_IRQ(DCOMU, 310), INTC_IRQ(DCOMU, 311),
INTC_IRQ(DCOMU, 312),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
PINT4, PINT5, PINT6, PINT7),
INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
{ 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
{ 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
{ 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
{ 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8, DMAC9,
DMAC10, DMAC11 } },
{ 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
DMAC14, DMAC15 } },
{ 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC3, CMT0, CMT1 } },
{ 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { BSC, WDT, MTU0_ABCD, MTU0_VEF } },
{ 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU1_AB, MTU1_VU,
MTU2_AB, MTU2_VU } },
{ 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU3_ABCD, MTU3_TCI3V,
MTU4_ABCD, MTU4_TCI4V } },
{ 0xfffe0c10, 0, 16, 4, /* IPR14 */ { PWMT1, PWMT2, ADC_ADI, 0 } },
{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSIF0, SSII1, SSII2, SSII3 } },
{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { RSPDIF, IIC30, IIC31, IIC32 } },
{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
{ 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
{ 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { SIO_FIFO, 0, RSPIC0, RSPIC1, } },
{ 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { RCAN0, RCAN1, IEBC, CD_ROMD } },
{ 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { NFMC, SDHI, RTC, 0 } },
{ 0xfffe0c20, 0, 16, 4, /* IPR22 */ { SRCC0, SRCC1, 0, DCOMU } },
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfffe0808, 0, 16, /* PINTER */
{ 0, 0, 0, 0, 0, 0, 0, 0,
PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7264", vectors, groups,
mask_registers, prio_registers, NULL);
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xfffe8000, 0x100),
DEFINE_RES_IRQ(233),
DEFINE_RES_IRQ(234),
DEFINE_RES_IRQ(235),
DEFINE_RES_IRQ(232),
};
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_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xfffe8800, 0x100),
DEFINE_RES_IRQ(237),
DEFINE_RES_IRQ(238),
DEFINE_RES_IRQ(239),
DEFINE_RES_IRQ(236),
};
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_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xfffe9000, 0x100),
DEFINE_RES_IRQ(241),
DEFINE_RES_IRQ(242),
DEFINE_RES_IRQ(243),
DEFINE_RES_IRQ(240),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xfffe9800, 0x100),
DEFINE_RES_IRQ(245),
DEFINE_RES_IRQ(246),
DEFINE_RES_IRQ(247),
DEFINE_RES_IRQ(244),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct plat_sci_port scif4_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif4_resources[] = {
DEFINE_RES_MEM(0xfffea000, 0x100),
DEFINE_RES_IRQ(249),
DEFINE_RES_IRQ(250),
DEFINE_RES_IRQ(251),
DEFINE_RES_IRQ(248),
};
static struct platform_device scif4_device = {
.name = "sh-sci",
.id = 4,
.resource = scif4_resources,
.num_resources = ARRAY_SIZE(scif4_resources),
.dev = {
.platform_data = &scif4_platform_data,
},
};
static struct plat_sci_port scif5_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif5_resources[] = {
DEFINE_RES_MEM(0xfffea800, 0x100),
DEFINE_RES_IRQ(253),
DEFINE_RES_IRQ(254),
DEFINE_RES_IRQ(255),
DEFINE_RES_IRQ(252),
};
static struct platform_device scif5_device = {
.name = "sh-sci",
.id = 5,
.resource = scif5_resources,
.num_resources = ARRAY_SIZE(scif5_resources),
.dev = {
.platform_data = &scif5_platform_data,
},
};
static struct plat_sci_port scif6_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif6_resources[] = {
DEFINE_RES_MEM(0xfffeb000, 0x100),
DEFINE_RES_IRQ(257),
DEFINE_RES_IRQ(258),
DEFINE_RES_IRQ(259),
DEFINE_RES_IRQ(256),
};
static struct platform_device scif6_device = {
.name = "sh-sci",
.id = 6,
.resource = scif6_resources,
.num_resources = ARRAY_SIZE(scif6_resources),
.dev = {
.platform_data = &scif6_platform_data,
},
};
static struct plat_sci_port scif7_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif7_resources[] = {
DEFINE_RES_MEM(0xfffeb800, 0x100),
DEFINE_RES_IRQ(261),
DEFINE_RES_IRQ(262),
DEFINE_RES_IRQ(263),
DEFINE_RES_IRQ(260),
};
static struct platform_device scif7_device = {
.name = "sh-sci",
.id = 7,
.resource = scif7_resources,
.num_resources = ARRAY_SIZE(scif7_resources),
.dev = {
.platform_data = &scif7_platform_data,
},
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 3,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0xfffec000, 0x10),
DEFINE_RES_IRQ(175),
DEFINE_RES_IRQ(176),
};
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 resource mtu2_resources[] = {
DEFINE_RES_MEM(0xfffe4000, 0x400),
DEFINE_RES_IRQ_NAMED(179, "tgi0a"),
DEFINE_RES_IRQ_NAMED(186, "tgi1a"),
};
static struct platform_device mtu2_device = {
.name = "sh-mtu2",
.id = -1,
.resource = mtu2_resources,
.num_resources = ARRAY_SIZE(mtu2_resources),
};
static struct resource rtc_resources[] = {
[0] = {
.start = 0xfffe6000,
.end = 0xfffe6000 + 0x30 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
.start = 296,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
/* USB Host */
static void usb_port_power(int port, int power)
{
__raw_writew(0x200 , 0xffffc0c2) ; /* Initialise UACS25 */
}
static struct r8a66597_platdata r8a66597_data = {
.on_chip = 1,
.endian = 1,
.port_power = usb_port_power,
};
static struct resource r8a66597_usb_host_resources[] = {
[0] = {
.start = 0xffffc000,
.end = 0xffffc0e4,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 170,
.end = 170,
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
static struct platform_device r8a66597_usb_host_device = {
.name = "r8a66597_hcd",
.id = 0,
.dev = {
.dma_mask = NULL, /* not use dma */
.coherent_dma_mask = 0xffffffff,
.platform_data = &r8a66597_data,
},
.num_resources = ARRAY_SIZE(r8a66597_usb_host_resources),
.resource = r8a66597_usb_host_resources,
};
static struct platform_device *sh7264_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&scif6_device,
&scif7_device,
&cmt_device,
&mtu2_device,
&rtc_device,
&r8a66597_usb_host_device,
};
static int __init sh7264_devices_setup(void)
{
return platform_add_devices(sh7264_devices,
ARRAY_SIZE(sh7264_devices));
}
arch_initcall(sh7264_devices_setup);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
static struct platform_device *sh7264_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&scif6_device,
&scif7_device,
&cmt_device,
&mtu2_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7264_early_devices,
ARRAY_SIZE(sh7264_early_devices));
}

View file

@ -0,0 +1,586 @@
/*
* SH7269 Setup
*
* Copyright (C) 2012 Renesas Electronics Europe Ltd
* Copyright (C) 2012 Phil Edworthy
*
* 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/usb/r8a66597.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
USB, VDC4, CMT0, CMT1, BSC, WDT,
MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
PWMT1, PWMT2, ADC_ADI,
SSIF0, SSII1, SSII2, SSII3, SSII4, SSII5,
RSPDIF,
IIC30, IIC31, IIC32, IIC33,
SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
RCAN0, RCAN1, RCAN2,
RSPIC0, RSPIC1,
IEBC, CD_ROMD,
NFMC,
SDHI0, SDHI1,
RTC,
SRCC0, SRCC1, SRCC2,
/* interrupt groups */
PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
};
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, 68), INTC_IRQ(IRQ5, 69),
INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
INTC_IRQ(USB, 170),
INTC_IRQ(VDC4, 171), INTC_IRQ(VDC4, 172),
INTC_IRQ(VDC4, 173), INTC_IRQ(VDC4, 174),
INTC_IRQ(VDC4, 175), INTC_IRQ(VDC4, 176),
INTC_IRQ(VDC4, 177), INTC_IRQ(VDC4, 177),
INTC_IRQ(CMT0, 188), INTC_IRQ(CMT1, 189),
INTC_IRQ(BSC, 190), INTC_IRQ(WDT, 191),
INTC_IRQ(MTU0_ABCD, 192), INTC_IRQ(MTU0_ABCD, 193),
INTC_IRQ(MTU0_ABCD, 194), INTC_IRQ(MTU0_ABCD, 195),
INTC_IRQ(MTU0_VEF, 196), INTC_IRQ(MTU0_VEF, 197),
INTC_IRQ(MTU0_VEF, 198),
INTC_IRQ(MTU1_AB, 199), INTC_IRQ(MTU1_AB, 200),
INTC_IRQ(MTU1_VU, 201), INTC_IRQ(MTU1_VU, 202),
INTC_IRQ(MTU2_AB, 203), INTC_IRQ(MTU2_AB, 204),
INTC_IRQ(MTU2_VU, 205), INTC_IRQ(MTU2_VU, 206),
INTC_IRQ(MTU3_ABCD, 207), INTC_IRQ(MTU3_ABCD, 208),
INTC_IRQ(MTU3_ABCD, 209), INTC_IRQ(MTU3_ABCD, 210),
INTC_IRQ(MTU3_TCI3V, 211),
INTC_IRQ(MTU4_ABCD, 212), INTC_IRQ(MTU4_ABCD, 213),
INTC_IRQ(MTU4_ABCD, 214), INTC_IRQ(MTU4_ABCD, 215),
INTC_IRQ(MTU4_TCI4V, 216),
INTC_IRQ(PWMT1, 217), INTC_IRQ(PWMT2, 218),
INTC_IRQ(ADC_ADI, 223),
INTC_IRQ(SSIF0, 224), INTC_IRQ(SSIF0, 225),
INTC_IRQ(SSIF0, 226),
INTC_IRQ(SSII1, 227), INTC_IRQ(SSII1, 228),
INTC_IRQ(SSII2, 229), INTC_IRQ(SSII2, 230),
INTC_IRQ(SSII3, 231), INTC_IRQ(SSII3, 232),
INTC_IRQ(SSII4, 233), INTC_IRQ(SSII4, 234),
INTC_IRQ(SSII5, 235), INTC_IRQ(SSII5, 236),
INTC_IRQ(RSPDIF, 237),
INTC_IRQ(IIC30, 238), INTC_IRQ(IIC30, 239),
INTC_IRQ(IIC30, 240), INTC_IRQ(IIC30, 241),
INTC_IRQ(IIC30, 242),
INTC_IRQ(IIC31, 243), INTC_IRQ(IIC31, 244),
INTC_IRQ(IIC31, 245), INTC_IRQ(IIC31, 246),
INTC_IRQ(IIC31, 247),
INTC_IRQ(IIC32, 248), INTC_IRQ(IIC32, 249),
INTC_IRQ(IIC32, 250), INTC_IRQ(IIC32, 251),
INTC_IRQ(IIC32, 252),
INTC_IRQ(IIC33, 253), INTC_IRQ(IIC33, 254),
INTC_IRQ(IIC33, 255), INTC_IRQ(IIC33, 256),
INTC_IRQ(IIC33, 257),
INTC_IRQ(SCIF0_BRI, 258), INTC_IRQ(SCIF0_ERI, 259),
INTC_IRQ(SCIF0_RXI, 260), INTC_IRQ(SCIF0_TXI, 261),
INTC_IRQ(SCIF1_BRI, 262), INTC_IRQ(SCIF1_ERI, 263),
INTC_IRQ(SCIF1_RXI, 264), INTC_IRQ(SCIF1_TXI, 265),
INTC_IRQ(SCIF2_BRI, 266), INTC_IRQ(SCIF2_ERI, 267),
INTC_IRQ(SCIF2_RXI, 268), INTC_IRQ(SCIF2_TXI, 269),
INTC_IRQ(SCIF3_BRI, 270), INTC_IRQ(SCIF3_ERI, 271),
INTC_IRQ(SCIF3_RXI, 272), INTC_IRQ(SCIF3_TXI, 273),
INTC_IRQ(SCIF4_BRI, 274), INTC_IRQ(SCIF4_ERI, 275),
INTC_IRQ(SCIF4_RXI, 276), INTC_IRQ(SCIF4_TXI, 277),
INTC_IRQ(SCIF5_BRI, 278), INTC_IRQ(SCIF5_ERI, 279),
INTC_IRQ(SCIF5_RXI, 280), INTC_IRQ(SCIF5_TXI, 281),
INTC_IRQ(SCIF6_BRI, 282), INTC_IRQ(SCIF6_ERI, 283),
INTC_IRQ(SCIF6_RXI, 284), INTC_IRQ(SCIF6_TXI, 285),
INTC_IRQ(SCIF7_BRI, 286), INTC_IRQ(SCIF7_ERI, 287),
INTC_IRQ(SCIF7_RXI, 288), INTC_IRQ(SCIF7_TXI, 289),
INTC_IRQ(RCAN0, 291), INTC_IRQ(RCAN0, 292),
INTC_IRQ(RCAN0, 293), INTC_IRQ(RCAN0, 294),
INTC_IRQ(RCAN0, 295),
INTC_IRQ(RCAN1, 296), INTC_IRQ(RCAN1, 297),
INTC_IRQ(RCAN1, 298), INTC_IRQ(RCAN1, 299),
INTC_IRQ(RCAN1, 300),
INTC_IRQ(RCAN2, 301), INTC_IRQ(RCAN2, 302),
INTC_IRQ(RCAN2, 303), INTC_IRQ(RCAN2, 304),
INTC_IRQ(RCAN2, 305),
INTC_IRQ(RSPIC0, 306), INTC_IRQ(RSPIC0, 307),
INTC_IRQ(RSPIC0, 308),
INTC_IRQ(RSPIC1, 309), INTC_IRQ(RSPIC1, 310),
INTC_IRQ(RSPIC1, 311),
INTC_IRQ(IEBC, 318),
INTC_IRQ(CD_ROMD, 319), INTC_IRQ(CD_ROMD, 320),
INTC_IRQ(CD_ROMD, 321), INTC_IRQ(CD_ROMD, 322),
INTC_IRQ(CD_ROMD, 323), INTC_IRQ(CD_ROMD, 324),
INTC_IRQ(NFMC, 325), INTC_IRQ(NFMC, 326),
INTC_IRQ(NFMC, 327), INTC_IRQ(NFMC, 328),
INTC_IRQ(SDHI0, 332), INTC_IRQ(SDHI0, 333),
INTC_IRQ(SDHI0, 334),
INTC_IRQ(SDHI1, 335), INTC_IRQ(SDHI1, 336),
INTC_IRQ(SDHI1, 337),
INTC_IRQ(RTC, 338), INTC_IRQ(RTC, 339),
INTC_IRQ(RTC, 340),
INTC_IRQ(SRCC0, 341), INTC_IRQ(SRCC0, 342),
INTC_IRQ(SRCC0, 343), INTC_IRQ(SRCC0, 344),
INTC_IRQ(SRCC0, 345),
INTC_IRQ(SRCC1, 346), INTC_IRQ(SRCC1, 347),
INTC_IRQ(SRCC1, 348), INTC_IRQ(SRCC1, 349),
INTC_IRQ(SRCC1, 350),
INTC_IRQ(SRCC2, 351), INTC_IRQ(SRCC2, 352),
INTC_IRQ(SRCC2, 353), INTC_IRQ(SRCC2, 354),
INTC_IRQ(SRCC2, 355),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
PINT4, PINT5, PINT6, PINT7),
INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
{ 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
{ 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
{ 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
{ 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8, DMAC9,
DMAC10, DMAC11 } },
{ 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
DMAC14, DMAC15 } },
{ 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC4, VDC4, VDC4 } },
{ 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { 0, 0, 0, 0 } },
{ 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { CMT0, CMT1, BSC, WDT } },
{ 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU0_ABCD, MTU0_VEF,
MTU1_AB, MTU1_VU } },
{ 0xfffe0c10, 0, 16, 4, /* IPR14 */ { MTU2_AB, MTU2_VU,
MTU3_ABCD, MTU3_TCI3V } },
{ 0xfffe0c12, 0, 16, 4, /* IPR15 */ { MTU4_ABCD, MTU4_TCI4V,
PWMT1, PWMT2 } },
{ 0xfffe0c14, 0, 16, 4, /* IPR16 */ { 0, 0, 0, 0 } },
{ 0xfffe0c16, 0, 16, 4, /* IPR17 */ { ADC_ADI, SSIF0, SSII1, SSII2 } },
{ 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SSII3, SSII4, SSII5, RSPDIF} },
{ 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { IIC30, IIC31, IIC32, IIC33 } },
{ 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
{ 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
{ 0xfffe0c20, 0, 16, 4, /* IPR22 */ { 0, RCAN0, RCAN1, RCAN2 } },
{ 0xfffe0c22, 0, 16, 4, /* IPR23 */ { RSPIC0, RSPIC1, 0, 0 } },
{ 0xfffe0c24, 0, 16, 4, /* IPR24 */ { IEBC, CD_ROMD, NFMC, 0 } },
{ 0xfffe0c26, 0, 16, 4, /* IPR25 */ { SDHI0, SDHI1, RTC, 0 } },
{ 0xfffe0c28, 0, 16, 4, /* IPR26 */ { SRCC0, SRCC1, SRCC2, 0 } },
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfffe0808, 0, 16, /* PINTER */
{ 0, 0, 0, 0, 0, 0, 0, 0,
PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7269", vectors, groups,
mask_registers, prio_registers, NULL);
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xe8007000, 0x100),
DEFINE_RES_IRQ(259),
DEFINE_RES_IRQ(260),
DEFINE_RES_IRQ(261),
DEFINE_RES_IRQ(258),
};
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_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xe8007800, 0x100),
DEFINE_RES_IRQ(263),
DEFINE_RES_IRQ(264),
DEFINE_RES_IRQ(265),
DEFINE_RES_IRQ(262),
};
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_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xe8008000, 0x100),
DEFINE_RES_IRQ(267),
DEFINE_RES_IRQ(268),
DEFINE_RES_IRQ(269),
DEFINE_RES_IRQ(266),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xe8008800, 0x100),
DEFINE_RES_IRQ(271),
DEFINE_RES_IRQ(272),
DEFINE_RES_IRQ(273),
DEFINE_RES_IRQ(270),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct plat_sci_port scif4_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif4_resources[] = {
DEFINE_RES_MEM(0xe8009000, 0x100),
DEFINE_RES_IRQ(275),
DEFINE_RES_IRQ(276),
DEFINE_RES_IRQ(277),
DEFINE_RES_IRQ(274),
};
static struct platform_device scif4_device = {
.name = "sh-sci",
.id = 4,
.resource = scif4_resources,
.num_resources = ARRAY_SIZE(scif4_resources),
.dev = {
.platform_data = &scif4_platform_data,
},
};
static struct plat_sci_port scif5_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif5_resources[] = {
DEFINE_RES_MEM(0xe8009800, 0x100),
DEFINE_RES_IRQ(279),
DEFINE_RES_IRQ(280),
DEFINE_RES_IRQ(281),
DEFINE_RES_IRQ(278),
};
static struct platform_device scif5_device = {
.name = "sh-sci",
.id = 5,
.resource = scif5_resources,
.num_resources = ARRAY_SIZE(scif5_resources),
.dev = {
.platform_data = &scif5_platform_data,
},
};
static struct plat_sci_port scif6_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif6_resources[] = {
DEFINE_RES_MEM(0xe800a000, 0x100),
DEFINE_RES_IRQ(283),
DEFINE_RES_IRQ(284),
DEFINE_RES_IRQ(285),
DEFINE_RES_IRQ(282),
};
static struct platform_device scif6_device = {
.name = "sh-sci",
.id = 6,
.resource = scif6_resources,
.num_resources = ARRAY_SIZE(scif6_resources),
.dev = {
.platform_data = &scif6_platform_data,
},
};
static struct plat_sci_port scif7_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
SCSCR_REIE | SCSCR_TOIE,
.type = PORT_SCIF,
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif7_resources[] = {
DEFINE_RES_MEM(0xe800a800, 0x100),
DEFINE_RES_IRQ(287),
DEFINE_RES_IRQ(288),
DEFINE_RES_IRQ(289),
DEFINE_RES_IRQ(286),
};
static struct platform_device scif7_device = {
.name = "sh-sci",
.id = 7,
.resource = scif7_resources,
.num_resources = ARRAY_SIZE(scif7_resources),
.dev = {
.platform_data = &scif7_platform_data,
},
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 3,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0xfffec000, 0x10),
DEFINE_RES_IRQ(188),
DEFINE_RES_IRQ(189),
};
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 resource mtu2_resources[] = {
DEFINE_RES_MEM(0xfffe4000, 0x400),
DEFINE_RES_IRQ_NAMED(192, "tgi0a"),
DEFINE_RES_IRQ_NAMED(203, "tgi1a"),
};
static struct platform_device mtu2_device = {
.name = "sh-mtu2",
.id = -1,
.resource = mtu2_resources,
.num_resources = ARRAY_SIZE(mtu2_resources),
};
static struct resource rtc_resources[] = {
[0] = {
.start = 0xfffe6000,
.end = 0xfffe6000 + 0x30 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
.start = 338,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
/* USB Host */
static struct r8a66597_platdata r8a66597_data = {
.on_chip = 1,
.endian = 1,
};
static struct resource r8a66597_usb_host_resources[] = {
[0] = {
.start = 0xe8010000,
.end = 0xe80100e4,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 170,
.end = 170,
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
static struct platform_device r8a66597_usb_host_device = {
.name = "r8a66597_hcd",
.id = 0,
.dev = {
.dma_mask = NULL, /* not use dma */
.coherent_dma_mask = 0xffffffff,
.platform_data = &r8a66597_data,
},
.num_resources = ARRAY_SIZE(r8a66597_usb_host_resources),
.resource = r8a66597_usb_host_resources,
};
static struct platform_device *sh7269_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&scif6_device,
&scif7_device,
&cmt_device,
&mtu2_device,
&rtc_device,
&r8a66597_usb_host_device,
};
static int __init sh7269_devices_setup(void)
{
return platform_add_devices(sh7269_devices,
ARRAY_SIZE(sh7269_devices));
}
arch_initcall(sh7269_devices_setup);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
static struct platform_device *sh7269_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&scif6_device,
&scif7_device,
&cmt_device,
&mtu2_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7269_early_devices,
ARRAY_SIZE(sh7269_early_devices));
}

View file

@ -0,0 +1,33 @@
#
# Makefile for the Linux/SuperH SH-3 backends.
#
obj-y := ex.o probe.o entry.o setup-sh3.o
obj-$(CONFIG_HIBERNATION) += swsusp.o
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o serial-sh770x.o
obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh770x.o serial-sh770x.o
obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh770x.o serial-sh770x.o
obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh770x.o serial-sh770x.o
obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh770x.o serial-sh770x.o
obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o serial-sh7710.o
obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o serial-sh7710.o
obj-$(CONFIG_CPU_SUBTYPE_SH7720) += setup-sh7720.o serial-sh7720.o
obj-$(CONFIG_CPU_SUBTYPE_SH7721) += setup-sh7720.o serial-sh7720.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH3) := clock-sh3.o
clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o
clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o
clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o
clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7710.o
clock-$(CONFIG_CPU_SUBTYPE_SH7720) := clock-sh7710.o
clock-$(CONFIG_CPU_SUBTYPE_SH7712) := clock-sh7712.o
# Pinmux setup
pinmux-$(CONFIG_CPU_SUBTYPE_SH7720) := pinmux-sh7720.o
obj-y += $(clock-y)
obj-$(CONFIG_GPIOLIB) += $(pinmux-y)

View file

@ -0,0 +1,89 @@
/*
* arch/sh/kernel/cpu/sh3/clock-sh3.c
*
* Generic SH-3 support for the clock framework
*
* Copyright (C) 2005 Paul Mundt
*
* FRQCR parsing hacked out of arch/sh/kernel/time.c
*
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (C) 2002, 2003, 2004 Paul Mundt
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
*
* 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>
static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 };
static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 };
static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 };
static void master_clk_init(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
clk->rate *= pfc_divisors[idx];
}
static struct sh_clk_ops sh3_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh3_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
return clk->parent->rate / stc_multipliers[idx];
}
static struct sh_clk_ops sh3_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh3_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh3_clk_ops[] = {
&sh3_master_clk_ops,
&sh3_module_clk_ops,
&sh3_bus_clk_ops,
&sh3_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh3_clk_ops))
*ops = sh3_clk_ops[idx];
}

View file

@ -0,0 +1,84 @@
/*
* arch/sh/kernel/cpu/sh3/clock-sh7705.c
*
* SH7705 support for the clock framework
*
* Copyright (C) 2005 Paul Mundt
*
* FRQCR parsing hacked out of arch/sh/kernel/time.c
*
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (C) 2002, 2003, 2004 Paul Mundt
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
*
* 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>
/*
* SH7705 uses the same divisors as the generic SH-3 case, it's just the
* FRQCR layout that is a bit different..
*/
static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 };
static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 };
static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 };
static void master_clk_init(struct clk *clk)
{
clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0003];
}
static struct sh_clk_ops sh7705_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int idx = __raw_readw(FRQCR) & 0x0003;
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh7705_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) & 0x0300) >> 8;
return clk->parent->rate / stc_multipliers[idx];
}
static struct sh_clk_ops sh7705_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) & 0x0030) >> 4;
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh7705_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7705_clk_ops[] = {
&sh7705_master_clk_ops,
&sh7705_module_clk_ops,
&sh7705_bus_clk_ops,
&sh7705_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7705_clk_ops))
*ops = sh7705_clk_ops[idx];
}

View file

@ -0,0 +1,84 @@
/*
* arch/sh/kernel/cpu/sh3/clock-sh7706.c
*
* SH7706 support for the clock framework
*
* Copyright (C) 2006 Takashi YOSHII
*
* Based on arch/sh/kernel/cpu/sh3/clock-sh7709.c
* Copyright (C) 2005 Andriy Skulysh
*
* 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>
static int stc_multipliers[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
static void master_clk_init(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
clk->rate *= pfc_divisors[idx];
}
static struct sh_clk_ops sh7706_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh7706_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
return clk->parent->rate / stc_multipliers[idx];
}
static struct sh_clk_ops sh7706_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh7706_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7706_clk_ops[] = {
&sh7706_master_clk_ops,
&sh7706_module_clk_ops,
&sh7706_bus_clk_ops,
&sh7706_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7706_clk_ops))
*ops = sh7706_clk_ops[idx];
}

View file

@ -0,0 +1,85 @@
/*
* arch/sh/kernel/cpu/sh3/clock-sh7709.c
*
* SH7709 support for the clock framework
*
* Copyright (C) 2005 Andriy Skulysh
*
* Based on arch/sh/kernel/cpu/sh3/clock-sh7705.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>
static int stc_multipliers[] = { 1, 2, 4, 8, 3, 6, 1, 1 };
static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
static void master_clk_init(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
clk->rate *= pfc_divisors[idx];
}
static struct sh_clk_ops sh7709_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh7709_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = (frqcr & 0x0080) ?
((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4) : 1;
return clk->parent->rate * stc_multipliers[idx];
}
static struct sh_clk_ops sh7709_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh7709_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7709_clk_ops[] = {
&sh7709_master_clk_ops,
&sh7709_module_clk_ops,
&sh7709_bus_clk_ops,
&sh7709_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7709_clk_ops))
*ops = sh7709_clk_ops[idx];
}

View file

@ -0,0 +1,78 @@
/*
* arch/sh/kernel/cpu/sh3/clock-sh7710.c
*
* SH7710 support for the clock framework
*
* Copyright (C) 2005 Paul Mundt
*
* FRQCR parsing hacked out of arch/sh/kernel/time.c
*
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (C) 2002, 2003, 2004 Paul Mundt
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
*
* 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>
static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 };
static void master_clk_init(struct clk *clk)
{
clk->rate *= md_table[__raw_readw(FRQCR) & 0x0007];
}
static struct sh_clk_ops sh7710_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) & 0x0007);
return clk->parent->rate / md_table[idx];
}
static struct sh_clk_ops sh7710_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) & 0x0700) >> 8;
return clk->parent->rate / md_table[idx];
}
static struct sh_clk_ops sh7710_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) & 0x0070) >> 4;
return clk->parent->rate / md_table[idx];
}
static struct sh_clk_ops sh7710_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7710_clk_ops[] = {
&sh7710_master_clk_ops,
&sh7710_module_clk_ops,
&sh7710_bus_clk_ops,
&sh7710_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7710_clk_ops))
*ops = sh7710_clk_ops[idx];
}

View file

@ -0,0 +1,71 @@
/*
* arch/sh/kernel/cpu/sh3/clock-sh7712.c
*
* SH7712 support for the clock framework
*
* Copyright (C) 2007 Andrew Murray <amurray@mpc-data.co.uk>
*
* Based on arch/sh/kernel/cpu/sh3/clock-sh3.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>
static int multipliers[] = { 1, 2, 3 };
static int divisors[] = { 1, 2, 3, 4, 6 };
static void master_clk_init(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = (frqcr & 0x0300) >> 8;
clk->rate *= multipliers[idx];
}
static struct sh_clk_ops sh7712_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = frqcr & 0x0007;
return clk->parent->rate / divisors[idx];
}
static struct sh_clk_ops sh7712_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int frqcr = __raw_readw(FRQCR);
int idx = (frqcr & 0x0030) >> 4;
return clk->parent->rate / divisors[idx];
}
static struct sh_clk_ops sh7712_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7712_clk_ops[] = {
&sh7712_master_clk_ops,
&sh7712_module_clk_ops,
&sh7712_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7712_clk_ops))
*ops = sh7712_clk_ops[idx];
}

View file

@ -0,0 +1,513 @@
/*
* arch/sh/kernel/cpu/sh3/entry.S
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
* Copyright (C) 2003 - 2012 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/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
#include <cpu/mmu_context.h>
#include <asm/page.h>
#include <asm/cache.h>
#include <asm/thread_info.h>
! NOTE:
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
! to be jumped is too far, but it causes illegal slot exception.
/*
* entry.S contains the system-call and fault low-level handling routines.
* This also contains the timer-interrupt handler, as well as all interrupts
* and faults that can result in a task-switch.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call.
*
* NOTE: This code uses a convention that instructions in the delay slot
* of a transfer-control instruction are indented by an extra space, thus:
*
* jmp @k0 ! control-transfer instruction
* ldc k1, ssr ! delay slot
*
* Stack layout in 'ret_from_syscall':
* ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
* updated in ptrace.c and ptrace.h
*
* r0
* ...
* r15 = stack pointer
* spc
* pr
* ssr
* gbr
* mach
* macl
* syscall #
*
*/
/* 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+8)
OFF_TRA = (16*4+6*4)
#define k0 r0
#define k1 r1
#define k2 r2
#define k3 r3
#define k4 r4
#define g_imask r6 /* r6_bank1 */
#define k_g_imask r6_bank /* r6_bank1 */
#define current r7 /* r7_bank1 */
#include <asm/entry-macros.S>
/*
* Kernel mode register usage:
* k0 scratch
* k1 scratch
* k2 scratch (Exception code)
* k3 scratch (Return address)
* k4 scratch
* k5 reserved
* k6 Global Interrupt Mask (0--15 << 4)
* k7 CURRENT_THREAD_INFO (pointer to current thread info)
*/
!
! TLB Miss / Initial Page write exception handling
! _and_
! TLB hits, but the access violate the protection.
! It can be valid access, such as stack grow and/or C-O-W.
!
!
! Find the pmd/pte entry and loadtlb
! If it's not found, cause address error (SEGV)
!
! Although this could be written in assembly language (and it'd be faster),
! this first version depends *much* on C implementation.
!
#if defined(CONFIG_MMU)
.align 2
ENTRY(tlb_miss_load)
bra call_handle_tlbmiss
mov #0, r5
.align 2
ENTRY(tlb_miss_store)
bra call_handle_tlbmiss
mov #FAULT_CODE_WRITE, r5
.align 2
ENTRY(initial_page_write)
bra call_handle_tlbmiss
mov #FAULT_CODE_INITIAL, r5
.align 2
ENTRY(tlb_protection_violation_load)
bra call_do_page_fault
mov #FAULT_CODE_PROT, r5
.align 2
ENTRY(tlb_protection_violation_store)
bra call_do_page_fault
mov #(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
call_handle_tlbmiss:
mov.l 1f, r0
mov r5, r8
mov.l @r0, r6
mov.l 2f, r0
sts pr, r10
jsr @r0
mov r15, r4
!
tst r0, r0
bf/s 0f
lds r10, pr
rts
nop
0:
mov r8, r5
call_do_page_fault:
mov.l 1f, r0
mov.l @r0, r6
mov.l 3f, r0
mov.l 4f, r1
mov r15, r4
jmp @r0
lds r1, pr
.align 2
1: .long MMU_TEA
2: .long handle_tlbmiss
3: .long do_page_fault
4: .long ret_from_exception
.align 2
ENTRY(address_error_load)
bra call_dae
mov #0,r5 ! writeaccess = 0
.align 2
ENTRY(address_error_store)
bra call_dae
mov #1,r5 ! writeaccess = 1
.align 2
call_dae:
mov.l 1f, r0
mov.l @r0, r6 ! address
mov.l 2f, r0
jmp @r0
mov r15, r4 ! regs
.align 2
1: .long MMU_TEA
2: .long do_address_error
#endif /* CONFIG_MMU */
#if defined(CONFIG_SH_STANDARD_BIOS)
/* Unwind the stack and jmp to the debug entry */
ENTRY(sh_bios_handler)
mov.l 1f, r8
bsr restore_regs
nop
lds k2, pr ! restore pr
mov k4, r15
!
mov.l 2f, k0
mov.l @k0, k0
jmp @k0
ldc k3, ssr
.align 2
1: .long 0x300000f0
2: .long gdb_vbr_vector
#endif /* CONFIG_SH_STANDARD_BIOS */
! restore_regs()
! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
! - switch bank
! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
! k2 returns original pr
! k3 returns original sr
! k4 returns original stack pointer
! r8 passes SR bitmask, overwritten with restored data on return
! r9 trashed
! BL=0 on entry, on exit BL=1 (depending on r8).
ENTRY(restore_regs)
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
!
stc sr, r9
or r8, r9
ldc r9, sr
!
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+, k4 ! original stack pointer
ldc.l @r15+, spc
mov.l @r15+, k2 ! original PR
mov.l @r15+, k3 ! original SR
ldc.l @r15+, gbr
lds.l @r15+, mach
lds.l @r15+, macl
rts
add #4, r15 ! Skip syscall number
restore_all:
mov.l 7f, r8
bsr restore_regs
nop
lds k2, pr ! restore pr
!
! Calculate new SR value
mov k3, k2 ! original SR value
mov #0xfffffff0, k1
extu.b k1, k1
not k1, k1
and k1, k2 ! Mask original SR value
!
mov k3, k0 ! Calculate IMASK-bits
shlr2 k0
and #0x3c, k0
cmp/eq #0x3c, k0
bt/s 6f
shll2 k0
mov g_imask, k0
!
6: or k0, k2 ! Set the IMASK-bits
ldc k2, ssr
!
mov k4, r15
rte
nop
.align 2
5: .long 0x00001000 ! DSP
7: .long 0x30000000
! common exception handler
#include "../../entry-common.S"
! Exception Vector Base
!
! Should be aligned page boundary.
!
.balign 4096,0,4096
ENTRY(vbr_base)
.long 0
!
! 0x100: General exception vector
!
.balign 256,0,256
general_exception:
bra handle_exception
sts pr, k3 ! save original pr value in k3
! prepare_stack()
! - roll back gRB
! - switch to kernel stack
! k0 returns original sp (after roll back)
! k1 trashed
! k2 trashed
prepare_stack:
#ifdef CONFIG_GUSA
! Check for roll back gRB (User and Kernel)
mov r15, k0
shll k0
bf/s 1f
shll k0
bf/s 1f
stc spc, k1
stc r0_bank, k0
cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0)
bt/s 2f
stc r1_bank, k1
add #-2, k0
add r15, k0
ldc k0, spc ! PC = saved r0 + r15 - 2
2: mov k1, r15 ! SP = r1
1:
#endif
! Switch to kernel stack if needed
stc ssr, k0 ! Is it from kernel space?
shll k0 ! Check MD bit (bit30) by shifting it into...
shll k0 ! ...the T bit
bt/s 1f ! It's a kernel to kernel transition.
mov r15, k0 ! save original stack to k0
/* User space to kernel */
mov #(THREAD_SIZE >> 10), k1
shll8 k1 ! k1 := THREAD_SIZE
shll2 k1
add current, k1
mov k1, r15 ! change to kernel stack
!
1:
rts
nop
!
! 0x400: Instruction and Data TLB miss exception vector
!
.balign 1024,0,1024
tlb_miss:
sts pr, k3 ! save original pr value in k3
handle_exception:
mova exception_data, k0
! Setup stack and save DSP context (k0 contains original r15 on return)
bsr prepare_stack
PREF(k0)
! Save registers / Switch to bank 0
mov.l 5f, k2 ! vector register address
mov.l 1f, k4 ! SR bits to clear in k4
bsr save_regs ! needs original pr value in k3
mov.l @k2, k2 ! read out vector and keep in k2
handle_exception_special:
setup_frame_reg
! Setup return address and jump to exception handler
mov.l 7f, r9 ! fetch return address
stc r2_bank, r0 ! k2 (vector)
mov.l 6f, r10
shlr2 r0
shlr r0
mov.l @(r0, r10), r10
jmp @r10
lds r9, pr ! put return address in pr
.align L1_CACHE_SHIFT
! save_regs()
! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
! - switch bank
! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
! k0 contains original stack pointer*
! k1 trashed
! k3 passes original pr*
! k4 passes SR bitmask
! BL=1 on entry, on exit BL=0.
ENTRY(save_regs)
mov #-1, r1
mov.l k1, @-r15 ! set TRA (default: -1)
sts.l macl, @-r15
sts.l mach, @-r15
stc.l gbr, @-r15
stc.l ssr, @-r15
mov.l k3, @-r15 ! original pr in k3
stc.l spc, @-r15
mov.l k0, @-r15 ! original stack pointer in k0
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 0f, k3 ! SR bits to set in k3
! fall-through
! save_low_regs()
! - modify SR for bank switch
! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
! k3 passes bits to set in SR
! k4 passes bits to clear in SR
ENTRY(save_low_regs)
stc sr, r8
or k3, r8
and k4, r8
ldc r8, sr
mov.l r7, @-r15
mov.l r6, @-r15
mov.l r5, @-r15
mov.l r4, @-r15
mov.l r3, @-r15
mov.l r2, @-r15
mov.l r1, @-r15
rts
mov.l r0, @-r15
!
! 0x600: Interrupt / NMI vector
!
.balign 512,0,512
ENTRY(handle_interrupt)
sts pr, k3 ! save original pr value in k3
mova exception_data, k0
! Setup stack and save DSP context (k0 contains original r15 on return)
bsr prepare_stack
PREF(k0)
! Save registers / Switch to bank 0
mov.l 1f, k4 ! SR bits to clear in k4
bsr save_regs ! needs original pr value in k3
mov #-1, k2 ! default vector kept in k2
setup_frame_reg
stc sr, r0 ! get status register
shlr2 r0
and #0x3c, r0
cmp/eq #0x3c, r0
bf 9f
TRACE_IRQS_OFF
9:
! Setup return address and jump to do_IRQ
mov.l 4f, r9 ! fetch return address
lds r9, pr ! put return address in pr
mov.l 2f, r4
mov.l 3f, r9
mov.l @r4, r4 ! pass INTEVT vector as arg0
shlr2 r4
shlr r4
mov r4, r0 ! save vector->jmp table offset for later
shlr2 r4 ! vector to IRQ# conversion
add #-0x10, r4
cmp/pz r4 ! is it a valid IRQ?
bt 10f
/*
* We got here as a result of taking the INTEVT path for something
* that isn't a valid hard IRQ, therefore we bypass the do_IRQ()
* path and special case the event dispatch instead. This is the
* expected path for the NMI (and any other brilliantly implemented
* exception), which effectively wants regular exception dispatch
* but is unfortunately reported through INTEVT rather than
* EXPEVT. Grr.
*/
mov.l 6f, r9
mov.l @(r0, r9), r9
jmp @r9
mov r15, r8 ! trap handlers take saved regs in r8
10:
jmp @r9 ! Off to do_IRQ() we go.
mov r15, r5 ! pass saved registers as arg1
ENTRY(exception_none)
rts
nop
.align L1_CACHE_SHIFT
exception_data:
0: .long 0x000080f0 ! FD=1, IMASK=15
1: .long 0xcfffffff ! RB=0, BL=0
2: .long INTEVT
3: .long do_IRQ
4: .long ret_from_irq
5: .long EXPEVT
6: .long exception_handling_table
7: .long ret_from_exception

View file

@ -0,0 +1,59 @@
/*
* arch/sh/kernel/cpu/sh3/ex.S
*
* The SH-3 and SH-4 exception vector table.
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
* Copyright (C) 2003 - 2008 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/linkage.h>
#if !defined(CONFIG_MMU)
#define tlb_miss_load exception_error
#define tlb_miss_store exception_error
#define initial_page_write exception_error
#define tlb_protection_violation_load exception_error
#define tlb_protection_violation_store exception_error
#define address_error_load exception_error
#define address_error_store exception_error
#endif
#if !defined(CONFIG_SH_FPU)
#define fpu_error_trap_handler exception_error
#endif
#if !defined(CONFIG_KGDB)
#define kgdb_handle_exception exception_error
#endif
.align 2
.data
ENTRY(exception_handling_table)
.long exception_error /* 000 */
.long exception_error
.long tlb_miss_load /* 040 */
.long tlb_miss_store
.long initial_page_write
.long tlb_protection_violation_load
.long tlb_protection_violation_store
.long address_error_load
.long address_error_store /* 100 */
.long fpu_error_trap_handler /* 120 */
.long exception_error /* 140 */
.long system_call ! Unconditional Trap /* 160 */
.long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
.long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
.long nmi_trap_handler /* 1C0 */ ! Allow trap to debugger
.long breakpoint_trap_handler /* 1E0 */
/*
* Pad the remainder of the table out, exceptions residing in far
* away offsets can be manually inserted in to their appropriate
* location via set_exception_table_{evt,vec}().
*/
.balign 4096,0,4096

View file

@ -0,0 +1,30 @@
/*
* SH7720 Pinmux
*
* Copyright (C) 2008 Magnus Damm
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7720_pfc_resources[] = {
[0] = {
.start = 0xa4050100,
.end = 0xa405016f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7720", sh7720_pfc_resources,
ARRAY_SIZE(sh7720_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,111 @@
/*
* arch/sh/kernel/cpu/sh3/probe.c
*
* CPU Subtype Probing for SH-3.
*
* Copyright (C) 1999, 2000 Niibe Yutaka
* 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>
#include <asm/io.h>
void cpu_probe(void)
{
unsigned long addr0, addr1, data0, data1, data2, data3;
jump_to_uncached();
/*
* Check if the entry shadows or not.
* When shadowed, it's 128-entry system.
* Otherwise, it's 256-entry system.
*/
addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
/* First, write back & invalidate */
data0 = __raw_readl(addr0);
__raw_writel(data0&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr0);
data1 = __raw_readl(addr1);
__raw_writel(data1&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr1);
/* Next, check if there's shadow or not */
data0 = __raw_readl(addr0);
data0 ^= SH_CACHE_VALID;
__raw_writel(data0, addr0);
data1 = __raw_readl(addr1);
data2 = data1 ^ SH_CACHE_VALID;
__raw_writel(data2, addr1);
data3 = __raw_readl(addr0);
/* Lastly, invaliate them. */
__raw_writel(data0&~SH_CACHE_VALID, addr0);
__raw_writel(data2&~SH_CACHE_VALID, addr1);
back_to_cached();
boot_cpu_data.dcache.ways = 4;
boot_cpu_data.dcache.entry_shift = 4;
boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
boot_cpu_data.dcache.flags = 0;
/*
* 7709A/7729 has 16K cache (256-entry), while 7702 has only
* 2K(direct) 7702 is not supported (yet)
*/
if (data0 == data1 && data2 == data3) { /* Shadow */
boot_cpu_data.dcache.way_incr = (1 << 11);
boot_cpu_data.dcache.entry_mask = 0x7f0;
boot_cpu_data.dcache.sets = 128;
boot_cpu_data.type = CPU_SH7708;
boot_cpu_data.flags |= CPU_HAS_MMU_PAGE_ASSOC;
} else { /* 7709A or 7729 */
boot_cpu_data.dcache.way_incr = (1 << 12);
boot_cpu_data.dcache.entry_mask = 0xff0;
boot_cpu_data.dcache.sets = 256;
boot_cpu_data.type = CPU_SH7729;
#if defined(CONFIG_CPU_SUBTYPE_SH7706)
boot_cpu_data.type = CPU_SH7706;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7710)
boot_cpu_data.type = CPU_SH7710;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7712)
boot_cpu_data.type = CPU_SH7712;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7720)
boot_cpu_data.type = CPU_SH7720;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7721)
boot_cpu_data.type = CPU_SH7721;
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
boot_cpu_data.type = CPU_SH7705;
#if defined(CONFIG_SH7705_CACHE_32KB)
boot_cpu_data.dcache.way_incr = (1 << 13);
boot_cpu_data.dcache.entry_mask = 0x1ff0;
boot_cpu_data.dcache.sets = 512;
__raw_writel(CCR_CACHE_32KB, CCR3_REG);
#else
__raw_writel(CCR_CACHE_16KB, CCR3_REG);
#endif
#endif
}
/*
* SH-3 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_SH3;
}

View file

@ -0,0 +1,33 @@
#include <linux/serial_sci.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <cpu/serial.h>
#define SCPCR 0xA4000116
#define SCPDR 0xA4000136
static void sh770x_sci_init_pins(struct uart_port *port, unsigned int cflag)
{
unsigned short data;
/* We need to set SCPCR to enable RTS/CTS */
data = __raw_readw(SCPCR);
/* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
__raw_writew(data & 0x0fcf, SCPCR);
if (!(cflag & CRTSCTS)) {
/* We need to set SCPCR to enable RTS/CTS */
data = __raw_readw(SCPCR);
/* Clear out SCP7MD1,0, SCP4MD1,0,
Set SCP6MD1,0 = {01} (output) */
__raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
data = __raw_readb(SCPDR);
/* Set /RTS2 (bit6) = 0 */
__raw_writeb(data & 0xbf, SCPDR);
}
}
struct plat_sci_port_ops sh770x_sci_port_ops = {
.init_pins = sh770x_sci_init_pins,
};

View file

@ -0,0 +1,20 @@
#include <linux/serial_sci.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <cpu/serial.h>
#define PACR 0xa4050100
#define PBCR 0xa4050102
static void sh7710_sci_init_pins(struct uart_port *port, unsigned int cflag)
{
if (port->mapbase == 0xA4400000) {
__raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
__raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
} else if (port->mapbase == 0xA4410000)
__raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
}
struct plat_sci_port_ops sh7710_sci_port_ops = {
.init_pins = sh7710_sci_init_pins,
};

View file

@ -0,0 +1,37 @@
#include <linux/serial_sci.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <cpu/serial.h>
#include <cpu/gpio.h>
static void sh7720_sci_init_pins(struct uart_port *port, unsigned int cflag)
{
unsigned short data;
if (cflag & CRTSCTS) {
/* enable RTS/CTS */
if (port->mapbase == 0xa4430000) { /* SCIF0 */
/* Clear PTCR bit 9-2; enable all scif pins but sck */
data = __raw_readw(PORT_PTCR);
__raw_writew((data & 0xfc03), PORT_PTCR);
} else if (port->mapbase == 0xa4438000) { /* SCIF1 */
/* Clear PVCR bit 9-2 */
data = __raw_readw(PORT_PVCR);
__raw_writew((data & 0xfc03), PORT_PVCR);
}
} else {
if (port->mapbase == 0xa4430000) { /* SCIF0 */
/* Clear PTCR bit 5-2; enable only tx and rx */
data = __raw_readw(PORT_PTCR);
__raw_writew((data & 0xffc3), PORT_PTCR);
} else if (port->mapbase == 0xa4438000) { /* SCIF1 */
/* Clear PVCR bit 5-2 */
data = __raw_readw(PORT_PVCR);
__raw_writew((data & 0xffc3), PORT_PVCR);
}
}
}
struct plat_sci_port_ops sh7720_sci_port_ops = {
.init_pins = sh7720_sci_init_pins,
};

View file

@ -0,0 +1,71 @@
/*
* Shared SH3 Setup code
*
* Copyright (C) 2008 Magnus Damm
*
* 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/irq.h>
#include <linux/io.h>
/* All SH3 devices are equipped with IRQ0->5 (except sh7708) */
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
};
static struct intc_vect vectors_irq0123[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
};
static struct intc_vect vectors_irq45[] __initdata = {
INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
{ 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
};
static struct intc_mask_reg ack_registers[] __initdata = {
{ 0xa4000004, 0, 8, /* IRR0 */
{ 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
};
static struct intc_sense_reg sense_registers[] __initdata = {
{ 0xa4000010, 16, 2, { 0, 0, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 } },
};
static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh3-irq0123",
vectors_irq0123, NULL, NULL,
prio_registers, sense_registers, ack_registers);
static DECLARE_INTC_DESC_ACK(intc_desc_irq45, "sh3-irq45",
vectors_irq45, NULL, NULL,
prio_registers, sense_registers, ack_registers);
#define INTC_ICR1 0xa4000010UL
#define INTC_ICR1_IRQLVL (1<<14)
void __init plat_irq_setup_pins(int mode)
{
if (mode == IRQ_MODE_IRQ) {
__raw_writew(__raw_readw(INTC_ICR1) & ~INTC_ICR1_IRQLVL, INTC_ICR1);
register_intc_controller(&intc_desc_irq0123);
return;
}
BUG();
}
void __init plat_irq_setup_sh3(void)
{
register_intc_controller(&intc_desc_irq45);
}

View file

@ -0,0 +1,196 @@
/*
* SH7705 Setup
*
* Copyright (C) 2006 - 2009 Paul Mundt
* Copyright (C) 2007 Nobuhiro Iwamatsu
*
* 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/irq.h>
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/rtc.h>
#include <cpu/serial.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
PINT07, PINT815,
DMAC, SCIF0, SCIF2, ADC_ADI, USB,
TPU0, TPU1, TPU2, TPU3,
TMU0, TMU1, TMU2,
RTC, WDT, REF_RCMI,
};
static struct intc_vect vectors[] __initdata = {
/* IRQ0->5 are handled in setup-sh3.c */
INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
INTC_VECT(DMAC, 0x800), INTC_VECT(DMAC, 0x820),
INTC_VECT(DMAC, 0x840), INTC_VECT(DMAC, 0x860),
INTC_VECT(SCIF0, 0x880), INTC_VECT(SCIF0, 0x8a0),
INTC_VECT(SCIF0, 0x8e0),
INTC_VECT(SCIF2, 0x900), INTC_VECT(SCIF2, 0x920),
INTC_VECT(SCIF2, 0x960),
INTC_VECT(ADC_ADI, 0x980),
INTC_VECT(USB, 0xa20), INTC_VECT(USB, 0xa40),
INTC_VECT(TPU0, 0xc00), INTC_VECT(TPU1, 0xc20),
INTC_VECT(TPU2, 0xc80), INTC_VECT(TPU3, 0xca0),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
INTC_VECT(RTC, 0x4c0),
INTC_VECT(WDT, 0x560),
INTC_VECT(REF_RCMI, 0x580),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, 0, 0 } },
{ 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
{ 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, IRQ5, IRQ4 } },
{ 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, SCIF0, SCIF2, ADC_ADI } },
{ 0xa4080000, 0, 16, 4, /* IPRF */ { 0, 0, USB } },
{ 0xa4080002, 0, 16, 4, /* IPRG */ { TPU0, TPU1 } },
{ 0xa4080004, 0, 16, 4, /* IPRH */ { TPU2, TPU3 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7705", vectors, NULL,
NULL, prio_registers, NULL);
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_TIE | SCSCR_RIE | SCSCR_TE |
SCSCR_RE | SCSCR_CKE1 | SCSCR_CKE0,
.type = PORT_SCIF,
.ops = &sh770x_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xa4410000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x900)),
};
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_TIE | SCSCR_RIE | SCSCR_TE | SCSCR_RE,
.type = PORT_SCIF,
.ops = &sh770x_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xa4400000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x880)),
};
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 resource rtc_resources[] = {
[0] = {
.start = 0xfffffec0,
.end = 0xfffffec0 + 0x1e,
.flags = IORESOURCE_IO,
},
[1] = {
.start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
static struct sh_rtc_platform_info rtc_info = {
.capabilities = RTC_CAP_4_DIGIT_YEAR,
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
.dev = {
.platform_data = &rtc_info,
},
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xfffffe90, 0x2c),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu-sh3",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh7705_devices[] __initdata = {
&scif0_device,
&scif1_device,
&tmu0_device,
&rtc_device,
};
static int __init sh7705_devices_setup(void)
{
return platform_add_devices(sh7705_devices,
ARRAY_SIZE(sh7705_devices));
}
arch_initcall(sh7705_devices_setup);
static struct platform_device *sh7705_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7705_early_devices,
ARRAY_SIZE(sh7705_early_devices));
}
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
plat_irq_setup_sh3();
}

View file

@ -0,0 +1,258 @@
/*
* SH3 Setup code for SH7706, SH7707, SH7708, SH7709
*
* Copyright (C) 2007 Magnus Damm
* Copyright (C) 2009 Paul Mundt
*
* Based on setup-sh7709.c
*
* Copyright (C) 2006 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/io.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <cpu/serial.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
PINT07, PINT815,
DMAC, SCIF0, SCIF2, SCI, ADC_ADI,
LCDC, PCC0, PCC1,
TMU0, TMU1, TMU2,
RTC, WDT, REF,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
INTC_VECT(RTC, 0x4c0),
INTC_VECT(SCI, 0x4e0), INTC_VECT(SCI, 0x500),
INTC_VECT(SCI, 0x520), INTC_VECT(SCI, 0x540),
INTC_VECT(WDT, 0x560),
INTC_VECT(REF, 0x580),
INTC_VECT(REF, 0x5a0),
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
/* IRQ0->5 are handled in setup-sh3.c */
INTC_VECT(DMAC, 0x800), INTC_VECT(DMAC, 0x820),
INTC_VECT(DMAC, 0x840), INTC_VECT(DMAC, 0x860),
INTC_VECT(ADC_ADI, 0x980),
INTC_VECT(SCIF2, 0x900), INTC_VECT(SCIF2, 0x920),
INTC_VECT(SCIF2, 0x940), INTC_VECT(SCIF2, 0x960),
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720),
INTC_VECT(SCIF0, 0x880), INTC_VECT(SCIF0, 0x8a0),
INTC_VECT(SCIF0, 0x8c0), INTC_VECT(SCIF0, 0x8e0),
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707)
INTC_VECT(LCDC, 0x9a0),
INTC_VECT(PCC0, 0x9c0), INTC_VECT(PCC1, 0x9e0),
#endif
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } },
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
{ 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
{ 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
{ 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, 0, SCIF2, ADC_ADI } },
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
{ 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, } },
{ 0xa400001a, 0, 16, 4, /* IPRE */ { 0, SCIF0 } },
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707)
{ 0xa400001c, 0, 16, 4, /* IPRF */ { 0, LCDC, PCC0, PCC1, } },
#endif
};
static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, NULL,
NULL, prio_registers, NULL);
static struct resource rtc_resources[] = {
[0] = {
.start = 0xfffffec0,
.end = 0xfffffec0 + 0x1e,
.flags = IORESOURCE_IO,
},
[1] = {
.start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
static struct plat_sci_port scif0_platform_data = {
.port_reg = 0xa4000136,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_TE | SCSCR_RE,
.type = PORT_SCI,
.ops = &sh770x_sci_port_ops,
.regshift = 1,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xfffffe80, 0x10),
DEFINE_RES_IRQ(evt2irq(0x4e0)),
};
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,
},
};
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
static struct plat_sci_port scif1_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_TE | SCSCR_RE,
.type = PORT_SCIF,
.ops = &sh770x_sci_port_ops,
.regtype = SCIx_SH3_SCIF_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xa4000150, 0x10),
DEFINE_RES_IRQ(evt2irq(0x900)),
};
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,
},
};
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
static struct plat_sci_port scif2_platform_data = {
.port_reg = SCIx_NOT_SUPPORTED,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_TE | SCSCR_RE,
.type = PORT_IRDA,
.ops = &sh770x_sci_port_ops,
.regshift = 1,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xa4000140, 0x10),
DEFINE_RES_IRQ(evt2irq(0x880)),
};
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,
},
};
#endif
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xfffffe90, 0x2c),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu-sh3",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh770x_devices[] __initdata = {
&scif0_device,
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
&scif1_device,
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
&scif2_device,
#endif
&tmu0_device,
&rtc_device,
};
static int __init sh770x_devices_setup(void)
{
return platform_add_devices(sh770x_devices,
ARRAY_SIZE(sh770x_devices));
}
arch_initcall(sh770x_devices_setup);
static struct platform_device *sh770x_early_devices[] __initdata = {
&scif0_device,
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
&scif1_device,
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
&scif2_device,
#endif
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh770x_early_devices,
ARRAY_SIZE(sh770x_early_devices));
}
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
plat_irq_setup_sh3();
#endif
}

View file

@ -0,0 +1,195 @@
/*
* SH3 Setup code for SH7710, SH7712
*
* Copyright (C) 2006 - 2009 Paul Mundt
* Copyright (C) 2007 Nobuhiro Iwamatsu
*
* 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/irq.h>
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/rtc.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5,
DMAC1, SCIF0, SCIF1, DMAC2, IPSEC,
EDMAC0, EDMAC1, EDMAC2,
SIOF0, SIOF1,
TMU0, TMU1, TMU2,
RTC, WDT, REF,
};
static struct intc_vect vectors[] __initdata = {
/* IRQ0->5 are handled in setup-sh3.c */
INTC_VECT(DMAC1, 0x800), INTC_VECT(DMAC1, 0x820),
INTC_VECT(DMAC1, 0x840), INTC_VECT(DMAC1, 0x860),
INTC_VECT(SCIF0, 0x880), INTC_VECT(SCIF0, 0x8a0),
INTC_VECT(SCIF0, 0x8c0), INTC_VECT(SCIF0, 0x8e0),
INTC_VECT(SCIF1, 0x900), INTC_VECT(SCIF1, 0x920),
INTC_VECT(SCIF1, 0x940), INTC_VECT(SCIF1, 0x960),
INTC_VECT(DMAC2, 0xb80), INTC_VECT(DMAC2, 0xba0),
#ifdef CONFIG_CPU_SUBTYPE_SH7710
INTC_VECT(IPSEC, 0xbe0),
#endif
INTC_VECT(EDMAC0, 0xc00), INTC_VECT(EDMAC1, 0xc20),
INTC_VECT(EDMAC2, 0xc40),
INTC_VECT(SIOF0, 0xe00), INTC_VECT(SIOF0, 0xe20),
INTC_VECT(SIOF0, 0xe40), INTC_VECT(SIOF0, 0xe60),
INTC_VECT(SIOF1, 0xe80), INTC_VECT(SIOF1, 0xea0),
INTC_VECT(SIOF1, 0xec0), INTC_VECT(SIOF1, 0xee0),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440),
INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
INTC_VECT(RTC, 0x4c0),
INTC_VECT(WDT, 0x560),
INTC_VECT(REF, 0x580),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
{ 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
{ 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } },
{ 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC1, SCIF0, SCIF1 } },
{ 0xa4080000, 0, 16, 4, /* IPRF */ { IPSEC, DMAC2 } },
{ 0xa4080002, 0, 16, 4, /* IPRG */ { EDMAC0, EDMAC1, EDMAC2 } },
{ 0xa4080004, 0, 16, 4, /* IPRH */ { 0, 0, 0, SIOF0 } },
{ 0xa4080006, 0, 16, 4, /* IPRI */ { 0, 0, SIOF1 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7710", vectors, NULL,
NULL, prio_registers, NULL);
static struct resource rtc_resources[] = {
[0] = {
.start = 0xa413fec0,
.end = 0xa413fec0 + 0x1e,
.flags = IORESOURCE_IO,
},
[1] = {
.start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
static struct sh_rtc_platform_info rtc_info = {
.capabilities = RTC_CAP_4_DIGIT_YEAR,
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
.dev = {
.platform_data = &rtc_info,
},
};
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_TE | SCSCR_RE | SCSCR_REIE |
SCSCR_CKE1 | SCSCR_CKE0,
.type = PORT_SCIF,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xa4400000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x880)),
};
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_TE | SCSCR_RE | SCSCR_REIE |
SCSCR_CKE1 | SCSCR_CKE0,
.type = PORT_SCIF,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xa4410000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x900)),
};
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 sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xa412fe90, 0x28),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu-sh3",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh7710_devices[] __initdata = {
&scif0_device,
&scif1_device,
&tmu0_device,
&rtc_device,
};
static int __init sh7710_devices_setup(void)
{
return platform_add_devices(sh7710_devices,
ARRAY_SIZE(sh7710_devices));
}
arch_initcall(sh7710_devices_setup);
static struct platform_device *sh7710_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7710_early_devices,
ARRAY_SIZE(sh7710_early_devices));
}
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
plat_irq_setup_sh3();
}

View file

@ -0,0 +1,292 @@
/*
* Setup code for SH7720, SH7721.
*
* Copyright (C) 2007 Markus Brunner, Mark Jonas
* Copyright (C) 2009 Paul Mundt
*
* Based on arch/sh/kernel/cpu/sh4/setup-sh7750.c:
*
* Copyright (C) 2006 Paul Mundt
* Copyright (C) 2006 Jamie Lenehan
*
* 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/io.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/usb/ohci_pdriver.h>
#include <asm/rtc.h>
#include <cpu/serial.h>
static struct resource rtc_resources[] = {
[0] = {
.start = 0xa413fec0,
.end = 0xa413fec0 + 0x28 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
.start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
static struct sh_rtc_platform_info rtc_info = {
.capabilities = RTC_CAP_4_DIGIT_YEAR,
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
.dev = {
.platform_data = &rtc_info,
},
};
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.type = PORT_SCIF,
.ops = &sh7720_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xa4430000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc00)),
};
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,
.type = PORT_SCIF,
.ops = &sh7720_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xa4438000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc20)),
};
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 resource usb_ohci_resources[] = {
[0] = {
.start = 0xA4428000,
.end = 0xA44280FF,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xa60),
.end = evt2irq(0xa60),
.flags = IORESOURCE_IRQ,
},
};
static u64 usb_ohci_dma_mask = 0xffffffffUL;
static struct usb_ohci_pdata usb_ohci_pdata;
static struct platform_device usb_ohci_device = {
.name = "ohci-platform",
.id = -1,
.dev = {
.dma_mask = &usb_ohci_dma_mask,
.coherent_dma_mask = 0xffffffff,
.platform_data = &usb_ohci_pdata,
},
.num_resources = ARRAY_SIZE(usb_ohci_resources),
.resource = usb_ohci_resources,
};
static struct resource usbf_resources[] = {
[0] = {
.name = "sh_udc",
.start = 0xA4420000,
.end = 0xA44200FF,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "sh_udc",
.start = evt2irq(0xa20),
.end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device usbf_device = {
.name = "sh_udc",
.id = -1,
.dev = {
.dma_mask = NULL,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(usbf_resources),
.resource = usbf_resources,
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 0x1f,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0x044a0000, 0x60),
DEFINE_RES_IRQ(evt2irq(0xf00)),
};
static struct platform_device cmt_device = {
.name = "sh-cmt-32",
.id = 0,
.dev = {
.platform_data = &cmt_platform_data,
},
.resource = cmt_resources,
.num_resources = ARRAY_SIZE(cmt_resources),
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xa412fe90, 0x28),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu-sh3",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh7720_devices[] __initdata = {
&scif0_device,
&scif1_device,
&cmt_device,
&tmu0_device,
&rtc_device,
&usb_ohci_device,
&usbf_device,
};
static int __init sh7720_devices_setup(void)
{
return platform_add_devices(sh7720_devices,
ARRAY_SIZE(sh7720_devices));
}
arch_initcall(sh7720_devices_setup);
static struct platform_device *sh7720_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&cmt_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7720_early_devices,
ARRAY_SIZE(sh7720_early_devices));
}
enum {
UNUSED = 0,
/* interrupt sources */
TMU0, TMU1, TMU2, RTC,
WDT, REF_RCMI, SIM,
IRQ0, IRQ1, IRQ2, IRQ3,
USBF_SPD, TMU_SUNI, IRQ5, IRQ4,
DMAC1, LCDC, SSL,
ADC, DMAC2, USBFI, CMT,
SCIF0, SCIF1,
PINT07, PINT815, TPU, IIC,
SIOF0, SIOF1, MMC, PCC,
USBHI, AFEIF,
H_UDI,
};
static struct intc_vect vectors[] __initdata = {
/* IRQ0->5 are handled in setup-sh3.c */
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440), INTC_VECT(RTC, 0x480),
INTC_VECT(RTC, 0x4a0), INTC_VECT(RTC, 0x4c0),
INTC_VECT(SIM, 0x4e0), INTC_VECT(SIM, 0x500),
INTC_VECT(SIM, 0x520), INTC_VECT(SIM, 0x540),
INTC_VECT(WDT, 0x560), INTC_VECT(REF_RCMI, 0x580),
/* H_UDI cannot be masked */ INTC_VECT(TMU_SUNI, 0x6c0),
INTC_VECT(USBF_SPD, 0x6e0), INTC_VECT(DMAC1, 0x800),
INTC_VECT(DMAC1, 0x820), INTC_VECT(DMAC1, 0x840),
INTC_VECT(DMAC1, 0x860), INTC_VECT(LCDC, 0x900),
#if defined(CONFIG_CPU_SUBTYPE_SH7720)
INTC_VECT(SSL, 0x980),
#endif
INTC_VECT(USBFI, 0xa20), INTC_VECT(USBFI, 0xa40),
INTC_VECT(USBHI, 0xa60),
INTC_VECT(DMAC2, 0xb80), INTC_VECT(DMAC2, 0xba0),
INTC_VECT(ADC, 0xbe0), INTC_VECT(SCIF0, 0xc00),
INTC_VECT(SCIF1, 0xc20), INTC_VECT(PINT07, 0xc80),
INTC_VECT(PINT815, 0xca0), INTC_VECT(SIOF0, 0xd00),
INTC_VECT(SIOF1, 0xd20), INTC_VECT(TPU, 0xd80),
INTC_VECT(TPU, 0xda0), INTC_VECT(TPU, 0xdc0),
INTC_VECT(TPU, 0xde0), INTC_VECT(IIC, 0xe00),
INTC_VECT(MMC, 0xe80), INTC_VECT(MMC, 0xea0),
INTC_VECT(MMC, 0xec0), INTC_VECT(MMC, 0xee0),
INTC_VECT(CMT, 0xf00), INTC_VECT(PCC, 0xf60),
INTC_VECT(AFEIF, 0xfe0),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xA414FEE2UL, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xA414FEE4UL, 0, 16, 4, /* IPRB */ { WDT, REF_RCMI, SIM, 0 } },
{ 0xA4140016UL, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } },
{ 0xA4140018UL, 0, 16, 4, /* IPRD */ { USBF_SPD, TMU_SUNI, IRQ5, IRQ4 } },
{ 0xA414001AUL, 0, 16, 4, /* IPRE */ { DMAC1, 0, LCDC, SSL } },
{ 0xA4080000UL, 0, 16, 4, /* IPRF */ { ADC, DMAC2, USBFI, CMT } },
{ 0xA4080002UL, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, 0, 0 } },
{ 0xA4080004UL, 0, 16, 4, /* IPRH */ { PINT07, PINT815, TPU, IIC } },
{ 0xA4080006UL, 0, 16, 4, /* IPRI */ { SIOF0, SIOF1, MMC, PCC } },
{ 0xA4080008UL, 0, 16, 4, /* IPRJ */ { 0, USBHI, 0, AFEIF } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7720", vectors, NULL,
NULL, prio_registers, NULL);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
plat_irq_setup_sh3();
}

View file

@ -0,0 +1,147 @@
/*
* arch/sh/kernel/cpu/sh3/swsusp.S
*
* Copyright (C) 2009 Magnus Damm
*
* 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/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>
#define k0 r0
#define k1 r1
#define k2 r2
#define k3 r3
#define k4 r4
! swsusp_arch_resume()
! - copy restore_pblist pages
! - restore registers from swsusp_arch_regs_cpu0
ENTRY(swsusp_arch_resume)
mov.l 1f, r15
mov.l 2f, r4
mov.l @r4, r4
swsusp_copy_loop:
mov r4, r0
cmp/eq #0, r0
bt swsusp_restore_regs
mov.l @(PBE_ADDRESS, r4), r2
mov.l @(PBE_ORIG_ADDRESS, r4), r5
mov #(PAGE_SIZE >> 10), r3
shll8 r3
shlr2 r3 /* PAGE_SIZE / 16 */
swsusp_copy_page:
dt r3
mov.l @r2+,r1 /* 16n+0 */
mov.l r1,@r5
add #4,r5
mov.l @r2+,r1 /* 16n+4 */
mov.l r1,@r5
add #4,r5
mov.l @r2+,r1 /* 16n+8 */
mov.l r1,@r5
add #4,r5
mov.l @r2+,r1 /* 16n+12 */
mov.l r1,@r5
bf/s swsusp_copy_page
add #4,r5
bra swsusp_copy_loop
mov.l @(PBE_NEXT, r4), r4
swsusp_restore_regs:
! BL=0: R7->R0 is bank0
mov.l 3f, r8
mov.l 4f, r5
jsr @r5
nop
! BL=1: R7->R0 is bank1
lds k2, pr
ldc k3, ssr
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
rte
nop
! BL=0: R7->R0 is bank0
.align 2
1: .long swsusp_arch_regs_cpu0
2: .long restore_pblist
3: .long 0x20000000 ! RB=1
4: .long restore_regs
! swsusp_arch_suspend()
! - prepare pc for resume, return from function without swsusp_save on resume
! - save registers in swsusp_arch_regs_cpu0
! - call swsusp_save write suspend image
ENTRY(swsusp_arch_suspend)
sts pr, r0 ! save pr in r0
mov r15, r2 ! save sp in r2
mov r8, r5 ! save r8 in r5
stc sr, r1
ldc r1, ssr ! save sr in ssr
mov.l 1f, r1
ldc r1, spc ! setup pc value for resuming
mov.l 5f, r15 ! use swsusp_arch_regs_cpu0 as stack
mov.l 6f, r3
add r3, r15 ! save from top of structure
! BL=0: R7->R0 is bank0
mov.l 2f, r3 ! get new SR value for bank1
mov #0, r4
mov.l 7f, r1
jsr @r1 ! switch to bank1 and save bank1 r7->r0
not r4, r4
! BL=1: R7->R0 is bank1
stc r2_bank, k0 ! fetch old sp from r2_bank0
mov.l 3f, k4 ! SR bits to clear in k4
mov.l 8f, k1
jsr @k1 ! switch to bank0 and save all regs
stc r0_bank, k3 ! fetch old pr from r0_bank0
! BL=0: R7->R0 is bank0
mov r2, r15 ! restore old sp
mov r5, r8 ! restore old r8
stc ssr, r1
ldc r1, sr ! restore old sr
lds r0, pr ! restore old pr
mov.l 4f, r0
jmp @r0
nop
swsusp_call_save:
mov r2, r15 ! restore old sp
mov r5, r8 ! restore old r8
lds r0, pr ! restore old pr
rts
mov #0, r0
.align 2
1: .long swsusp_call_save
2: .long 0x20000000 ! RB=1
3: .long 0xdfffffff ! RB=0
4: .long swsusp_save
5: .long swsusp_arch_regs_cpu0
6: .long SWSUSP_ARCH_REGS_SIZE
7: .long save_low_regs
8: .long save_regs

View file

@ -0,0 +1,36 @@
#
# Makefile for the Linux/SuperH SH-4 backends.
#
obj-y := probe.o common.o
common-y += $(addprefix ../sh3/, entry.o ex.o)
obj-$(CONFIG_HIBERNATION) += $(addprefix ../sh3/, swsusp.o)
obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
# Perf events
perf-$(CONFIG_CPU_SUBTYPE_SH7750) := perf_event.o
perf-$(CONFIG_CPU_SUBTYPE_SH7750S) := perf_event.o
perf-$(CONFIG_CPU_SUBTYPE_SH7091) := perf_event.o
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7750S) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7091) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o
obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o
# Primary on-chip clocks (common)
ifndef CONFIG_CPU_SH4A
clock-$(CONFIG_CPU_SH4) := clock-sh4.o
endif
# Additional clocks by subtype
clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o
obj-y += $(clock-y)
obj-$(CONFIG_PERF_EVENTS) += $(perf-y)

View file

@ -0,0 +1,177 @@
/*
* arch/sh/kernel/cpu/sh4/clock-sh4-202.c
*
* Additional SH4-202 support for the clock framework
*
* 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/err.h>
#include <linux/io.h>
#include <linux/clkdev.h>
#include <asm/clock.h>
#include <asm/freq.h>
#define CPG2_FRQCR3 0xfe0a0018
static int frqcr3_divisors[] = { 1, 2, 3, 4, 6, 8, 16 };
static int frqcr3_values[] = { 0, 1, 2, 3, 4, 5, 6 };
static unsigned long emi_clk_recalc(struct clk *clk)
{
int idx = __raw_readl(CPG2_FRQCR3) & 0x0007;
return clk->parent->rate / frqcr3_divisors[idx];
}
static inline int frqcr3_lookup(struct clk *clk, unsigned long rate)
{
int divisor = clk->parent->rate / rate;
int i;
for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++)
if (frqcr3_divisors[i] == divisor)
return frqcr3_values[i];
/* Safe fallback */
return 5;
}
static struct sh_clk_ops sh4202_emi_clk_ops = {
.recalc = emi_clk_recalc,
};
static struct clk sh4202_emi_clk = {
.flags = CLK_ENABLE_ON_INIT,
.ops = &sh4202_emi_clk_ops,
};
static unsigned long femi_clk_recalc(struct clk *clk)
{
int idx = (__raw_readl(CPG2_FRQCR3) >> 3) & 0x0007;
return clk->parent->rate / frqcr3_divisors[idx];
}
static struct sh_clk_ops sh4202_femi_clk_ops = {
.recalc = femi_clk_recalc,
};
static struct clk sh4202_femi_clk = {
.flags = CLK_ENABLE_ON_INIT,
.ops = &sh4202_femi_clk_ops,
};
static void shoc_clk_init(struct clk *clk)
{
int i;
/*
* For some reason, the shoc_clk seems to be set to some really
* insane value at boot (values outside of the allowable frequency
* range for instance). We deal with this by scaling it back down
* to something sensible just in case.
*
* Start scaling from the high end down until we find something
* that passes rate verification..
*/
for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
int divisor = frqcr3_divisors[i];
if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0)
break;
}
WARN_ON(i == ARRAY_SIZE(frqcr3_divisors)); /* Undefined clock */
}
static unsigned long shoc_clk_recalc(struct clk *clk)
{
int idx = (__raw_readl(CPG2_FRQCR3) >> 6) & 0x0007;
return clk->parent->rate / frqcr3_divisors[idx];
}
static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate)
{
struct clk *bclk = clk_get(NULL, "bus_clk");
unsigned long bclk_rate = clk_get_rate(bclk);
clk_put(bclk);
if (rate > bclk_rate)
return 1;
if (rate > 66000000)
return 1;
return 0;
}
static int shoc_clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long frqcr3;
unsigned int tmp;
/* Make sure we have something sensible to switch to */
if (shoc_clk_verify_rate(clk, rate) != 0)
return -EINVAL;
tmp = frqcr3_lookup(clk, rate);
frqcr3 = __raw_readl(CPG2_FRQCR3);
frqcr3 &= ~(0x0007 << 6);
frqcr3 |= tmp << 6;
__raw_writel(frqcr3, CPG2_FRQCR3);
clk->rate = clk->parent->rate / frqcr3_divisors[tmp];
return 0;
}
static struct sh_clk_ops sh4202_shoc_clk_ops = {
.init = shoc_clk_init,
.recalc = shoc_clk_recalc,
.set_rate = shoc_clk_set_rate,
};
static struct clk sh4202_shoc_clk = {
.flags = CLK_ENABLE_ON_INIT,
.ops = &sh4202_shoc_clk_ops,
};
static struct clk *sh4202_onchip_clocks[] = {
&sh4202_emi_clk,
&sh4202_femi_clk,
&sh4202_shoc_clk,
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("emi_clk", &sh4202_emi_clk),
CLKDEV_CON_ID("femi_clk", &sh4202_femi_clk),
CLKDEV_CON_ID("shoc_clk", &sh4202_shoc_clk),
};
int __init arch_clk_init(void)
{
struct clk *clk;
int i, ret = 0;
cpg_clk_init();
clk = clk_get(NULL, "master_clk");
for (i = 0; i < ARRAY_SIZE(sh4202_onchip_clocks); i++) {
struct clk *clkp = sh4202_onchip_clocks[i];
clkp->parent = clk;
ret |= clk_register(clkp);
}
clk_put(clk);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
return ret;
}

View file

@ -0,0 +1,80 @@
/*
* arch/sh/kernel/cpu/sh4/clock-sh4.c
*
* Generic SH-4 support for the clock framework
*
* Copyright (C) 2005 Paul Mundt
*
* FRQCR parsing hacked out of arch/sh/kernel/time.c
*
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (C) 2002, 2003, 2004 Paul Mundt
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
*
* 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>
static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 };
#define bfc_divisors ifc_divisors /* Same */
static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 };
static void master_clk_init(struct clk *clk)
{
clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0007];
}
static struct sh_clk_ops sh4_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) & 0x0007);
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh4_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) >> 3) & 0x0007;
return clk->parent->rate / bfc_divisors[idx];
}
static struct sh_clk_ops sh4_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int idx = (__raw_readw(FRQCR) >> 6) & 0x0007;
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh4_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh4_clk_ops[] = {
&sh4_master_clk_ops,
&sh4_module_clk_ops,
&sh4_bus_clk_ops,
&sh4_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh4_clk_ops))
*ops = sh4_clk_ops[idx];
}

View file

@ -0,0 +1,429 @@
/*
* Save/restore floating point context for signal handlers.
*
* 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.
*
* Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
* Copyright (C) 2006 ST Microelectronics Ltd. (denorm support)
*
* FIXME! These routines have not been tested for big endian case.
*/
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/io.h>
#include <cpu/fpu.h>
#include <asm/processor.h>
#include <asm/fpu.h>
#include <asm/traps.h>
/* The PR (precision) bit in the FP Status Register must be clear when
* an frchg instruction is executed, otherwise the instruction is undefined.
* Executing frchg with PR set causes a trap on some SH4 implementations.
*/
#define FPSCR_RCHG 0x00000000
extern unsigned long long float64_div(unsigned long long a,
unsigned long long b);
extern unsigned long int float32_div(unsigned long int a, unsigned long int b);
extern unsigned long long float64_mul(unsigned long long a,
unsigned long long b);
extern unsigned long int float32_mul(unsigned long int a, unsigned long int b);
extern unsigned long long float64_add(unsigned long long a,
unsigned long long b);
extern unsigned long int float32_add(unsigned long int a, unsigned long int b);
extern unsigned long long float64_sub(unsigned long long a,
unsigned long long b);
extern unsigned long int float32_sub(unsigned long int a, unsigned long int b);
extern unsigned long int float64_to_float32(unsigned long long a);
static unsigned int fpu_exception_flags;
/*
* Save FPU registers onto task structure.
*/
void save_fpu(struct task_struct *tsk)
{
unsigned long dummy;
enable_fpu();
asm volatile ("sts.l fpul, @-%0\n\t"
"sts.l fpscr, @-%0\n\t"
"lds %2, fpscr\n\t"
"frchg\n\t"
"fmov.s fr15, @-%0\n\t"
"fmov.s fr14, @-%0\n\t"
"fmov.s fr13, @-%0\n\t"
"fmov.s fr12, @-%0\n\t"
"fmov.s fr11, @-%0\n\t"
"fmov.s fr10, @-%0\n\t"
"fmov.s fr9, @-%0\n\t"
"fmov.s fr8, @-%0\n\t"
"fmov.s fr7, @-%0\n\t"
"fmov.s fr6, @-%0\n\t"
"fmov.s fr5, @-%0\n\t"
"fmov.s fr4, @-%0\n\t"
"fmov.s fr3, @-%0\n\t"
"fmov.s fr2, @-%0\n\t"
"fmov.s fr1, @-%0\n\t"
"fmov.s fr0, @-%0\n\t"
"frchg\n\t"
"fmov.s fr15, @-%0\n\t"
"fmov.s fr14, @-%0\n\t"
"fmov.s fr13, @-%0\n\t"
"fmov.s fr12, @-%0\n\t"
"fmov.s fr11, @-%0\n\t"
"fmov.s fr10, @-%0\n\t"
"fmov.s fr9, @-%0\n\t"
"fmov.s fr8, @-%0\n\t"
"fmov.s fr7, @-%0\n\t"
"fmov.s fr6, @-%0\n\t"
"fmov.s fr5, @-%0\n\t"
"fmov.s fr4, @-%0\n\t"
"fmov.s fr3, @-%0\n\t"
"fmov.s fr2, @-%0\n\t"
"fmov.s fr1, @-%0\n\t"
"fmov.s fr0, @-%0\n\t"
"lds %3, fpscr\n\t":"=r" (dummy)
:"0"((char *)(&tsk->thread.xstate->hardfpu.status)),
"r"(FPSCR_RCHG), "r"(FPSCR_INIT)
:"memory");
disable_fpu();
}
void restore_fpu(struct task_struct *tsk)
{
unsigned long dummy;
enable_fpu();
asm volatile ("lds %2, fpscr\n\t"
"fmov.s @%0+, fr0\n\t"
"fmov.s @%0+, fr1\n\t"
"fmov.s @%0+, fr2\n\t"
"fmov.s @%0+, fr3\n\t"
"fmov.s @%0+, fr4\n\t"
"fmov.s @%0+, fr5\n\t"
"fmov.s @%0+, fr6\n\t"
"fmov.s @%0+, fr7\n\t"
"fmov.s @%0+, fr8\n\t"
"fmov.s @%0+, fr9\n\t"
"fmov.s @%0+, fr10\n\t"
"fmov.s @%0+, fr11\n\t"
"fmov.s @%0+, fr12\n\t"
"fmov.s @%0+, fr13\n\t"
"fmov.s @%0+, fr14\n\t"
"fmov.s @%0+, fr15\n\t"
"frchg\n\t"
"fmov.s @%0+, fr0\n\t"
"fmov.s @%0+, fr1\n\t"
"fmov.s @%0+, fr2\n\t"
"fmov.s @%0+, fr3\n\t"
"fmov.s @%0+, fr4\n\t"
"fmov.s @%0+, fr5\n\t"
"fmov.s @%0+, fr6\n\t"
"fmov.s @%0+, fr7\n\t"
"fmov.s @%0+, fr8\n\t"
"fmov.s @%0+, fr9\n\t"
"fmov.s @%0+, fr10\n\t"
"fmov.s @%0+, fr11\n\t"
"fmov.s @%0+, fr12\n\t"
"fmov.s @%0+, fr13\n\t"
"fmov.s @%0+, fr14\n\t"
"fmov.s @%0+, fr15\n\t"
"frchg\n\t"
"lds.l @%0+, fpscr\n\t"
"lds.l @%0+, fpul\n\t"
:"=r" (dummy)
:"0" (tsk->thread.xstate), "r" (FPSCR_RCHG)
:"memory");
disable_fpu();
}
/**
* denormal_to_double - Given denormalized float number,
* store double float
*
* @fpu: Pointer to sh_fpu_hard structure
* @n: Index to FP register
*/
static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n)
{
unsigned long du, dl;
unsigned long x = fpu->fpul;
int exp = 1023 - 126;
if (x != 0 && (x & 0x7f800000) == 0) {
du = (x & 0x80000000);
while ((x & 0x00800000) == 0) {
x <<= 1;
exp--;
}
x &= 0x007fffff;
du |= (exp << 20) | (x >> 3);
dl = x << 29;
fpu->fp_regs[n] = du;
fpu->fp_regs[n + 1] = dl;
}
}
/**
* ieee_fpe_handler - Handle denormalized number exception
*
* @regs: Pointer to register structure
*
* Returns 1 when it's handled (should not cause exception).
*/
static int ieee_fpe_handler(struct pt_regs *regs)
{
unsigned short insn = *(unsigned short *)regs->pc;
unsigned short finsn;
unsigned long nextpc;
int nib[4] = {
(insn >> 12) & 0xf,
(insn >> 8) & 0xf,
(insn >> 4) & 0xf,
insn & 0xf
};
if (nib[0] == 0xb || (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb))
regs->pr = regs->pc + 4; /* bsr & jsr */
if (nib[0] == 0xa || nib[0] == 0xb) {
/* bra & bsr */
nextpc = regs->pc + 4 + ((short)((insn & 0xfff) << 4) >> 3);
finsn = *(unsigned short *)(regs->pc + 2);
} else if (nib[0] == 0x8 && nib[1] == 0xd) {
/* bt/s */
if (regs->sr & 1)
nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
else
nextpc = regs->pc + 4;
finsn = *(unsigned short *)(regs->pc + 2);
} else if (nib[0] == 0x8 && nib[1] == 0xf) {
/* bf/s */
if (regs->sr & 1)
nextpc = regs->pc + 4;
else
nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
finsn = *(unsigned short *)(regs->pc + 2);
} else if (nib[0] == 0x4 && nib[3] == 0xb &&
(nib[2] == 0x0 || nib[2] == 0x2)) {
/* jmp & jsr */
nextpc = regs->regs[nib[1]];
finsn = *(unsigned short *)(regs->pc + 2);
} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
(nib[2] == 0x0 || nib[2] == 0x2)) {
/* braf & bsrf */
nextpc = regs->pc + 4 + regs->regs[nib[1]];
finsn = *(unsigned short *)(regs->pc + 2);
} else if (insn == 0x000b) {
/* rts */
nextpc = regs->pr;
finsn = *(unsigned short *)(regs->pc + 2);
} else {
nextpc = regs->pc + instruction_size(insn);
finsn = insn;
}
if ((finsn & 0xf1ff) == 0xf0ad) {
/* fcnvsd */
struct task_struct *tsk = current;
if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_CAUSE_ERROR))
/* FPU error */
denormal_to_double(&tsk->thread.xstate->hardfpu,
(finsn >> 8) & 0xf);
else
return 0;
regs->pc = nextpc;
return 1;
} else if ((finsn & 0xf00f) == 0xf002) {
/* fmul */
struct task_struct *tsk = current;
int fpscr;
int n, m, prec;
unsigned int hx, hy;
n = (finsn >> 8) & 0xf;
m = (finsn >> 4) & 0xf;
hx = tsk->thread.xstate->hardfpu.fp_regs[n];
hy = tsk->thread.xstate->hardfpu.fp_regs[m];
fpscr = tsk->thread.xstate->hardfpu.fpscr;
prec = fpscr & FPSCR_DBL_PRECISION;
if ((fpscr & FPSCR_CAUSE_ERROR)
&& (prec && ((hx & 0x7fffffff) < 0x00100000
|| (hy & 0x7fffffff) < 0x00100000))) {
long long llx, lly;
/* FPU error because of denormal (doubles) */
llx = ((long long)hx << 32)
| tsk->thread.xstate->hardfpu.fp_regs[n + 1];
lly = ((long long)hy << 32)
| tsk->thread.xstate->hardfpu.fp_regs[m + 1];
llx = float64_mul(llx, lly);
tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff;
} else if ((fpscr & FPSCR_CAUSE_ERROR)
&& (!prec && ((hx & 0x7fffffff) < 0x00800000
|| (hy & 0x7fffffff) < 0x00800000))) {
/* FPU error because of denormal (floats) */
hx = float32_mul(hx, hy);
tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
} else
return 0;
regs->pc = nextpc;
return 1;
} else if ((finsn & 0xf00e) == 0xf000) {
/* fadd, fsub */
struct task_struct *tsk = current;
int fpscr;
int n, m, prec;
unsigned int hx, hy;
n = (finsn >> 8) & 0xf;
m = (finsn >> 4) & 0xf;
hx = tsk->thread.xstate->hardfpu.fp_regs[n];
hy = tsk->thread.xstate->hardfpu.fp_regs[m];
fpscr = tsk->thread.xstate->hardfpu.fpscr;
prec = fpscr & FPSCR_DBL_PRECISION;
if ((fpscr & FPSCR_CAUSE_ERROR)
&& (prec && ((hx & 0x7fffffff) < 0x00100000
|| (hy & 0x7fffffff) < 0x00100000))) {
long long llx, lly;
/* FPU error because of denormal (doubles) */
llx = ((long long)hx << 32)
| tsk->thread.xstate->hardfpu.fp_regs[n + 1];
lly = ((long long)hy << 32)
| tsk->thread.xstate->hardfpu.fp_regs[m + 1];
if ((finsn & 0xf00f) == 0xf000)
llx = float64_add(llx, lly);
else
llx = float64_sub(llx, lly);
tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff;
} else if ((fpscr & FPSCR_CAUSE_ERROR)
&& (!prec && ((hx & 0x7fffffff) < 0x00800000
|| (hy & 0x7fffffff) < 0x00800000))) {
/* FPU error because of denormal (floats) */
if ((finsn & 0xf00f) == 0xf000)
hx = float32_add(hx, hy);
else
hx = float32_sub(hx, hy);
tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
} else
return 0;
regs->pc = nextpc;
return 1;
} else if ((finsn & 0xf003) == 0xf003) {
/* fdiv */
struct task_struct *tsk = current;
int fpscr;
int n, m, prec;
unsigned int hx, hy;
n = (finsn >> 8) & 0xf;
m = (finsn >> 4) & 0xf;
hx = tsk->thread.xstate->hardfpu.fp_regs[n];
hy = tsk->thread.xstate->hardfpu.fp_regs[m];
fpscr = tsk->thread.xstate->hardfpu.fpscr;
prec = fpscr & FPSCR_DBL_PRECISION;
if ((fpscr & FPSCR_CAUSE_ERROR)
&& (prec && ((hx & 0x7fffffff) < 0x00100000
|| (hy & 0x7fffffff) < 0x00100000))) {
long long llx, lly;
/* FPU error because of denormal (doubles) */
llx = ((long long)hx << 32)
| tsk->thread.xstate->hardfpu.fp_regs[n + 1];
lly = ((long long)hy << 32)
| tsk->thread.xstate->hardfpu.fp_regs[m + 1];
llx = float64_div(llx, lly);
tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff;
} else if ((fpscr & FPSCR_CAUSE_ERROR)
&& (!prec && ((hx & 0x7fffffff) < 0x00800000
|| (hy & 0x7fffffff) < 0x00800000))) {
/* FPU error because of denormal (floats) */
hx = float32_div(hx, hy);
tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
} else
return 0;
regs->pc = nextpc;
return 1;
} else if ((finsn & 0xf0bd) == 0xf0bd) {
/* fcnvds - double to single precision convert */
struct task_struct *tsk = current;
int m;
unsigned int hx;
m = (finsn >> 8) & 0x7;
hx = tsk->thread.xstate->hardfpu.fp_regs[m];
if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_CAUSE_ERROR)
&& ((hx & 0x7fffffff) < 0x00100000)) {
/* subnormal double to float conversion */
long long llx;
llx = ((long long)tsk->thread.xstate->hardfpu.fp_regs[m] << 32)
| tsk->thread.xstate->hardfpu.fp_regs[m + 1];
tsk->thread.xstate->hardfpu.fpul = float64_to_float32(llx);
} else
return 0;
regs->pc = nextpc;
return 1;
}
return 0;
}
void float_raise(unsigned int flags)
{
fpu_exception_flags |= flags;
}
int float_rounding_mode(void)
{
struct task_struct *tsk = current;
int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.xstate->hardfpu.fpscr);
return roundingMode;
}
BUILD_TRAP_HANDLER(fpu_error)
{
struct task_struct *tsk = current;
TRAP_HANDLER_DECL;
__unlazy_fpu(tsk, regs);
fpu_exception_flags = 0;
if (ieee_fpe_handler(regs)) {
tsk->thread.xstate->hardfpu.fpscr &=
~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
tsk->thread.xstate->hardfpu.fpscr |= fpu_exception_flags;
/* Set the FPSCR flag as well as cause bits - simply
* replicate the cause */
tsk->thread.xstate->hardfpu.fpscr |= (fpu_exception_flags >> 10);
grab_fpu(regs);
restore_fpu(tsk);
task_thread_info(tsk)->status |= TS_USEDFPU;
if ((((tsk->thread.xstate->hardfpu.fpscr & FPSCR_ENABLE_MASK) >> 7) &
(fpu_exception_flags >> 2)) == 0) {
return;
}
}
force_sig(SIGFPE, tsk);
}

View file

@ -0,0 +1,268 @@
/*
* Performance events support for SH7750-style performance counters
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/perf_event.h>
#include <asm/processor.h>
#define PM_CR_BASE 0xff000084 /* 16-bit */
#define PM_CTR_BASE 0xff100004 /* 32-bit */
#define PMCR(n) (PM_CR_BASE + ((n) * 0x04))
#define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08))
#define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08))
#define PMCR_PMM_MASK 0x0000003f
#define PMCR_CLKF 0x00000100
#define PMCR_PMCLR 0x00002000
#define PMCR_PMST 0x00004000
#define PMCR_PMEN 0x00008000
static struct sh_pmu sh7750_pmu;
/*
* There are a number of events supported by each counter (33 in total).
* Since we have 2 counters, each counter will take the event code as it
* corresponds to the PMCR PMM setting. Each counter can be configured
* independently.
*
* Event Code Description
* ---------- -----------
*
* 0x01 Operand read access
* 0x02 Operand write access
* 0x03 UTLB miss
* 0x04 Operand cache read miss
* 0x05 Operand cache write miss
* 0x06 Instruction fetch (w/ cache)
* 0x07 Instruction TLB miss
* 0x08 Instruction cache miss
* 0x09 All operand accesses
* 0x0a All instruction accesses
* 0x0b OC RAM operand access
* 0x0d On-chip I/O space access
* 0x0e Operand access (r/w)
* 0x0f Operand cache miss (r/w)
* 0x10 Branch instruction
* 0x11 Branch taken
* 0x12 BSR/BSRF/JSR
* 0x13 Instruction execution
* 0x14 Instruction execution in parallel
* 0x15 FPU Instruction execution
* 0x16 Interrupt
* 0x17 NMI
* 0x18 trapa instruction execution
* 0x19 UBCA match
* 0x1a UBCB match
* 0x21 Instruction cache fill
* 0x22 Operand cache fill
* 0x23 Elapsed time
* 0x24 Pipeline freeze by I-cache miss
* 0x25 Pipeline freeze by D-cache miss
* 0x27 Pipeline freeze by branch instruction
* 0x28 Pipeline freeze by CPU register
* 0x29 Pipeline freeze by FPU
*/
static const int sh7750_general_events[] = {
[PERF_COUNT_HW_CPU_CYCLES] = 0x0023,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x000a,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x0006, /* I-cache */
[PERF_COUNT_HW_CACHE_MISSES] = 0x0008, /* I-cache */
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0010,
[PERF_COUNT_HW_BRANCH_MISSES] = -1,
[PERF_COUNT_HW_BUS_CYCLES] = -1,
};
#define C(x) PERF_COUNT_HW_CACHE_##x
static const int sh7750_cache_events
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
{
[ C(L1D) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0001,
[ C(RESULT_MISS) ] = 0x0004,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0002,
[ C(RESULT_MISS) ] = 0x0005,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(L1I) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0006,
[ C(RESULT_MISS) ] = 0x0008,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(LL) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(DTLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0x0003,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(ITLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0x0007,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
[ C(BPU) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
[ C(NODE) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
};
static int sh7750_event_map(int event)
{
return sh7750_general_events[event];
}
static u64 sh7750_pmu_read(int idx)
{
return (u64)((u64)(__raw_readl(PMCTRH(idx)) & 0xffff) << 32) |
__raw_readl(PMCTRL(idx));
}
static void sh7750_pmu_disable(struct hw_perf_event *hwc, int idx)
{
unsigned int tmp;
tmp = __raw_readw(PMCR(idx));
tmp &= ~(PMCR_PMM_MASK | PMCR_PMEN);
__raw_writew(tmp, PMCR(idx));
}
static void sh7750_pmu_enable(struct hw_perf_event *hwc, int idx)
{
__raw_writew(__raw_readw(PMCR(idx)) | PMCR_PMCLR, PMCR(idx));
__raw_writew(hwc->config | PMCR_PMEN | PMCR_PMST, PMCR(idx));
}
static void sh7750_pmu_disable_all(void)
{
int i;
for (i = 0; i < sh7750_pmu.num_events; i++)
__raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i));
}
static void sh7750_pmu_enable_all(void)
{
int i;
for (i = 0; i < sh7750_pmu.num_events; i++)
__raw_writew(__raw_readw(PMCR(i)) | PMCR_PMEN, PMCR(i));
}
static struct sh_pmu sh7750_pmu = {
.name = "sh7750",
.num_events = 2,
.event_map = sh7750_event_map,
.max_events = ARRAY_SIZE(sh7750_general_events),
.raw_event_mask = PMCR_PMM_MASK,
.cache_events = &sh7750_cache_events,
.read = sh7750_pmu_read,
.disable = sh7750_pmu_disable,
.enable = sh7750_pmu_enable,
.disable_all = sh7750_pmu_disable_all,
.enable_all = sh7750_pmu_enable_all,
};
static int __init sh7750_pmu_init(void)
{
/*
* Make sure this CPU actually has perf counters.
*/
if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
pr_notice("HW perf events unsupported, software events only.\n");
return -ENODEV;
}
return register_sh_pmu(&sh7750_pmu);
}
early_initcall(sh7750_pmu_init);

View file

@ -0,0 +1,263 @@
/*
* arch/sh/kernel/cpu/sh4/probe.c
*
* CPU Subtype Probing for SH-4.
*
* Copyright (C) 2001 - 2007 Paul Mundt
* Copyright (C) 2003 Richard Curnow
*
* 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/io.h>
#include <asm/processor.h>
#include <asm/cache.h>
void cpu_probe(void)
{
unsigned long pvr, prr, cvr;
unsigned long size;
static unsigned long sizes[16] = {
[1] = (1 << 12),
[2] = (1 << 13),
[4] = (1 << 14),
[8] = (1 << 15),
[9] = (1 << 16)
};
pvr = (__raw_readl(CCN_PVR) >> 8) & 0xffffff;
prr = (__raw_readl(CCN_PRR) >> 4) & 0xff;
cvr = (__raw_readl(CCN_CVR));
/*
* Setup some sane SH-4 defaults for the icache
*/
boot_cpu_data.icache.way_incr = (1 << 13);
boot_cpu_data.icache.entry_shift = 5;
boot_cpu_data.icache.sets = 256;
boot_cpu_data.icache.ways = 1;
boot_cpu_data.icache.linesz = L1_CACHE_BYTES;
/*
* And again for the dcache ..
*/
boot_cpu_data.dcache.way_incr = (1 << 14);
boot_cpu_data.dcache.entry_shift = 5;
boot_cpu_data.dcache.sets = 512;
boot_cpu_data.dcache.ways = 1;
boot_cpu_data.dcache.linesz = L1_CACHE_BYTES;
/* We don't know the chip cut */
boot_cpu_data.cut_major = boot_cpu_data.cut_minor = -1;
/*
* Setup some generic flags we can probe on SH-4A parts
*/
if (((pvr >> 16) & 0xff) == 0x10) {
boot_cpu_data.family = CPU_FAMILY_SH4A;
if ((cvr & 0x10000000) == 0) {
boot_cpu_data.flags |= CPU_HAS_DSP;
boot_cpu_data.family = CPU_FAMILY_SH4AL_DSP;
}
boot_cpu_data.flags |= CPU_HAS_LLSC | CPU_HAS_PERF_COUNTER;
boot_cpu_data.cut_major = pvr & 0x7f;
boot_cpu_data.icache.ways = 4;
boot_cpu_data.dcache.ways = 4;
} else {
/* And some SH-4 defaults.. */
boot_cpu_data.flags |= CPU_HAS_PTEA | CPU_HAS_FPU;
boot_cpu_data.family = CPU_FAMILY_SH4;
}
/* FPU detection works for almost everyone */
if ((cvr & 0x20000000))
boot_cpu_data.flags |= CPU_HAS_FPU;
/* Mask off the upper chip ID */
pvr &= 0xffff;
/*
* Probe the underlying processor version/revision and
* adjust cpu_data setup accordingly.
*/
switch (pvr) {
case 0x205:
boot_cpu_data.type = CPU_SH7750;
boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG |
CPU_HAS_PERF_COUNTER;
break;
case 0x206:
boot_cpu_data.type = CPU_SH7750S;
boot_cpu_data.flags |= CPU_HAS_P2_FLUSH_BUG |
CPU_HAS_PERF_COUNTER;
break;
case 0x1100:
boot_cpu_data.type = CPU_SH7751;
break;
case 0x2001:
case 0x2004:
boot_cpu_data.type = CPU_SH7770;
break;
case 0x2006:
case 0x200A:
if (prr == 0x61)
boot_cpu_data.type = CPU_SH7781;
else if (prr == 0xa1)
boot_cpu_data.type = CPU_SH7763;
else
boot_cpu_data.type = CPU_SH7780;
break;
case 0x3000:
case 0x3003:
case 0x3009:
boot_cpu_data.type = CPU_SH7343;
break;
case 0x3004:
case 0x3007:
boot_cpu_data.type = CPU_SH7785;
break;
case 0x4004:
case 0x4005:
boot_cpu_data.type = CPU_SH7786;
boot_cpu_data.flags |= CPU_HAS_PTEAEX | CPU_HAS_L2_CACHE;
break;
case 0x3008:
switch (prr) {
case 0x50:
case 0x51:
boot_cpu_data.type = CPU_SH7723;
boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
break;
case 0x70:
boot_cpu_data.type = CPU_SH7366;
break;
case 0xa0:
case 0xa1:
boot_cpu_data.type = CPU_SH7722;
break;
}
break;
case 0x300b:
switch (prr) {
case 0x20:
boot_cpu_data.type = CPU_SH7724;
boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
break;
case 0x10:
case 0x11:
boot_cpu_data.type = CPU_SH7757;
break;
case 0xd0:
case 0x40: /* yon-ten-go */
boot_cpu_data.type = CPU_SH7372;
break;
case 0xE0: /* 0x4E0 */
boot_cpu_data.type = CPU_SH7734; /* SH7733/SH7734 */
break;
}
break;
case 0x4000: /* 1st cut */
case 0x4001: /* 2nd cut */
boot_cpu_data.type = CPU_SHX3;
break;
case 0x700:
boot_cpu_data.type = CPU_SH4_501;
boot_cpu_data.flags &= ~CPU_HAS_FPU;
boot_cpu_data.icache.ways = 2;
boot_cpu_data.dcache.ways = 2;
break;
case 0x600:
boot_cpu_data.type = CPU_SH4_202;
boot_cpu_data.icache.ways = 2;
boot_cpu_data.dcache.ways = 2;
break;
case 0x500 ... 0x501:
switch (prr) {
case 0x10:
boot_cpu_data.type = CPU_SH7750R;
break;
case 0x11:
boot_cpu_data.type = CPU_SH7751R;
break;
case 0x50 ... 0x5f:
boot_cpu_data.type = CPU_SH7760;
break;
}
boot_cpu_data.icache.ways = 2;
boot_cpu_data.dcache.ways = 2;
break;
}
/*
* On anything that's not a direct-mapped cache, look to the CVR
* for I/D-cache specifics.
*/
if (boot_cpu_data.icache.ways > 1) {
size = sizes[(cvr >> 20) & 0xf];
boot_cpu_data.icache.way_incr = (size >> 1);
boot_cpu_data.icache.sets = (size >> 6);
}
/* And the rest of the D-cache */
if (boot_cpu_data.dcache.ways > 1) {
size = sizes[(cvr >> 16) & 0xf];
boot_cpu_data.dcache.way_incr = (size >> 1);
boot_cpu_data.dcache.sets = (size >> 6);
}
/*
* SH-4A's have an optional PIPT L2.
*/
if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) {
/*
* Verify that it really has something hooked up, this
* is the safety net for CPUs that have optional L2
* support yet do not implement it.
*/
if ((cvr & 0xf) == 0)
boot_cpu_data.flags &= ~CPU_HAS_L2_CACHE;
else {
/*
* Silicon and specifications have clearly never
* met..
*/
cvr ^= 0xf;
/*
* Size calculation is much more sensible
* than it is for the L1.
*
* Sizes are 128KB, 256KB, 512KB, and 1MB.
*/
size = (cvr & 0xf) << 17;
boot_cpu_data.scache.way_incr = (1 << 16);
boot_cpu_data.scache.entry_shift = 5;
boot_cpu_data.scache.ways = 4;
boot_cpu_data.scache.linesz = L1_CACHE_BYTES;
boot_cpu_data.scache.entry_mask =
(boot_cpu_data.scache.way_incr -
boot_cpu_data.scache.linesz);
boot_cpu_data.scache.sets = size /
(boot_cpu_data.scache.linesz *
boot_cpu_data.scache.ways);
boot_cpu_data.scache.way_size =
(boot_cpu_data.scache.sets *
boot_cpu_data.scache.linesz);
}
}
}

View file

@ -0,0 +1,142 @@
/*
* SH4-202 Setup
*
* Copyright (C) 2006 Paul Mundt
* Copyright (C) 2009 Magnus Damm
*
* 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_timer.h>
#include <linux/sh_intc.h>
#include <linux/io.h>
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(0xffe80000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x700)),
DEFINE_RES_IRQ(evt2irq(0x720)),
DEFINE_RES_IRQ(evt2irq(0x760)),
DEFINE_RES_IRQ(evt2irq(0x740)),
};
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 sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xffd80000, 0x30),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh4202_devices[] __initdata = {
&scif0_device,
&tmu0_device,
};
static int __init sh4202_devices_setup(void)
{
return platform_add_devices(sh4202_devices,
ARRAY_SIZE(sh4202_devices));
}
arch_initcall(sh4202_devices_setup);
static struct platform_device *sh4202_early_devices[] __initdata = {
&scif0_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh4202_early_devices,
ARRAY_SIZE(sh4202_early_devices));
}
enum {
UNUSED = 0,
/* interrupt sources */
IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
HUDI, TMU0, TMU1, TMU2, RTC, SCIF, WDT,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(HUDI, 0x600),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
INTC_VECT(RTC, 0x4c0),
INTC_VECT(SCIF, 0x700), INTC_VECT(SCIF, 0x720),
INTC_VECT(SCIF, 0x740), INTC_VECT(SCIF, 0x760),
INTC_VECT(WDT, 0x560),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, 0, 0, 0 } },
{ 0xffd0000c, 0, 16, 4, /* IPRC */ { 0, 0, SCIF, HUDI } },
{ 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
};
static DECLARE_INTC_DESC(intc_desc, "sh4-202", vectors, NULL,
NULL, prio_registers, NULL);
static struct intc_vect vectors_irlm[] __initdata = {
INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
};
static DECLARE_INTC_DESC(intc_desc_irlm, "sh4-202_irlm", vectors_irlm, NULL,
NULL, prio_registers, NULL);
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
#define INTC_ICR 0xffd00000UL
#define INTC_ICR_IRLM (1<<7)
void __init plat_irq_setup_pins(int mode)
{
switch (mode) {
case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */
__raw_writew(__raw_readw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
register_intc_controller(&intc_desc_irlm);
break;
default:
BUG();
}
}

View file

@ -0,0 +1,366 @@
/*
* SH7091/SH7750/SH7750S/SH7750R/SH7751/SH7751R Setup
*
* Copyright (C) 2006 Paul Mundt
* Copyright (C) 2006 Jamie Lenehan
*
* 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/io.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <generated/machtypes.h>
static struct resource rtc_resources[] = {
[0] = {
.start = 0xffc80000,
.end = 0xffc80000 + 0x58 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
.start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
static struct plat_sci_port sci_platform_data = {
.port_reg = 0xffe0001C,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_TE | SCSCR_RE,
.type = PORT_SCI,
.regshift = 2,
};
static struct resource sci_resources[] = {
DEFINE_RES_MEM(0xffe00000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x4e0)),
};
static struct platform_device sci_device = {
.name = "sh-sci",
.id = 0,
.resource = sci_resources,
.num_resources = ARRAY_SIZE(sci_resources),
.dev = {
.platform_data = &sci_platform_data,
},
};
static struct plat_sci_port scif_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_TE | SCSCR_RE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif_resources[] = {
DEFINE_RES_MEM(0xffe80000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x700)),
};
static struct platform_device scif_device = {
.name = "sh-sci",
.id = 1,
.resource = scif_resources,
.num_resources = ARRAY_SIZE(scif_resources),
.dev = {
.platform_data = &scif_platform_data,
},
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xffd80000, 0x30),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R)
static struct sh_timer_config tmu1_platform_data = {
.channels_mask = 3,
};
static struct resource tmu1_resources[] = {
DEFINE_RES_MEM(0xfe100000, 0x20),
DEFINE_RES_IRQ(evt2irq(0xb00)),
DEFINE_RES_IRQ(evt2irq(0xb80)),
};
static struct platform_device tmu1_device = {
.name = "sh-tmu",
.id = 1,
.dev = {
.platform_data = &tmu1_platform_data,
},
.resource = tmu1_resources,
.num_resources = ARRAY_SIZE(tmu1_resources),
};
#endif
static struct platform_device *sh7750_devices[] __initdata = {
&rtc_device,
&tmu0_device,
#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R)
&tmu1_device,
#endif
};
static int __init sh7750_devices_setup(void)
{
if (mach_is_rts7751r2d()) {
platform_device_register(&scif_device);
} else {
platform_device_register(&sci_device);
platform_device_register(&scif_device);
}
return platform_add_devices(sh7750_devices,
ARRAY_SIZE(sh7750_devices));
}
arch_initcall(sh7750_devices_setup);
static struct platform_device *sh7750_early_devices[] __initdata = {
&tmu0_device,
#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R)
&tmu1_device,
#endif
};
void __init plat_early_device_setup(void)
{
struct platform_device *dev[1];
if (mach_is_rts7751r2d()) {
scif_platform_data.scscr |= SCSCR_CKE1;
dev[0] = &scif_device;
early_platform_add_devices(dev, 1);
} else {
dev[0] = &sci_device;
early_platform_add_devices(dev, 1);
dev[0] = &scif_device;
early_platform_add_devices(dev, 1);
}
early_platform_add_devices(sh7750_early_devices,
ARRAY_SIZE(sh7750_early_devices));
}
enum {
UNUSED = 0,
/* interrupt sources */
IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
HUDI, GPIOI, DMAC,
PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
TMU3, TMU4, TMU0, TMU1, TMU2, RTC, SCI1, SCIF, WDT, REF,
/* interrupt groups */
PCIC1,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
INTC_VECT(RTC, 0x4c0),
INTC_VECT(SCI1, 0x4e0), INTC_VECT(SCI1, 0x500),
INTC_VECT(SCI1, 0x520), INTC_VECT(SCI1, 0x540),
INTC_VECT(SCIF, 0x700), INTC_VECT(SCIF, 0x720),
INTC_VECT(SCIF, 0x740), INTC_VECT(SCIF, 0x760),
INTC_VECT(WDT, 0x560),
INTC_VECT(REF, 0x580), INTC_VECT(REF, 0x5a0),
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
{ 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
{ 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
{ 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
{ 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
TMU4, TMU3,
PCIC1, PCIC0_PCISERR } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, NULL,
NULL, prio_registers, NULL);
/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7091)
static struct intc_vect vectors_dma4[] __initdata = {
INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
INTC_VECT(DMAC, 0x6c0),
};
static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
vectors_dma4, NULL,
NULL, prio_registers, NULL);
#endif
/* SH7750R and SH7751R both have 8-channel DMA controllers */
#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
static struct intc_vect vectors_dma8[] __initdata = {
INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
INTC_VECT(DMAC, 0x780), INTC_VECT(DMAC, 0x7a0),
INTC_VECT(DMAC, 0x7c0), INTC_VECT(DMAC, 0x7e0),
INTC_VECT(DMAC, 0x6c0),
};
static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
vectors_dma8, NULL,
NULL, prio_registers, NULL);
#endif
/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R)
static struct intc_vect vectors_tmu34[] __initdata = {
INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, TMU4, TMU3,
PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
PCIC1_PCIDMA3, PCIC0_PCISERR } },
};
static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
vectors_tmu34, NULL,
mask_registers, prio_registers, NULL);
#endif
/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
static struct intc_vect vectors_irlm[] __initdata = {
INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
};
static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
NULL, prio_registers, NULL);
/* SH7751 and SH7751R both have PCI */
#if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
static struct intc_vect vectors_pci[] __initdata = {
INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
};
static struct intc_group groups_pci[] __initdata = {
INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
};
static DECLARE_INTC_DESC(intc_desc_pci, "sh7750_pci", vectors_pci, groups_pci,
mask_registers, prio_registers, NULL);
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
defined(CONFIG_CPU_SUBTYPE_SH7091)
void __init plat_irq_setup(void)
{
/*
* same vectors for SH7750, SH7750S and SH7091 except for IRLM,
* see below..
*/
register_intc_controller(&intc_desc);
register_intc_controller(&intc_desc_dma4);
}
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7750R)
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
register_intc_controller(&intc_desc_dma8);
register_intc_controller(&intc_desc_tmu34);
}
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7751)
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
register_intc_controller(&intc_desc_dma4);
register_intc_controller(&intc_desc_tmu34);
register_intc_controller(&intc_desc_pci);
}
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7751R)
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
register_intc_controller(&intc_desc_dma8);
register_intc_controller(&intc_desc_tmu34);
register_intc_controller(&intc_desc_pci);
}
#endif
#define INTC_ICR 0xffd00000UL
#define INTC_ICR_IRLM (1<<7)
void __init plat_irq_setup_pins(int mode)
{
#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091)
BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */
return;
#endif
switch (mode) {
case IRQ_MODE_IRQ: /* individual interrupt mode for IRL3-0 */
__raw_writew(__raw_readw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
register_intc_controller(&intc_desc_irlm);
break;
default:
BUG();
}
}

View file

@ -0,0 +1,298 @@
/*
* SH7760 Setup
*
* Copyright (C) 2006 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/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <linux/io.h>
enum {
UNUSED = 0,
/* interrupt sources */
IRL0, IRL1, IRL2, IRL3,
HUDI, GPIOI, DMAC,
IRQ4, IRQ5, IRQ6, IRQ7,
HCAN20, HCAN21,
SSI0, SSI1,
HAC0, HAC1,
I2C0, I2C1,
USB, LCDC,
DMABRG0, DMABRG1, DMABRG2,
SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI,
SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
HSPI,
MMCIF0, MMCIF1, MMCIF2, MMCIF3,
MFI, ADC, CMT,
TMU0, TMU1, TMU2,
WDT, REF,
/* interrupt groups */
DMABRG, SCIF0, SCIF1, SCIF2, SIM, MMCIF,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
INTC_VECT(DMAC, 0x780), INTC_VECT(DMAC, 0x7a0),
INTC_VECT(DMAC, 0x7c0), INTC_VECT(DMAC, 0x7e0),
INTC_VECT(DMAC, 0x6c0),
INTC_VECT(IRQ4, 0x800), INTC_VECT(IRQ5, 0x820),
INTC_VECT(IRQ6, 0x840), INTC_VECT(IRQ6, 0x860),
INTC_VECT(HCAN20, 0x900), INTC_VECT(HCAN21, 0x920),
INTC_VECT(SSI0, 0x940), INTC_VECT(SSI1, 0x960),
INTC_VECT(HAC0, 0x980), INTC_VECT(HAC1, 0x9a0),
INTC_VECT(I2C0, 0x9c0), INTC_VECT(I2C1, 0x9e0),
INTC_VECT(USB, 0xa00), INTC_VECT(LCDC, 0xa20),
INTC_VECT(DMABRG0, 0xa80), INTC_VECT(DMABRG1, 0xaa0),
INTC_VECT(DMABRG2, 0xac0),
INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0),
INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0),
INTC_VECT(SCIF1_ERI, 0xb00), INTC_VECT(SCIF1_RXI, 0xb20),
INTC_VECT(SCIF1_BRI, 0xb40), INTC_VECT(SCIF1_TXI, 0xb60),
INTC_VECT(SCIF2_ERI, 0xb80), INTC_VECT(SCIF2_RXI, 0xba0),
INTC_VECT(SCIF2_BRI, 0xbc0), INTC_VECT(SCIF2_TXI, 0xbe0),
INTC_VECT(SIM_ERI, 0xc00), INTC_VECT(SIM_RXI, 0xc20),
INTC_VECT(SIM_TXI, 0xc40), INTC_VECT(SIM_TEI, 0xc60),
INTC_VECT(HSPI, 0xc80),
INTC_VECT(MMCIF0, 0xd00), INTC_VECT(MMCIF1, 0xd20),
INTC_VECT(MMCIF2, 0xd40), INTC_VECT(MMCIF3, 0xd60),
INTC_VECT(MFI, 0xe80), /* 0xf80 according to data sheet */
INTC_VECT(ADC, 0xf80), INTC_VECT(CMT, 0xfa0),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
INTC_VECT(WDT, 0x560),
INTC_VECT(REF, 0x580), INTC_VECT(REF, 0x5a0),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(DMABRG, DMABRG0, DMABRG1, DMABRG2),
INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
INTC_GROUP(MMCIF, MMCIF0, MMCIF1, MMCIF2, MMCIF3),
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
{ IRQ4, IRQ5, IRQ6, IRQ7, 0, 0, HCAN20, HCAN21,
SSI0, SSI1, HAC0, HAC1, I2C0, I2C1, USB, LCDC,
0, DMABRG0, DMABRG1, DMABRG2,
SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, } },
{ 0xfe080044, 0xfe080064, 32, /* INTMSK04 / INTMSKCLR04 */
{ 0, 0, 0, 0, 0, 0, 0, 0,
SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
HSPI, MMCIF0, MMCIF1, MMCIF2,
MMCIF3, 0, 0, 0, 0, 0, 0, 0,
0, MFI, 0, 0, 0, 0, ADC, CMT, } },
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2 } },
{ 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, 0, 0 } },
{ 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, 0, HUDI } },
{ 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
{ 0xfe080000, 0, 32, 4, /* INTPRI00 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
{ 0xfe080004, 0, 32, 4, /* INTPRI04 */ { HCAN20, HCAN21, SSI0, SSI1,
HAC0, HAC1, I2C0, I2C1 } },
{ 0xfe080008, 0, 32, 4, /* INTPRI08 */ { USB, LCDC, DMABRG, SCIF0,
SCIF1, SCIF2, SIM, HSPI } },
{ 0xfe08000c, 0, 32, 4, /* INTPRI0C */ { 0, 0, MMCIF, 0,
MFI, 0, ADC, CMT } },
};
static DECLARE_INTC_DESC(intc_desc, "sh7760", vectors, groups,
mask_registers, prio_registers, NULL);
static struct intc_vect vectors_irq[] __initdata = {
INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
};
static DECLARE_INTC_DESC(intc_desc_irq, "sh7760-irq", vectors_irq, groups,
mask_registers, 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,
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xfe600000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x880)),
DEFINE_RES_IRQ(evt2irq(0x8a0)),
DEFINE_RES_IRQ(evt2irq(0x8e0)),
DEFINE_RES_IRQ(evt2irq(0x8c0)),
};
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,
.type = PORT_SCIF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xfe610000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xb00)),
DEFINE_RES_IRQ(evt2irq(0xb20)),
DEFINE_RES_IRQ(evt2irq(0xb60)),
DEFINE_RES_IRQ(evt2irq(0xb40)),
};
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,
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xfe620000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xb80)),
DEFINE_RES_IRQ(evt2irq(0xba0)),
DEFINE_RES_IRQ(evt2irq(0xbe0)),
DEFINE_RES_IRQ(evt2irq(0xbc0)),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCI,
.regshift = 2,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xfe480000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc00)),
DEFINE_RES_IRQ(evt2irq(0xc20)),
DEFINE_RES_IRQ(evt2irq(0xc40)),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xffd80000, 0x30),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh7760_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&tmu0_device,
};
static int __init sh7760_devices_setup(void)
{
return platform_add_devices(sh7760_devices,
ARRAY_SIZE(sh7760_devices));
}
arch_initcall(sh7760_devices_setup);
static struct platform_device *sh7760_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7760_early_devices,
ARRAY_SIZE(sh7760_early_devices));
}
#define INTC_ICR 0xffd00000UL
#define INTC_ICR_IRLM (1 << 7)
void __init plat_irq_setup_pins(int mode)
{
switch (mode) {
case IRQ_MODE_IRQ:
__raw_writew(__raw_readw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
register_intc_controller(&intc_desc_irq);
break;
default:
BUG();
}
}
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}

View file

@ -0,0 +1,930 @@
/*
* Floating point emulation support for subnormalised numbers on SH4
* architecture This file is derived from the SoftFloat IEC/IEEE
* Floating-point Arithmetic Package, Release 2 the original license of
* which is reproduced below.
*
* ========================================================================
*
* This C source file is part of the SoftFloat IEC/IEEE Floating-point
* Arithmetic Package, Release 2.
*
* Written by John R. Hauser. This work was made possible in part by the
* International Computer Science Institute, located at Suite 600, 1947 Center
* Street, Berkeley, California 94704. Funding was partially provided by the
* National Science Foundation under grant MIP-9311980. The original version
* of this code was written as part of a project to build a fixed-point vector
* processor in collaboration with the University of California at Berkeley,
* overseen by Profs. Nelson Morgan and John Wawrzynek. More information
* is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
* arithmetic/softfloat.html'.
*
* THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
* has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
* TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
* PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
* AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
*
* Derivative works are acceptable, even for commercial purposes, so long as
* (1) they include prominent notice that the work is derivative, and (2) they
* include prominent notice akin to these three paragraphs for those parts of
* this code that are retained.
*
* ========================================================================
*
* SH4 modifications by Ismail Dhaoui <ismail.dhaoui@st.com>
* and Kamel Khelifi <kamel.khelifi@st.com>
*/
#include <linux/kernel.h>
#include <cpu/fpu.h>
#include <asm/div64.h>
#define LIT64( a ) a##LL
typedef char flag;
typedef unsigned char uint8;
typedef signed char int8;
typedef int uint16;
typedef int int16;
typedef unsigned int uint32;
typedef signed int int32;
typedef unsigned long long int bits64;
typedef signed long long int sbits64;
typedef unsigned char bits8;
typedef signed char sbits8;
typedef unsigned short int bits16;
typedef signed short int sbits16;
typedef unsigned int bits32;
typedef signed int sbits32;
typedef unsigned long long int uint64;
typedef signed long long int int64;
typedef unsigned long int float32;
typedef unsigned long long float64;
extern void float_raise(unsigned int flags); /* in fpu.c */
extern int float_rounding_mode(void); /* in fpu.c */
bits64 extractFloat64Frac(float64 a);
flag extractFloat64Sign(float64 a);
int16 extractFloat64Exp(float64 a);
int16 extractFloat32Exp(float32 a);
flag extractFloat32Sign(float32 a);
bits32 extractFloat32Frac(float32 a);
float64 packFloat64(flag zSign, int16 zExp, bits64 zSig);
void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr);
float32 packFloat32(flag zSign, int16 zExp, bits32 zSig);
void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr);
float64 float64_sub(float64 a, float64 b);
float32 float32_sub(float32 a, float32 b);
float32 float32_add(float32 a, float32 b);
float64 float64_add(float64 a, float64 b);
float64 float64_div(float64 a, float64 b);
float32 float32_div(float32 a, float32 b);
float32 float32_mul(float32 a, float32 b);
float64 float64_mul(float64 a, float64 b);
float32 float64_to_float32(float64 a);
void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
bits64 * z1Ptr);
void sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
bits64 * z1Ptr);
void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr);
static int8 countLeadingZeros32(bits32 a);
static int8 countLeadingZeros64(bits64 a);
static float64 normalizeRoundAndPackFloat64(flag zSign, int16 zExp,
bits64 zSig);
static float64 subFloat64Sigs(float64 a, float64 b, flag zSign);
static float64 addFloat64Sigs(float64 a, float64 b, flag zSign);
static float32 roundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig);
static float32 normalizeRoundAndPackFloat32(flag zSign, int16 zExp,
bits32 zSig);
static float64 roundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig);
static float32 subFloat32Sigs(float32 a, float32 b, flag zSign);
static float32 addFloat32Sigs(float32 a, float32 b, flag zSign);
static void normalizeFloat64Subnormal(bits64 aSig, int16 * zExpPtr,
bits64 * zSigPtr);
static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b);
static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr,
bits32 * zSigPtr);
bits64 extractFloat64Frac(float64 a)
{
return a & LIT64(0x000FFFFFFFFFFFFF);
}
flag extractFloat64Sign(float64 a)
{
return a >> 63;
}
int16 extractFloat64Exp(float64 a)
{
return (a >> 52) & 0x7FF;
}
int16 extractFloat32Exp(float32 a)
{
return (a >> 23) & 0xFF;
}
flag extractFloat32Sign(float32 a)
{
return a >> 31;
}
bits32 extractFloat32Frac(float32 a)
{
return a & 0x007FFFFF;
}
float64 packFloat64(flag zSign, int16 zExp, bits64 zSig)
{
return (((bits64) zSign) << 63) + (((bits64) zExp) << 52) + zSig;
}
void shift64RightJamming(bits64 a, int16 count, bits64 * zPtr)
{
bits64 z;
if (count == 0) {
z = a;
} else if (count < 64) {
z = (a >> count) | ((a << ((-count) & 63)) != 0);
} else {
z = (a != 0);
}
*zPtr = z;
}
static int8 countLeadingZeros32(bits32 a)
{
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int8 shiftCount;
shiftCount = 0;
if (a < 0x10000) {
shiftCount += 16;
a <<= 16;
}
if (a < 0x1000000) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[a >> 24];
return shiftCount;
}
static int8 countLeadingZeros64(bits64 a)
{
int8 shiftCount;
shiftCount = 0;
if (a < ((bits64) 1) << 32) {
shiftCount += 32;
} else {
a >>= 32;
}
shiftCount += countLeadingZeros32(a);
return shiftCount;
}
static float64 normalizeRoundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig)
{
int8 shiftCount;
shiftCount = countLeadingZeros64(zSig) - 1;
return roundAndPackFloat64(zSign, zExp - shiftCount,
zSig << shiftCount);
}
static float64 subFloat64Sigs(float64 a, float64 b, flag zSign)
{
int16 aExp, bExp, zExp;
bits64 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat64Frac(a);
aExp = extractFloat64Exp(a);
bSig = extractFloat64Frac(b);
bExp = extractFloat64Exp(b);
expDiff = aExp - bExp;
aSig <<= 10;
bSig <<= 10;
if (0 < expDiff)
goto aExpBigger;
if (expDiff < 0)
goto bExpBigger;
if (aExp == 0) {
aExp = 1;
bExp = 1;
}
if (bSig < aSig)
goto aBigger;
if (aSig < bSig)
goto bBigger;
return packFloat64(float_rounding_mode() == FPSCR_RM_ZERO, 0, 0);
bExpBigger:
if (bExp == 0x7FF) {
return packFloat64(zSign ^ 1, 0x7FF, 0);
}
if (aExp == 0) {
++expDiff;
} else {
aSig |= LIT64(0x4000000000000000);
}
shift64RightJamming(aSig, -expDiff, &aSig);
bSig |= LIT64(0x4000000000000000);
bBigger:
zSig = bSig - aSig;
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if (aExp == 0x7FF) {
return a;
}
if (bExp == 0) {
--expDiff;
} else {
bSig |= LIT64(0x4000000000000000);
}
shift64RightJamming(bSig, expDiff, &bSig);
aSig |= LIT64(0x4000000000000000);
aBigger:
zSig = aSig - bSig;
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat64(zSign, zExp, zSig);
}
static float64 addFloat64Sigs(float64 a, float64 b, flag zSign)
{
int16 aExp, bExp, zExp;
bits64 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat64Frac(a);
aExp = extractFloat64Exp(a);
bSig = extractFloat64Frac(b);
bExp = extractFloat64Exp(b);
expDiff = aExp - bExp;
aSig <<= 9;
bSig <<= 9;
if (0 < expDiff) {
if (aExp == 0x7FF) {
return a;
}
if (bExp == 0) {
--expDiff;
} else {
bSig |= LIT64(0x2000000000000000);
}
shift64RightJamming(bSig, expDiff, &bSig);
zExp = aExp;
} else if (expDiff < 0) {
if (bExp == 0x7FF) {
return packFloat64(zSign, 0x7FF, 0);
}
if (aExp == 0) {
++expDiff;
} else {
aSig |= LIT64(0x2000000000000000);
}
shift64RightJamming(aSig, -expDiff, &aSig);
zExp = bExp;
} else {
if (aExp == 0x7FF) {
return a;
}
if (aExp == 0)
return packFloat64(zSign, 0, (aSig + bSig) >> 9);
zSig = LIT64(0x4000000000000000) + aSig + bSig;
zExp = aExp;
goto roundAndPack;
}
aSig |= LIT64(0x2000000000000000);
zSig = (aSig + bSig) << 1;
--zExp;
if ((sbits64) zSig < 0) {
zSig = aSig + bSig;
++zExp;
}
roundAndPack:
return roundAndPackFloat64(zSign, zExp, zSig);
}
float32 packFloat32(flag zSign, int16 zExp, bits32 zSig)
{
return (((bits32) zSign) << 31) + (((bits32) zExp) << 23) + zSig;
}
void shift32RightJamming(bits32 a, int16 count, bits32 * zPtr)
{
bits32 z;
if (count == 0) {
z = a;
} else if (count < 32) {
z = (a >> count) | ((a << ((-count) & 31)) != 0);
} else {
z = (a != 0);
}
*zPtr = z;
}
static float32 roundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig)
{
flag roundNearestEven;
int8 roundIncrement, roundBits;
flag isTiny;
/* SH4 has only 2 rounding modes - round to nearest and round to zero */
roundNearestEven = (float_rounding_mode() == FPSCR_RM_NEAREST);
roundIncrement = 0x40;
if (!roundNearestEven) {
roundIncrement = 0;
}
roundBits = zSig & 0x7F;
if (0xFD <= (bits16) zExp) {
if ((0xFD < zExp)
|| ((zExp == 0xFD)
&& ((sbits32) (zSig + roundIncrement) < 0))
) {
float_raise(FPSCR_CAUSE_OVERFLOW | FPSCR_CAUSE_INEXACT);
return packFloat32(zSign, 0xFF,
0) - (roundIncrement == 0);
}
if (zExp < 0) {
isTiny = (zExp < -1)
|| (zSig + roundIncrement < 0x80000000);
shift32RightJamming(zSig, -zExp, &zSig);
zExp = 0;
roundBits = zSig & 0x7F;
if (isTiny && roundBits)
float_raise(FPSCR_CAUSE_UNDERFLOW);
}
}
if (roundBits)
float_raise(FPSCR_CAUSE_INEXACT);
zSig = (zSig + roundIncrement) >> 7;
zSig &= ~(((roundBits ^ 0x40) == 0) & roundNearestEven);
if (zSig == 0)
zExp = 0;
return packFloat32(zSign, zExp, zSig);
}
static float32 normalizeRoundAndPackFloat32(flag zSign, int16 zExp, bits32 zSig)
{
int8 shiftCount;
shiftCount = countLeadingZeros32(zSig) - 1;
return roundAndPackFloat32(zSign, zExp - shiftCount,
zSig << shiftCount);
}
static float64 roundAndPackFloat64(flag zSign, int16 zExp, bits64 zSig)
{
flag roundNearestEven;
int16 roundIncrement, roundBits;
flag isTiny;
/* SH4 has only 2 rounding modes - round to nearest and round to zero */
roundNearestEven = (float_rounding_mode() == FPSCR_RM_NEAREST);
roundIncrement = 0x200;
if (!roundNearestEven) {
roundIncrement = 0;
}
roundBits = zSig & 0x3FF;
if (0x7FD <= (bits16) zExp) {
if ((0x7FD < zExp)
|| ((zExp == 0x7FD)
&& ((sbits64) (zSig + roundIncrement) < 0))
) {
float_raise(FPSCR_CAUSE_OVERFLOW | FPSCR_CAUSE_INEXACT);
return packFloat64(zSign, 0x7FF,
0) - (roundIncrement == 0);
}
if (zExp < 0) {
isTiny = (zExp < -1)
|| (zSig + roundIncrement <
LIT64(0x8000000000000000));
shift64RightJamming(zSig, -zExp, &zSig);
zExp = 0;
roundBits = zSig & 0x3FF;
if (isTiny && roundBits)
float_raise(FPSCR_CAUSE_UNDERFLOW);
}
}
if (roundBits)
float_raise(FPSCR_CAUSE_INEXACT);
zSig = (zSig + roundIncrement) >> 10;
zSig &= ~(((roundBits ^ 0x200) == 0) & roundNearestEven);
if (zSig == 0)
zExp = 0;
return packFloat64(zSign, zExp, zSig);
}
static float32 subFloat32Sigs(float32 a, float32 b, flag zSign)
{
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac(a);
aExp = extractFloat32Exp(a);
bSig = extractFloat32Frac(b);
bExp = extractFloat32Exp(b);
expDiff = aExp - bExp;
aSig <<= 7;
bSig <<= 7;
if (0 < expDiff)
goto aExpBigger;
if (expDiff < 0)
goto bExpBigger;
if (aExp == 0) {
aExp = 1;
bExp = 1;
}
if (bSig < aSig)
goto aBigger;
if (aSig < bSig)
goto bBigger;
return packFloat32(float_rounding_mode() == FPSCR_RM_ZERO, 0, 0);
bExpBigger:
if (bExp == 0xFF) {
return packFloat32(zSign ^ 1, 0xFF, 0);
}
if (aExp == 0) {
++expDiff;
} else {
aSig |= 0x40000000;
}
shift32RightJamming(aSig, -expDiff, &aSig);
bSig |= 0x40000000;
bBigger:
zSig = bSig - aSig;
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if (aExp == 0xFF) {
return a;
}
if (bExp == 0) {
--expDiff;
} else {
bSig |= 0x40000000;
}
shift32RightJamming(bSig, expDiff, &bSig);
aSig |= 0x40000000;
aBigger:
zSig = aSig - bSig;
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat32(zSign, zExp, zSig);
}
static float32 addFloat32Sigs(float32 a, float32 b, flag zSign)
{
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac(a);
aExp = extractFloat32Exp(a);
bSig = extractFloat32Frac(b);
bExp = extractFloat32Exp(b);
expDiff = aExp - bExp;
aSig <<= 6;
bSig <<= 6;
if (0 < expDiff) {
if (aExp == 0xFF) {
return a;
}
if (bExp == 0) {
--expDiff;
} else {
bSig |= 0x20000000;
}
shift32RightJamming(bSig, expDiff, &bSig);
zExp = aExp;
} else if (expDiff < 0) {
if (bExp == 0xFF) {
return packFloat32(zSign, 0xFF, 0);
}
if (aExp == 0) {
++expDiff;
} else {
aSig |= 0x20000000;
}
shift32RightJamming(aSig, -expDiff, &aSig);
zExp = bExp;
} else {
if (aExp == 0xFF) {
return a;
}
if (aExp == 0)
return packFloat32(zSign, 0, (aSig + bSig) >> 6);
zSig = 0x40000000 + aSig + bSig;
zExp = aExp;
goto roundAndPack;
}
aSig |= 0x20000000;
zSig = (aSig + bSig) << 1;
--zExp;
if ((sbits32) zSig < 0) {
zSig = aSig + bSig;
++zExp;
}
roundAndPack:
return roundAndPackFloat32(zSign, zExp, zSig);
}
float64 float64_sub(float64 a, float64 b)
{
flag aSign, bSign;
aSign = extractFloat64Sign(a);
bSign = extractFloat64Sign(b);
if (aSign == bSign) {
return subFloat64Sigs(a, b, aSign);
} else {
return addFloat64Sigs(a, b, aSign);
}
}
float32 float32_sub(float32 a, float32 b)
{
flag aSign, bSign;
aSign = extractFloat32Sign(a);
bSign = extractFloat32Sign(b);
if (aSign == bSign) {
return subFloat32Sigs(a, b, aSign);
} else {
return addFloat32Sigs(a, b, aSign);
}
}
float32 float32_add(float32 a, float32 b)
{
flag aSign, bSign;
aSign = extractFloat32Sign(a);
bSign = extractFloat32Sign(b);
if (aSign == bSign) {
return addFloat32Sigs(a, b, aSign);
} else {
return subFloat32Sigs(a, b, aSign);
}
}
float64 float64_add(float64 a, float64 b)
{
flag aSign, bSign;
aSign = extractFloat64Sign(a);
bSign = extractFloat64Sign(b);
if (aSign == bSign) {
return addFloat64Sigs(a, b, aSign);
} else {
return subFloat64Sigs(a, b, aSign);
}
}
static void
normalizeFloat64Subnormal(bits64 aSig, int16 * zExpPtr, bits64 * zSigPtr)
{
int8 shiftCount;
shiftCount = countLeadingZeros64(aSig) - 11;
*zSigPtr = aSig << shiftCount;
*zExpPtr = 1 - shiftCount;
}
void add128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
bits64 * z1Ptr)
{
bits64 z1;
z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + (z1 < a1);
}
void
sub128(bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 * z0Ptr,
bits64 * z1Ptr)
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - (a1 < b1);
}
static bits64 estimateDiv128To64(bits64 a0, bits64 a1, bits64 b)
{
bits64 b0, b1;
bits64 rem0, rem1, term0, term1;
bits64 z, tmp;
if (b <= a0)
return LIT64(0xFFFFFFFFFFFFFFFF);
b0 = b >> 32;
tmp = a0;
do_div(tmp, b0);
z = (b0 << 32 <= a0) ? LIT64(0xFFFFFFFF00000000) : tmp << 32;
mul64To128(b, z, &term0, &term1);
sub128(a0, a1, term0, term1, &rem0, &rem1);
while (((sbits64) rem0) < 0) {
z -= LIT64(0x100000000);
b1 = b << 32;
add128(rem0, rem1, b0, b1, &rem0, &rem1);
}
rem0 = (rem0 << 32) | (rem1 >> 32);
tmp = rem0;
do_div(tmp, b0);
z |= (b0 << 32 <= rem0) ? 0xFFFFFFFF : tmp;
return z;
}
void mul64To128(bits64 a, bits64 b, bits64 * z0Ptr, bits64 * z1Ptr)
{
bits32 aHigh, aLow, bHigh, bLow;
bits64 z0, zMiddleA, zMiddleB, z1;
aLow = a;
aHigh = a >> 32;
bLow = b;
bHigh = b >> 32;
z1 = ((bits64) aLow) * bLow;
zMiddleA = ((bits64) aLow) * bHigh;
zMiddleB = ((bits64) aHigh) * bLow;
z0 = ((bits64) aHigh) * bHigh;
zMiddleA += zMiddleB;
z0 += (((bits64) (zMiddleA < zMiddleB)) << 32) + (zMiddleA >> 32);
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += (z1 < zMiddleA);
*z1Ptr = z1;
*z0Ptr = z0;
}
static void normalizeFloat32Subnormal(bits32 aSig, int16 * zExpPtr,
bits32 * zSigPtr)
{
int8 shiftCount;
shiftCount = countLeadingZeros32(aSig) - 8;
*zSigPtr = aSig << shiftCount;
*zExpPtr = 1 - shiftCount;
}
float64 float64_div(float64 a, float64 b)
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits64 aSig, bSig, zSig;
bits64 rem0, rem1;
bits64 term0, term1;
aSig = extractFloat64Frac(a);
aExp = extractFloat64Exp(a);
aSign = extractFloat64Sign(a);
bSig = extractFloat64Frac(b);
bExp = extractFloat64Exp(b);
bSign = extractFloat64Sign(b);
zSign = aSign ^ bSign;
if (aExp == 0x7FF) {
if (bExp == 0x7FF) {
}
return packFloat64(zSign, 0x7FF, 0);
}
if (bExp == 0x7FF) {
return packFloat64(zSign, 0, 0);
}
if (bExp == 0) {
if (bSig == 0) {
if ((aExp | aSig) == 0) {
float_raise(FPSCR_CAUSE_INVALID);
}
return packFloat64(zSign, 0x7FF, 0);
}
normalizeFloat64Subnormal(bSig, &bExp, &bSig);
}
if (aExp == 0) {
if (aSig == 0)
return packFloat64(zSign, 0, 0);
normalizeFloat64Subnormal(aSig, &aExp, &aSig);
}
zExp = aExp - bExp + 0x3FD;
aSig = (aSig | LIT64(0x0010000000000000)) << 10;
bSig = (bSig | LIT64(0x0010000000000000)) << 11;
if (bSig <= (aSig + aSig)) {
aSig >>= 1;
++zExp;
}
zSig = estimateDiv128To64(aSig, 0, bSig);
if ((zSig & 0x1FF) <= 2) {
mul64To128(bSig, zSig, &term0, &term1);
sub128(aSig, 0, term0, term1, &rem0, &rem1);
while ((sbits64) rem0 < 0) {
--zSig;
add128(rem0, rem1, 0, bSig, &rem0, &rem1);
}
zSig |= (rem1 != 0);
}
return roundAndPackFloat64(zSign, zExp, zSig);
}
float32 float32_div(float32 a, float32 b)
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig, bSig;
uint64_t zSig;
aSig = extractFloat32Frac(a);
aExp = extractFloat32Exp(a);
aSign = extractFloat32Sign(a);
bSig = extractFloat32Frac(b);
bExp = extractFloat32Exp(b);
bSign = extractFloat32Sign(b);
zSign = aSign ^ bSign;
if (aExp == 0xFF) {
if (bExp == 0xFF) {
}
return packFloat32(zSign, 0xFF, 0);
}
if (bExp == 0xFF) {
return packFloat32(zSign, 0, 0);
}
if (bExp == 0) {
if (bSig == 0) {
return packFloat32(zSign, 0xFF, 0);
}
normalizeFloat32Subnormal(bSig, &bExp, &bSig);
}
if (aExp == 0) {
if (aSig == 0)
return packFloat32(zSign, 0, 0);
normalizeFloat32Subnormal(aSig, &aExp, &aSig);
}
zExp = aExp - bExp + 0x7D;
aSig = (aSig | 0x00800000) << 7;
bSig = (bSig | 0x00800000) << 8;
if (bSig <= (aSig + aSig)) {
aSig >>= 1;
++zExp;
}
zSig = (((bits64) aSig) << 32);
do_div(zSig, bSig);
if ((zSig & 0x3F) == 0) {
zSig |= (((bits64) bSig) * zSig != ((bits64) aSig) << 32);
}
return roundAndPackFloat32(zSign, zExp, (bits32)zSig);
}
float32 float32_mul(float32 a, float32 b)
{
char aSign, bSign, zSign;
int aExp, bExp, zExp;
unsigned int aSig, bSig;
unsigned long long zSig64;
unsigned int zSig;
aSig = extractFloat32Frac(a);
aExp = extractFloat32Exp(a);
aSign = extractFloat32Sign(a);
bSig = extractFloat32Frac(b);
bExp = extractFloat32Exp(b);
bSign = extractFloat32Sign(b);
zSign = aSign ^ bSign;
if (aExp == 0) {
if (aSig == 0)
return packFloat32(zSign, 0, 0);
normalizeFloat32Subnormal(aSig, &aExp, &aSig);
}
if (bExp == 0) {
if (bSig == 0)
return packFloat32(zSign, 0, 0);
normalizeFloat32Subnormal(bSig, &bExp, &bSig);
}
if ((bExp == 0xff && bSig == 0) || (aExp == 0xff && aSig == 0))
return roundAndPackFloat32(zSign, 0xff, 0);
zExp = aExp + bExp - 0x7F;
aSig = (aSig | 0x00800000) << 7;
bSig = (bSig | 0x00800000) << 8;
shift64RightJamming(((unsigned long long)aSig) * bSig, 32, &zSig64);
zSig = zSig64;
if (0 <= (signed int)(zSig << 1)) {
zSig <<= 1;
--zExp;
}
return roundAndPackFloat32(zSign, zExp, zSig);
}
float64 float64_mul(float64 a, float64 b)
{
char aSign, bSign, zSign;
int aExp, bExp, zExp;
unsigned long long int aSig, bSig, zSig0, zSig1;
aSig = extractFloat64Frac(a);
aExp = extractFloat64Exp(a);
aSign = extractFloat64Sign(a);
bSig = extractFloat64Frac(b);
bExp = extractFloat64Exp(b);
bSign = extractFloat64Sign(b);
zSign = aSign ^ bSign;
if (aExp == 0) {
if (aSig == 0)
return packFloat64(zSign, 0, 0);
normalizeFloat64Subnormal(aSig, &aExp, &aSig);
}
if (bExp == 0) {
if (bSig == 0)
return packFloat64(zSign, 0, 0);
normalizeFloat64Subnormal(bSig, &bExp, &bSig);
}
if ((aExp == 0x7ff && aSig == 0) || (bExp == 0x7ff && bSig == 0))
return roundAndPackFloat64(zSign, 0x7ff, 0);
zExp = aExp + bExp - 0x3FF;
aSig = (aSig | 0x0010000000000000LL) << 10;
bSig = (bSig | 0x0010000000000000LL) << 11;
mul64To128(aSig, bSig, &zSig0, &zSig1);
zSig0 |= (zSig1 != 0);
if (0 <= (signed long long int)(zSig0 << 1)) {
zSig0 <<= 1;
--zExp;
}
return roundAndPackFloat64(zSign, zExp, zSig0);
}
/*
* -------------------------------------------------------------------------------
* Returns the result of converting the double-precision floating-point value
* `a' to the single-precision floating-point format. The conversion is
* performed according to the IEC/IEEE Standard for Binary Floating-point
* Arithmetic.
* -------------------------------------------------------------------------------
* */
float32 float64_to_float32(float64 a)
{
flag aSign;
int16 aExp;
bits64 aSig;
bits32 zSig;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
shift64RightJamming( aSig, 22, &aSig );
zSig = aSig;
if ( aExp || zSig ) {
zSig |= 0x40000000;
aExp -= 0x381;
}
return roundAndPackFloat32(aSign, aExp, zSig);
}

416
arch/sh/kernel/cpu/sh4/sq.c Normal file
View file

@ -0,0 +1,416 @@
/*
* arch/sh/kernel/cpu/sh4/sq.c
*
* General management API for SH-4 integrated Store Queues
*
* Copyright (C) 2001 - 2006 Paul Mundt
* Copyright (C) 2001, 2002 M. R. Brown
*
* 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/cpu.h>
#include <linux/bitmap.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/prefetch.h>
#include <asm/page.h>
#include <asm/cacheflush.h>
#include <cpu/sq.h>
struct sq_mapping;
struct sq_mapping {
const char *name;
unsigned long sq_addr;
unsigned long addr;
unsigned int size;
struct sq_mapping *next;
};
static struct sq_mapping *sq_mapping_list;
static DEFINE_SPINLOCK(sq_mapping_lock);
static struct kmem_cache *sq_cache;
static unsigned long *sq_bitmap;
#define store_queue_barrier() \
do { \
(void)__raw_readl(P4SEG_STORE_QUE); \
__raw_writel(0, P4SEG_STORE_QUE + 0); \
__raw_writel(0, P4SEG_STORE_QUE + 8); \
} while (0);
/**
* sq_flush_range - Flush (prefetch) a specific SQ range
* @start: the store queue address to start flushing from
* @len: the length to flush
*
* Flushes the store queue cache from @start to @start + @len in a
* linear fashion.
*/
void sq_flush_range(unsigned long start, unsigned int len)
{
unsigned long *sq = (unsigned long *)start;
/* Flush the queues */
for (len >>= 5; len--; sq += 8)
prefetchw(sq);
/* Wait for completion */
store_queue_barrier();
}
EXPORT_SYMBOL(sq_flush_range);
static inline void sq_mapping_list_add(struct sq_mapping *map)
{
struct sq_mapping **p, *tmp;
spin_lock_irq(&sq_mapping_lock);
p = &sq_mapping_list;
while ((tmp = *p) != NULL)
p = &tmp->next;
map->next = tmp;
*p = map;
spin_unlock_irq(&sq_mapping_lock);
}
static inline void sq_mapping_list_del(struct sq_mapping *map)
{
struct sq_mapping **p, *tmp;
spin_lock_irq(&sq_mapping_lock);
for (p = &sq_mapping_list; (tmp = *p); p = &tmp->next)
if (tmp == map) {
*p = tmp->next;
break;
}
spin_unlock_irq(&sq_mapping_lock);
}
static int __sq_remap(struct sq_mapping *map, pgprot_t prot)
{
#if defined(CONFIG_MMU)
struct vm_struct *vma;
vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
if (!vma)
return -ENOMEM;
vma->phys_addr = map->addr;
if (ioremap_page_range((unsigned long)vma->addr,
(unsigned long)vma->addr + map->size,
vma->phys_addr, prot)) {
vunmap(vma->addr);
return -EAGAIN;
}
#else
/*
* Without an MMU (or with it turned off), this is much more
* straightforward, as we can just load up each queue's QACR with
* the physical address appropriately masked.
*/
__raw_writel(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
__raw_writel(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
#endif
return 0;
}
/**
* sq_remap - Map a physical address through the Store Queues
* @phys: Physical address of mapping.
* @size: Length of mapping.
* @name: User invoking mapping.
* @prot: Protection bits.
*
* Remaps the physical address @phys through the next available store queue
* address of @size length. @name is logged at boot time as well as through
* the sysfs interface.
*/
unsigned long sq_remap(unsigned long phys, unsigned int size,
const char *name, pgprot_t prot)
{
struct sq_mapping *map;
unsigned long end;
unsigned int psz;
int ret, page;
/* Don't allow wraparound or zero size */
end = phys + size - 1;
if (unlikely(!size || end < phys))
return -EINVAL;
/* Don't allow anyone to remap normal memory.. */
if (unlikely(phys < virt_to_phys(high_memory)))
return -EINVAL;
phys &= PAGE_MASK;
size = PAGE_ALIGN(end + 1) - phys;
map = kmem_cache_alloc(sq_cache, GFP_KERNEL);
if (unlikely(!map))
return -ENOMEM;
map->addr = phys;
map->size = size;
map->name = name;
page = bitmap_find_free_region(sq_bitmap, 0x04000000 >> PAGE_SHIFT,
get_order(map->size));
if (unlikely(page < 0)) {
ret = -ENOSPC;
goto out;
}
map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT);
ret = __sq_remap(map, prot);
if (unlikely(ret != 0))
goto out;
psz = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pr_info("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n",
likely(map->name) ? map->name : "???",
psz, psz == 1 ? " " : "s",
map->sq_addr, map->addr);
sq_mapping_list_add(map);
return map->sq_addr;
out:
kmem_cache_free(sq_cache, map);
return ret;
}
EXPORT_SYMBOL(sq_remap);
/**
* sq_unmap - Unmap a Store Queue allocation
* @vaddr: Pre-allocated Store Queue mapping.
*
* Unmaps the store queue allocation @map that was previously created by
* sq_remap(). Also frees up the pte that was previously inserted into
* the kernel page table and discards the UTLB translation.
*/
void sq_unmap(unsigned long vaddr)
{
struct sq_mapping **p, *map;
int page;
for (p = &sq_mapping_list; (map = *p); p = &map->next)
if (map->sq_addr == vaddr)
break;
if (unlikely(!map)) {
printk("%s: bad store queue address 0x%08lx\n",
__func__, vaddr);
return;
}
page = (map->sq_addr - P4SEG_STORE_QUE) >> PAGE_SHIFT;
bitmap_release_region(sq_bitmap, page, get_order(map->size));
#ifdef CONFIG_MMU
{
/*
* Tear down the VMA in the MMU case.
*/
struct vm_struct *vma;
vma = remove_vm_area((void *)(map->sq_addr & PAGE_MASK));
if (!vma) {
printk(KERN_ERR "%s: bad address 0x%08lx\n",
__func__, map->sq_addr);
return;
}
}
#endif
sq_mapping_list_del(map);
kmem_cache_free(sq_cache, map);
}
EXPORT_SYMBOL(sq_unmap);
/*
* Needlessly complex sysfs interface. Unfortunately it doesn't seem like
* there is any other easy way to add things on a per-cpu basis without
* putting the directory entries somewhere stupid and having to create
* links in sysfs by hand back in to the per-cpu directories.
*
* Some day we may want to have an additional abstraction per store
* queue, but considering the kobject hell we already have to deal with,
* it's simply not worth the trouble.
*/
static struct kobject *sq_kobject[NR_CPUS];
struct sq_sysfs_attr {
struct attribute attr;
ssize_t (*show)(char *buf);
ssize_t (*store)(const char *buf, size_t count);
};
#define to_sq_sysfs_attr(a) container_of(a, struct sq_sysfs_attr, attr)
static ssize_t sq_sysfs_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
if (likely(sattr->show))
return sattr->show(buf);
return -EIO;
}
static ssize_t sq_sysfs_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
if (likely(sattr->store))
return sattr->store(buf, count);
return -EIO;
}
static ssize_t mapping_show(char *buf)
{
struct sq_mapping **list, *entry;
char *p = buf;
for (list = &sq_mapping_list; (entry = *list); list = &entry->next)
p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n",
entry->sq_addr, entry->sq_addr + entry->size,
entry->addr, entry->name);
return p - buf;
}
static ssize_t mapping_store(const char *buf, size_t count)
{
unsigned long base = 0, len = 0;
sscanf(buf, "%lx %lx", &base, &len);
if (!base)
return -EIO;
if (likely(len)) {
int ret = sq_remap(base, len, "Userspace", PAGE_SHARED);
if (ret < 0)
return ret;
} else
sq_unmap(base);
return count;
}
static struct sq_sysfs_attr mapping_attr =
__ATTR(mapping, 0644, mapping_show, mapping_store);
static struct attribute *sq_sysfs_attrs[] = {
&mapping_attr.attr,
NULL,
};
static const struct sysfs_ops sq_sysfs_ops = {
.show = sq_sysfs_show,
.store = sq_sysfs_store,
};
static struct kobj_type ktype_percpu_entry = {
.sysfs_ops = &sq_sysfs_ops,
.default_attrs = sq_sysfs_attrs,
};
static int sq_dev_add(struct device *dev, struct subsys_interface *sif)
{
unsigned int cpu = dev->id;
struct kobject *kobj;
int error;
sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
if (unlikely(!sq_kobject[cpu]))
return -ENOMEM;
kobj = sq_kobject[cpu];
error = kobject_init_and_add(kobj, &ktype_percpu_entry, &dev->kobj,
"%s", "sq");
if (!error)
kobject_uevent(kobj, KOBJ_ADD);
return error;
}
static int sq_dev_remove(struct device *dev, struct subsys_interface *sif)
{
unsigned int cpu = dev->id;
struct kobject *kobj = sq_kobject[cpu];
kobject_put(kobj);
return 0;
}
static struct subsys_interface sq_interface = {
.name = "sq",
.subsys = &cpu_subsys,
.add_dev = sq_dev_add,
.remove_dev = sq_dev_remove,
};
static int __init sq_api_init(void)
{
unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT;
unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
int ret = -ENOMEM;
printk(KERN_NOTICE "sq: Registering store queue API.\n");
sq_cache = kmem_cache_create("store_queue_cache",
sizeof(struct sq_mapping), 0, 0, NULL);
if (unlikely(!sq_cache))
return ret;
sq_bitmap = kzalloc(size, GFP_KERNEL);
if (unlikely(!sq_bitmap))
goto out;
ret = subsys_interface_register(&sq_interface);
if (unlikely(ret != 0))
goto out;
return 0;
out:
kfree(sq_bitmap);
kmem_cache_destroy(sq_cache);
return ret;
}
static void __exit sq_api_exit(void)
{
subsys_interface_unregister(&sq_interface);
kfree(sq_bitmap);
kmem_cache_destroy(sq_cache);
}
module_init(sq_api_init);
module_exit(sq_api_exit);
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,52 @@
#
# Makefile for the Linux/SuperH SH-4 backends.
#
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7757) += setup-sh7757.o
obj-$(CONFIG_CPU_SUBTYPE_SH7763) += setup-sh7763.o
obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
obj-$(CONFIG_CPU_SUBTYPE_SH7786) += setup-sh7786.o intc-shx3.o
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o serial-sh7722.o
obj-$(CONFIG_CPU_SUBTYPE_SH7723) += setup-sh7723.o
obj-$(CONFIG_CPU_SUBTYPE_SH7724) += setup-sh7724.o
obj-$(CONFIG_CPU_SUBTYPE_SH7734) += setup-sh7734.o
obj-$(CONFIG_CPU_SUBTYPE_SH7366) += setup-sh7366.o
obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o intc-shx3.o
# SMP setup
smp-$(CONFIG_CPU_SHX3) := smp-shx3.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SUBTYPE_SH7757) := clock-sh7757.o
clock-$(CONFIG_CPU_SUBTYPE_SH7763) := clock-sh7763.o
clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o
clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o
clock-$(CONFIG_CPU_SUBTYPE_SH7734) := clock-sh7734.o
clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o
clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
# Pinmux setup
pinmux-$(CONFIG_CPU_SUBTYPE_SH7722) := pinmux-sh7722.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7723) := pinmux-sh7723.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7724) := pinmux-sh7724.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7734) := pinmux-sh7734.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7757) := pinmux-sh7757.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7785) := pinmux-sh7785.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o
pinmux-$(CONFIG_CPU_SUBTYPE_SHX3) := pinmux-shx3.o
obj-y += $(clock-y)
obj-$(CONFIG_SMP) += $(smp-y)
obj-$(CONFIG_GPIOLIB) += $(pinmux-y)
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += ubc.o

View file

@ -0,0 +1,289 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7343.c
*
* SH7343 clock framework support
*
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clkdev.h>
#include <asm/clock.h>
/* SH7343 registers */
#define FRQCR 0xa4150000
#define VCLKCR 0xa4150004
#define SCLKACR 0xa4150008
#define SCLKBCR 0xa415000c
#define PLLCR 0xa4150024
#define MSTPCR0 0xa4150030
#define MSTPCR1 0xa4150034
#define MSTPCR2 0xa4150038
#define DLLFRQ 0xa4150050
/* Fixed 32 KHz root clock for RTC and Power Management purposes */
static struct clk r_clk = {
.rate = 32768,
};
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
struct clk extal_clk = {
.rate = 33333333,
};
/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
static unsigned long dll_recalc(struct clk *clk)
{
unsigned long mult;
if (__raw_readl(PLLCR) & 0x1000)
mult = __raw_readl(DLLFRQ);
else
mult = 0;
return clk->parent->rate * mult;
}
static struct sh_clk_ops dll_clk_ops = {
.recalc = dll_recalc,
};
static struct clk dll_clk = {
.ops = &dll_clk_ops,
.parent = &r_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static unsigned long pll_recalc(struct clk *clk)
{
unsigned long mult = 1;
if (__raw_readl(PLLCR) & 0x4000)
mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
return clk->parent->rate * mult;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.flags = CLK_ENABLE_ON_INIT,
};
struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&dll_clk,
&pll_clk,
};
static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = divisors,
.nr_divisors = ARRAY_SIZE(divisors),
.multipliers = multipliers,
.nr_multipliers = ARRAY_SIZE(multipliers),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
DIV4_SIUA, DIV4_SIUB, DIV4_NR };
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQCR, 20, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_U] = DIV4(FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_B3] = DIV4(FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_P] = DIV4(FRQCR, 0, 0x1fff, 0),
[DIV4_SIUA] = DIV4(SCLKACR, 0, 0x1fff, 0),
[DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x1fff, 0),
};
enum { DIV6_V, DIV6_NR };
struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
};
#define MSTP(_parent, _reg, _bit, _flags) \
SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026,
MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016,
MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010,
MSTP007, MSTP006, MSTP005, MSTP004, MSTP003, MSTP002, MSTP001,
MSTP109, MSTP108, MSTP100,
MSTP225, MSTP224, MSTP218, MSTP217, MSTP216,
MSTP214, MSTP213, MSTP212, MSTP211, MSTP208,
MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
[MSTP031] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
[MSTP030] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
[MSTP029] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
[MSTP028] = MSTP(&div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
[MSTP026] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
[MSTP023] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
[MSTP022] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
[MSTP021] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
[MSTP020] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 20, 0),
[MSTP019] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
[MSTP017] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 17, 0),
[MSTP015] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
[MSTP014] = MSTP(&r_clk, MSTPCR0, 14, 0),
[MSTP013] = MSTP(&r_clk, MSTPCR0, 13, 0),
[MSTP011] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
[MSTP010] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
[MSTP007] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
[MSTP006] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
[MSTP005] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
[MSTP004] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 4, 0),
[MSTP003] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 3, 0),
[MSTP002] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
[MSTP001] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
[MSTP109] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
[MSTP108] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 8, 0),
[MSTP225] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 25, 0),
[MSTP224] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
[MSTP218] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
[MSTP217] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 17, 0),
[MSTP216] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 16, 0),
[MSTP214] = MSTP(&r_clk, MSTPCR2, 14, 0),
[MSTP213] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 13, 0),
[MSTP212] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 12, 0),
[MSTP211] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
[MSTP208] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 8, 0),
[MSTP206] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT),
[MSTP205] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
[MSTP204] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
[MSTP203] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
[MSTP202] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
[MSTP201] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
[MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("rclk", &r_clk),
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("dll_clk", &dll_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]),
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("siua_clk", &div4_clks[DIV4_SIUA]),
CLKDEV_CON_ID("siub_clk", &div4_clks[DIV4_SIUB]),
/* DIV6 clocks */
CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
/* MSTP32 clocks */
CLKDEV_CON_ID("tlb0", &mstp_clks[MSTP031]),
CLKDEV_CON_ID("ic0", &mstp_clks[MSTP030]),
CLKDEV_CON_ID("oc0", &mstp_clks[MSTP029]),
CLKDEV_CON_ID("uram0", &mstp_clks[MSTP028]),
CLKDEV_CON_ID("xymem0", &mstp_clks[MSTP026]),
CLKDEV_CON_ID("intc3", &mstp_clks[MSTP023]),
CLKDEV_CON_ID("intc0", &mstp_clks[MSTP022]),
CLKDEV_CON_ID("dmac0", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("sh0", &mstp_clks[MSTP020]),
CLKDEV_CON_ID("hudi0", &mstp_clks[MSTP019]),
CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP017]),
CLKDEV_CON_ID("tmu_fck", &mstp_clks[MSTP015]),
CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[MSTP014]),
CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP004]),
CLKDEV_CON_ID("sio0", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("siof0", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("siof1", &mstp_clks[MSTP001]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP108]),
CLKDEV_CON_ID("tpu0", &mstp_clks[MSTP225]),
CLKDEV_CON_ID("irda0", &mstp_clks[MSTP224]),
CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]),
CLKDEV_CON_ID("mmcif0", &mstp_clks[MSTP217]),
CLKDEV_CON_ID("sim0", &mstp_clks[MSTP216]),
CLKDEV_CON_ID("keysc0", &mstp_clks[MSTP214]),
CLKDEV_CON_ID("tsif0", &mstp_clks[MSTP213]),
CLKDEV_CON_ID("s3d40", &mstp_clks[MSTP212]),
CLKDEV_CON_ID("usbf0", &mstp_clks[MSTP211]),
CLKDEV_CON_ID("siu0", &mstp_clks[MSTP208]),
CLKDEV_CON_ID("jpu0", &mstp_clks[MSTP206]),
CLKDEV_CON_ID("vou0", &mstp_clks[MSTP205]),
CLKDEV_CON_ID("beu0", &mstp_clks[MSTP204]),
CLKDEV_CON_ID("ceu0", &mstp_clks[MSTP203]),
CLKDEV_CON_ID("veu0", &mstp_clks[MSTP202]),
CLKDEV_CON_ID("vpu0", &mstp_clks[MSTP201]),
CLKDEV_CON_ID("lcdc0", &mstp_clks[MSTP200]),
};
int __init arch_clk_init(void)
{
int k, ret = 0;
/* autodetect extal or dll configuration */
if (__raw_readl(PLLCR) & 0x1000)
pll_clk.parent = &dll_clk;
else
pll_clk.parent = &extal_clk;
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
ret = sh_clk_div6_register(div6_clks, DIV6_NR);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,282 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7366.c
*
* SH7366 clock framework support
*
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clkdev.h>
#include <asm/clock.h>
/* SH7366 registers */
#define FRQCR 0xa4150000
#define VCLKCR 0xa4150004
#define SCLKACR 0xa4150008
#define SCLKBCR 0xa415000c
#define PLLCR 0xa4150024
#define MSTPCR0 0xa4150030
#define MSTPCR1 0xa4150034
#define MSTPCR2 0xa4150038
#define DLLFRQ 0xa4150050
/* Fixed 32 KHz root clock for RTC and Power Management purposes */
static struct clk r_clk = {
.rate = 32768,
};
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
struct clk extal_clk = {
.rate = 33333333,
};
/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
static unsigned long dll_recalc(struct clk *clk)
{
unsigned long mult;
if (__raw_readl(PLLCR) & 0x1000)
mult = __raw_readl(DLLFRQ);
else
mult = 0;
return clk->parent->rate * mult;
}
static struct sh_clk_ops dll_clk_ops = {
.recalc = dll_recalc,
};
static struct clk dll_clk = {
.ops = &dll_clk_ops,
.parent = &r_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static unsigned long pll_recalc(struct clk *clk)
{
unsigned long mult = 1;
unsigned long div = 1;
if (__raw_readl(PLLCR) & 0x4000)
mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
else
div = 2;
return (clk->parent->rate * mult) / div;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.flags = CLK_ENABLE_ON_INIT,
};
struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&dll_clk,
&pll_clk,
};
static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = divisors,
.nr_divisors = ARRAY_SIZE(divisors),
.multipliers = multipliers,
.nr_multipliers = ARRAY_SIZE(multipliers),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
DIV4_SIUA, DIV4_SIUB, DIV4_NR };
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
[DIV4_U] = DIV4(FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_B3] = DIV4(FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_P] = DIV4(FRQCR, 0, 0x1fff, 0),
[DIV4_SIUA] = DIV4(SCLKACR, 0, 0x1fff, 0),
[DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x1fff, 0),
};
enum { DIV6_V, DIV6_NR };
struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
};
#define MSTP(_parent, _reg, _bit, _flags) \
SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026,
MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016,
MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010,
MSTP007, MSTP006, MSTP005, MSTP002, MSTP001,
MSTP109, MSTP100,
MSTP227, MSTP226, MSTP224, MSTP223, MSTP222, MSTP218, MSTP217,
MSTP211, MSTP207, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
/* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
[MSTP031] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
[MSTP030] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
[MSTP029] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
[MSTP028] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
[MSTP026] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
[MSTP023] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
[MSTP022] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
[MSTP021] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
[MSTP020] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 20, 0),
[MSTP019] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
[MSTP017] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 17, 0),
[MSTP015] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
[MSTP014] = MSTP(&r_clk, MSTPCR0, 14, 0),
[MSTP013] = MSTP(&r_clk, MSTPCR0, 13, 0),
[MSTP011] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
[MSTP010] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
[MSTP007] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
[MSTP006] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
[MSTP005] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
[MSTP002] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
[MSTP001] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
[MSTP109] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
[MSTP227] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 27, 0),
[MSTP226] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 26, 0),
[MSTP224] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
[MSTP223] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 23, 0),
[MSTP222] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 22, 0),
[MSTP218] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
[MSTP217] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 17, 0),
[MSTP211] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
[MSTP207] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT),
[MSTP205] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
[MSTP204] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
[MSTP203] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
[MSTP202] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
[MSTP201] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
[MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("rclk", &r_clk),
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("dll_clk", &dll_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]),
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("siua_clk", &div4_clks[DIV4_SIUA]),
CLKDEV_CON_ID("siub_clk", &div4_clks[DIV4_SIUB]),
/* DIV6 clocks */
CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
/* MSTP32 clocks */
CLKDEV_CON_ID("tlb0", &mstp_clks[MSTP031]),
CLKDEV_CON_ID("ic0", &mstp_clks[MSTP030]),
CLKDEV_CON_ID("oc0", &mstp_clks[MSTP029]),
CLKDEV_CON_ID("rsmem0", &mstp_clks[MSTP028]),
CLKDEV_CON_ID("xymem0", &mstp_clks[MSTP026]),
CLKDEV_CON_ID("intc3", &mstp_clks[MSTP023]),
CLKDEV_CON_ID("intc0", &mstp_clks[MSTP022]),
CLKDEV_CON_ID("dmac0", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("sh0", &mstp_clks[MSTP020]),
CLKDEV_CON_ID("hudi0", &mstp_clks[MSTP019]),
CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP017]),
CLKDEV_CON_ID("tmu_fck", &mstp_clks[MSTP015]),
CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[MSTP014]),
CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
CLKDEV_CON_ID("icb0", &mstp_clks[MSTP227]),
CLKDEV_CON_ID("meram0", &mstp_clks[MSTP226]),
CLKDEV_CON_ID("dacy1", &mstp_clks[MSTP224]),
CLKDEV_CON_ID("dacy0", &mstp_clks[MSTP223]),
CLKDEV_CON_ID("tsif0", &mstp_clks[MSTP222]),
CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]),
CLKDEV_CON_ID("mmcif0", &mstp_clks[MSTP217]),
CLKDEV_CON_ID("usbf0", &mstp_clks[MSTP211]),
CLKDEV_CON_ID("veu1", &mstp_clks[MSTP207]),
CLKDEV_CON_ID("vou0", &mstp_clks[MSTP205]),
CLKDEV_CON_ID("beu0", &mstp_clks[MSTP204]),
CLKDEV_CON_ID("ceu0", &mstp_clks[MSTP203]),
CLKDEV_CON_ID("veu0", &mstp_clks[MSTP202]),
CLKDEV_CON_ID("vpu0", &mstp_clks[MSTP201]),
CLKDEV_CON_ID("lcdc0", &mstp_clks[MSTP200]),
};
int __init arch_clk_init(void)
{
int k, ret = 0;
/* autodetect extal or dll configuration */
if (__raw_readl(PLLCR) & 0x1000)
pll_clk.parent = &dll_clk;
else
pll_clk.parent = &extal_clk;
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
ret = sh_clk_div6_register(div6_clks, DIV6_NR);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,265 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7722.c
*
* SH7722 clock framework support
*
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clkdev.h>
#include <linux/sh_clk.h>
#include <asm/clock.h>
#include <cpu/sh7722.h>
/* SH7722 registers */
#define FRQCR 0xa4150000
#define VCLKCR 0xa4150004
#define SCLKACR 0xa4150008
#define SCLKBCR 0xa415000c
#define IRDACLKCR 0xa4150018
#define PLLCR 0xa4150024
#define MSTPCR0 0xa4150030
#define MSTPCR1 0xa4150034
#define MSTPCR2 0xa4150038
#define DLLFRQ 0xa4150050
/* Fixed 32 KHz root clock for RTC and Power Management purposes */
static struct clk r_clk = {
.rate = 32768,
};
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
struct clk extal_clk = {
.rate = 33333333,
};
/* The dll block multiplies the 32khz r_clk, may be used instead of extal */
static unsigned long dll_recalc(struct clk *clk)
{
unsigned long mult;
if (__raw_readl(PLLCR) & 0x1000)
mult = __raw_readl(DLLFRQ);
else
mult = 0;
return clk->parent->rate * mult;
}
static struct sh_clk_ops dll_clk_ops = {
.recalc = dll_recalc,
};
static struct clk dll_clk = {
.ops = &dll_clk_ops,
.parent = &r_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static unsigned long pll_recalc(struct clk *clk)
{
unsigned long mult = 1;
unsigned long div = 1;
if (__raw_readl(PLLCR) & 0x4000)
mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
else
div = 2;
return (clk->parent->rate * mult) / div;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.flags = CLK_ENABLE_ON_INIT,
};
struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&dll_clk,
&pll_clk,
};
static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = divisors,
.nr_divisors = ARRAY_SIZE(divisors),
.multipliers = multipliers,
.nr_multipliers = ARRAY_SIZE(multipliers),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, DIV4_NR };
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
[DIV4_U] = DIV4(FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_B3] = DIV4(FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
[DIV4_P] = DIV4(FRQCR, 0, 0x1fff, 0),
};
enum { DIV4_IRDA, DIV4_ENABLE_NR };
struct clk div4_enable_clks[DIV4_ENABLE_NR] = {
[DIV4_IRDA] = DIV4(IRDACLKCR, 0, 0x1fff, 0),
};
enum { DIV4_SIUA, DIV4_SIUB, DIV4_REPARENT_NR };
struct clk div4_reparent_clks[DIV4_REPARENT_NR] = {
[DIV4_SIUA] = DIV4(SCLKACR, 0, 0x1fff, 0),
[DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x1fff, 0),
};
enum { DIV6_V, DIV6_NR };
struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
};
static struct clk mstp_clks[HWBLK_NR] = {
[HWBLK_URAM] = SH_CLK_MSTP32(&div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
[HWBLK_XYMEM] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
[HWBLK_TMU] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
[HWBLK_CMT] = SH_CLK_MSTP32(&r_clk, MSTPCR0, 14, 0),
[HWBLK_RWDT] = SH_CLK_MSTP32(&r_clk, MSTPCR0, 13, 0),
[HWBLK_FLCTL] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
[HWBLK_SCIF0] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
[HWBLK_SCIF1] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
[HWBLK_SCIF2] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
[HWBLK_IIC] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
[HWBLK_RTC] = SH_CLK_MSTP32(&r_clk, MSTPCR1, 8, 0),
[HWBLK_SDHI] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
[HWBLK_KEYSC] = SH_CLK_MSTP32(&r_clk, MSTPCR2, 14, 0),
[HWBLK_USBF] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
[HWBLK_2DG] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 9, 0),
[HWBLK_SIU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 8, 0),
[HWBLK_JPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 6, 0),
[HWBLK_VOU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
[HWBLK_BEU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
[HWBLK_CEU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
[HWBLK_VEU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 2, 0),
[HWBLK_VPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 1, 0),
[HWBLK_LCDC] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("rclk", &r_clk),
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("dll_clk", &dll_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]),
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("irda_clk", &div4_enable_clks[DIV4_IRDA]),
CLKDEV_CON_ID("siua_clk", &div4_reparent_clks[DIV4_SIUA]),
CLKDEV_CON_ID("siub_clk", &div4_reparent_clks[DIV4_SIUB]),
/* DIV6 clocks */
CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
/* MSTP clocks */
CLKDEV_CON_ID("uram0", &mstp_clks[HWBLK_URAM]),
CLKDEV_CON_ID("xymem0", &mstp_clks[HWBLK_XYMEM]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[HWBLK_TMU]),
CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[HWBLK_CMT]),
CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI]),
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
CLKDEV_CON_ID("usbf0", &mstp_clks[HWBLK_USBF]),
CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
CLKDEV_DEV_ID("siu-pcm-audio", &mstp_clks[HWBLK_SIU]),
CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]),
CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
};
int __init arch_clk_init(void)
{
int k, ret = 0;
/* autodetect extal or dll configuration */
if (__raw_readl(PLLCR) & 0x1000)
pll_clk.parent = &dll_clk;
else
pll_clk.parent = &extal_clk;
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
ret = sh_clk_div4_enable_register(div4_enable_clks,
DIV4_ENABLE_NR, &div4_table);
if (!ret)
ret = sh_clk_div4_reparent_register(div4_reparent_clks,
DIV4_REPARENT_NR, &div4_table);
if (!ret)
ret = sh_clk_div6_register(div6_clks, DIV6_NR);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, HWBLK_NR);
return ret;
}

View file

@ -0,0 +1,313 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7723.c
*
* SH7723 clock framework support
*
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/sh_clk.h>
#include <asm/clock.h>
#include <cpu/sh7723.h>
/* SH7723 registers */
#define FRQCR 0xa4150000
#define VCLKCR 0xa4150004
#define SCLKACR 0xa4150008
#define SCLKBCR 0xa415000c
#define IRDACLKCR 0xa4150018
#define PLLCR 0xa4150024
#define MSTPCR0 0xa4150030
#define MSTPCR1 0xa4150034
#define MSTPCR2 0xa4150038
#define DLLFRQ 0xa4150050
/* Fixed 32 KHz root clock for RTC and Power Management purposes */
static struct clk r_clk = {
.rate = 32768,
};
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
struct clk extal_clk = {
.rate = 33333333,
};
/* The dll multiplies the 32khz r_clk, may be used instead of extal */
static unsigned long dll_recalc(struct clk *clk)
{
unsigned long mult;
if (__raw_readl(PLLCR) & 0x1000)
mult = __raw_readl(DLLFRQ);
else
mult = 0;
return clk->parent->rate * mult;
}
static struct sh_clk_ops dll_clk_ops = {
.recalc = dll_recalc,
};
static struct clk dll_clk = {
.ops = &dll_clk_ops,
.parent = &r_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static unsigned long pll_recalc(struct clk *clk)
{
unsigned long mult = 1;
unsigned long div = 1;
if (__raw_readl(PLLCR) & 0x4000)
mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
else
div = 2;
return (clk->parent->rate * mult) / div;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.flags = CLK_ENABLE_ON_INIT,
};
struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&dll_clk,
&pll_clk,
};
static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = divisors,
.nr_divisors = ARRAY_SIZE(divisors),
.multipliers = multipliers,
.nr_multipliers = ARRAY_SIZE(multipliers),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, DIV4_NR };
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQCR, 20, 0x0dbf, CLK_ENABLE_ON_INIT),
[DIV4_U] = DIV4(FRQCR, 16, 0x0dbf, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(FRQCR, 12, 0x0dbf, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(FRQCR, 8, 0x0dbf, CLK_ENABLE_ON_INIT),
[DIV4_B3] = DIV4(FRQCR, 4, 0x0db4, CLK_ENABLE_ON_INIT),
[DIV4_P] = DIV4(FRQCR, 0, 0x0dbf, 0),
};
enum { DIV4_IRDA, DIV4_ENABLE_NR };
struct clk div4_enable_clks[DIV4_ENABLE_NR] = {
[DIV4_IRDA] = DIV4(IRDACLKCR, 0, 0x0dbf, 0),
};
enum { DIV4_SIUA, DIV4_SIUB, DIV4_REPARENT_NR };
struct clk div4_reparent_clks[DIV4_REPARENT_NR] = {
[DIV4_SIUA] = DIV4(SCLKACR, 0, 0x0dbf, 0),
[DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x0dbf, 0),
};
enum { DIV6_V, DIV6_NR };
struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
};
static struct clk mstp_clks[] = {
/* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
[HWBLK_TLB] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
[HWBLK_IC] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
[HWBLK_OC] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
[HWBLK_L2C] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
[HWBLK_ILMEM] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 27, CLK_ENABLE_ON_INIT),
[HWBLK_FPU] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 24, CLK_ENABLE_ON_INIT),
[HWBLK_INTC] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 22, CLK_ENABLE_ON_INIT),
[HWBLK_DMAC0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 21, 0),
[HWBLK_SHYWAY] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 20, CLK_ENABLE_ON_INIT),
[HWBLK_HUDI] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
[HWBLK_UBC] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 17, 0),
[HWBLK_TMU0] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
[HWBLK_CMT] = SH_CLK_MSTP32(&r_clk, MSTPCR0, 14, 0),
[HWBLK_RWDT] = SH_CLK_MSTP32(&r_clk, MSTPCR0, 13, 0),
[HWBLK_DMAC1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 12, 0),
[HWBLK_TMU1] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
[HWBLK_FLCTL] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
[HWBLK_SCIF0] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
[HWBLK_SCIF1] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
[HWBLK_SCIF2] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
[HWBLK_SCIF3] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 6, 0),
[HWBLK_SCIF4] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 5, 0),
[HWBLK_SCIF5] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 4, 0),
[HWBLK_MSIOF0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 2, 0),
[HWBLK_MSIOF1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 1, 0),
[HWBLK_MERAM] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 0, 0),
[HWBLK_IIC] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
[HWBLK_RTC] = SH_CLK_MSTP32(&r_clk, MSTPCR1, 8, 0),
[HWBLK_ATAPI] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR2, 28, 0),
[HWBLK_ADC] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 27, 0),
[HWBLK_TPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 25, 0),
[HWBLK_IRDA] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
[HWBLK_TSIF] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 22, 0),
[HWBLK_ICB] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 21, CLK_ENABLE_ON_INIT),
[HWBLK_SDHI0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 18, 0),
[HWBLK_SDHI1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 17, 0),
[HWBLK_KEYSC] = SH_CLK_MSTP32(&r_clk, MSTPCR2, 14, 0),
[HWBLK_USB] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 11, 0),
[HWBLK_2DG] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 10, 0),
[HWBLK_SIU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 8, 0),
[HWBLK_VEU2H1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 6, 0),
[HWBLK_VOU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
[HWBLK_BEU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
[HWBLK_CEU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
[HWBLK_VEU2H0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 2, 0),
[HWBLK_VPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 1, 0),
[HWBLK_LCDC] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("rclk", &r_clk),
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("dll_clk", &dll_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]),
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("irda_clk", &div4_enable_clks[DIV4_IRDA]),
CLKDEV_CON_ID("siua_clk", &div4_reparent_clks[DIV4_SIUA]),
CLKDEV_CON_ID("siub_clk", &div4_reparent_clks[DIV4_SIUB]),
/* DIV6 clocks */
CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
/* MSTP clocks */
CLKDEV_CON_ID("tlb0", &mstp_clks[HWBLK_TLB]),
CLKDEV_CON_ID("ic0", &mstp_clks[HWBLK_IC]),
CLKDEV_CON_ID("oc0", &mstp_clks[HWBLK_OC]),
CLKDEV_CON_ID("l2c0", &mstp_clks[HWBLK_L2C]),
CLKDEV_CON_ID("ilmem0", &mstp_clks[HWBLK_ILMEM]),
CLKDEV_CON_ID("fpu0", &mstp_clks[HWBLK_FPU]),
CLKDEV_CON_ID("intc0", &mstp_clks[HWBLK_INTC]),
CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[HWBLK_DMAC0]),
CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[HWBLK_CMT]),
CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[HWBLK_DMAC1]),
CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[HWBLK_MSIOF0]),
CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[HWBLK_MSIOF1]),
CLKDEV_DEV_ID("sh_mobile_meram.0", &mstp_clks[HWBLK_MERAM]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
CLKDEV_CON_ID("adc0", &mstp_clks[HWBLK_ADC]),
CLKDEV_CON_ID("tpu0", &mstp_clks[HWBLK_TPU]),
CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),
CLKDEV_CON_ID("tsif0", &mstp_clks[HWBLK_TSIF]),
CLKDEV_CON_ID("icb0", &mstp_clks[HWBLK_ICB]),
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]),
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]),
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB]),
CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
CLKDEV_DEV_ID("siu-pcm-audio", &mstp_clks[HWBLK_SIU]),
CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU2H1]),
CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]),
CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU2H0]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[HWBLK_TMU0]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[HWBLK_TMU1]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
};
int __init arch_clk_init(void)
{
int k, ret = 0;
/* autodetect extal or dll configuration */
if (__raw_readl(PLLCR) & 0x1000)
pll_clk.parent = &dll_clk;
else
pll_clk.parent = &extal_clk;
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret |= clk_register(main_clks[k]);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
ret = sh_clk_div4_enable_register(div4_enable_clks,
DIV4_ENABLE_NR, &div4_table);
if (!ret)
ret = sh_clk_div4_reparent_register(div4_reparent_clks,
DIV4_REPARENT_NR, &div4_table);
if (!ret)
ret = sh_clk_div6_register(div6_clks, DIV6_NR);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, HWBLK_NR);
return ret;
}

View file

@ -0,0 +1,379 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7724.c
*
* SH7724 clock framework support
*
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/sh_clk.h>
#include <asm/clock.h>
#include <cpu/sh7724.h>
/* SH7724 registers */
#define FRQCRA 0xa4150000
#define FRQCRB 0xa4150004
#define VCLKCR 0xa4150048
#define FCLKACR 0xa4150008
#define FCLKBCR 0xa415000c
#define IRDACLKCR 0xa4150018
#define PLLCR 0xa4150024
#define MSTPCR0 0xa4150030
#define MSTPCR1 0xa4150034
#define MSTPCR2 0xa4150038
#define SPUCLKCR 0xa415003c
#define FLLFRQ 0xa4150050
#define LSTATS 0xa4150060
/* Fixed 32 KHz root clock for RTC and Power Management purposes */
static struct clk r_clk = {
.rate = 32768,
};
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
static struct clk extal_clk = {
.rate = 33333333,
};
/* The fll multiplies the 32khz r_clk, may be used instead of extal */
static unsigned long fll_recalc(struct clk *clk)
{
unsigned long mult = 0;
unsigned long div = 1;
if (__raw_readl(PLLCR) & 0x1000)
mult = __raw_readl(FLLFRQ) & 0x3ff;
if (__raw_readl(FLLFRQ) & 0x4000)
div = 2;
return (clk->parent->rate * mult) / div;
}
static struct sh_clk_ops fll_clk_ops = {
.recalc = fll_recalc,
};
static struct clk fll_clk = {
.ops = &fll_clk_ops,
.parent = &r_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static unsigned long pll_recalc(struct clk *clk)
{
unsigned long mult = 1;
if (__raw_readl(PLLCR) & 0x4000)
mult = (((__raw_readl(FRQCRA) >> 24) & 0x3f) + 1) * 2;
return clk->parent->rate * mult;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.flags = CLK_ENABLE_ON_INIT,
};
/* A fixed divide-by-3 block use by the div6 clocks */
static unsigned long div3_recalc(struct clk *clk)
{
return clk->parent->rate / 3;
}
static struct sh_clk_ops div3_clk_ops = {
.recalc = div3_recalc,
};
static struct clk div3_clk = {
.ops = &div3_clk_ops,
.parent = &pll_clk,
};
/* External input clock (pin name: FSIMCKA/FSIMCKB/DV_CLKI ) */
struct clk sh7724_fsimcka_clk = {
};
struct clk sh7724_fsimckb_clk = {
};
struct clk sh7724_dv_clki = {
};
static struct clk *main_clks[] = {
&r_clk,
&extal_clk,
&fll_clk,
&pll_clk,
&div3_clk,
&sh7724_fsimcka_clk,
&sh7724_fsimckb_clk,
&sh7724_dv_clki,
};
static void div4_kick(struct clk *clk)
{
unsigned long value;
/* set KICK bit in FRQCRA to update hardware setting */
value = __raw_readl(FRQCRA);
value |= (1 << 31);
__raw_writel(value, FRQCRA);
}
static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 0, 24, 32, 36, 48, 0, 72 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = divisors,
.nr_divisors = ARRAY_SIZE(divisors),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
.kick = div4_kick,
};
enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_P, DIV4_M1, DIV4_NR };
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQCRA, 20, 0x2f7d, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(FRQCRA, 12, 0x2f7c, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(FRQCRA, 8, 0x2f7c, CLK_ENABLE_ON_INIT),
[DIV4_P] = DIV4(FRQCRA, 0, 0x2f7c, 0),
[DIV4_M1] = DIV4(FRQCRB, 4, 0x2f7c, CLK_ENABLE_ON_INIT),
};
enum { DIV6_V, DIV6_I, DIV6_S, DIV6_FA, DIV6_FB, DIV6_NR };
/* Indices are important - they are the actual src selecting values */
static struct clk *common_parent[] = {
[0] = &div3_clk,
[1] = NULL,
};
static struct clk *vclkcr_parent[8] = {
[0] = &div3_clk,
[2] = &sh7724_dv_clki,
[4] = &extal_clk,
};
static struct clk *fclkacr_parent[] = {
[0] = &div3_clk,
[1] = NULL,
[2] = &sh7724_fsimcka_clk,
[3] = NULL,
};
static struct clk *fclkbcr_parent[] = {
[0] = &div3_clk,
[1] = NULL,
[2] = &sh7724_fsimckb_clk,
[3] = NULL,
};
static struct clk div6_clks[DIV6_NR] = {
[DIV6_V] = SH_CLK_DIV6_EXT(VCLKCR, 0,
vclkcr_parent, ARRAY_SIZE(vclkcr_parent), 12, 3),
[DIV6_I] = SH_CLK_DIV6_EXT(IRDACLKCR, 0,
common_parent, ARRAY_SIZE(common_parent), 6, 1),
[DIV6_S] = SH_CLK_DIV6_EXT(SPUCLKCR, CLK_ENABLE_ON_INIT,
common_parent, ARRAY_SIZE(common_parent), 6, 1),
[DIV6_FA] = SH_CLK_DIV6_EXT(FCLKACR, 0,
fclkacr_parent, ARRAY_SIZE(fclkacr_parent), 6, 2),
[DIV6_FB] = SH_CLK_DIV6_EXT(FCLKBCR, 0,
fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),
};
static struct clk mstp_clks[HWBLK_NR] = {
[HWBLK_TLB] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
[HWBLK_IC] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
[HWBLK_OC] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
[HWBLK_RSMEM] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
[HWBLK_ILMEM] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 27, CLK_ENABLE_ON_INIT),
[HWBLK_L2C] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
[HWBLK_FPU] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 24, CLK_ENABLE_ON_INIT),
[HWBLK_INTC] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, CLK_ENABLE_ON_INIT),
[HWBLK_DMAC0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 21, 0),
[HWBLK_SHYWAY] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 20, CLK_ENABLE_ON_INIT),
[HWBLK_HUDI] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
[HWBLK_UBC] = SH_CLK_MSTP32(&div4_clks[DIV4_I], MSTPCR0, 17, 0),
[HWBLK_TMU0] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
[HWBLK_CMT] = SH_CLK_MSTP32(&r_clk, MSTPCR0, 14, 0),
[HWBLK_RWDT] = SH_CLK_MSTP32(&r_clk, MSTPCR0, 13, 0),
[HWBLK_DMAC1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 12, 0),
[HWBLK_TMU1] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
[HWBLK_SCIF0] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
[HWBLK_SCIF1] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
[HWBLK_SCIF2] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
[HWBLK_SCIF3] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 6, 0),
[HWBLK_SCIF4] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 5, 0),
[HWBLK_SCIF5] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 4, 0),
[HWBLK_MSIOF0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 2, 0),
[HWBLK_MSIOF1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 1, 0),
[HWBLK_KEYSC] = SH_CLK_MSTP32(&r_clk, MSTPCR1, 12, 0),
[HWBLK_RTC] = SH_CLK_MSTP32(&r_clk, MSTPCR1, 11, 0),
[HWBLK_IIC0] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
[HWBLK_IIC1] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 8, 0),
[HWBLK_MMC] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 29, 0),
[HWBLK_ETHER] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 28, 0),
[HWBLK_ATAPI] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 26, 0),
[HWBLK_TPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 25, 0),
[HWBLK_IRDA] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
[HWBLK_TSIF] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 22, 0),
[HWBLK_USB1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 21, 0),
[HWBLK_USB0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 20, 0),
[HWBLK_2DG] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 19, 0),
[HWBLK_SDHI0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 18, 0),
[HWBLK_SDHI1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 17, 0),
[HWBLK_VEU1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 15, 0),
[HWBLK_CEU1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 13, 0),
[HWBLK_BEU1] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 12, 0),
[HWBLK_2DDMAC] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR2, 10, 0),
[HWBLK_SPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 9, 0),
[HWBLK_JPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 6, 0),
[HWBLK_VOU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
[HWBLK_BEU0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
[HWBLK_CEU0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
[HWBLK_VEU0] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 2, 0),
[HWBLK_VPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 1, 0),
[HWBLK_LCDC] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("rclk", &r_clk),
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("fll_clk", &fll_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
CLKDEV_CON_ID("div3_clk", &div3_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("vpu_clk", &div4_clks[DIV4_M1]),
/* DIV6 clocks */
CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FA]),
CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FB]),
CLKDEV_CON_ID("irda_clk", &div6_clks[DIV6_I]),
CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_S]),
/* MSTP clocks */
CLKDEV_CON_ID("tlb0", &mstp_clks[HWBLK_TLB]),
CLKDEV_CON_ID("ic0", &mstp_clks[HWBLK_IC]),
CLKDEV_CON_ID("oc0", &mstp_clks[HWBLK_OC]),
CLKDEV_CON_ID("rs0", &mstp_clks[HWBLK_RSMEM]),
CLKDEV_CON_ID("ilmem0", &mstp_clks[HWBLK_ILMEM]),
CLKDEV_CON_ID("l2c0", &mstp_clks[HWBLK_L2C]),
CLKDEV_CON_ID("fpu0", &mstp_clks[HWBLK_FPU]),
CLKDEV_CON_ID("intc0", &mstp_clks[HWBLK_INTC]),
CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[HWBLK_DMAC0]),
CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[HWBLK_TMU0]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[HWBLK_TMU1]),
CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[HWBLK_CMT]),
CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[HWBLK_DMAC1]),
CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[HWBLK_MSIOF0]),
CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[HWBLK_MSIOF1]),
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC0]),
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[HWBLK_IIC1]),
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[HWBLK_MMC]),
CLKDEV_DEV_ID("sh7724-ether.0", &mstp_clks[HWBLK_ETHER]),
CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
CLKDEV_CON_ID("tpu0", &mstp_clks[HWBLK_TPU]),
CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),
CLKDEV_CON_ID("tsif0", &mstp_clks[HWBLK_TSIF]),
CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[HWBLK_USB1]),
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[HWBLK_USB0]),
CLKDEV_CON_ID("usb1", &mstp_clks[HWBLK_USB1]),
CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB0]),
CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]),
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]),
CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU1]),
CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[HWBLK_CEU1]),
CLKDEV_CON_ID("beu1", &mstp_clks[HWBLK_BEU1]),
CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]),
CLKDEV_DEV_ID("sh_fsi.0", &mstp_clks[HWBLK_SPU]),
CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]),
CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]),
CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]),
CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
};
int __init arch_clk_init(void)
{
int k, ret = 0;
/* autodetect extal or fll configuration */
if (__raw_readl(PLLCR) & 0x1000)
pll_clk.parent = &fll_clk;
else
pll_clk.parent = &extal_clk;
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
if (!ret)
ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, HWBLK_NR);
return ret;
}

View file

@ -0,0 +1,260 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7734.c
*
* Clock framework for SH7734
*
* Copyright (C) 2011, 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
* Copyright (C) 2011, 2012 Renesas Solutions Corp.
*
* 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 <linux/clkdev.h>
#include <linux/delay.h>
#include <asm/clock.h>
#include <asm/freq.h>
static struct clk extal_clk = {
.rate = 33333333,
};
#define MODEMR (0xFFCC0020)
#define MODEMR_MASK (0x6)
#define MODEMR_533MHZ (0x2)
static unsigned long pll_recalc(struct clk *clk)
{
int mode = 12;
u32 r = __raw_readl(MODEMR);
if ((r & MODEMR_MASK) & MODEMR_533MHZ)
mode = 16;
return clk->parent->rate * mode;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.parent = &extal_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static struct clk *main_clks[] = {
&extal_clk,
&pll_clk,
};
static int multipliers[] = { 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static int divisors[] = { 1, 3, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = divisors,
.nr_divisors = ARRAY_SIZE(divisors),
.multipliers = multipliers,
.nr_multipliers = ARRAY_SIZE(multipliers),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_S, DIV4_B, DIV4_M, DIV4_S1, DIV4_P, DIV4_NR };
#define DIV4(_reg, _bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_I] = DIV4(FRQMR1, 28, 0x0003, CLK_ENABLE_ON_INIT),
[DIV4_S] = DIV4(FRQMR1, 20, 0x000C, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(FRQMR1, 16, 0x0140, CLK_ENABLE_ON_INIT),
[DIV4_M] = DIV4(FRQMR1, 12, 0x0004, CLK_ENABLE_ON_INIT),
[DIV4_S1] = DIV4(FRQMR1, 4, 0x0030, CLK_ENABLE_ON_INIT),
[DIV4_P] = DIV4(FRQMR1, 0, 0x0140, CLK_ENABLE_ON_INIT),
};
#define MSTPCR0 0xFFC80030
#define MSTPCR1 0xFFC80034
#define MSTPCR3 0xFFC8003C
enum {
MSTP030, MSTP029, /* IIC */
MSTP026, MSTP025, MSTP024, /* SCIF */
MSTP023,
MSTP022, MSTP021,
MSTP019, /* HSCIF */
MSTP016, MSTP015, MSTP014, /* TMU / TIMER */
MSTP012, MSTP011, MSTP010, MSTP009, MSTP008, /* SSI */
MSTP007, /* HSPI */
MSTP115, /* ADMAC */
MSTP114, /* GETHER */
MSTP111, /* DMAC */
MSTP109, /* VIDEOIN1 */
MSTP108, /* VIDEOIN0 */
MSTP107, /* RGPVBG */
MSTP106, /* 2DG */
MSTP103, /* VIEW */
MSTP100, /* USB */
MSTP331, /* MMC */
MSTP330, /* MIMLB */
MSTP323, /* SDHI0 */
MSTP322, /* SDHI1 */
MSTP321, /* SDHI2 */
MSTP320, /* RQSPI */
MSTP319, /* SRC0 */
MSTP318, /* SRC1 */
MSTP317, /* RSPI */
MSTP316, /* RCAN0 */
MSTP315, /* RCAN1 */
MSTP314, /* FLTCL */
MSTP313, /* ADC */
MSTP312, /* MTU */
MSTP304, /* IE-BUS */
MSTP303, /* RTC */
MSTP302, /* HIF */
MSTP301, /* STIF0 */
MSTP300, /* STIF1 */
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
/* MSTPCR0 */
[MSTP030] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 30, 0),
[MSTP029] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 29, 0),
[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
[MSTP023] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
[MSTP022] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
[MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
[MSTP019] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
[MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0),
[MSTP015] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
[MSTP014] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 14, 0),
[MSTP012] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 12, 0),
[MSTP011] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
[MSTP010] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
[MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
[MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
[MSTP007] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
/* MSTPCR1 */
[MSTP115] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 15, 0),
[MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
[MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
[MSTP109] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
[MSTP108] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 8, 0),
[MSTP107] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 7, 0),
[MSTP106] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 6, 0),
[MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
[MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 0, 0),
/* MSTPCR3 */
[MSTP331] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 31, 0),
[MSTP330] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 30, 0),
[MSTP323] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 23, 0),
[MSTP322] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 22, 0),
[MSTP321] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 21, 0),
[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 20, 0),
[MSTP319] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 19, 0),
[MSTP318] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 18, 0),
[MSTP317] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 17, 0),
[MSTP316] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 16, 0),
[MSTP315] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 15, 0),
[MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 14, 0),
[MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 13, 0),
[MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 12, 0),
[MSTP304] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 4, 0),
[MSTP303] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 3, 0),
[MSTP302] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 2, 0),
[MSTP301] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 1, 0),
[MSTP300] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 0, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* clocks */
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_S]),
CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_M]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("shyway_clk1", &div4_clks[DIV4_S1]),
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
/* MSTP32 clocks */
CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]),
CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP024]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP023]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP022]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP016]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP015]),
CLKDEV_ICK_ID("fck", "sh-tmu.2", &mstp_clks[MSTP014]),
CLKDEV_CON_ID("ssi0", &mstp_clks[MSTP012]),
CLKDEV_CON_ID("ssi1", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("ssi2", &mstp_clks[MSTP010]),
CLKDEV_CON_ID("ssi3", &mstp_clks[MSTP009]),
CLKDEV_CON_ID("sss", &mstp_clks[MSTP008]),
CLKDEV_CON_ID("hspi", &mstp_clks[MSTP007]),
CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP100]),
CLKDEV_CON_ID("videoin0", &mstp_clks[MSTP109]),
CLKDEV_CON_ID("videoin1", &mstp_clks[MSTP108]),
CLKDEV_CON_ID("rgpvg", &mstp_clks[MSTP107]),
CLKDEV_CON_ID("2dg", &mstp_clks[MSTP106]),
CLKDEV_CON_ID("view", &mstp_clks[MSTP103]),
CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP331]),
CLKDEV_CON_ID("mimlb0", &mstp_clks[MSTP330]),
CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP323]),
CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP322]),
CLKDEV_CON_ID("sdhi2", &mstp_clks[MSTP321]),
CLKDEV_CON_ID("rqspi0", &mstp_clks[MSTP320]),
CLKDEV_CON_ID("src0", &mstp_clks[MSTP319]),
CLKDEV_CON_ID("src1", &mstp_clks[MSTP318]),
CLKDEV_CON_ID("rsp0", &mstp_clks[MSTP317]),
CLKDEV_CON_ID("rcan0", &mstp_clks[MSTP316]),
CLKDEV_CON_ID("rcan1", &mstp_clks[MSTP315]),
CLKDEV_CON_ID("fltcl0", &mstp_clks[MSTP314]),
CLKDEV_CON_ID("adc0", &mstp_clks[MSTP313]),
CLKDEV_CON_ID("mtu0", &mstp_clks[MSTP312]),
CLKDEV_CON_ID("iebus0", &mstp_clks[MSTP304]),
CLKDEV_DEV_ID("sh7734-gether.0", &mstp_clks[MSTP114]),
CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP303]),
CLKDEV_CON_ID("hif0", &mstp_clks[MSTP302]),
CLKDEV_CON_ID("stif0", &mstp_clks[MSTP301]),
CLKDEV_CON_ID("stif1", &mstp_clks[MSTP300]),
};
int __init arch_clk_init(void)
{
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(main_clks); i++)
ret |= clk_register(main_clks[i]);
for (i = 0; i < ARRAY_SIZE(lookups); i++)
clkdev_add(&lookups[i]);
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
&div4_table);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,155 @@
/*
* arch/sh/kernel/cpu/sh4/clock-sh7757.c
*
* SH7757 support for the clock framework
*
* Copyright (C) 2009-2010 Renesas Solutions Corp.
*
* 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 <linux/clkdev.h>
#include <asm/clock.h>
#include <asm/freq.h>
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
static struct clk extal_clk = {
.rate = 48000000,
};
static unsigned long pll_recalc(struct clk *clk)
{
int multiplier;
multiplier = test_mode_pin(MODE_PIN0) ? 24 : 16;
return clk->parent->rate * multiplier;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.parent = &extal_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static struct clk *clks[] = {
&extal_clk,
&pll_clk,
};
static unsigned int div2[] = { 1, 1, 2, 1, 1, 4, 1, 6,
1, 1, 1, 16, 1, 24, 1, 1 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = div2,
.nr_divisors = ARRAY_SIZE(div2),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_SH, DIV4_P, DIV4_NR };
#define DIV4(_bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, FRQCR, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
/*
* P clock is always enable, because some P clock modules is used
* by Host PC.
*/
[DIV4_P] = DIV4(0, 0x2800, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(12, 0x00a0, CLK_ENABLE_ON_INIT),
[DIV4_I] = DIV4(20, 0x0004, CLK_ENABLE_ON_INIT),
};
#define MSTPCR0 0xffc80030
#define MSTPCR1 0xffc80034
#define MSTPCR2 0xffc10028
enum { MSTP004, MSTP000, MSTP127, MSTP114, MSTP113, MSTP112,
MSTP111, MSTP110, MSTP103, MSTP102, MSTP220,
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
/* MSTPCR0 */
[MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0),
[MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
/* MSTPCR1 */
[MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 27, 0),
[MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
[MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0),
[MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0),
[MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
[MSTP110] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 10, 0),
[MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
[MSTP102] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 2, 0),
/* MSTPCR2 */
[MSTP220] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 20, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP004]),
CLKDEV_CON_ID("riic0", &mstp_clks[MSTP000]),
CLKDEV_CON_ID("riic1", &mstp_clks[MSTP000]),
CLKDEV_CON_ID("riic2", &mstp_clks[MSTP000]),
CLKDEV_CON_ID("riic3", &mstp_clks[MSTP000]),
CLKDEV_CON_ID("riic4", &mstp_clks[MSTP000]),
CLKDEV_CON_ID("riic5", &mstp_clks[MSTP000]),
CLKDEV_CON_ID("riic6", &mstp_clks[MSTP000]),
CLKDEV_CON_ID("riic7", &mstp_clks[MSTP000]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP113]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP114]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP112]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP111]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP110]),
CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
CLKDEV_DEV_ID("rspi.2", &mstp_clks[MSTP127]),
};
int __init arch_clk_init(void)
{
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
for (i = 0; i < ARRAY_SIZE(lookups); i++)
clkdev_add(&lookups[i]);
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
&div4_table);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,119 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7763.c
*
* SH7763 support for the clock framework
*
* Copyright (C) 2005 Paul Mundt
* Copyright (C) 2007 Yoshihiro Shimoda
*
* 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 <linux/clkdev.h>
#include <asm/clock.h>
#include <asm/freq.h>
#include <asm/io.h>
static int bfc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
static int p0fc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
static int cfc_divisors[] = { 1, 1, 4, 1, 1, 1, 1, 1 };
static void master_clk_init(struct clk *clk)
{
clk->rate *= p0fc_divisors[(__raw_readl(FRQCR) >> 4) & 0x07];
}
static struct sh_clk_ops sh7763_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 4) & 0x07);
return clk->parent->rate / p0fc_divisors[idx];
}
static struct sh_clk_ops sh7763_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 16) & 0x07);
return clk->parent->rate / bfc_divisors[idx];
}
static struct sh_clk_ops sh7763_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static struct sh_clk_ops sh7763_cpu_clk_ops = {
.recalc = followparent_recalc,
};
static struct sh_clk_ops *sh7763_clk_ops[] = {
&sh7763_master_clk_ops,
&sh7763_module_clk_ops,
&sh7763_bus_clk_ops,
&sh7763_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7763_clk_ops))
*ops = sh7763_clk_ops[idx];
}
static unsigned long shyway_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 20) & 0x07);
return clk->parent->rate / cfc_divisors[idx];
}
static struct sh_clk_ops sh7763_shyway_clk_ops = {
.recalc = shyway_clk_recalc,
};
static struct clk sh7763_shyway_clk = {
.flags = CLK_ENABLE_ON_INIT,
.ops = &sh7763_shyway_clk_ops,
};
/*
* Additional SH7763-specific on-chip clocks that aren't already part of the
* clock framework
*/
static struct clk *sh7763_onchip_clocks[] = {
&sh7763_shyway_clk,
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("shyway_clk", &sh7763_shyway_clk),
};
int __init arch_clk_init(void)
{
struct clk *clk;
int i, ret = 0;
cpg_clk_init();
clk = clk_get(NULL, "master_clk");
for (i = 0; i < ARRAY_SIZE(sh7763_onchip_clocks); i++) {
struct clk *clkp = sh7763_onchip_clocks[i];
clkp->parent = clk;
ret |= clk_register(clkp);
}
clk_put(clk);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
return ret;
}

View file

@ -0,0 +1,73 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7770.c
*
* SH7770 support for the clock framework
*
* 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>
static int ifc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 1 };
static int bfc_divisors[] = { 1, 1, 1, 1, 1, 8,12, 1 };
static int pfc_divisors[] = { 1, 8, 1,10,12,16, 1, 1 };
static void master_clk_init(struct clk *clk)
{
clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> 28) & 0x000f];
}
static struct sh_clk_ops sh7770_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 28) & 0x000f);
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh7770_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = (__raw_readl(FRQCR) & 0x000f);
return clk->parent->rate / bfc_divisors[idx];
}
static struct sh_clk_ops sh7770_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 24) & 0x000f);
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh7770_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7770_clk_ops[] = {
&sh7770_master_clk_ops,
&sh7770_module_clk_ops,
&sh7770_bus_clk_ops,
&sh7770_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7770_clk_ops))
*ops = sh7770_clk_ops[idx];
}

View file

@ -0,0 +1,125 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7780.c
*
* SH7780 support for the clock framework
*
* 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 <linux/clkdev.h>
#include <asm/clock.h>
#include <asm/freq.h>
#include <asm/io.h>
static int ifc_divisors[] = { 2, 4 };
static int bfc_divisors[] = { 1, 1, 1, 8, 12, 16, 24, 1 };
static int pfc_divisors[] = { 1, 24, 24, 1 };
static int cfc_divisors[] = { 1, 1, 4, 1, 6, 1, 1, 1 };
static void master_clk_init(struct clk *clk)
{
clk->rate *= pfc_divisors[__raw_readl(FRQCR) & 0x0003];
}
static struct sh_clk_ops sh7780_master_clk_ops = {
.init = master_clk_init,
};
static unsigned long module_clk_recalc(struct clk *clk)
{
int idx = (__raw_readl(FRQCR) & 0x0003);
return clk->parent->rate / pfc_divisors[idx];
}
static struct sh_clk_ops sh7780_module_clk_ops = {
.recalc = module_clk_recalc,
};
static unsigned long bus_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 16) & 0x0007);
return clk->parent->rate / bfc_divisors[idx];
}
static struct sh_clk_ops sh7780_bus_clk_ops = {
.recalc = bus_clk_recalc,
};
static unsigned long cpu_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 24) & 0x0001);
return clk->parent->rate / ifc_divisors[idx];
}
static struct sh_clk_ops sh7780_cpu_clk_ops = {
.recalc = cpu_clk_recalc,
};
static struct sh_clk_ops *sh7780_clk_ops[] = {
&sh7780_master_clk_ops,
&sh7780_module_clk_ops,
&sh7780_bus_clk_ops,
&sh7780_cpu_clk_ops,
};
void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
{
if (idx < ARRAY_SIZE(sh7780_clk_ops))
*ops = sh7780_clk_ops[idx];
}
static unsigned long shyway_clk_recalc(struct clk *clk)
{
int idx = ((__raw_readl(FRQCR) >> 20) & 0x0007);
return clk->parent->rate / cfc_divisors[idx];
}
static struct sh_clk_ops sh7780_shyway_clk_ops = {
.recalc = shyway_clk_recalc,
};
static struct clk sh7780_shyway_clk = {
.flags = CLK_ENABLE_ON_INIT,
.ops = &sh7780_shyway_clk_ops,
};
/*
* Additional SH7780-specific on-chip clocks that aren't already part of the
* clock framework
*/
static struct clk *sh7780_onchip_clocks[] = {
&sh7780_shyway_clk,
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("shyway_clk", &sh7780_shyway_clk),
};
int __init arch_clk_init(void)
{
struct clk *clk;
int i, ret = 0;
cpg_clk_init();
clk = clk_get(NULL, "master_clk");
for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) {
struct clk *clkp = sh7780_onchip_clocks[i];
clkp->parent = clk;
ret |= clk_register(clkp);
}
clk_put(clk);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
return ret;
}

View file

@ -0,0 +1,177 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7785.c
*
* SH7785 support for the clock framework
*
* Copyright (C) 2007 - 2010 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/clk.h>
#include <linux/io.h>
#include <linux/cpufreq.h>
#include <linux/clkdev.h>
#include <asm/clock.h>
#include <asm/freq.h>
#include <cpu/sh7785.h>
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
static struct clk extal_clk = {
.rate = 33333333,
};
static unsigned long pll_recalc(struct clk *clk)
{
int multiplier;
multiplier = test_mode_pin(MODE_PIN4) ? 36 : 72;
return clk->parent->rate * multiplier;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.parent = &extal_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static struct clk *clks[] = {
&extal_clk,
&pll_clk,
};
static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
24, 32, 36, 48 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = div2,
.nr_divisors = ARRAY_SIZE(div2),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_GA,
DIV4_DU, DIV4_P, DIV4_NR };
#define DIV4(_bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_P] = DIV4(0, 0x0f80, 0),
[DIV4_DU] = DIV4(4, 0x0ff0, 0),
[DIV4_GA] = DIV4(8, 0x0030, 0),
[DIV4_DDR] = DIV4(12, 0x000c, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(16, 0x0fe0, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(20, 0x000c, CLK_ENABLE_ON_INIT),
[DIV4_U] = DIV4(24, 0x000c, CLK_ENABLE_ON_INIT),
[DIV4_I] = DIV4(28, 0x000e, CLK_ENABLE_ON_INIT),
};
#define MSTPCR0 0xffc80030
#define MSTPCR1 0xffc80034
enum { MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024,
MSTP021, MSTP020, MSTP017, MSTP016,
MSTP013, MSTP012, MSTP009, MSTP008, MSTP003, MSTP002,
MSTP119, MSTP117, MSTP105, MSTP104, MSTP100,
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
/* MSTPCR0 */
[MSTP029] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 29, 0),
[MSTP028] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 28, 0),
[MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0),
[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
[MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
[MSTP020] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 20, 0),
[MSTP017] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 17, 0),
[MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0),
[MSTP013] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 13, 0),
[MSTP012] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 12, 0),
[MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
[MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
[MSTP003] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 3, 0),
[MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
/* MSTPCR1 */
[MSTP119] = SH_CLK_MSTP32(NULL, MSTPCR1, 19, 0),
[MSTP117] = SH_CLK_MSTP32(NULL, MSTPCR1, 17, 0),
[MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0),
[MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
[MSTP100] = SH_CLK_MSTP32(NULL, MSTPCR1, 0, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("du_clk", &div4_clks[DIV4_DU]),
CLKDEV_CON_ID("ga_clk", &div4_clks[DIV4_GA]),
CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]),
CLKDEV_CON_ID("hac1_fck", &mstp_clks[MSTP017]),
CLKDEV_CON_ID("hac0_fck", &mstp_clks[MSTP016]),
CLKDEV_CON_ID("mmcif_fck", &mstp_clks[MSTP013]),
CLKDEV_CON_ID("flctl_fck", &mstp_clks[MSTP012]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP008]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP009]),
CLKDEV_CON_ID("siof_fck", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP117]),
CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
CLKDEV_CON_ID("gdta_fck", &mstp_clks[MSTP100]),
};
int __init arch_clk_init(void)
{
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
for (i = 0; i < ARRAY_SIZE(lookups); i++)
clkdev_add(&lookups[i]);
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
&div4_table);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,192 @@
/*
* arch/sh/kernel/cpu/sh4a/clock-sh7786.c
*
* SH7786 support for the clock framework
*
* Copyright (C) 2010 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/clk.h>
#include <linux/io.h>
#include <linux/clkdev.h>
#include <asm/clock.h>
#include <asm/freq.h>
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
static struct clk extal_clk = {
.rate = 33333333,
};
static unsigned long pll_recalc(struct clk *clk)
{
int multiplier;
/*
* Clock modes 0, 1, and 2 use an x64 multiplier against PLL1,
* while modes 3, 4, and 5 use an x32.
*/
multiplier = (sh_mv.mv_mode_pins() & 0xf) < 3 ? 64 : 32;
return clk->parent->rate * multiplier;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.parent = &extal_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static struct clk *clks[] = {
&extal_clk,
&pll_clk,
};
static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
24, 32, 36, 48 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = div2,
.nr_divisors = ARRAY_SIZE(div2),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_DU, DIV4_P, DIV4_NR };
#define DIV4(_bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_P] = DIV4(0, 0x0b40, 0),
[DIV4_DU] = DIV4(4, 0x0010, 0),
[DIV4_DDR] = DIV4(12, 0x0002, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(16, 0x0360, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(20, 0x0002, CLK_ENABLE_ON_INIT),
[DIV4_I] = DIV4(28, 0x0006, CLK_ENABLE_ON_INIT),
};
#define MSTPCR0 0xffc40030
#define MSTPCR1 0xffc40034
enum { MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024,
MSTP023, MSTP022, MSTP021, MSTP020, MSTP017, MSTP016,
MSTP015, MSTP014, MSTP011, MSTP010, MSTP009, MSTP008,
MSTP005, MSTP004, MSTP002,
MSTP112, MSTP110, MSTP109, MSTP108,
MSTP105, MSTP104, MSTP103, MSTP102,
MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
/* MSTPCR0 */
[MSTP029] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 29, 0),
[MSTP028] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 28, 0),
[MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0),
[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
[MSTP023] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
[MSTP022] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
[MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
[MSTP020] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 20, 0),
[MSTP017] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 17, 0),
[MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0),
[MSTP015] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
[MSTP014] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 14, 0),
[MSTP011] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
[MSTP010] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
[MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
[MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
[MSTP005] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
[MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0),
[MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
/* MSTPCR1 */
[MSTP112] = SH_CLK_MSTP32(NULL, MSTPCR1, 12, 0),
[MSTP110] = SH_CLK_MSTP32(NULL, MSTPCR1, 10, 0),
[MSTP109] = SH_CLK_MSTP32(NULL, MSTPCR1, 9, 0),
[MSTP108] = SH_CLK_MSTP32(NULL, MSTPCR1, 8, 0),
[MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0),
[MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
[MSTP103] = SH_CLK_MSTP32(NULL, MSTPCR1, 3, 0),
[MSTP102] = SH_CLK_MSTP32(NULL, MSTPCR1, 2, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("du_clk", &div4_clks[DIV4_DU]),
CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]),
CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]),
CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]),
CLKDEV_CON_ID("hac1_fck", &mstp_clks[MSTP017]),
CLKDEV_CON_ID("hac0_fck", &mstp_clks[MSTP016]),
CLKDEV_CON_ID("i2c1_fck", &mstp_clks[MSTP015]),
CLKDEV_CON_ID("i2c0_fck", &mstp_clks[MSTP014]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP008]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP009]),
CLKDEV_ICK_ID("fck", "sh-tmu.2", &mstp_clks[MSTP010]),
CLKDEV_ICK_ID("fck", "sh-tmu.3", &mstp_clks[MSTP011]),
CLKDEV_CON_ID("sdif1_fck", &mstp_clks[MSTP005]),
CLKDEV_CON_ID("sdif0_fck", &mstp_clks[MSTP004]),
CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP112]),
CLKDEV_CON_ID("pcie2_fck", &mstp_clks[MSTP110]),
CLKDEV_CON_ID("pcie1_fck", &mstp_clks[MSTP109]),
CLKDEV_CON_ID("pcie0_fck", &mstp_clks[MSTP108]),
CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
CLKDEV_CON_ID("du_fck", &mstp_clks[MSTP103]),
CLKDEV_CON_ID("ether_fck", &mstp_clks[MSTP102]),
};
int __init arch_clk_init(void)
{
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
for (i = 0; i < ARRAY_SIZE(lookups); i++)
clkdev_add(&lookups[i]);
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
&div4_table);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,151 @@
/*
* arch/sh/kernel/cpu/sh4/clock-shx3.c
*
* SH-X3 support for the clock framework
*
* Copyright (C) 2006-2007 Renesas Technology Corp.
* Copyright (C) 2006-2007 Renesas Solutions Corp.
* Copyright (C) 2006-2010 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 <linux/clkdev.h>
#include <asm/clock.h>
#include <asm/freq.h>
/*
* Default rate for the root input clock, reset this with clk_set_rate()
* from the platform code.
*/
static struct clk extal_clk = {
.rate = 16666666,
};
static unsigned long pll_recalc(struct clk *clk)
{
/* PLL1 has a fixed x72 multiplier. */
return clk->parent->rate * 72;
}
static struct sh_clk_ops pll_clk_ops = {
.recalc = pll_recalc,
};
static struct clk pll_clk = {
.ops = &pll_clk_ops,
.parent = &extal_clk,
.flags = CLK_ENABLE_ON_INIT,
};
static struct clk *clks[] = {
&extal_clk,
&pll_clk,
};
static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
24, 32, 36, 48 };
static struct clk_div_mult_table div4_div_mult_table = {
.divisors = div2,
.nr_divisors = ARRAY_SIZE(div2),
};
static struct clk_div4_table div4_table = {
.div_mult_table = &div4_div_mult_table,
};
enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_SHA, DIV4_P, DIV4_NR };
#define DIV4(_bit, _mask, _flags) \
SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags)
struct clk div4_clks[DIV4_NR] = {
[DIV4_P] = DIV4(0, 0x0f80, 0),
[DIV4_SHA] = DIV4(4, 0x0ff0, 0),
[DIV4_DDR] = DIV4(12, 0x000c, CLK_ENABLE_ON_INIT),
[DIV4_B] = DIV4(16, 0x0fe0, CLK_ENABLE_ON_INIT),
[DIV4_SH] = DIV4(20, 0x000c, CLK_ENABLE_ON_INIT),
[DIV4_I] = DIV4(28, 0x000e, CLK_ENABLE_ON_INIT),
};
#define MSTPCR0 0xffc00030
#define MSTPCR1 0xffc00034
enum { MSTP027, MSTP026, MSTP025, MSTP024,
MSTP009, MSTP008, MSTP003, MSTP002,
MSTP001, MSTP000, MSTP119, MSTP105,
MSTP104, MSTP_NR };
static struct clk mstp_clks[MSTP_NR] = {
/* MSTPCR0 */
[MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0),
[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
[MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
[MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
[MSTP003] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 3, 0),
[MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
[MSTP001] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
[MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
/* MSTPCR1 */
[MSTP119] = SH_CLK_MSTP32(NULL, MSTPCR1, 19, 0),
[MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0),
[MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
};
static struct clk_lookup lookups[] = {
/* main clocks */
CLKDEV_CON_ID("extal", &extal_clk),
CLKDEV_CON_ID("pll_clk", &pll_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
CLKDEV_CON_ID("shywaya_clk", &div4_clks[DIV4_SHA]),
CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]),
CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
/* MSTP32 clocks */
CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]),
CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]),
CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP008]),
CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP009]),
CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
};
int __init arch_clk_init(void)
{
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(clks); i++)
ret |= clk_register(clks[i]);
for (i = 0; i < ARRAY_SIZE(lookups); i++)
clkdev_add(&lookups[i]);
if (!ret)
ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
&div4_table);
if (!ret)
ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
return ret;
}

View file

@ -0,0 +1,34 @@
/*
* Shared support for SH-X3 interrupt controllers.
*
* Copyright (C) 2009 - 2010 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/irq.h>
#include <linux/io.h>
#include <linux/init.h>
#define INTACK 0xfe4100b8
#define INTACKCLR 0xfe4100bc
#define INTC_USERIMASK 0xfe411000
#ifdef CONFIG_INTC_BALANCING
unsigned int irq_lookup(unsigned int irq)
{
return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
}
void irq_finish(unsigned int irq)
{
__raw_writel(irq2evt(irq), INTACKCLR);
}
#endif
static int __init shx3_irq_setup(void)
{
return register_intc_userimask(INTC_USERIMASK);
}
arch_initcall(shx3_irq_setup);

View file

@ -0,0 +1,302 @@
/*
* Performance events support for SH-4A performance counters
*
* Copyright (C) 2009, 2010 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/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/perf_event.h>
#include <asm/processor.h>
#define PPC_CCBR(idx) (0xff200800 + (sizeof(u32) * idx))
#define PPC_PMCTR(idx) (0xfc100000 + (sizeof(u32) * idx))
#define CCBR_CIT_MASK (0x7ff << 6)
#define CCBR_DUC (1 << 3)
#define CCBR_CMDS (1 << 1)
#define CCBR_PPCE (1 << 0)
#ifdef CONFIG_CPU_SHX3
/*
* The PMCAT location for SH-X3 CPUs was quietly moved, while the CCBR
* and PMCTR locations remains tentatively constant. This change remains
* wholly undocumented, and was simply found through trial and error.
*
* Early cuts of SH-X3 still appear to use the SH-X/SH-X2 locations, and
* it's unclear when this ceased to be the case. For now we always use
* the new location (if future parts keep up with this trend then
* scanning for them at runtime also remains a viable option.)
*
* The gap in the register space also suggests that there are other
* undocumented counters, so this will need to be revisited at a later
* point in time.
*/
#define PPC_PMCAT 0xfc100240
#else
#define PPC_PMCAT 0xfc100080
#endif
#define PMCAT_OVF3 (1 << 27)
#define PMCAT_CNN3 (1 << 26)
#define PMCAT_CLR3 (1 << 25)
#define PMCAT_OVF2 (1 << 19)
#define PMCAT_CLR2 (1 << 17)
#define PMCAT_OVF1 (1 << 11)
#define PMCAT_CNN1 (1 << 10)
#define PMCAT_CLR1 (1 << 9)
#define PMCAT_OVF0 (1 << 3)
#define PMCAT_CLR0 (1 << 1)
static struct sh_pmu sh4a_pmu;
/*
* Supported raw event codes:
*
* Event Code Description
* ---------- -----------
*
* 0x0000 number of elapsed cycles
* 0x0200 number of elapsed cycles in privileged mode
* 0x0280 number of elapsed cycles while SR.BL is asserted
* 0x0202 instruction execution
* 0x0203 instruction execution in parallel
* 0x0204 number of unconditional branches
* 0x0208 number of exceptions
* 0x0209 number of interrupts
* 0x0220 UTLB miss caused by instruction fetch
* 0x0222 UTLB miss caused by operand access
* 0x02a0 number of ITLB misses
* 0x0028 number of accesses to instruction memories
* 0x0029 number of accesses to instruction cache
* 0x002a instruction cache miss
* 0x022e number of access to instruction X/Y memory
* 0x0030 number of reads to operand memories
* 0x0038 number of writes to operand memories
* 0x0031 number of operand cache read accesses
* 0x0039 number of operand cache write accesses
* 0x0032 operand cache read miss
* 0x003a operand cache write miss
* 0x0236 number of reads to operand X/Y memory
* 0x023e number of writes to operand X/Y memory
* 0x0237 number of reads to operand U memory
* 0x023f number of writes to operand U memory
* 0x0337 number of U memory read buffer misses
* 0x02b4 number of wait cycles due to operand read access
* 0x02bc number of wait cycles due to operand write access
* 0x0033 number of wait cycles due to operand cache read miss
* 0x003b number of wait cycles due to operand cache write miss
*/
/*
* Special reserved bits used by hardware emulators, read values will
* vary, but writes must always be 0.
*/
#define PMCAT_EMU_CLR_MASK ((1 << 24) | (1 << 16) | (1 << 8) | (1 << 0))
static const int sh4a_general_events[] = {
[PERF_COUNT_HW_CPU_CYCLES] = 0x0000,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x0202,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x0029, /* I-cache */
[PERF_COUNT_HW_CACHE_MISSES] = 0x002a, /* I-cache */
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0204,
[PERF_COUNT_HW_BRANCH_MISSES] = -1,
[PERF_COUNT_HW_BUS_CYCLES] = -1,
};
#define C(x) PERF_COUNT_HW_CACHE_##x
static const int sh4a_cache_events
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
{
[ C(L1D) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0031,
[ C(RESULT_MISS) ] = 0x0032,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0039,
[ C(RESULT_MISS) ] = 0x003a,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(L1I) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0029,
[ C(RESULT_MISS) ] = 0x002a,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(LL) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0030,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0038,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(DTLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0222,
[ C(RESULT_MISS) ] = 0x0220,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(ITLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0x02a0,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
[ C(BPU) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
[ C(NODE) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
};
static int sh4a_event_map(int event)
{
return sh4a_general_events[event];
}
static u64 sh4a_pmu_read(int idx)
{
return __raw_readl(PPC_PMCTR(idx));
}
static void sh4a_pmu_disable(struct hw_perf_event *hwc, int idx)
{
unsigned int tmp;
tmp = __raw_readl(PPC_CCBR(idx));
tmp &= ~(CCBR_CIT_MASK | CCBR_DUC);
__raw_writel(tmp, PPC_CCBR(idx));
}
static void sh4a_pmu_enable(struct hw_perf_event *hwc, int idx)
{
unsigned int tmp;
tmp = __raw_readl(PPC_PMCAT);
tmp &= ~PMCAT_EMU_CLR_MASK;
tmp |= idx ? PMCAT_CLR1 : PMCAT_CLR0;
__raw_writel(tmp, PPC_PMCAT);
tmp = __raw_readl(PPC_CCBR(idx));
tmp |= (hwc->config << 6) | CCBR_CMDS | CCBR_PPCE;
__raw_writel(tmp, PPC_CCBR(idx));
__raw_writel(__raw_readl(PPC_CCBR(idx)) | CCBR_DUC, PPC_CCBR(idx));
}
static void sh4a_pmu_disable_all(void)
{
int i;
for (i = 0; i < sh4a_pmu.num_events; i++)
__raw_writel(__raw_readl(PPC_CCBR(i)) & ~CCBR_DUC, PPC_CCBR(i));
}
static void sh4a_pmu_enable_all(void)
{
int i;
for (i = 0; i < sh4a_pmu.num_events; i++)
__raw_writel(__raw_readl(PPC_CCBR(i)) | CCBR_DUC, PPC_CCBR(i));
}
static struct sh_pmu sh4a_pmu = {
.name = "sh4a",
.num_events = 2,
.event_map = sh4a_event_map,
.max_events = ARRAY_SIZE(sh4a_general_events),
.raw_event_mask = 0x3ff,
.cache_events = &sh4a_cache_events,
.read = sh4a_pmu_read,
.disable = sh4a_pmu_disable,
.enable = sh4a_pmu_enable,
.disable_all = sh4a_pmu_disable_all,
.enable_all = sh4a_pmu_enable_all,
};
static int __init sh4a_pmu_init(void)
{
/*
* Make sure this CPU actually has perf counters.
*/
if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
pr_notice("HW perf events unsupported, software events only.\n");
return -ENODEV;
}
return register_sh_pmu(&sh4a_pmu);
}
early_initcall(sh4a_pmu_init);

View file

@ -0,0 +1,20 @@
#include <linux/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7722_pfc_resources[] = {
[0] = {
.start = 0xa4050100,
.end = 0xa405018f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7722", sh7722_pfc_resources,
ARRAY_SIZE(sh7722_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,30 @@
/*
* SH7723 Pinmux
*
* Copyright (C) 2008 Magnus Damm
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7723_pfc_resources[] = {
[0] = {
.start = 0xa4050100,
.end = 0xa405016f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7723", sh7723_pfc_resources,
ARRAY_SIZE(sh7723_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,35 @@
/*
* SH7724 Pinmux
*
* Copyright (C) 2009 Renesas Solutions Corp.
*
* Kuninori Morimoto <morimoto.kuninori@renesas.com>
*
* Based on SH7723 Pinmux
* Copyright (C) 2008 Magnus Damm
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7724_pfc_resources[] = {
[0] = {
.start = 0xa4050100,
.end = 0xa405016f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7724", sh7724_pfc_resources,
ARRAY_SIZE(sh7724_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,35 @@
/*
* SH7734 processor support - PFC hardware block
*
* Copyright (C) 2012 Renesas Solutions Corp.
* Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7734_pfc_resources[] = {
[0] = { /* PFC */
.start = 0xFFFC0000,
.end = 0xFFFC011C,
.flags = IORESOURCE_MEM,
},
[1] = { /* GPIO */
.start = 0xFFC40000,
.end = 0xFFC4502B,
.flags = IORESOURCE_MEM,
}
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7734", sh7734_pfc_resources,
ARRAY_SIZE(sh7734_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,35 @@
/*
* SH7757 (B0 step) Pinmux
*
* Copyright (C) 2009-2010 Renesas Solutions Corp.
*
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
*
* Based on SH7723 Pinmux
* Copyright (C) 2008 Magnus Damm
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7757_pfc_resources[] = {
[0] = {
.start = 0xffec0000,
.end = 0xffec008f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7757", sh7757_pfc_resources,
ARRAY_SIZE(sh7757_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,30 @@
/*
* SH7785 Pinmux
*
* Copyright (C) 2008 Magnus Damm
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7785_pfc_resources[] = {
[0] = {
.start = 0xffe70000,
.end = 0xffe7008f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7785", sh7785_pfc_resources,
ARRAY_SIZE(sh7785_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,35 @@
/*
* SH7786 Pinmux
*
* Copyright (C) 2008, 2009 Renesas Solutions Corp.
* Kuninori Morimoto <morimoto.kuninori@renesas.com>
*
* Based on SH7785 pinmux
*
* Copyright (C) 2008 Magnus Damm
*
* 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource sh7786_pfc_resources[] = {
[0] = {
.start = 0xffcc0000,
.end = 0xffcc008f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-sh7786", sh7786_pfc_resources,
ARRAY_SIZE(sh7786_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,29 @@
/*
* SH-X3 prototype CPU pinmux
*
* Copyright (C) 2010 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/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <cpu/pfc.h>
static struct resource shx3_pfc_resources[] = {
[0] = {
.start = 0xffc70000,
.end = 0xffc7001f,
.flags = IORESOURCE_MEM,
},
};
static int __init plat_pinmux_setup(void)
{
return sh_pfc_register("pfc-shx3", shx3_pfc_resources,
ARRAY_SIZE(shx3_pfc_resources));
}
arch_initcall(plat_pinmux_setup);

View file

@ -0,0 +1,23 @@
#include <linux/serial_sci.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#define PSCR 0xA405011E
static void sh7722_sci_init_pins(struct uart_port *port, unsigned int cflag)
{
unsigned short data;
if (port->mapbase == 0xffe00000) {
data = __raw_readw(PSCR);
data &= ~0x03cf;
if (!(cflag & CRTSCTS))
data |= 0x0340;
__raw_writew(data, PSCR);
}
}
struct plat_sci_port_ops sh7722_sci_port_ops = {
.init_pins = sh7722_sci_init_pins,
};

View file

@ -0,0 +1,450 @@
/*
* SH7343 Setup
*
* Copyright (C) 2006 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/uio_driver.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <asm/clock.h>
/* Serial */
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.type = PORT_SCIF,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xffe00000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc00)),
};
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_CKE1,
.type = PORT_SCIF,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xffe10000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc20)),
};
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_CKE1,
.type = PORT_SCIF,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xffe20000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc40)),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.type = PORT_SCIF,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xffe30000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc60)),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct resource iic0_resources[] = {
[0] = {
.name = "IIC0",
.start = 0x04470000,
.end = 0x04470017,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xe00),
.end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device iic0_device = {
.name = "i2c-sh_mobile",
.id = 0, /* "i2c0" clock */
.num_resources = ARRAY_SIZE(iic0_resources),
.resource = iic0_resources,
};
static struct resource iic1_resources[] = {
[0] = {
.name = "IIC1",
.start = 0x04750000,
.end = 0x04750017,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0x780),
.end = evt2irq(0x7e0),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device iic1_device = {
.name = "i2c-sh_mobile",
.id = 1, /* "i2c1" clock */
.num_resources = ARRAY_SIZE(iic1_resources),
.resource = iic1_resources,
};
static struct uio_info vpu_platform_data = {
.name = "VPU4",
.version = "0",
.irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
[0] = {
.name = "VPU",
.start = 0xfe900000,
.end = 0xfe9022eb,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device vpu_device = {
.name = "uio_pdrv_genirq",
.id = 0,
.dev = {
.platform_data = &vpu_platform_data,
},
.resource = vpu_resources,
.num_resources = ARRAY_SIZE(vpu_resources),
};
static struct uio_info veu_platform_data = {
.name = "VEU",
.version = "0",
.irq = evt2irq(0x8c0),
};
static struct resource veu_resources[] = {
[0] = {
.name = "VEU",
.start = 0xfe920000,
.end = 0xfe9200b7,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device veu_device = {
.name = "uio_pdrv_genirq",
.id = 1,
.dev = {
.platform_data = &veu_platform_data,
},
.resource = veu_resources,
.num_resources = ARRAY_SIZE(veu_resources),
};
static struct uio_info jpu_platform_data = {
.name = "JPU",
.version = "0",
.irq = evt2irq(0x560),
};
static struct resource jpu_resources[] = {
[0] = {
.name = "JPU",
.start = 0xfea00000,
.end = 0xfea102d3,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device jpu_device = {
.name = "uio_pdrv_genirq",
.id = 2,
.dev = {
.platform_data = &jpu_platform_data,
},
.resource = jpu_resources,
.num_resources = ARRAY_SIZE(jpu_resources),
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 0x20,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0x044a0000, 0x70),
DEFINE_RES_IRQ(evt2irq(0xf00)),
};
static struct platform_device cmt_device = {
.name = "sh-cmt-32",
.id = 0,
.dev = {
.platform_data = &cmt_platform_data,
},
.resource = cmt_resources,
.num_resources = ARRAY_SIZE(cmt_resources),
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xffd80000, 0x2c),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh7343_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&cmt_device,
&tmu0_device,
&iic0_device,
&iic1_device,
&vpu_device,
&veu_device,
&jpu_device,
};
static int __init sh7343_devices_setup(void)
{
platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20);
platform_resource_setup_memory(&veu_device, "veu", 2 << 20);
platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
return platform_add_devices(sh7343_devices,
ARRAY_SIZE(sh7343_devices));
}
arch_initcall(sh7343_devices_setup);
static struct platform_device *sh7343_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&cmt_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7343_early_devices,
ARRAY_SIZE(sh7343_early_devices));
}
enum {
UNUSED = 0,
ENABLED,
DISABLED,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
DMAC0, DMAC1, DMAC2, DMAC3,
VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU,
MFI, VPU, TPU, Z3D4, USBI0, USBI1,
MMC_ERR, MMC_TRAN, MMC_FSTAT, MMC_FRDY,
DMAC4, DMAC5, DMAC_DADERR,
KEYSC,
SCIF, SCIF1, SCIF2, SCIF3,
SIOF0, SIOF1, SIO,
FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI,
I2C1_ALI, I2C1_TACKI, I2C1_WAITI, I2C1_DTEI,
SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI,
IRDA, SDHI, CMT, TSIF, SIU,
TMU0, TMU1, TMU2,
JPU, LCDC,
/* interrupt groups */
DMAC0123, VIOVOU, MMC, DMAC45, FLCTL, I2C0, I2C1, SIM, USB,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
INTC_VECT(I2C1_ALI, 0x780), INTC_VECT(I2C1_TACKI, 0x7a0),
INTC_VECT(I2C1_WAITI, 0x7c0), INTC_VECT(I2C1_DTEI, 0x7e0),
INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820),
INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860),
INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0),
INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0),
INTC_VECT(MFI, 0x900), INTC_VECT(VPU, 0x980),
INTC_VECT(TPU, 0x9a0), INTC_VECT(Z3D4, 0x9e0),
INTC_VECT(USBI0, 0xa20), INTC_VECT(USBI1, 0xa40),
INTC_VECT(MMC_ERR, 0xb00), INTC_VECT(MMC_TRAN, 0xb20),
INTC_VECT(MMC_FSTAT, 0xb40), INTC_VECT(MMC_FRDY, 0xb60),
INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0),
INTC_VECT(DMAC_DADERR, 0xbc0), INTC_VECT(KEYSC, 0xbe0),
INTC_VECT(SCIF, 0xc00), INTC_VECT(SCIF1, 0xc20),
INTC_VECT(SCIF2, 0xc40), INTC_VECT(SCIF3, 0xc60),
INTC_VECT(SIOF0, 0xc80), INTC_VECT(SIOF1, 0xca0),
INTC_VECT(SIO, 0xd00),
INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0),
INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0),
INTC_VECT(I2C0_ALI, 0xe00), INTC_VECT(I2C0_TACKI, 0xe20),
INTC_VECT(I2C0_WAITI, 0xe40), INTC_VECT(I2C0_DTEI, 0xe60),
INTC_VECT(SDHI, 0xe80), INTC_VECT(SDHI, 0xea0),
INTC_VECT(SDHI, 0xec0), INTC_VECT(SDHI, 0xee0),
INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20),
INTC_VECT(SIU, 0xf80),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440),
INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU),
INTC_GROUP(MMC, MMC_FRDY, MMC_FSTAT, MMC_TRAN, MMC_ERR),
INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR),
INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI,
FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
INTC_GROUP(I2C0, I2C0_ALI, I2C0_TACKI, I2C0_WAITI, I2C0_DTEI),
INTC_GROUP(I2C1, I2C1_ALI, I2C1_TACKI, I2C1_WAITI, I2C1_DTEI),
INTC_GROUP(SIM, SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI),
INTC_GROUP(USB, USBI0, USBI1),
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
{ VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } },
{ 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
{ 0, 0, 0, VPU, 0, 0, 0, MFI } },
{ 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
{ SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI, 0, 0, 0, IRDA } },
{ 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
{ 0, TMU2, TMU1, TMU0, JPU, 0, 0, LCDC } },
{ 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
{ KEYSC, DMAC_DADERR, DMAC5, DMAC4, SCIF3, SCIF2, SCIF1, SCIF } },
{ 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
{ 0, 0, 0, SIO, Z3D4, 0, SIOF1, SIOF0 } },
{ 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
{ I2C0_DTEI, I2C0_WAITI, I2C0_TACKI, I2C0_ALI,
FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } },
{ 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
{ DISABLED, ENABLED, ENABLED, ENABLED, 0, 0, 0, SIU } },
{ 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
{ 0, 0, 0, CMT, 0, USBI1, USBI0 } },
{ 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
{ MMC_FRDY, MMC_FSTAT, MMC_TRAN, MMC_ERR } },
{ 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
{ I2C1_DTEI, I2C1_WAITI, I2C1_TACKI, I2C1_ALI, TPU, 0, 0, TSIF } },
{ 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2 } },
{ 0xa4080004, 0, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
{ 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, MFI, VPU } },
{ 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
{ 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF, SCIF1, SCIF2, SCIF3 } },
{ 0xa408001c, 0, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C0 } },
{ 0xa4080020, 0, 16, 4, /* IPRI */ { SIO, 0, TSIF, I2C1 } },
{ 0xa4080024, 0, 16, 4, /* IPRJ */ { Z3D4, 0, SIU } },
{ 0xa4080028, 0, 16, 4, /* IPRK */ { 0, MMC, 0, SDHI } },
{ 0xa408002c, 0, 16, 4, /* IPRL */ { 0, 0, TPU } },
{ 0xa4140010, 0, 32, 4, /* INTPRI00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_sense_reg sense_registers[] __initdata = {
{ 0xa414001c, 16, 2, /* ICR1 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_mask_reg ack_registers[] __initdata = {
{ 0xa4140024, 0, 8, /* INTREQ00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_desc intc_desc __initdata = {
.name = "sh7343",
.force_enable = ENABLED,
.force_disable = DISABLED,
.hw = INTC_HW_DESC(vectors, groups, mask_registers,
prio_registers, sense_registers, ack_registers),
};
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}

View file

@ -0,0 +1,392 @@
/*
* SH7366 Setup
*
* Copyright (C) 2008 Renesas Solutions
*
* Based on linux/arch/sh/kernel/cpu/sh4a/setup-sh7722.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/platform_device.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/uio_driver.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/usb/r8a66597.h>
#include <asm/clock.h>
static struct plat_sci_port scif0_platform_data = {
.port_reg = 0xa405013e,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xffe00000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc00)),
};
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 resource iic_resources[] = {
[0] = {
.name = "IIC",
.start = 0x04470000,
.end = 0x04470017,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xe00),
.end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device iic_device = {
.name = "i2c-sh_mobile",
.id = 0, /* "i2c0" clock */
.num_resources = ARRAY_SIZE(iic_resources),
.resource = iic_resources,
};
static struct r8a66597_platdata r8a66597_data = {
.on_chip = 1,
};
static struct resource usb_host_resources[] = {
[0] = {
.start = 0xa4d80000,
.end = 0xa4d800ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xa20),
.end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
static struct platform_device usb_host_device = {
.name = "r8a66597_hcd",
.id = -1,
.dev = {
.dma_mask = NULL,
.coherent_dma_mask = 0xffffffff,
.platform_data = &r8a66597_data,
},
.num_resources = ARRAY_SIZE(usb_host_resources),
.resource = usb_host_resources,
};
static struct uio_info vpu_platform_data = {
.name = "VPU5",
.version = "0",
.irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
[0] = {
.name = "VPU",
.start = 0xfe900000,
.end = 0xfe902807,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device vpu_device = {
.name = "uio_pdrv_genirq",
.id = 0,
.dev = {
.platform_data = &vpu_platform_data,
},
.resource = vpu_resources,
.num_resources = ARRAY_SIZE(vpu_resources),
};
static struct uio_info veu0_platform_data = {
.name = "VEU",
.version = "0",
.irq = evt2irq(0x8c0),
};
static struct resource veu0_resources[] = {
[0] = {
.name = "VEU(1)",
.start = 0xfe920000,
.end = 0xfe9200b7,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device veu0_device = {
.name = "uio_pdrv_genirq",
.id = 1,
.dev = {
.platform_data = &veu0_platform_data,
},
.resource = veu0_resources,
.num_resources = ARRAY_SIZE(veu0_resources),
};
static struct uio_info veu1_platform_data = {
.name = "VEU",
.version = "0",
.irq = evt2irq(0x560),
};
static struct resource veu1_resources[] = {
[0] = {
.name = "VEU(2)",
.start = 0xfe924000,
.end = 0xfe9240b7,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device veu1_device = {
.name = "uio_pdrv_genirq",
.id = 2,
.dev = {
.platform_data = &veu1_platform_data,
},
.resource = veu1_resources,
.num_resources = ARRAY_SIZE(veu1_resources),
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 0x20,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0x044a0000, 0x70),
DEFINE_RES_IRQ(evt2irq(0xf00)),
};
static struct platform_device cmt_device = {
.name = "sh-cmt-32",
.id = 0,
.dev = {
.platform_data = &cmt_platform_data,
},
.resource = cmt_resources,
.num_resources = ARRAY_SIZE(cmt_resources),
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xffd80000, 0x2c),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct platform_device *sh7366_devices[] __initdata = {
&scif0_device,
&cmt_device,
&tmu0_device,
&iic_device,
&usb_host_device,
&vpu_device,
&veu0_device,
&veu1_device,
};
static int __init sh7366_devices_setup(void)
{
platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20);
platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
return platform_add_devices(sh7366_devices,
ARRAY_SIZE(sh7366_devices));
}
arch_initcall(sh7366_devices_setup);
static struct platform_device *sh7366_early_devices[] __initdata = {
&scif0_device,
&cmt_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7366_early_devices,
ARRAY_SIZE(sh7366_early_devices));
}
enum {
UNUSED=0,
ENABLED,
DISABLED,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
ICB,
DMAC0, DMAC1, DMAC2, DMAC3,
VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU,
MFI, VPU, USB,
MMC_MMC1I, MMC_MMC2I, MMC_MMC3I,
DMAC4, DMAC5, DMAC_DADERR,
SCIF, SCIFA1, SCIFA2,
DENC, MSIOF,
FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI,
SDHI, CMT, TSIF, SIU,
TMU0, TMU1, TMU2,
VEU2, LCDC,
/* interrupt groups */
DMAC0123, VIOVOU, MMC, DMAC45, FLCTL, I2C,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
INTC_VECT(ICB, 0x700),
INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820),
INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860),
INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0),
INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0),
INTC_VECT(MFI, 0x900), INTC_VECT(VPU, 0x980), INTC_VECT(USB, 0xa20),
INTC_VECT(MMC_MMC1I, 0xb00), INTC_VECT(MMC_MMC2I, 0xb20),
INTC_VECT(MMC_MMC3I, 0xb40),
INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0),
INTC_VECT(DMAC_DADERR, 0xbc0),
INTC_VECT(SCIF, 0xc00), INTC_VECT(SCIFA1, 0xc20),
INTC_VECT(SCIFA2, 0xc40),
INTC_VECT(DENC, 0xc60), INTC_VECT(MSIOF, 0xc80),
INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0),
INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0),
INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20),
INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60),
INTC_VECT(SDHI, 0xe80), INTC_VECT(SDHI, 0xea0),
INTC_VECT(SDHI, 0xec0), INTC_VECT(SDHI, 0xee0),
INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20),
INTC_VECT(SIU, 0xf80),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440),
INTC_VECT(VEU2, 0x560), INTC_VECT(LCDC, 0x580),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU),
INTC_GROUP(MMC, MMC_MMC1I, MMC_MMC2I, MMC_MMC3I),
INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR),
INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI,
FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI),
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
{ } },
{ 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
{ VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } },
{ 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
{ 0, 0, 0, VPU, 0, 0, 0, MFI } },
{ 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
{ 0, 0, 0, ICB } },
{ 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
{ 0, TMU2, TMU1, TMU0, VEU2, 0, 0, LCDC } },
{ 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
{ 0, DMAC_DADERR, DMAC5, DMAC4, DENC, SCIFA2, SCIFA1, SCIF } },
{ 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
{ 0, 0, 0, 0, 0, 0, 0, MSIOF } },
{ 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
{ I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI,
FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } },
{ 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
{ DISABLED, ENABLED, ENABLED, ENABLED, 0, 0, 0, SIU } },
{ 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
{ 0, 0, 0, CMT, 0, USB, } },
{ 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
{ 0, MMC_MMC3I, MMC_MMC2I, MMC_MMC1I } },
{ 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
{ 0, 0, 0, 0, 0, 0, 0, TSIF } },
{ 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2 } },
{ 0xa4080004, 0, 16, 4, /* IPRB */ { VEU2, LCDC, ICB } },
{ 0xa4080008, 0, 16, 4, /* IPRC */ { } },
{ 0xa408000c, 0, 16, 4, /* IPRD */ { } },
{ 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, MFI, VPU } },
{ 0xa4080014, 0, 16, 4, /* IPRF */ { 0, DMAC45, USB, CMT } },
{ 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF, SCIFA1, SCIFA2, DENC } },
{ 0xa408001c, 0, 16, 4, /* IPRH */ { MSIOF, 0, FLCTL, I2C } },
{ 0xa4080020, 0, 16, 4, /* IPRI */ { 0, 0, TSIF, } },
{ 0xa4080024, 0, 16, 4, /* IPRJ */ { 0, 0, SIU } },
{ 0xa4080028, 0, 16, 4, /* IPRK */ { 0, MMC, 0, SDHI } },
{ 0xa408002c, 0, 16, 4, /* IPRL */ { } },
{ 0xa4140010, 0, 32, 4, /* INTPRI00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_sense_reg sense_registers[] __initdata = {
{ 0xa414001c, 16, 2, /* ICR1 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_mask_reg ack_registers[] __initdata = {
{ 0xa4140024, 0, 8, /* INTREQ00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_desc intc_desc __initdata = {
.name = "sh7366",
.force_enable = ENABLED,
.force_disable = DISABLED,
.hw = INTC_HW_DESC(vectors, groups, mask_registers,
prio_registers, sense_registers, ack_registers),
};
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
void __init plat_mem_setup(void)
{
/* TODO: Register Node 1 */
}

View file

@ -0,0 +1,671 @@
/*
* SH7722 Setup
*
* Copyright (C) 2006 - 2008 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/mm.h>
#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_dma.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/uio_driver.h>
#include <linux/usb/m66592.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
#include <asm/siu.h>
#include <cpu/dma-register.h>
#include <cpu/sh7722.h>
#include <cpu/serial.h>
static const struct sh_dmae_slave_config sh7722_dmae_slaves[] = {
{
.slave_id = SHDMA_SLAVE_SCIF0_TX,
.addr = 0xffe0000c,
.chcr = DM_FIX | SM_INC | RS_ERS | TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x21,
}, {
.slave_id = SHDMA_SLAVE_SCIF0_RX,
.addr = 0xffe00014,
.chcr = DM_INC | SM_FIX | RS_ERS | TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x22,
}, {
.slave_id = SHDMA_SLAVE_SCIF1_TX,
.addr = 0xffe1000c,
.chcr = DM_FIX | SM_INC | RS_ERS | TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x25,
}, {
.slave_id = SHDMA_SLAVE_SCIF1_RX,
.addr = 0xffe10014,
.chcr = DM_INC | SM_FIX | RS_ERS | TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x26,
}, {
.slave_id = SHDMA_SLAVE_SCIF2_TX,
.addr = 0xffe2000c,
.chcr = DM_FIX | SM_INC | RS_ERS | TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x29,
}, {
.slave_id = SHDMA_SLAVE_SCIF2_RX,
.addr = 0xffe20014,
.chcr = DM_INC | SM_FIX | RS_ERS | TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x2a,
}, {
.slave_id = SHDMA_SLAVE_SIUA_TX,
.addr = 0xa454c098,
.chcr = DM_FIX | SM_INC | RS_ERS | TS_INDEX2VAL(XMIT_SZ_32BIT),
.mid_rid = 0xb1,
}, {
.slave_id = SHDMA_SLAVE_SIUA_RX,
.addr = 0xa454c090,
.chcr = DM_INC | SM_FIX | RS_ERS | TS_INDEX2VAL(XMIT_SZ_32BIT),
.mid_rid = 0xb2,
}, {
.slave_id = SHDMA_SLAVE_SIUB_TX,
.addr = 0xa454c09c,
.chcr = DM_FIX | SM_INC | RS_ERS | TS_INDEX2VAL(XMIT_SZ_32BIT),
.mid_rid = 0xb5,
}, {
.slave_id = SHDMA_SLAVE_SIUB_RX,
.addr = 0xa454c094,
.chcr = DM_INC | SM_FIX | RS_ERS | TS_INDEX2VAL(XMIT_SZ_32BIT),
.mid_rid = 0xb6,
}, {
.slave_id = SHDMA_SLAVE_SDHI0_TX,
.addr = 0x04ce0030,
.chcr = DM_FIX | SM_INC | RS_ERS | TS_INDEX2VAL(XMIT_SZ_16BIT),
.mid_rid = 0xc1,
}, {
.slave_id = SHDMA_SLAVE_SDHI0_RX,
.addr = 0x04ce0030,
.chcr = DM_INC | SM_FIX | RS_ERS | TS_INDEX2VAL(XMIT_SZ_16BIT),
.mid_rid = 0xc2,
},
};
static const struct sh_dmae_channel sh7722_dmae_channels[] = {
{
.offset = 0,
.dmars = 0,
.dmars_bit = 0,
}, {
.offset = 0x10,
.dmars = 0,
.dmars_bit = 8,
}, {
.offset = 0x20,
.dmars = 4,
.dmars_bit = 0,
}, {
.offset = 0x30,
.dmars = 4,
.dmars_bit = 8,
}, {
.offset = 0x50,
.dmars = 8,
.dmars_bit = 0,
}, {
.offset = 0x60,
.dmars = 8,
.dmars_bit = 8,
}
};
static const unsigned int ts_shift[] = TS_SHIFT;
static struct sh_dmae_pdata dma_platform_data = {
.slave = sh7722_dmae_slaves,
.slave_num = ARRAY_SIZE(sh7722_dmae_slaves),
.channel = sh7722_dmae_channels,
.channel_num = ARRAY_SIZE(sh7722_dmae_channels),
.ts_low_shift = CHCR_TS_LOW_SHIFT,
.ts_low_mask = CHCR_TS_LOW_MASK,
.ts_high_shift = CHCR_TS_HIGH_SHIFT,
.ts_high_mask = CHCR_TS_HIGH_MASK,
.ts_shift = ts_shift,
.ts_shift_num = ARRAY_SIZE(ts_shift),
.dmaor_init = DMAOR_INIT,
};
static struct resource sh7722_dmae_resources[] = {
[0] = {
/* Channel registers and DMAOR */
.start = 0xfe008020,
.end = 0xfe00808f,
.flags = IORESOURCE_MEM,
},
[1] = {
/* DMARSx */
.start = 0xfe009000,
.end = 0xfe00900b,
.flags = IORESOURCE_MEM,
},
{
.name = "error_irq",
.start = evt2irq(0xbc0),
.end = evt2irq(0xbc0),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 0-3 */
.start = evt2irq(0x800),
.end = evt2irq(0x860),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 4-5 */
.start = evt2irq(0xb80),
.end = evt2irq(0xba0),
.flags = IORESOURCE_IRQ,
},
};
struct platform_device dma_device = {
.name = "sh-dma-engine",
.id = -1,
.resource = sh7722_dmae_resources,
.num_resources = ARRAY_SIZE(sh7722_dmae_resources),
.dev = {
.platform_data = &dma_platform_data,
},
};
/* Serial */
static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
.ops = &sh7722_sci_port_ops,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xffe00000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc00)),
};
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,
.ops = &sh7722_sci_port_ops,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xffe10000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc20)),
};
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,
.ops = &sh7722_sci_port_ops,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xffe20000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc40)),
};
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 resource rtc_resources[] = {
[0] = {
.start = 0xa465fec0,
.end = 0xa465fec0 + 0x58 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Period IRQ */
.start = evt2irq(0x7a0),
.flags = IORESOURCE_IRQ,
},
[2] = {
/* Carry IRQ */
.start = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ,
},
[3] = {
/* Alarm IRQ */
.start = evt2irq(0x780),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
static struct m66592_platdata usbf_platdata = {
.on_chip = 1,
};
static struct resource usbf_resources[] = {
[0] = {
.name = "USBF",
.start = 0x04480000,
.end = 0x044800FF,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xa20),
.end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device usbf_device = {
.name = "m66592_udc",
.id = 0, /* "usbf0" clock */
.dev = {
.dma_mask = NULL,
.coherent_dma_mask = 0xffffffff,
.platform_data = &usbf_platdata,
},
.num_resources = ARRAY_SIZE(usbf_resources),
.resource = usbf_resources,
};
static struct resource iic_resources[] = {
[0] = {
.name = "IIC",
.start = 0x04470000,
.end = 0x04470017,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xe00),
.end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device iic_device = {
.name = "i2c-sh_mobile",
.id = 0, /* "i2c0" clock */
.num_resources = ARRAY_SIZE(iic_resources),
.resource = iic_resources,
};
static struct uio_info vpu_platform_data = {
.name = "VPU4",
.version = "0",
.irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
[0] = {
.name = "VPU",
.start = 0xfe900000,
.end = 0xfe9022eb,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device vpu_device = {
.name = "uio_pdrv_genirq",
.id = 0,
.dev = {
.platform_data = &vpu_platform_data,
},
.resource = vpu_resources,
.num_resources = ARRAY_SIZE(vpu_resources),
};
static struct uio_info veu_platform_data = {
.name = "VEU",
.version = "0",
.irq = evt2irq(0x8c0),
};
static struct resource veu_resources[] = {
[0] = {
.name = "VEU",
.start = 0xfe920000,
.end = 0xfe9200b7,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device veu_device = {
.name = "uio_pdrv_genirq",
.id = 1,
.dev = {
.platform_data = &veu_platform_data,
},
.resource = veu_resources,
.num_resources = ARRAY_SIZE(veu_resources),
};
static struct uio_info jpu_platform_data = {
.name = "JPU",
.version = "0",
.irq = evt2irq(0x560),
};
static struct resource jpu_resources[] = {
[0] = {
.name = "JPU",
.start = 0xfea00000,
.end = 0xfea102d3,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device jpu_device = {
.name = "uio_pdrv_genirq",
.id = 2,
.dev = {
.platform_data = &jpu_platform_data,
},
.resource = jpu_resources,
.num_resources = ARRAY_SIZE(jpu_resources),
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 0x20,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0x044a0000, 0x70),
DEFINE_RES_IRQ(evt2irq(0xf00)),
};
static struct platform_device cmt_device = {
.name = "sh-cmt-32",
.id = 0,
.dev = {
.platform_data = &cmt_platform_data,
},
.resource = cmt_resources,
.num_resources = ARRAY_SIZE(cmt_resources),
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xffd80000, 0x2c),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct siu_platform siu_platform_data = {
.dma_slave_tx_a = SHDMA_SLAVE_SIUA_TX,
.dma_slave_rx_a = SHDMA_SLAVE_SIUA_RX,
.dma_slave_tx_b = SHDMA_SLAVE_SIUB_TX,
.dma_slave_rx_b = SHDMA_SLAVE_SIUB_RX,
};
static struct resource siu_resources[] = {
[0] = {
.start = 0xa4540000,
.end = 0xa454c10f,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xf80),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device siu_device = {
.name = "siu-pcm-audio",
.id = -1,
.dev = {
.platform_data = &siu_platform_data,
},
.resource = siu_resources,
.num_resources = ARRAY_SIZE(siu_resources),
};
static struct platform_device *sh7722_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&cmt_device,
&tmu0_device,
&rtc_device,
&usbf_device,
&iic_device,
&vpu_device,
&veu_device,
&jpu_device,
&siu_device,
&dma_device,
};
static int __init sh7722_devices_setup(void)
{
platform_resource_setup_memory(&vpu_device, "vpu", 1 << 20);
platform_resource_setup_memory(&veu_device, "veu", 2 << 20);
platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
return platform_add_devices(sh7722_devices,
ARRAY_SIZE(sh7722_devices));
}
arch_initcall(sh7722_devices_setup);
static struct platform_device *sh7722_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&cmt_device,
&tmu0_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7722_early_devices,
ARRAY_SIZE(sh7722_early_devices));
}
enum {
UNUSED=0,
ENABLED,
DISABLED,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
HUDI,
SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
RTC_ATI, RTC_PRI, RTC_CUI,
DMAC0, DMAC1, DMAC2, DMAC3,
VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU,
VPU, TPU,
USB_USBI0, USB_USBI1,
DMAC4, DMAC5, DMAC_DADERR,
KEYSC,
SCIF0, SCIF1, SCIF2, SIOF0, SIOF1, SIO,
FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI,
CMT, TSIF, SIU, TWODG,
TMU0, TMU1, TMU2,
IRDA, JPU, LCDC,
/* interrupt groups */
SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
INTC_VECT(SIM_ERI, 0x700), INTC_VECT(SIM_RXI, 0x720),
INTC_VECT(SIM_TXI, 0x740), INTC_VECT(SIM_TEI, 0x760),
INTC_VECT(RTC_ATI, 0x780), INTC_VECT(RTC_PRI, 0x7a0),
INTC_VECT(RTC_CUI, 0x7c0),
INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820),
INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860),
INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0),
INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0),
INTC_VECT(VPU, 0x980), INTC_VECT(TPU, 0x9a0),
INTC_VECT(USB_USBI0, 0xa20), INTC_VECT(USB_USBI1, 0xa40),
INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0),
INTC_VECT(DMAC_DADERR, 0xbc0), INTC_VECT(KEYSC, 0xbe0),
INTC_VECT(SCIF0, 0xc00), INTC_VECT(SCIF1, 0xc20),
INTC_VECT(SCIF2, 0xc40), INTC_VECT(SIOF0, 0xc80),
INTC_VECT(SIOF1, 0xca0), INTC_VECT(SIO, 0xd00),
INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0),
INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0),
INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20),
INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60),
INTC_VECT(SDHI, 0xe80), INTC_VECT(SDHI, 0xea0),
INTC_VECT(SDHI, 0xec0), INTC_VECT(SDHI, 0xee0),
INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20),
INTC_VECT(SIU, 0xf80), INTC_VECT(TWODG, 0xfa0),
INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
INTC_VECT(TMU2, 0x440), INTC_VECT(IRDA, 0x480),
INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU),
INTC_GROUP(USB, USB_USBI0, USB_USBI1),
INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR),
INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI,
FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI),
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
{ } },
{ 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
{ VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } },
{ 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
{ 0, 0, 0, VPU, } },
{ 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
{ SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI, 0, 0, 0, IRDA } },
{ 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
{ 0, TMU2, TMU1, TMU0, JPU, 0, 0, LCDC } },
{ 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
{ KEYSC, DMAC_DADERR, DMAC5, DMAC4, 0, SCIF2, SCIF1, SCIF0 } },
{ 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
{ 0, 0, 0, SIO, 0, 0, SIOF1, SIOF0 } },
{ 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
{ I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI,
FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } },
{ 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
{ DISABLED, ENABLED, ENABLED, ENABLED, 0, 0, TWODG, SIU } },
{ 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
{ 0, 0, 0, CMT, 0, USB_USBI1, USB_USBI0, } },
{ 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
{ } },
{ 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
{ 0, RTC_CUI, RTC_PRI, RTC_ATI, 0, TPU, 0, TSIF } },
{ 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
{ 0xa4080004, 0, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
{ 0xa4080008, 0, 16, 4, /* IPRC */ { } },
{ 0xa408000c, 0, 16, 4, /* IPRD */ { } },
{ 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
{ 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
{ 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
{ 0xa408001c, 0, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
{ 0xa4080020, 0, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
{ 0xa4080024, 0, 16, 4, /* IPRJ */ { 0, 0, SIU } },
{ 0xa4080028, 0, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
{ 0xa408002c, 0, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
{ 0xa4140010, 0, 32, 4, /* INTPRI00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_sense_reg sense_registers[] __initdata = {
{ 0xa414001c, 16, 2, /* ICR1 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_mask_reg ack_registers[] __initdata = {
{ 0xa4140024, 0, 8, /* INTREQ00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_desc intc_desc __initdata = {
.name = "sh7722",
.force_enable = ENABLED,
.force_disable = DISABLED,
.hw = INTC_HW_DESC(vectors, groups, mask_registers,
prio_registers, sense_registers, ack_registers),
};
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
void __init plat_mem_setup(void)
{
/* Register the URAM space as Node 1 */
setup_bootmem_node(1, 0x055f0000, 0x05610000);
}

View file

@ -0,0 +1,661 @@
/*
* SH7723 Setup
*
* Copyright (C) 2008 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/mm.h>
#include <linux/serial_sci.h>
#include <linux/uio_driver.h>
#include <linux/usb/r8a66597.h>
#include <linux/sh_timer.h>
#include <linux/sh_intc.h>
#include <linux/io.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
#include <cpu/sh7723.h>
/* Serial */
static struct plat_sci_port scif0_platform_data = {
.port_reg = 0xa4050160,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
static struct resource scif0_resources[] = {
DEFINE_RES_MEM(0xffe00000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc00)),
};
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 = {
.port_reg = SCIx_NOT_SUPPORTED,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
static struct resource scif1_resources[] = {
DEFINE_RES_MEM(0xffe10000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc20)),
};
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 = {
.port_reg = SCIx_NOT_SUPPORTED,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.type = PORT_SCIF,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
static struct resource scif2_resources[] = {
DEFINE_RES_MEM(0xffe20000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xc40)),
};
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 plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.port_reg = SCIx_NOT_SUPPORTED,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.sampling_rate = 8,
.type = PORT_SCIFA,
};
static struct resource scif3_resources[] = {
DEFINE_RES_MEM(0xa4e30000, 0x100),
DEFINE_RES_IRQ(evt2irq(0x900)),
};
static struct platform_device scif3_device = {
.name = "sh-sci",
.id = 3,
.resource = scif3_resources,
.num_resources = ARRAY_SIZE(scif3_resources),
.dev = {
.platform_data = &scif3_platform_data,
},
};
static struct plat_sci_port scif4_platform_data = {
.port_reg = SCIx_NOT_SUPPORTED,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.sampling_rate = 8,
.type = PORT_SCIFA,
};
static struct resource scif4_resources[] = {
DEFINE_RES_MEM(0xa4e40000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xd00)),
};
static struct platform_device scif4_device = {
.name = "sh-sci",
.id = 4,
.resource = scif4_resources,
.num_resources = ARRAY_SIZE(scif4_resources),
.dev = {
.platform_data = &scif4_platform_data,
},
};
static struct plat_sci_port scif5_platform_data = {
.port_reg = SCIx_NOT_SUPPORTED,
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.sampling_rate = 8,
.type = PORT_SCIFA,
};
static struct resource scif5_resources[] = {
DEFINE_RES_MEM(0xa4e50000, 0x100),
DEFINE_RES_IRQ(evt2irq(0xfa0)),
};
static struct platform_device scif5_device = {
.name = "sh-sci",
.id = 5,
.resource = scif5_resources,
.num_resources = ARRAY_SIZE(scif5_resources),
.dev = {
.platform_data = &scif5_platform_data,
},
};
static struct uio_info vpu_platform_data = {
.name = "VPU5",
.version = "0",
.irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
[0] = {
.name = "VPU",
.start = 0xfe900000,
.end = 0xfe902807,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device vpu_device = {
.name = "uio_pdrv_genirq",
.id = 0,
.dev = {
.platform_data = &vpu_platform_data,
},
.resource = vpu_resources,
.num_resources = ARRAY_SIZE(vpu_resources),
};
static struct uio_info veu0_platform_data = {
.name = "VEU2H",
.version = "0",
.irq = evt2irq(0x8c0),
};
static struct resource veu0_resources[] = {
[0] = {
.name = "VEU2H0",
.start = 0xfe920000,
.end = 0xfe92027b,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device veu0_device = {
.name = "uio_pdrv_genirq",
.id = 1,
.dev = {
.platform_data = &veu0_platform_data,
},
.resource = veu0_resources,
.num_resources = ARRAY_SIZE(veu0_resources),
};
static struct uio_info veu1_platform_data = {
.name = "VEU2H",
.version = "0",
.irq = evt2irq(0x560),
};
static struct resource veu1_resources[] = {
[0] = {
.name = "VEU2H1",
.start = 0xfe924000,
.end = 0xfe92427b,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device veu1_device = {
.name = "uio_pdrv_genirq",
.id = 2,
.dev = {
.platform_data = &veu1_platform_data,
},
.resource = veu1_resources,
.num_resources = ARRAY_SIZE(veu1_resources),
};
static struct sh_timer_config cmt_platform_data = {
.channels_mask = 0x20,
};
static struct resource cmt_resources[] = {
DEFINE_RES_MEM(0x044a0000, 0x70),
DEFINE_RES_IRQ(evt2irq(0xf00)),
};
static struct platform_device cmt_device = {
.name = "sh-cmt-32",
.id = 0,
.dev = {
.platform_data = &cmt_platform_data,
},
.resource = cmt_resources,
.num_resources = ARRAY_SIZE(cmt_resources),
};
static struct sh_timer_config tmu0_platform_data = {
.channels_mask = 7,
};
static struct resource tmu0_resources[] = {
DEFINE_RES_MEM(0xffd80000, 0x2c),
DEFINE_RES_IRQ(evt2irq(0x400)),
DEFINE_RES_IRQ(evt2irq(0x420)),
DEFINE_RES_IRQ(evt2irq(0x440)),
};
static struct platform_device tmu0_device = {
.name = "sh-tmu",
.id = 0,
.dev = {
.platform_data = &tmu0_platform_data,
},
.resource = tmu0_resources,
.num_resources = ARRAY_SIZE(tmu0_resources),
};
static struct sh_timer_config tmu1_platform_data = {
.channels_mask = 7,
};
static struct resource tmu1_resources[] = {
DEFINE_RES_MEM(0xffd90000, 0x2c),
DEFINE_RES_IRQ(evt2irq(0x920)),
DEFINE_RES_IRQ(evt2irq(0x940)),
DEFINE_RES_IRQ(evt2irq(0x960)),
};
static struct platform_device tmu1_device = {
.name = "sh-tmu",
.id = 1,
.dev = {
.platform_data = &tmu1_platform_data,
},
.resource = tmu1_resources,
.num_resources = ARRAY_SIZE(tmu1_resources),
};
static struct resource rtc_resources[] = {
[0] = {
.start = 0xa465fec0,
.end = 0xa465fec0 + 0x58 - 1,
.flags = IORESOURCE_IO,
},
[1] = {
/* Period IRQ */
.start = evt2irq(0xaa0),
.flags = IORESOURCE_IRQ,
},
[2] = {
/* Carry IRQ */
.start = evt2irq(0xac0),
.flags = IORESOURCE_IRQ,
},
[3] = {
/* Alarm IRQ */
.start = evt2irq(0xa80),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device rtc_device = {
.name = "sh-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resources),
.resource = rtc_resources,
};
static struct r8a66597_platdata r8a66597_data = {
.on_chip = 1,
};
static struct resource sh7723_usb_host_resources[] = {
[0] = {
.start = 0xa4d80000,
.end = 0xa4d800ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xa20),
.end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
static struct platform_device sh7723_usb_host_device = {
.name = "r8a66597_hcd",
.id = 0,
.dev = {
.dma_mask = NULL, /* not use dma */
.coherent_dma_mask = 0xffffffff,
.platform_data = &r8a66597_data,
},
.num_resources = ARRAY_SIZE(sh7723_usb_host_resources),
.resource = sh7723_usb_host_resources,
};
static struct resource iic_resources[] = {
[0] = {
.name = "IIC",
.start = 0x04470000,
.end = 0x04470017,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = evt2irq(0xe00),
.end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device iic_device = {
.name = "i2c-sh_mobile",
.id = 0, /* "i2c0" clock */
.num_resources = ARRAY_SIZE(iic_resources),
.resource = iic_resources,
};
static struct platform_device *sh7723_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&cmt_device,
&tmu0_device,
&tmu1_device,
&rtc_device,
&iic_device,
&sh7723_usb_host_device,
&vpu_device,
&veu0_device,
&veu1_device,
};
static int __init sh7723_devices_setup(void)
{
platform_resource_setup_memory(&vpu_device, "vpu", 2 << 20);
platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
return platform_add_devices(sh7723_devices,
ARRAY_SIZE(sh7723_devices));
}
arch_initcall(sh7723_devices_setup);
static struct platform_device *sh7723_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
&scif2_device,
&scif3_device,
&scif4_device,
&scif5_device,
&cmt_device,
&tmu0_device,
&tmu1_device,
};
void __init plat_early_device_setup(void)
{
early_platform_add_devices(sh7723_early_devices,
ARRAY_SIZE(sh7723_early_devices));
}
#define RAMCR_CACHE_L2FC 0x0002
#define RAMCR_CACHE_L2E 0x0001
#define L2_CACHE_ENABLE (RAMCR_CACHE_L2E|RAMCR_CACHE_L2FC)
void l2_cache_init(void)
{
/* Enable L2 cache */
__raw_writel(L2_CACHE_ENABLE, RAMCR);
}
enum {
UNUSED=0,
ENABLED,
DISABLED,
/* interrupt sources */
IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
HUDI,
DMAC1A_DEI0,DMAC1A_DEI1,DMAC1A_DEI2,DMAC1A_DEI3,
_2DG_TRI,_2DG_INI,_2DG_CEI,
DMAC0A_DEI0,DMAC0A_DEI1,DMAC0A_DEI2,DMAC0A_DEI3,
VIO_CEUI,VIO_BEUI,VIO_VEU2HI,VIO_VOUI,
SCIFA_SCIFA0,
VPU_VPUI,
TPU_TPUI,
ADC_ADI,
USB_USI0,
RTC_ATI,RTC_PRI,RTC_CUI,
DMAC1B_DEI4,DMAC1B_DEI5,DMAC1B_DADERR,
DMAC0B_DEI4,DMAC0B_DEI5,DMAC0B_DADERR,
KEYSC_KEYI,
SCIF_SCIF0,SCIF_SCIF1,SCIF_SCIF2,
MSIOF_MSIOFI0,MSIOF_MSIOFI1,
SCIFA_SCIFA1,
FLCTL_FLSTEI,FLCTL_FLTENDI,FLCTL_FLTREQ0I,FLCTL_FLTREQ1I,
I2C_ALI,I2C_TACKI,I2C_WAITI,I2C_DTEI,
CMT_CMTI,
TSIF_TSIFI,
SIU_SIUI,
SCIFA_SCIFA2,
TMU0_TUNI0, TMU0_TUNI1, TMU0_TUNI2,
IRDA_IRDAI,
ATAPI_ATAPII,
VEU2H1_VEU2HI,
LCDC_LCDCI,
TMU1_TUNI0,TMU1_TUNI1,TMU1_TUNI2,
/* interrupt groups */
DMAC1A, DMAC0A, VIO, DMAC0B, FLCTL, I2C, _2DG,
SDHI1, RTC, DMAC1B, SDHI0,
};
static struct intc_vect vectors[] __initdata = {
INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
INTC_VECT(DMAC1A_DEI0,0x700),
INTC_VECT(DMAC1A_DEI1,0x720),
INTC_VECT(DMAC1A_DEI2,0x740),
INTC_VECT(DMAC1A_DEI3,0x760),
INTC_VECT(_2DG_TRI, 0x780),
INTC_VECT(_2DG_INI, 0x7A0),
INTC_VECT(_2DG_CEI, 0x7C0),
INTC_VECT(DMAC0A_DEI0,0x800),
INTC_VECT(DMAC0A_DEI1,0x820),
INTC_VECT(DMAC0A_DEI2,0x840),
INTC_VECT(DMAC0A_DEI3,0x860),
INTC_VECT(VIO_CEUI,0x880),
INTC_VECT(VIO_BEUI,0x8A0),
INTC_VECT(VIO_VEU2HI,0x8C0),
INTC_VECT(VIO_VOUI,0x8E0),
INTC_VECT(SCIFA_SCIFA0,0x900),
INTC_VECT(VPU_VPUI,0x980),
INTC_VECT(TPU_TPUI,0x9A0),
INTC_VECT(ADC_ADI,0x9E0),
INTC_VECT(USB_USI0,0xA20),
INTC_VECT(RTC_ATI,0xA80),
INTC_VECT(RTC_PRI,0xAA0),
INTC_VECT(RTC_CUI,0xAC0),
INTC_VECT(DMAC1B_DEI4,0xB00),
INTC_VECT(DMAC1B_DEI5,0xB20),
INTC_VECT(DMAC1B_DADERR,0xB40),
INTC_VECT(DMAC0B_DEI4,0xB80),
INTC_VECT(DMAC0B_DEI5,0xBA0),
INTC_VECT(DMAC0B_DADERR,0xBC0),
INTC_VECT(KEYSC_KEYI,0xBE0),
INTC_VECT(SCIF_SCIF0,0xC00),
INTC_VECT(SCIF_SCIF1,0xC20),
INTC_VECT(SCIF_SCIF2,0xC40),
INTC_VECT(MSIOF_MSIOFI0,0xC80),
INTC_VECT(MSIOF_MSIOFI1,0xCA0),
INTC_VECT(SCIFA_SCIFA1,0xD00),
INTC_VECT(FLCTL_FLSTEI,0xD80),
INTC_VECT(FLCTL_FLTENDI,0xDA0),
INTC_VECT(FLCTL_FLTREQ0I,0xDC0),
INTC_VECT(FLCTL_FLTREQ1I,0xDE0),
INTC_VECT(I2C_ALI,0xE00),
INTC_VECT(I2C_TACKI,0xE20),
INTC_VECT(I2C_WAITI,0xE40),
INTC_VECT(I2C_DTEI,0xE60),
INTC_VECT(SDHI0, 0xE80),
INTC_VECT(SDHI0, 0xEA0),
INTC_VECT(SDHI0, 0xEC0),
INTC_VECT(CMT_CMTI,0xF00),
INTC_VECT(TSIF_TSIFI,0xF20),
INTC_VECT(SIU_SIUI,0xF80),
INTC_VECT(SCIFA_SCIFA2,0xFA0),
INTC_VECT(TMU0_TUNI0,0x400),
INTC_VECT(TMU0_TUNI1,0x420),
INTC_VECT(TMU0_TUNI2,0x440),
INTC_VECT(IRDA_IRDAI,0x480),
INTC_VECT(ATAPI_ATAPII,0x4A0),
INTC_VECT(SDHI1, 0x4E0),
INTC_VECT(SDHI1, 0x500),
INTC_VECT(SDHI1, 0x520),
INTC_VECT(VEU2H1_VEU2HI,0x560),
INTC_VECT(LCDC_LCDCI,0x580),
INTC_VECT(TMU1_TUNI0,0x920),
INTC_VECT(TMU1_TUNI1,0x940),
INTC_VECT(TMU1_TUNI2,0x960),
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(DMAC1A,DMAC1A_DEI0,DMAC1A_DEI1,DMAC1A_DEI2,DMAC1A_DEI3),
INTC_GROUP(DMAC0A,DMAC0A_DEI0,DMAC0A_DEI1,DMAC0A_DEI2,DMAC0A_DEI3),
INTC_GROUP(VIO, VIO_CEUI,VIO_BEUI,VIO_VEU2HI,VIO_VOUI),
INTC_GROUP(DMAC0B, DMAC0B_DEI4,DMAC0B_DEI5,DMAC0B_DADERR),
INTC_GROUP(FLCTL,FLCTL_FLSTEI,FLCTL_FLTENDI,FLCTL_FLTREQ0I,FLCTL_FLTREQ1I),
INTC_GROUP(I2C,I2C_ALI,I2C_TACKI,I2C_WAITI,I2C_DTEI),
INTC_GROUP(_2DG, _2DG_TRI,_2DG_INI,_2DG_CEI),
INTC_GROUP(RTC, RTC_ATI,RTC_PRI,RTC_CUI),
INTC_GROUP(DMAC1B, DMAC1B_DEI4,DMAC1B_DEI5,DMAC1B_DADERR),
};
static struct intc_mask_reg mask_registers[] __initdata = {
{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
{ 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0,
0, ENABLED, ENABLED, ENABLED } },
{ 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
{ VIO_VOUI, VIO_VEU2HI,VIO_BEUI,VIO_CEUI,DMAC0A_DEI3,DMAC0A_DEI2,DMAC0A_DEI1,DMAC0A_DEI0 } },
{ 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
{ 0, 0, 0, VPU_VPUI,0,0,0,SCIFA_SCIFA0 } },
{ 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
{ DMAC1A_DEI3,DMAC1A_DEI2,DMAC1A_DEI1,DMAC1A_DEI0,0,0,0,IRDA_IRDAI } },
{ 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
{ 0,TMU0_TUNI2,TMU0_TUNI1,TMU0_TUNI0,VEU2H1_VEU2HI,0,0,LCDC_LCDCI } },
{ 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
{ KEYSC_KEYI,DMAC0B_DADERR,DMAC0B_DEI5,DMAC0B_DEI4,0,SCIF_SCIF2,SCIF_SCIF1,SCIF_SCIF0 } },
{ 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
{ 0,0,0,SCIFA_SCIFA1,ADC_ADI,0,MSIOF_MSIOFI1,MSIOF_MSIOFI0 } },
{ 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
{ I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI,
FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
{ 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
{ 0, ENABLED, ENABLED, ENABLED,
0, 0, SCIFA_SCIFA2, SIU_SIUI } },
{ 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
{ 0, 0, 0, CMT_CMTI, 0, 0, USB_USI0,0 } },
{ 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
{ 0, DMAC1B_DADERR,DMAC1B_DEI5,DMAC1B_DEI4,0,RTC_ATI,RTC_PRI,RTC_CUI } },
{ 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
{ 0,_2DG_CEI,_2DG_INI,_2DG_TRI,0,TPU_TPUI,0,TSIF_TSIFI } },
{ 0xa40800b0, 0xa40800f0, 8, /* IMR12 / IMCR12 */
{ 0,0,0,0,0,0,0,ATAPI_ATAPII } },
{ 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_prio_reg prio_registers[] __initdata = {
{ 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0_TUNI0, TMU0_TUNI1, TMU0_TUNI2, IRDA_IRDAI } },
{ 0xa4080004, 0, 16, 4, /* IPRB */ { VEU2H1_VEU2HI, LCDC_LCDCI, DMAC1A, 0} },
{ 0xa4080008, 0, 16, 4, /* IPRC */ { TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2, 0} },
{ 0xa408000c, 0, 16, 4, /* IPRD */ { } },
{ 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0A, VIO, SCIFA_SCIFA0, VPU_VPUI } },
{ 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC_KEYI, DMAC0B, USB_USI0, CMT_CMTI } },
{ 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF_SCIF0, SCIF_SCIF1, SCIF_SCIF2,0 } },
{ 0xa408001c, 0, 16, 4, /* IPRH */ { MSIOF_MSIOFI0,MSIOF_MSIOFI1, FLCTL, I2C } },
{ 0xa4080020, 0, 16, 4, /* IPRI */ { SCIFA_SCIFA1,0,TSIF_TSIFI,_2DG } },
{ 0xa4080024, 0, 16, 4, /* IPRJ */ { ADC_ADI,0,SIU_SIUI,SDHI1 } },
{ 0xa4080028, 0, 16, 4, /* IPRK */ { RTC,DMAC1B,0,SDHI0 } },
{ 0xa408002c, 0, 16, 4, /* IPRL */ { SCIFA_SCIFA2,0,TPU_TPUI,ATAPI_ATAPII } },
{ 0xa4140010, 0, 32, 4, /* INTPRI00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_sense_reg sense_registers[] __initdata = {
{ 0xa414001c, 16, 2, /* ICR1 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_mask_reg ack_registers[] __initdata = {
{ 0xa4140024, 0, 8, /* INTREQ00 */
{ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
static struct intc_desc intc_desc __initdata = {
.name = "sh7723",
.force_enable = ENABLED,
.force_disable = DISABLED,
.hw = INTC_HW_DESC(vectors, groups, mask_registers,
prio_registers, sense_registers, ack_registers),
};
void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}

Some files were not shown because too many files have changed in this diff Show more