aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2008-09-29 07:09:17 -0400
committerPaul Mundt <lethal@linux-sh.org>2008-09-29 07:09:17 -0400
commit4d01cdafbafc0fdeb730838ca38a48e5ca2894cd (patch)
tree5157d3e9dd1882253ce848fd2d2650aaa17241aa /arch/sh/kernel
parent50b72e600b62bcdf40971e55f609cf4771346cc1 (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/Makefile5
-rw-r--r--arch/sh/kernel/cpu/sh5/clock-sh5.c79
-rw-r--r--arch/sh/kernel/time_64.c168
3 files changed, 91 insertions, 161 deletions
diff --git a/arch/sh/kernel/cpu/sh5/Makefile b/arch/sh/kernel/cpu/sh5/Makefile
index 8646363e9ded..ce4602ea23a8 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
5 5
6obj-$(CONFIG_SH_FPU) += fpu.o 6obj-$(CONFIG_SH_FPU) += fpu.o
7obj-$(CONFIG_KALLSYMS) += unwind.o 7obj-$(CONFIG_KALLSYMS) += unwind.o
8
9# Primary on-chip clocks (common)
10clock-$(CONFIG_CPU_SH5) := clock-sh5.o
11
12obj-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 000000000000..52c49248833a
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh5/clock-sh5.c
@@ -0,0 +1,79 @@
1/*
2 * arch/sh/kernel/cpu/sh5/clock-sh5.c
3 *
4 * SH-5 support for the clock framework
5 *
6 * Copyright (C) 2008 Paul Mundt
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <asm/clock.h>
15#include <asm/io.h>
16
17static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 };
18
19/* Clock, Power and Reset Controller */
20#define CPRC_BLOCK_OFF 0x01010000
21#define CPRC_BASE (PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF)
22
23static unsigned long cprc_base;
24
25static void master_clk_init(struct clk *clk)
26{
27 int idx = (ctrl_inl(cprc_base + 0x00) >> 6) & 0x0007;
28 clk->rate *= ifc_table[idx];
29}
30
31static struct clk_ops sh5_master_clk_ops = {
32 .init = master_clk_init,
33};
34
35static void module_clk_recalc(struct clk *clk)
36{
37 int idx = (ctrl_inw(cprc_base) >> 12) & 0x0007;
38 clk->rate = clk->parent->rate / ifc_table[idx];
39}
40
41static struct clk_ops sh5_module_clk_ops = {
42 .recalc = module_clk_recalc,
43};
44
45static void bus_clk_recalc(struct clk *clk)
46{
47 int idx = (ctrl_inw(cprc_base) >> 3) & 0x0007;
48 clk->rate = clk->parent->rate / ifc_table[idx];
49}
50
51static struct clk_ops sh5_bus_clk_ops = {
52 .recalc = bus_clk_recalc,
53};
54
55static void cpu_clk_recalc(struct clk *clk)
56{
57 int idx = (ctrl_inw(cprc_base) & 0x0007);
58 clk->rate = clk->parent->rate / ifc_table[idx];
59}
60
61static struct clk_ops sh5_cpu_clk_ops = {
62 .recalc = cpu_clk_recalc,
63};
64
65static struct clk_ops *sh5_clk_ops[] = {
66 &sh5_master_clk_ops,
67 &sh5_module_clk_ops,
68 &sh5_bus_clk_ops,
69 &sh5_cpu_clk_ops,
70};
71
72void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
73{
74 cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC");
75 BUG_ON(!cprc_base);
76
77 if (idx < ARRAY_SIZE(sh5_clk_ops))
78 *ops = sh5_clk_ops[idx];
79}
diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c
index 791edabf7d83..bbb2af1004d9 100644
--- a/arch/sh/kernel/time_64.c
+++ b/arch/sh/kernel/time_64.c
@@ -39,6 +39,7 @@
39#include <asm/processor.h> 39#include <asm/processor.h>
40#include <asm/uaccess.h> 40#include <asm/uaccess.h>
41#include <asm/delay.h> 41#include <asm/delay.h>
42#include <asm/clock.h>
42 43
43#define TMU_TOCR_INIT 0x00 44#define TMU_TOCR_INIT 0x00
44#define TMU0_TCR_INIT 0x0020 45#define TMU0_TCR_INIT 0x0020
@@ -51,14 +52,6 @@
51#define RTC_RCR1_CIE 0x10 /* Carry Interrupt Enable */ 52#define RTC_RCR1_CIE 0x10 /* Carry Interrupt Enable */
52#define RTC_RCR1 (rtc_base + 0x38) 53#define RTC_RCR1 (rtc_base + 0x38)
53 54
54/* Clock, Power and Reset Controller */
55#define CPRC_BLOCK_OFF 0x01010000
56#define CPRC_BASE PHYS_PERIPHERAL_BLOCK + CPRC_BLOCK_OFF
57
58#define FRQCR (cprc_base+0x0)
59#define WTCSR (cprc_base+0x0018)
60#define STBCR (cprc_base+0x0030)
61
62/* Time Management Unit */ 55/* Time Management Unit */
63#define TMU_BLOCK_OFF 0x01020000 56#define TMU_BLOCK_OFF 0x01020000
64#define TMU_BASE PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF 57#define TMU_BASE PHYS_PERIPHERAL_BLOCK + TMU_BLOCK_OFF
@@ -293,103 +286,17 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
293 return IRQ_HANDLED; 286 return IRQ_HANDLED;
294} 287}
295 288
296
297static __init unsigned int get_cpu_hz(void)
298{
299 unsigned int count;
300 unsigned long __dummy;
301 unsigned long ctc_val_init, ctc_val;
302
303 /*
304 ** Regardless the toolchain, force the compiler to use the
305 ** arbitrary register r3 as a clock tick counter.
306 ** NOTE: r3 must be in accordance with sh64_rtc_interrupt()
307 */
308 register unsigned long long __rtc_irq_flag __asm__ ("r3");
309
310 local_irq_enable();
311 do {} while (ctrl_inb(rtc_base) != 0);
312 ctrl_outb(RTC_RCR1_CIE, RTC_RCR1); /* Enable carry interrupt */
313
314 /*
315 * r3 is arbitrary. CDC does not support "=z".
316 */
317 ctc_val_init = 0xffffffff;
318 ctc_val = ctc_val_init;
319
320 asm volatile("gettr tr0, %1\n\t"
321 "putcon %0, " __CTC "\n\t"
322 "and %2, r63, %2\n\t"
323 "pta $+4, tr0\n\t"
324 "beq/l %2, r63, tr0\n\t"
325 "ptabs %1, tr0\n\t"
326 "getcon " __CTC ", %0\n\t"
327 : "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag)
328 : "0" (0));
329 local_irq_disable();
330 /*
331 * SH-3:
332 * CPU clock = 4 stages * loop
333 * tst rm,rm if id ex
334 * bt/s 1b if id ex
335 * add #1,rd if id ex
336 * (if) pipe line stole
337 * tst rm,rm if id ex
338 * ....
339 *
340 *
341 * SH-4:
342 * CPU clock = 6 stages * loop
343 * I don't know why.
344 * ....
345 *
346 * SH-5:
347 * Use CTC register to count. This approach returns the right value
348 * even if the I-cache is disabled (e.g. whilst debugging.)
349 *
350 */
351
352 count = ctc_val_init - ctc_val; /* CTC counts down */
353
354 /*
355 * This really is count by the number of clock cycles
356 * by the ratio between a complete R64CNT
357 * wrap-around (128) and CUI interrupt being raised (64).
358 */
359 return count*2;
360}
361
362static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
363{
364 struct pt_regs *regs = get_irq_regs();
365
366 ctrl_outb(0, RTC_RCR1); /* Disable Carry Interrupts */
367 regs->regs[3] = 1; /* Using r3 */
368
369 return IRQ_HANDLED;
370}
371
372static struct irqaction irq0 = { 289static struct irqaction irq0 = {
373 .handler = timer_interrupt, 290 .handler = timer_interrupt,
374 .flags = IRQF_DISABLED, 291 .flags = IRQF_DISABLED,
375 .mask = CPU_MASK_NONE, 292 .mask = CPU_MASK_NONE,
376 .name = "timer", 293 .name = "timer",
377}; 294};
378static struct irqaction irq1 = {
379 .handler = sh64_rtc_interrupt,
380 .flags = IRQF_DISABLED,
381 .mask = CPU_MASK_NONE,
382 .name = "rtc",
383};
384 295
385void __init time_init(void) 296void __init time_init(void)
386{ 297{
387 unsigned int cpu_clock, master_clock, bus_clock, module_clock;
388 unsigned long interval; 298 unsigned long interval;
389 unsigned long frqcr, ifc, pfc; 299 struct clk *clk;
390 static int ifc_table[] = { 2, 4, 6, 8, 10, 12, 16, 24 };
391#define bfc_table ifc_table /* Same */
392#define pfc_table ifc_table /* Same */
393 300
394 tmu_base = onchip_remap(TMU_BASE, 1024, "TMU"); 301 tmu_base = onchip_remap(TMU_BASE, 1024, "TMU");
395 if (!tmu_base) { 302 if (!tmu_base) {
@@ -401,50 +308,19 @@ void __init time_init(void)
401 panic("Unable to remap RTC\n"); 308 panic("Unable to remap RTC\n");
402 } 309 }
403 310
404 cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC"); 311 clk = clk_get(NULL, "cpu_clk");
405 if (!cprc_base) { 312 scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) /
406 panic("Unable to remap CPRC\n"); 313 (unsigned long long)(clk_get_rate(clk) / HZ));
407 }
408 314
409 rtc_sh_get_time(&xtime); 315 rtc_sh_get_time(&xtime);
410 316
411 setup_irq(TIMER_IRQ, &irq0); 317 setup_irq(TIMER_IRQ, &irq0);
412 setup_irq(RTC_IRQ, &irq1);
413
414 /* Check how fast it is.. */
415 cpu_clock = get_cpu_hz();
416
417 /* Note careful order of operations to maintain reasonable precision and avoid overflow. */
418 scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ));
419
420 free_irq(RTC_IRQ, NULL);
421
422 printk("CPU clock: %d.%02dMHz\n",
423 (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
424 {
425 unsigned short bfc;
426 frqcr = ctrl_inl(FRQCR);
427 ifc = ifc_table[(frqcr>> 6) & 0x0007];
428 bfc = bfc_table[(frqcr>> 3) & 0x0007];
429 pfc = pfc_table[(frqcr>> 12) & 0x0007];
430 master_clock = cpu_clock * ifc;
431 bus_clock = master_clock/bfc;
432 }
433 318
434 printk("Bus clock: %d.%02dMHz\n", 319 clk = clk_get(NULL, "module_clk");
435 (bus_clock/1000000), (bus_clock % 1000000)/10000); 320 interval = (clk_get_rate(clk)/(HZ*4));
436 module_clock = master_clock/pfc;
437 printk("Module clock: %d.%02dMHz\n",
438 (module_clock/1000000), (module_clock % 1000000)/10000);
439 interval = (module_clock/(HZ*4));
440 321
441 printk("Interval = %ld\n", interval); 322 printk("Interval = %ld\n", interval);
442 323
443 current_cpu_data.cpu_clock = cpu_clock;
444 current_cpu_data.master_clock = master_clock;
445 current_cpu_data.bus_clock = bus_clock;
446 current_cpu_data.module_clock = module_clock;
447
448 /* Start TMU0 */ 324 /* Start TMU0 */
449 ctrl_outb(TMU_TSTR_OFF, TMU_TSTR); 325 ctrl_outb(TMU_TSTR_OFF, TMU_TSTR);
450 ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); 326 ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
@@ -454,36 +330,6 @@ void __init time_init(void)
454 ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); 330 ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
455} 331}
456 332
457void enter_deep_standby(void)
458{
459 /* Disable watchdog timer */
460 ctrl_outl(0xa5000000, WTCSR);
461 /* Configure deep standby on sleep */
462 ctrl_outl(0x03, STBCR);
463
464#ifdef CONFIG_SH_ALPHANUMERIC
465 {
466 extern void mach_alphanum(int position, unsigned char value);
467 extern void mach_alphanum_brightness(int setting);
468 char halted[] = "Halted. ";
469 int i;
470 mach_alphanum_brightness(6); /* dimmest setting above off */
471 for (i=0; i<8; i++) {
472 mach_alphanum(i, halted[i]);
473 }
474 asm __volatile__ ("synco");
475 }
476#endif
477
478 asm __volatile__ ("sleep");
479 asm __volatile__ ("synci");
480 asm __volatile__ ("nop");
481 asm __volatile__ ("nop");
482 asm __volatile__ ("nop");
483 asm __volatile__ ("nop");
484 panic("Unexpected wakeup!\n");
485}
486
487static struct resource rtc_resources[] = { 333static struct resource rtc_resources[] = {
488 [0] = { 334 [0] = {
489 /* RTC base, filled in by rtc_init */ 335 /* RTC base, filled in by rtc_init */