Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #include <linux/module.h> |
2 | #include <linux/smp.h> | |
3 | #include <linux/time.h> | |
4 | #include <linux/errno.h> | |
4e57b681 | 5 | #include <linux/timex.h> |
0aa366f3 | 6 | #include <linux/clocksource.h> |
2584cf83 | 7 | #include <linux/io.h> |
1da177e4 LT |
8 | |
9 | /* IBM Summit (EXA) Cyclone counter code*/ | |
10 | #define CYCLONE_CBAR_ADDR 0xFEB00CD0 | |
11 | #define CYCLONE_PMCC_OFFSET 0x51A0 | |
12 | #define CYCLONE_MPMC_OFFSET 0x51D0 | |
13 | #define CYCLONE_MPCS_OFFSET 0x51A8 | |
14 | #define CYCLONE_TIMER_FREQ 100000000 | |
15 | ||
16 | int use_cyclone; | |
17 | void __init cyclone_setup(void) | |
18 | { | |
19 | use_cyclone = 1; | |
20 | } | |
21 | ||
0aa366f3 | 22 | static void __iomem *cyclone_mc; |
1da177e4 | 23 | |
8e19608e | 24 | static cycle_t read_cyclone(struct clocksource *cs) |
0aa366f3 TL |
25 | { |
26 | return (cycle_t)readq((void __iomem *)cyclone_mc); | |
27 | } | |
28 | ||
29 | static struct clocksource clocksource_cyclone = { | |
30 | .name = "cyclone", | |
31 | .rating = 300, | |
32 | .read = read_cyclone, | |
33 | .mask = (1LL << 40) - 1, | |
0aa366f3 | 34 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
1da177e4 LT |
35 | }; |
36 | ||
37 | int __init init_cyclone_clock(void) | |
38 | { | |
6aa8b049 | 39 | u64 __iomem *reg; |
1da177e4 LT |
40 | u64 base; /* saved cyclone base address */ |
41 | u64 offset; /* offset from pageaddr to cyclone_timer register */ | |
42 | int i; | |
6aa8b049 | 43 | u32 __iomem *cyclone_timer; /* Cyclone MPMC0 register */ |
1da177e4 LT |
44 | |
45 | if (!use_cyclone) | |
6c5e6215 | 46 | return 0; |
1da177e4 LT |
47 | |
48 | printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n"); | |
49 | ||
50 | /* find base address */ | |
51 | offset = (CYCLONE_CBAR_ADDR); | |
6aa8b049 | 52 | reg = ioremap_nocache(offset, sizeof(u64)); |
1da177e4 | 53 | if(!reg){ |
0aa366f3 TL |
54 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR" |
55 | " register.\n"); | |
1da177e4 LT |
56 | use_cyclone = 0; |
57 | return -ENODEV; | |
58 | } | |
59 | base = readq(reg); | |
ddad53ee | 60 | iounmap(reg); |
1da177e4 | 61 | if(!base){ |
0aa366f3 TL |
62 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR" |
63 | " value.\n"); | |
1da177e4 LT |
64 | use_cyclone = 0; |
65 | return -ENODEV; | |
66 | } | |
1da177e4 LT |
67 | |
68 | /* setup PMCC */ | |
69 | offset = (base + CYCLONE_PMCC_OFFSET); | |
6aa8b049 | 70 | reg = ioremap_nocache(offset, sizeof(u64)); |
1da177e4 | 71 | if(!reg){ |
0aa366f3 TL |
72 | printk(KERN_ERR "Summit chipset: Could not find valid PMCC" |
73 | " register.\n"); | |
1da177e4 LT |
74 | use_cyclone = 0; |
75 | return -ENODEV; | |
76 | } | |
77 | writel(0x00000001,reg); | |
78 | iounmap(reg); | |
79 | ||
80 | /* setup MPCS */ | |
81 | offset = (base + CYCLONE_MPCS_OFFSET); | |
6aa8b049 | 82 | reg = ioremap_nocache(offset, sizeof(u64)); |
1da177e4 | 83 | if(!reg){ |
0aa366f3 TL |
84 | printk(KERN_ERR "Summit chipset: Could not find valid MPCS" |
85 | " register.\n"); | |
1da177e4 LT |
86 | use_cyclone = 0; |
87 | return -ENODEV; | |
88 | } | |
89 | writel(0x00000001,reg); | |
90 | iounmap(reg); | |
91 | ||
92 | /* map in cyclone_timer */ | |
93 | offset = (base + CYCLONE_MPMC_OFFSET); | |
6aa8b049 | 94 | cyclone_timer = ioremap_nocache(offset, sizeof(u32)); |
1da177e4 | 95 | if(!cyclone_timer){ |
0aa366f3 TL |
96 | printk(KERN_ERR "Summit chipset: Could not find valid MPMC" |
97 | " register.\n"); | |
1da177e4 LT |
98 | use_cyclone = 0; |
99 | return -ENODEV; | |
100 | } | |
101 | ||
102 | /*quick test to make sure its ticking*/ | |
103 | for(i=0; i<3; i++){ | |
104 | u32 old = readl(cyclone_timer); | |
105 | int stall = 100; | |
106 | while(stall--) barrier(); | |
107 | if(readl(cyclone_timer) == old){ | |
0aa366f3 TL |
108 | printk(KERN_ERR "Summit chipset: Counter not counting!" |
109 | " DISABLED\n"); | |
1da177e4 | 110 | iounmap(cyclone_timer); |
6aa8b049 | 111 | cyclone_timer = NULL; |
1da177e4 LT |
112 | use_cyclone = 0; |
113 | return -ENODEV; | |
114 | } | |
115 | } | |
116 | /* initialize last tick */ | |
0aa366f3 | 117 | cyclone_mc = cyclone_timer; |
574c44fa | 118 | clocksource_cyclone.archdata.fsys_mmio = cyclone_timer; |
d60c3041 | 119 | clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ); |
1da177e4 LT |
120 | |
121 | return 0; | |
122 | } | |
123 | ||
124 | __initcall(init_cyclone_clock); |