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 19int use_cyclone = 0; 20static void __iomem *cyclone_ptr; 21 22static cycle_t read_cyclone(struct clocksource *cs) 23{ 24 return (cycle_t)readl(cyclone_ptr); 25} 26 27static 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 35static 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, 110 CYCLONE_TIMER_FREQ); 111} 112 113arch_initcall(init_cyclone_clocksource); 114