Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cyclone.c
Go to the documentation of this file.
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,
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  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,
111 }
112 
113 arch_initcall(init_cyclone_clocksource);