2006-06-26 11:25:12 +04:00
# include <linux/clocksource.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/timex.h>
# include <linux/init.h>
# include <asm/pgtable.h>
# include <asm/io.h>
2009-01-28 21:34:09 +03:00
# include <asm/mach_timer.h>
2006-06-26 11:25:12 +04:00
# define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */
# define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */
# define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */
# define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */
# define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */
2006-06-26 11:25:15 +04:00
# define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */
2006-06-26 11:25:12 +04:00
int use_cyclone = 0 ;
static void __iomem * cyclone_ptr ;
2009-04-21 23:24:00 +04:00
static cycle_t read_cyclone ( struct clocksource * cs )
2006-06-26 11:25:12 +04:00
{
return ( cycle_t ) readl ( cyclone_ptr ) ;
}
static struct clocksource clocksource_cyclone = {
. name = " cyclone " ,
. rating = 250 ,
. read = read_cyclone ,
2006-06-26 11:25:15 +04:00
. mask = CYCLONE_TIMER_MASK ,
2007-02-16 12:27:36 +03:00
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
2006-06-26 11:25:12 +04:00
} ;
static int __init init_cyclone_clocksource ( void )
{
unsigned long base ; /* saved value from CBAR */
unsigned long offset ;
u32 __iomem * volatile cyclone_timer ; /* Cyclone MPMC0 register */
u32 __iomem * reg ;
int i ;
/* make sure we're on a summit box: */
if ( ! use_cyclone )
return - ENODEV ;
printk ( KERN_INFO " Summit chipset: Starting Cyclone Counter. \n " ) ;
/* find base address: */
offset = CYCLONE_CBAR_ADDR ;
reg = ioremap_nocache ( offset , sizeof ( reg ) ) ;
if ( ! reg ) {
printk ( KERN_ERR " Summit chipset: Could not find valid CBAR register. \n " ) ;
return - ENODEV ;
}
/* even on 64bit systems, this is only 32bits: */
base = readl ( reg ) ;
2012-01-12 13:55:15 +04:00
iounmap ( reg ) ;
2006-06-26 11:25:12 +04:00
if ( ! base ) {
printk ( KERN_ERR " Summit chipset: Could not find valid CBAR value. \n " ) ;
return - ENODEV ;
}
/* setup PMCC: */
offset = base + CYCLONE_PMCC_OFFSET ;
reg = ioremap_nocache ( offset , sizeof ( reg ) ) ;
if ( ! reg ) {
printk ( KERN_ERR " Summit chipset: Could not find valid PMCC register. \n " ) ;
return - ENODEV ;
}
writel ( 0x00000001 , reg ) ;
iounmap ( reg ) ;
/* setup MPCS: */
offset = base + CYCLONE_MPCS_OFFSET ;
reg = ioremap_nocache ( offset , sizeof ( reg ) ) ;
if ( ! reg ) {
printk ( KERN_ERR " Summit chipset: Could not find valid MPCS register. \n " ) ;
return - ENODEV ;
}
writel ( 0x00000001 , reg ) ;
iounmap ( reg ) ;
/* map in cyclone_timer: */
offset = base + CYCLONE_MPMC_OFFSET ;
cyclone_timer = ioremap_nocache ( offset , sizeof ( u64 ) ) ;
if ( ! cyclone_timer ) {
printk ( KERN_ERR " Summit chipset: Could not find valid MPMC register. \n " ) ;
return - ENODEV ;
}
/* quick test to make sure its ticking: */
for ( i = 0 ; i < 3 ; i + + ) {
u32 old = readl ( cyclone_timer ) ;
int stall = 100 ;
while ( stall - - )
barrier ( ) ;
if ( readl ( cyclone_timer ) = = old ) {
printk ( KERN_ERR " Summit chipset: Counter not counting! DISABLED \n " ) ;
iounmap ( cyclone_timer ) ;
cyclone_timer = NULL ;
return - ENODEV ;
}
}
cyclone_ptr = cyclone_timer ;
2010-04-27 06:03:05 +04:00
return clocksource_register_hz ( & clocksource_cyclone ,
CYCLONE_TIMER_FREQ ) ;
2006-06-26 11:25:12 +04:00
}
2007-03-05 11:30:50 +03:00
arch_initcall ( init_cyclone_clocksource ) ;