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> | |
5 | #include <asm/io.h> | |
6 | ||
7 | /* IBM Summit (EXA) Cyclone counter code*/ | |
8 | #define CYCLONE_CBAR_ADDR 0xFEB00CD0 | |
9 | #define CYCLONE_PMCC_OFFSET 0x51A0 | |
10 | #define CYCLONE_MPMC_OFFSET 0x51D0 | |
11 | #define CYCLONE_MPCS_OFFSET 0x51A8 | |
12 | #define CYCLONE_TIMER_FREQ 100000000 | |
13 | ||
14 | int use_cyclone; | |
15 | void __init cyclone_setup(void) | |
16 | { | |
17 | use_cyclone = 1; | |
18 | } | |
19 | ||
20 | ||
21 | struct time_interpolator cyclone_interpolator = { | |
22 | .source = TIME_SOURCE_MMIO64, | |
23 | .shift = 16, | |
24 | .frequency = CYCLONE_TIMER_FREQ, | |
25 | .drift = -100, | |
26 | .mask = (1LL << 40) - 1 | |
27 | }; | |
28 | ||
29 | int __init init_cyclone_clock(void) | |
30 | { | |
31 | u64* reg; | |
32 | u64 base; /* saved cyclone base address */ | |
33 | u64 offset; /* offset from pageaddr to cyclone_timer register */ | |
34 | int i; | |
35 | u32* volatile cyclone_timer; /* Cyclone MPMC0 register */ | |
36 | ||
37 | if (!use_cyclone) | |
38 | return -ENODEV; | |
39 | ||
40 | printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n"); | |
41 | ||
42 | /* find base address */ | |
43 | offset = (CYCLONE_CBAR_ADDR); | |
44 | reg = (u64*)ioremap_nocache(offset, sizeof(u64)); | |
45 | if(!reg){ | |
46 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n"); | |
47 | use_cyclone = 0; | |
48 | return -ENODEV; | |
49 | } | |
50 | base = readq(reg); | |
51 | if(!base){ | |
52 | printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n"); | |
53 | use_cyclone = 0; | |
54 | return -ENODEV; | |
55 | } | |
56 | iounmap(reg); | |
57 | ||
58 | /* setup PMCC */ | |
59 | offset = (base + CYCLONE_PMCC_OFFSET); | |
60 | reg = (u64*)ioremap_nocache(offset, sizeof(u64)); | |
61 | if(!reg){ | |
62 | printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n"); | |
63 | use_cyclone = 0; | |
64 | return -ENODEV; | |
65 | } | |
66 | writel(0x00000001,reg); | |
67 | iounmap(reg); | |
68 | ||
69 | /* setup MPCS */ | |
70 | offset = (base + CYCLONE_MPCS_OFFSET); | |
71 | reg = (u64*)ioremap_nocache(offset, sizeof(u64)); | |
72 | if(!reg){ | |
73 | printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n"); | |
74 | use_cyclone = 0; | |
75 | return -ENODEV; | |
76 | } | |
77 | writel(0x00000001,reg); | |
78 | iounmap(reg); | |
79 | ||
80 | /* map in cyclone_timer */ | |
81 | offset = (base + CYCLONE_MPMC_OFFSET); | |
82 | cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32)); | |
83 | if(!cyclone_timer){ | |
84 | printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n"); | |
85 | use_cyclone = 0; | |
86 | return -ENODEV; | |
87 | } | |
88 | ||
89 | /*quick test to make sure its ticking*/ | |
90 | for(i=0; i<3; i++){ | |
91 | u32 old = readl(cyclone_timer); | |
92 | int stall = 100; | |
93 | while(stall--) barrier(); | |
94 | if(readl(cyclone_timer) == old){ | |
95 | printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n"); | |
96 | iounmap(cyclone_timer); | |
97 | cyclone_timer = 0; | |
98 | use_cyclone = 0; | |
99 | return -ENODEV; | |
100 | } | |
101 | } | |
102 | /* initialize last tick */ | |
103 | cyclone_interpolator.addr = cyclone_timer; | |
104 | register_time_interpolator(&cyclone_interpolator); | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | __initcall(init_cyclone_clock); |