diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-09-29 20:09:17 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-09-29 20:09:17 +0900 |
commit | 4d01cdafbafc0fdeb730838ca38a48e5ca2894cd (patch) | |
tree | 5157d3e9dd1882253ce848fd2d2650aaa17241aa /arch/sh/kernel | |
parent | 50b72e600b62bcdf40971e55f609cf4771346cc1 (diff) |
sh: SH-5 clk fwk support.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/cpu/sh5/Makefile | 5 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh5/clock-sh5.c | 79 | ||||
-rw-r--r-- | arch/sh/kernel/time_64.c | 168 |
3 files changed, 91 insertions, 161 deletions
diff --git a/arch/sh/kernel/cpu/sh5/Makefile b/arch/sh/kernel/cpu/sh5/Makefile index 8646363e9de..ce4602ea23a 100644 --- a/arch/sh/kernel/cpu/sh5/Makefile +++ b/arch/sh/kernel/cpu/sh5/Makefile @@ -5,3 +5,8 @@ obj-y := entry.o probe.o switchto.o obj-$(CONFIG_SH_FPU) += fpu.o obj-$(CONFIG_KALLSYMS) += unwind.o + +# Primary on-chip clocks (common) +clock-$(CONFIG_CPU_SH5) := clock-sh5.o + +obj-y += $(clock-y) diff --git a/arch/sh/kernel/cpu/sh5/clock-sh5.c b/arch/sh/kernel/cpu/sh5/clock-sh5.c new file mode 100644 index 00000000000..52c49248833 --- /dev/null +++ b/arch/sh/kernel/cpu/sh5/clock-sh5.c @@ -0,0 +1,79 @@ +/* + * arch/sh/kernel/cpu/sh5/clock-sh5.c + * + * SH-5 support for the clock framework + * + * 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/init.h> +#include <linux/kernel.h> +#include <asm/clock.h> +#include <asm/io.h> + +static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 }; + +/* Clock, Power and Reset Controller */ +#define CPRC_BLOCK_OFF 0x01010000 +#define CPRC_BASE (PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF) + +static unsigned long cprc_base; + +static void master_clk_init(struct clk *clk) +{ + int idx = (ctrl_inl(cprc_base + 0x00) >> 6) & 0x0007; + clk->rate *= ifc_table[idx]; +} + +static struct clk_ops sh5_master_clk_ops = { + .init = master_clk_init, +}; + +static void module_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(cprc_base) >> 12) & 0x0007; + clk->rate = clk->parent->rate / ifc_table[idx]; +} + +static struct clk_ops sh5_module_clk_ops = { + .recalc = module_clk_recalc, +}; + +static void bus_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(cprc_base) >> 3) & 0x0007; + clk->rate = clk->parent->rate / ifc_table[idx]; +} + +static struct clk_ops sh5_bus_clk_ops = { + .recalc = bus_clk_recalc, +}; + +static void cpu_clk_recalc(struct clk *clk) +{ + int idx = (ctrl_inw(cprc_base) & 0x0007); + clk->rate = clk->parent->rate / ifc_table[idx]; +} + +static struct clk_ops sh5_cpu_clk_ops = { + .recalc = cpu_clk_recalc, +}; + +static struct clk_ops *sh5_clk_ops[] = { + &sh5_master_clk_ops, + &sh5_module_clk_ops, + &sh5_bus_clk_ops, + &sh5_cpu_clk_ops, +}; + +void __init arch_init_clk_ops(struct clk_ops **ops, int idx) +{ + cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC"); + BUG_ON(!cprc_base); + + if (idx < ARRAY_SIZE(sh5_clk_ops)) + *ops = sh5_clk_ops[idx]; +} diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c index 791edabf7d8..bbb2af1004d 100644 --- a/arch/sh/kernel/time_64.c +++ b/arch/sh/kernel/time_64.c @@ -39,6 +39,7 @@ #include <asm/processor.h> #include <asm/uaccess.h> #include <asm/delay.h> +#include <asm/clock.h> #define TMU_TOCR_INIT 0x00 #define TMU0_TCR_INIT 0x0020 @@ -51,14 +52,6 @@ #define RTC_RCR1_CIE 0x10 /* Carry Interrupt Enable */ #define RTC_RCR1 (rtc_base + 0x38) -/* Clock, Power and Reset Controller */ -#define CPRC_BLOCK_OFF 0x01010000 -#define CPRC_BASE PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF - -#define FRQCR (cprc_base+0x0) -#define WTCSR (cprc_base+0x0018) -#define STBCR (cprc_base+0x0030) - /* Time Management Unit */ #define TMU_BLOCK_OFF 0x01020000 #define TMU_BASE PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF @@ -293,103 +286,17 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } - -static __init unsigned int get_cpu_hz(void) -{ - unsigned int count; - unsigned long __dummy; - unsigned long ctc_val_init, ctc_val; - - /* - ** Regardless the toolchain, force the compiler to use the - ** arbitrary register r3 as a clock tick counter. - ** NOTE: r3 must be in accordance with sh64_rtc_interrupt() - */ - register unsigned long long __rtc_irq_flag __asm__ ("r3"); - - local_irq_enable(); - do {} while (ctrl_inb(rtc_base) != 0); - ctrl_outb(RTC_RCR1_CIE, RTC_RCR1); /* Enable carry interrupt */ - - /* - * r3 is arbitrary. CDC does not support "=z". - */ - ctc_val_init = 0xffffffff; - ctc_val = ctc_val_init; - - asm volatile("gettr tr0, %1\n\t" - "putcon %0, " __CTC "\n\t" - "and %2, r63, %2\n\t" - "pta $+4, tr0\n\t" - "beq/l %2, r63, tr0\n\t" - "ptabs %1, tr0\n\t" - "getcon " __CTC ", %0\n\t" - : "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag) - : "0" (0)); - local_irq_disable(); - /* - * SH-3: - * CPU clock = 4 stages * loop - * tst rm,rm if id ex - * bt/s 1b if id ex - * add #1,rd if id ex - * (if) pipe line stole - * tst rm,rm if id ex - * .... - * - * - * SH-4: - * CPU clock = 6 stages * loop - * I don't know why. - * .... - * - * SH-5: - * Use CTC register to count. This approach returns the right value - * even if the I-cache is disabled (e.g. whilst debugging.) - * - */ - - count = ctc_val_init - ctc_val; /* CTC counts down */ - - /* - * This really is count by the number of clock cycles - * by the ratio between a complete R64CNT - * wrap-around (128) and CUI interrupt being raised (64). - */ - return count*2; -} - -static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id) -{ - struct pt_regs *regs = get_irq_regs(); - - ctrl_outb(0, RTC_RCR1); /* Disable Carry Interrupts */ - regs->regs[3] = 1; /* Using r3 */ - - return IRQ_HANDLED; -} - static struct irqaction irq0 = { .handler = timer_interrupt, .flags = IRQF_DISABLED, .mask = CPU_MASK_NONE, .name = "timer", }; -static struct irqaction irq1 = { - .handler = sh64_rtc_interrupt, - .flags = IRQF_DISABLED, - .mask = CPU_MASK_NONE, - .name = "rtc", -}; void __init time_init(void) { - unsigned int cpu_clock, master_clock, bus_clock, module_clock; unsigned long interval; - unsigned long frqcr, ifc, pfc; - static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 }; -#define bfc_table ifc_table /* Same */ -#define pfc_table ifc_table /* Same */ + struct clk *clk; tmu_base = onchip_remap(TMU_BASE, 1024, "TMU"); if (!tmu_base) { @@ -401,50 +308,19 @@ void __init time_init(void) panic("Unable to remap RTC\n"); } - cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC"); - if (!cprc_base) { - panic("Unable to remap CPRC\n"); - } + clk = clk_get(NULL, "cpu_clk"); + scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / + (unsigned long long)(clk_get_rate(clk) / HZ)); rtc_sh_get_time(&xtime); setup_irq(TIMER_IRQ, &irq0); - setup_irq(RTC_IRQ, &irq1); - - /* Check how fast it is.. */ - cpu_clock = get_cpu_hz(); - - /* Note careful order of operations to maintain reasonable precision and avoid overflow. */ - scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ)); - - free_irq(RTC_IRQ, NULL); - - printk("CPU clock: %d.%02dMHz\n", - (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); - { - unsigned short bfc; - frqcr = ctrl_inl(FRQCR); - ifc = ifc_table[(frqcr>> 6) & 0x0007]; - bfc = bfc_table[(frqcr>> 3) & 0x0007]; - pfc = pfc_table[(frqcr>> 12) & 0x0007]; - master_clock = cpu_clock * ifc; - bus_clock = master_clock/bfc; - } - printk("Bus clock: %d.%02dMHz\n", - (bus_clock/1000000), (bus_clock % 1000000)/10000); - module_clock = master_clock/pfc; - printk("Module clock: %d.%02dMHz\n", - (module_clock/1000000), (module_clock % 1000000)/10000); - interval = (module_clock/(HZ*4)); + clk = clk_get(NULL, "module_clk"); + interval = (clk_get_rate(clk)/(HZ*4)); printk("Interval = %ld\n", interval); - current_cpu_data.cpu_clock = cpu_clock; - current_cpu_data.master_clock = master_clock; - current_cpu_data.bus_clock = bus_clock; - current_cpu_data.module_clock = module_clock; - /* Start TMU0 */ ctrl_outb(TMU_TSTR_OFF, TMU_TSTR); ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); @@ -454,36 +330,6 @@ void __init time_init(void) ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); } -void enter_deep_standby(void) -{ - /* Disable watchdog timer */ - ctrl_outl(0xa5000000, WTCSR); - /* Configure deep standby on sleep */ - ctrl_outl(0x03, STBCR); - -#ifdef CONFIG_SH_ALPHANUMERIC - { - extern void mach_alphanum(int position, unsigned char value); - extern void mach_alphanum_brightness(int setting); - char halted[] = "Halted. "; - int i; - mach_alphanum_brightness(6); /* dimmest setting above off */ - for (i=0; i<8; i++) { - mach_alphanum(i, halted[i]); - } - asm __volatile__ ("synco"); - } -#endif - - asm __volatile__ ("sleep"); - asm __volatile__ ("synci"); - asm __volatile__ ("nop"); - asm __volatile__ ("nop"); - asm __volatile__ ("nop"); - asm __volatile__ ("nop"); - panic("Unexpected wakeup!\n"); -} - static struct resource rtc_resources[] = { [0] = { /* RTC base, filled in by rtc_init */ |