2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/smp.h>
# include <linux/time.h>
# include <linux/errno.h>
2005-10-31 02:03:48 +03:00
# include <linux/timex.h>
2007-07-20 22:22:30 +04:00
# include <linux/clocksource.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
/* IBM Summit (EXA) Cyclone counter code*/
# define CYCLONE_CBAR_ADDR 0xFEB00CD0
# define CYCLONE_PMCC_OFFSET 0x51A0
# define CYCLONE_MPMC_OFFSET 0x51D0
# define CYCLONE_MPCS_OFFSET 0x51A8
# define CYCLONE_TIMER_FREQ 100000000
int use_cyclone ;
void __init cyclone_setup ( void )
{
use_cyclone = 1 ;
}
2007-07-20 22:22:30 +04:00
static void __iomem * cyclone_mc ;
2005-04-17 02:20:36 +04:00
2007-07-20 22:22:30 +04:00
static cycle_t read_cyclone ( void )
{
return ( cycle_t ) readq ( ( void __iomem * ) cyclone_mc ) ;
}
static struct clocksource clocksource_cyclone = {
. name = " cyclone " ,
. rating = 300 ,
. read = read_cyclone ,
. mask = ( 1LL < < 40 ) - 1 ,
. mult = 0 , /*to be caluclated*/
. shift = 16 ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
2005-04-17 02:20:36 +04:00
} ;
int __init init_cyclone_clock ( void )
{
2007-07-26 20:34:59 +04:00
u64 __iomem * reg ;
2005-04-17 02:20:36 +04:00
u64 base ; /* saved cyclone base address */
u64 offset ; /* offset from pageaddr to cyclone_timer register */
int i ;
2007-07-26 20:34:59 +04:00
u32 __iomem * cyclone_timer ; /* Cyclone MPMC0 register */
2005-04-17 02:20:36 +04:00
if ( ! use_cyclone )
2006-03-04 01:33:47 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " Summit chipset: Starting Cyclone Counter. \n " ) ;
/* find base address */
offset = ( CYCLONE_CBAR_ADDR ) ;
2007-07-26 20:34:59 +04:00
reg = ioremap_nocache ( offset , sizeof ( u64 ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! reg ) {
2007-07-20 22:22:30 +04:00
printk ( KERN_ERR " Summit chipset: Could not find valid CBAR "
" register. \n " ) ;
2005-04-17 02:20:36 +04:00
use_cyclone = 0 ;
return - ENODEV ;
}
base = readq ( reg ) ;
if ( ! base ) {
2007-07-20 22:22:30 +04:00
printk ( KERN_ERR " Summit chipset: Could not find valid CBAR "
" value. \n " ) ;
2005-04-17 02:20:36 +04:00
use_cyclone = 0 ;
return - ENODEV ;
}
iounmap ( reg ) ;
/* setup PMCC */
offset = ( base + CYCLONE_PMCC_OFFSET ) ;
2007-07-26 20:34:59 +04:00
reg = ioremap_nocache ( offset , sizeof ( u64 ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! reg ) {
2007-07-20 22:22:30 +04:00
printk ( KERN_ERR " Summit chipset: Could not find valid PMCC "
" register. \n " ) ;
2005-04-17 02:20:36 +04:00
use_cyclone = 0 ;
return - ENODEV ;
}
writel ( 0x00000001 , reg ) ;
iounmap ( reg ) ;
/* setup MPCS */
offset = ( base + CYCLONE_MPCS_OFFSET ) ;
2007-07-26 20:34:59 +04:00
reg = ioremap_nocache ( offset , sizeof ( u64 ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! reg ) {
2007-07-20 22:22:30 +04:00
printk ( KERN_ERR " Summit chipset: Could not find valid MPCS "
" register. \n " ) ;
2005-04-17 02:20:36 +04:00
use_cyclone = 0 ;
return - ENODEV ;
}
writel ( 0x00000001 , reg ) ;
iounmap ( reg ) ;
/* map in cyclone_timer */
offset = ( base + CYCLONE_MPMC_OFFSET ) ;
2007-07-26 20:34:59 +04:00
cyclone_timer = ioremap_nocache ( offset , sizeof ( u32 ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! cyclone_timer ) {
2007-07-20 22:22:30 +04:00
printk ( KERN_ERR " Summit chipset: Could not find valid MPMC "
" register. \n " ) ;
2005-04-17 02:20:36 +04:00
use_cyclone = 0 ;
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 ) {
2007-07-20 22:22:30 +04:00
printk ( KERN_ERR " Summit chipset: Counter not counting! "
" DISABLED \n " ) ;
2005-04-17 02:20:36 +04:00
iounmap ( cyclone_timer ) ;
2007-07-26 20:34:59 +04:00
cyclone_timer = NULL ;
2005-04-17 02:20:36 +04:00
use_cyclone = 0 ;
return - ENODEV ;
}
}
/* initialize last tick */
2007-07-20 22:22:30 +04:00
cyclone_mc = cyclone_timer ;
clocksource_cyclone . fsys_mmio = cyclone_timer ;
clocksource_cyclone . mult = clocksource_hz2mult ( CYCLONE_TIMER_FREQ ,
clocksource_cyclone . shift ) ;
clocksource_register ( & clocksource_cyclone ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
__initcall ( init_cyclone_clock ) ;