sh: SH-5 clk fwk support.
authorPaul Mundt <lethal@linux-sh.org>
Mon, 29 Sep 2008 11:09:17 +0000 (20:09 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Mon, 29 Sep 2008 11:09:17 +0000 (20:09 +0900)
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/kernel/cpu/sh5/Makefile
arch/sh/kernel/cpu/sh5/clock-sh5.c [new file with mode: 0644]
arch/sh/kernel/time_64.c

index 8646363e9dedd2f3090781c6108c500a45791bf8..ce4602ea23a81dbf1e49a4a55e5c2bdc766d535c 100644 (file)
@@ -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 (file)
index 0000000..52c4924
--- /dev/null
@@ -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];
+}
index 791edabf7d834fe8d52410b508f50bc18f9fe981..bbb2af1004d9eb2639598c1eef87b8954e147ef8 100644 (file)
@@ -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
 #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 */