linux/drivers/clocksource/cyclone.c
<<
>>
Prefs
   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 "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(void)
  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        .mult           = 10,
  33        .shift          = 0,
  34        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  35};
  36
  37static int __init init_cyclone_clocksource(void)
  38{
  39        unsigned long base;     /* saved value from CBAR */
  40        unsigned long offset;
  41        u32 __iomem* volatile cyclone_timer;    /* Cyclone MPMC0 register */
  42        u32 __iomem* reg;
  43        int i;
  44
  45        /* make sure we're on a summit box: */
  46        if (!use_cyclone)
  47                return -ENODEV;
  48
  49        printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
  50
  51        /* find base address: */
  52        offset = CYCLONE_CBAR_ADDR;
  53        reg = ioremap_nocache(offset, sizeof(reg));
  54        if (!reg) {
  55                printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
  56                return -ENODEV;
  57        }
  58        /* even on 64bit systems, this is only 32bits: */
  59        base = readl(reg);
  60        if (!base) {
  61                printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
  62                return -ENODEV;
  63        }
  64        iounmap(reg);
  65
  66        /* setup PMCC: */
  67        offset = base + CYCLONE_PMCC_OFFSET;
  68        reg = ioremap_nocache(offset, sizeof(reg));
  69        if (!reg) {
  70                printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
  71                return -ENODEV;
  72        }
  73        writel(0x00000001,reg);
  74        iounmap(reg);
  75
  76        /* setup MPCS: */
  77        offset = base + CYCLONE_MPCS_OFFSET;
  78        reg = ioremap_nocache(offset, sizeof(reg));
  79        if (!reg) {
  80                printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
  81                return -ENODEV;
  82        }
  83        writel(0x00000001,reg);
  84        iounmap(reg);
  85
  86        /* map in cyclone_timer: */
  87        offset = base + CYCLONE_MPMC_OFFSET;
  88        cyclone_timer = ioremap_nocache(offset, sizeof(u64));
  89        if (!cyclone_timer) {
  90                printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
  91                return -ENODEV;
  92        }
  93
  94        /* quick test to make sure its ticking: */
  95        for (i = 0; i < 3; i++){
  96                u32 old = readl(cyclone_timer);
  97                int stall = 100;
  98
  99                while (stall--)
 100                        barrier();
 101
 102                if (readl(cyclone_timer) == old) {
 103                        printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
 104                        iounmap(cyclone_timer);
 105                        cyclone_timer = NULL;
 106                        return -ENODEV;
 107                }
 108        }
 109        cyclone_ptr = cyclone_timer;
 110
 111        /* sort out mult/shift values: */
 112        clocksource_cyclone.shift = 22;
 113        clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
 114                                                clocksource_cyclone.shift);
 115
 116        return clocksource_register(&clocksource_cyclone);
 117}
 118
 119arch_initcall(init_cyclone_clocksource);
 120