blob: f80eb7fb544d71f80ff852c6333d6cdd7fb22a5c [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#include <linux/module.h>
3#include <linux/smp.h>
4#include <linux/time.h>
5#include <linux/errno.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -08006#include <linux/timex.h>
Tony Luck0aa366f2007-07-20 11:22:30 -07007#include <linux/clocksource.h>
Dan Williams2584cf82015-08-10 23:07:05 -04008#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
10/* IBM Summit (EXA) Cyclone counter code*/
11#define CYCLONE_CBAR_ADDR 0xFEB00CD0
12#define CYCLONE_PMCC_OFFSET 0x51A0
13#define CYCLONE_MPMC_OFFSET 0x51D0
14#define CYCLONE_MPCS_OFFSET 0x51A8
15#define CYCLONE_TIMER_FREQ 100000000
16
17int use_cyclone;
18void __init cyclone_setup(void)
19{
20 use_cyclone = 1;
21}
22
Tony Luck0aa366f2007-07-20 11:22:30 -070023static void __iomem *cyclone_mc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Thomas Gleixnera5a1d1c2016-12-21 20:32:01 +010025static u64 read_cyclone(struct clocksource *cs)
Tony Luck0aa366f2007-07-20 11:22:30 -070026{
Thomas Gleixnera5a1d1c2016-12-21 20:32:01 +010027 return (u64)readq((void __iomem *)cyclone_mc);
Tony Luck0aa366f2007-07-20 11:22:30 -070028}
29
30static struct clocksource clocksource_cyclone = {
31 .name = "cyclone",
32 .rating = 300,
33 .read = read_cyclone,
34 .mask = (1LL << 40) - 1,
Tony Luck0aa366f2007-07-20 11:22:30 -070035 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
Linus Torvalds1da177e2005-04-16 15:20:36 -070036};
37
38int __init init_cyclone_clock(void)
39{
Al Viro6aa8b042007-07-26 17:34:59 +010040 u64 __iomem *reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 u64 base; /* saved cyclone base address */
42 u64 offset; /* offset from pageaddr to cyclone_timer register */
43 int i;
Al Viro6aa8b042007-07-26 17:34:59 +010044 u32 __iomem *cyclone_timer; /* Cyclone MPMC0 register */
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 if (!use_cyclone)
Bjorn Helgaas6c5e6212006-03-03 15:33:47 -070047 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49 printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
50
51 /* find base address */
52 offset = (CYCLONE_CBAR_ADDR);
Al Viro6aa8b042007-07-26 17:34:59 +010053 reg = ioremap_nocache(offset, sizeof(u64));
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 if(!reg){
Tony Luck0aa366f2007-07-20 11:22:30 -070055 printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
56 " register.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 use_cyclone = 0;
58 return -ENODEV;
59 }
60 base = readq(reg);
Julia Lawallddad53e2010-08-27 23:01:30 +020061 iounmap(reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 if(!base){
Tony Luck0aa366f2007-07-20 11:22:30 -070063 printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
64 " value.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 use_cyclone = 0;
66 return -ENODEV;
67 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69 /* setup PMCC */
70 offset = (base + CYCLONE_PMCC_OFFSET);
Al Viro6aa8b042007-07-26 17:34:59 +010071 reg = ioremap_nocache(offset, sizeof(u64));
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 if(!reg){
Tony Luck0aa366f2007-07-20 11:22:30 -070073 printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
74 " register.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 use_cyclone = 0;
76 return -ENODEV;
77 }
78 writel(0x00000001,reg);
79 iounmap(reg);
80
81 /* setup MPCS */
82 offset = (base + CYCLONE_MPCS_OFFSET);
Al Viro6aa8b042007-07-26 17:34:59 +010083 reg = ioremap_nocache(offset, sizeof(u64));
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 if(!reg){
Tony Luck0aa366f2007-07-20 11:22:30 -070085 printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
86 " register.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 use_cyclone = 0;
88 return -ENODEV;
89 }
90 writel(0x00000001,reg);
91 iounmap(reg);
92
93 /* map in cyclone_timer */
94 offset = (base + CYCLONE_MPMC_OFFSET);
Al Viro6aa8b042007-07-26 17:34:59 +010095 cyclone_timer = ioremap_nocache(offset, sizeof(u32));
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 if(!cyclone_timer){
Tony Luck0aa366f2007-07-20 11:22:30 -070097 printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
98 " register.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 use_cyclone = 0;
100 return -ENODEV;
101 }
102
103 /*quick test to make sure its ticking*/
104 for(i=0; i<3; i++){
105 u32 old = readl(cyclone_timer);
106 int stall = 100;
107 while(stall--) barrier();
108 if(readl(cyclone_timer) == old){
Tony Luck0aa366f2007-07-20 11:22:30 -0700109 printk(KERN_ERR "Summit chipset: Counter not counting!"
110 " DISABLED\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 iounmap(cyclone_timer);
Al Viro6aa8b042007-07-26 17:34:59 +0100112 cyclone_timer = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 use_cyclone = 0;
114 return -ENODEV;
115 }
116 }
117 /* initialize last tick */
Tony Luck0aa366f2007-07-20 11:22:30 -0700118 cyclone_mc = cyclone_timer;
Andy Lutomirski574c44f2011-07-13 09:24:15 -0400119 clocksource_cyclone.archdata.fsys_mmio = cyclone_timer;
John Stultzd60c3042010-04-26 20:20:47 -0700120 clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 return 0;
123}
124
125__initcall(init_cyclone_clock);