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