2007-10-27 11:13:04 +04:00
/* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
2005-04-17 02:20:36 +04:00
*
2008-09-01 07:56:15 +04:00
* Copyright ( C ) 1997 , 1999 , 2008 David S . Miller ( davem @ davemloft . net )
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/string.h>
# include <linux/init.h>
2008-09-01 07:56:15 +04:00
# include <linux/of_device.h>
# include <linux/platform_device.h>
2005-04-17 02:20:36 +04:00
# include <asm/fhc.h>
2008-09-01 07:56:15 +04:00
# include <asm/upa.h>
struct clock_board {
void __iomem * clock_freq_regs ;
void __iomem * clock_regs ;
void __iomem * clock_ver_reg ;
int num_slots ;
struct resource leds_resource ;
struct platform_device leds_pdev ;
} ;
struct fhc {
void __iomem * pregs ;
bool central ;
bool jtag_master ;
int board_num ;
struct resource leds_resource ;
struct platform_device leds_pdev ;
} ;
static int __devinit clock_board_calc_nslots ( struct clock_board * p )
{
u8 reg = upa_readb ( p - > clock_regs + CLOCK_STAT1 ) & 0xc0 ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
switch ( reg ) {
case 0x40 :
return 16 ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
case 0xc0 :
return 8 ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
case 0x80 :
reg = 0 ;
if ( p - > clock_ver_reg )
reg = upa_readb ( p - > clock_ver_reg ) ;
if ( reg ) {
if ( reg & 0x80 )
return 4 ;
else
return 5 ;
}
/* Fallthrough */
default :
return 4 ;
2006-06-23 06:53:24 +04:00
}
2005-04-17 02:20:36 +04:00
}
2008-09-01 07:56:15 +04:00
static int __devinit clock_board_probe ( struct of_device * op ,
const struct of_device_id * match )
2005-04-17 02:20:36 +04:00
{
2008-09-01 07:56:15 +04:00
struct clock_board * p = kzalloc ( sizeof ( * p ) , GFP_KERNEL ) ;
int err = - ENOMEM ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
if ( ! p ) {
printk ( KERN_ERR " clock_board: Cannot allocate struct clock_board \n " ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-09-01 07:56:15 +04:00
p - > clock_freq_regs = of_ioremap ( & op - > resource [ 0 ] , 0 ,
resource_size ( & op - > resource [ 0 ] ) ,
" clock_board_freq " ) ;
if ( ! p - > clock_freq_regs ) {
printk ( KERN_ERR " clock_board: Cannot map clock_freq_regs \n " ) ;
goto out_free ;
}
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
p - > clock_regs = of_ioremap ( & op - > resource [ 1 ] , 0 ,
resource_size ( & op - > resource [ 1 ] ) ,
" clock_board_regs " ) ;
if ( ! p - > clock_regs ) {
printk ( KERN_ERR " clock_board: Cannot map clock_regs \n " ) ;
goto out_unmap_clock_freq_regs ;
}
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
if ( op - > resource [ 2 ] . flags ) {
p - > clock_ver_reg = of_ioremap ( & op - > resource [ 2 ] , 0 ,
resource_size ( & op - > resource [ 2 ] ) ,
" clock_ver_reg " ) ;
if ( ! p - > clock_ver_reg ) {
printk ( KERN_ERR " clock_board: Cannot map clock_ver_reg \n " ) ;
goto out_unmap_clock_regs ;
}
}
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
p - > num_slots = clock_board_calc_nslots ( p ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
p - > leds_resource . start = ( unsigned long )
( p - > clock_regs + CLOCK_CTRL ) ;
p - > leds_resource . end = p - > leds_resource . end ;
p - > leds_resource . name = " leds " ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
p - > leds_pdev . name = " sunfire-clockboard-leds " ;
2009-01-19 09:42:15 +03:00
p - > leds_pdev . id = - 1 ;
2008-09-01 07:56:15 +04:00
p - > leds_pdev . resource = & p - > leds_resource ;
p - > leds_pdev . num_resources = 1 ;
p - > leds_pdev . dev . parent = & op - > dev ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
err = platform_device_register ( & p - > leds_pdev ) ;
if ( err ) {
printk ( KERN_ERR " clock_board: Could not register LEDS "
" platform device \n " ) ;
goto out_unmap_clock_ver_reg ;
2005-04-17 02:20:36 +04:00
}
2008-09-01 07:56:15 +04:00
printk ( KERN_INFO " clock_board: Detected %d slot Enterprise system. \n " ,
p - > num_slots ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
err = 0 ;
out :
return err ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
out_unmap_clock_ver_reg :
if ( p - > clock_ver_reg )
of_iounmap ( & op - > resource [ 2 ] , p - > clock_ver_reg ,
resource_size ( & op - > resource [ 2 ] ) ) ;
2006-06-23 06:53:24 +04:00
2008-09-01 07:56:15 +04:00
out_unmap_clock_regs :
of_iounmap ( & op - > resource [ 1 ] , p - > clock_regs ,
resource_size ( & op - > resource [ 1 ] ) ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
out_unmap_clock_freq_regs :
of_iounmap ( & op - > resource [ 0 ] , p - > clock_freq_regs ,
resource_size ( & op - > resource [ 0 ] ) ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
out_free :
kfree ( p ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-09-01 07:56:15 +04:00
static struct of_device_id __initdata clock_board_match [ ] = {
{
. name = " clock-board " ,
} ,
{ } ,
} ;
static struct of_platform_driver clock_board_driver = {
. match_table = clock_board_match ,
. probe = clock_board_probe ,
. driver = {
. name = " clock_board " ,
} ,
} ;
static int __devinit fhc_probe ( struct of_device * op ,
const struct of_device_id * match )
2005-04-17 02:20:36 +04:00
{
2008-09-01 07:56:15 +04:00
struct fhc * p = kzalloc ( sizeof ( * p ) , GFP_KERNEL ) ;
int err = - ENOMEM ;
u32 reg ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
if ( ! p ) {
printk ( KERN_ERR " fhc: Cannot allocate struct fhc \n " ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-09-01 07:56:15 +04:00
if ( ! strcmp ( op - > node - > parent - > name , " central " ) )
p - > central = true ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
p - > pregs = of_ioremap ( & op - > resource [ 0 ] , 0 ,
resource_size ( & op - > resource [ 0 ] ) ,
" fhc_pregs " ) ;
if ( ! p - > pregs ) {
printk ( KERN_ERR " fhc: Cannot map pregs \n " ) ;
goto out_free ;
2006-06-23 06:53:24 +04:00
}
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
if ( p - > central ) {
reg = upa_readl ( p - > pregs + FHC_PREGS_BSR ) ;
p - > board_num = ( ( reg > > 16 ) & 1 ) | ( ( reg > > 12 ) & 0x0e ) ;
} else {
p - > board_num = of_getintprop_default ( op - > node , " board# " , - 1 ) ;
if ( p - > board_num = = - 1 ) {
printk ( KERN_ERR " fhc: No board# property \n " ) ;
goto out_unmap_pregs ;
}
if ( upa_readl ( p - > pregs + FHC_PREGS_JCTRL ) & FHC_JTAG_CTRL_MENAB )
p - > jtag_master = true ;
}
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
if ( ! p - > central ) {
p - > leds_resource . start = ( unsigned long )
( p - > pregs + FHC_PREGS_CTRL ) ;
p - > leds_resource . end = p - > leds_resource . end ;
p - > leds_resource . name = " leds " ;
p - > leds_pdev . name = " sunfire-fhc-leds " ;
2009-01-19 09:42:15 +03:00
p - > leds_pdev . id = p - > board_num ;
2008-09-01 07:56:15 +04:00
p - > leds_pdev . resource = & p - > leds_resource ;
p - > leds_pdev . num_resources = 1 ;
p - > leds_pdev . dev . parent = & op - > dev ;
err = platform_device_register ( & p - > leds_pdev ) ;
if ( err ) {
printk ( KERN_ERR " fhc: Could not register LEDS "
" platform device \n " ) ;
goto out_unmap_pregs ;
}
}
reg = upa_readl ( p - > pregs + FHC_PREGS_CTRL ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
if ( ! p - > central )
reg | = FHC_CONTROL_IXIST ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
reg & = ~ ( FHC_CONTROL_AOFF |
FHC_CONTROL_BOFF |
FHC_CONTROL_SLINE ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
upa_writel ( reg , p - > pregs + FHC_PREGS_CTRL ) ;
upa_readl ( p - > pregs + FHC_PREGS_CTRL ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
reg = upa_readl ( p - > pregs + FHC_PREGS_ID ) ;
printk ( KERN_INFO " fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s \n " ,
p - > board_num ,
( reg & FHC_ID_VERS ) > > 28 ,
( reg & FHC_ID_PARTID ) > > 12 ,
( reg & FHC_ID_MANUF ) > > 1 ,
( p - > jtag_master ?
" (JTAG Master) " :
( p - > central ? " (Central) " : " " ) ) ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
err = 0 ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
out :
return err ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
out_unmap_pregs :
of_iounmap ( & op - > resource [ 0 ] , p - > pregs , resource_size ( & op - > resource [ 0 ] ) ) ;
2005-04-17 02:20:36 +04:00
2008-09-01 07:56:15 +04:00
out_free :
kfree ( p ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-09-01 07:56:15 +04:00
static struct of_device_id __initdata fhc_match [ ] = {
{
. name = " fhc " ,
} ,
{ } ,
} ;
static struct of_platform_driver fhc_driver = {
. match_table = fhc_match ,
. probe = fhc_probe ,
. driver = {
. name = " fhc " ,
} ,
} ;
static int __init sunfire_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-09-01 07:56:15 +04:00
( void ) of_register_driver ( & fhc_driver , & of_platform_bus_type ) ;
( void ) of_register_driver ( & clock_board_driver , & of_platform_bus_type ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-09-01 07:56:15 +04:00
subsys_initcall ( sunfire_init ) ;