Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/clocksource/cyclone.c
15109 views
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
19
int use_cyclone = 0;
20
static void __iomem *cyclone_ptr;
21
22
static cycle_t read_cyclone(struct clocksource *cs)
23
{
24
return (cycle_t)readl(cyclone_ptr);
25
}
26
27
static 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
35
static 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
if (!base) {
59
printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
60
return -ENODEV;
61
}
62
iounmap(reg);
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
113
arch_initcall(init_cyclone_clocksource);
114
115