Root/drivers/clocksource/cyclone.c

1#include <linux/clocksource.h>
2#include <linux/string.h>
3#include <linux/errno.h>
4#include <linux/timex.h>
5#include <linux/init.h>
6
7#include <asm/pgtable.h>
8#include <asm/io.h>
9
10#include <asm/mach_timer.h>
11
12#define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */
13#define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */
14#define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */
15#define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */
16#define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */
17#define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */
18
19int use_cyclone = 0;
20static void __iomem *cyclone_ptr;
21
22static cycle_t read_cyclone(struct clocksource *cs)
23{
24    return (cycle_t)readl(cyclone_ptr);
25}
26
27static struct clocksource clocksource_cyclone = {
28    .name = "cyclone",
29    .rating = 250,
30    .read = read_cyclone,
31    .mask = CYCLONE_TIMER_MASK,
32    .flags = CLOCK_SOURCE_IS_CONTINUOUS,
33};
34
35static int __init init_cyclone_clocksource(void)
36{
37    unsigned long base; /* saved value from CBAR */
38    unsigned long offset;
39    u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */
40    u32 __iomem* reg;
41    int i;
42
43    /* make sure we're on a summit box: */
44    if (!use_cyclone)
45        return -ENODEV;
46
47    printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
48
49    /* find base address: */
50    offset = CYCLONE_CBAR_ADDR;
51    reg = ioremap_nocache(offset, sizeof(reg));
52    if (!reg) {
53        printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
54        return -ENODEV;
55    }
56    /* even on 64bit systems, this is only 32bits: */
57    base = readl(reg);
58    iounmap(reg);
59    if (!base) {
60        printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
61        return -ENODEV;
62    }
63
64    /* setup PMCC: */
65    offset = base + CYCLONE_PMCC_OFFSET;
66    reg = ioremap_nocache(offset, sizeof(reg));
67    if (!reg) {
68        printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
69        return -ENODEV;
70    }
71    writel(0x00000001,reg);
72    iounmap(reg);
73
74    /* setup MPCS: */
75    offset = base + CYCLONE_MPCS_OFFSET;
76    reg = ioremap_nocache(offset, sizeof(reg));
77    if (!reg) {
78        printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
79        return -ENODEV;
80    }
81    writel(0x00000001,reg);
82    iounmap(reg);
83
84    /* map in cyclone_timer: */
85    offset = base + CYCLONE_MPMC_OFFSET;
86    cyclone_timer = ioremap_nocache(offset, sizeof(u64));
87    if (!cyclone_timer) {
88        printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
89        return -ENODEV;
90    }
91
92    /* quick test to make sure its ticking: */
93    for (i = 0; i < 3; i++){
94        u32 old = readl(cyclone_timer);
95        int stall = 100;
96
97        while (stall--)
98            barrier();
99
100        if (readl(cyclone_timer) == old) {
101            printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
102            iounmap(cyclone_timer);
103            cyclone_timer = NULL;
104            return -ENODEV;
105        }
106    }
107    cyclone_ptr = cyclone_timer;
108
109    return clocksource_register_hz(&clocksource_cyclone,
110                    CYCLONE_TIMER_FREQ);
111}
112
113arch_initcall(init_cyclone_clocksource);
114

Archive Download this file



interactive