2006-11-11 17:24:53 +11:00
/*
* ( c ) Copyright 2006 Benjamin Herrenschmidt , IBM Corp .
* < benh @ kernel . crashing . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See
* the GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# undef DEBUG
# include <linux/kernel.h>
# include <asm/prom.h>
# include <asm/dcr.h>
unsigned int dcr_resource_start ( struct device_node * np , unsigned int index )
{
unsigned int ds ;
2007-04-03 22:26:41 +10:00
const u32 * dr = of_get_property ( np , " dcr-reg " , & ds ) ;
2006-11-11 17:24:53 +11:00
if ( dr = = NULL | | ds & 1 | | index > = ( ds / 8 ) )
return 0 ;
return dr [ index * 2 ] ;
}
2007-08-09 07:46:49 +10:00
EXPORT_SYMBOL_GPL ( dcr_resource_start ) ;
2006-11-11 17:24:53 +11:00
unsigned int dcr_resource_len ( struct device_node * np , unsigned int index )
{
unsigned int ds ;
2007-04-03 22:26:41 +10:00
const u32 * dr = of_get_property ( np , " dcr-reg " , & ds ) ;
2006-11-11 17:24:53 +11:00
if ( dr = = NULL | | ds & 1 | | index > = ( ds / 8 ) )
return 0 ;
return dr [ index * 2 + 1 ] ;
}
2007-08-09 07:46:49 +10:00
EXPORT_SYMBOL_GPL ( dcr_resource_len ) ;
2006-11-11 17:24:53 +11:00
# ifndef CONFIG_PPC_DCR_NATIVE
static struct device_node * find_dcr_parent ( struct device_node * node )
{
struct device_node * par , * tmp ;
const u32 * p ;
for ( par = of_node_get ( node ) ; par ; ) {
2007-04-03 22:26:41 +10:00
if ( of_get_property ( par , " dcr-controller " , NULL ) )
2006-11-11 17:24:53 +11:00
break ;
2007-04-03 22:26:41 +10:00
p = of_get_property ( par , " dcr-parent " , NULL ) ;
2006-11-11 17:24:53 +11:00
tmp = par ;
if ( p = = NULL )
par = of_get_parent ( par ) ;
else
par = of_find_node_by_phandle ( * p ) ;
of_node_put ( tmp ) ;
}
return par ;
}
u64 of_translate_dcr_address ( struct device_node * dev ,
unsigned int dcr_n ,
unsigned int * out_stride )
{
struct device_node * dp ;
const u32 * p ;
unsigned int stride ;
u64 ret ;
dp = find_dcr_parent ( dev ) ;
if ( dp = = NULL )
return OF_BAD_ADDR ;
/* Stride is not properly defined yet, default to 0x10 for Axon */
2007-04-03 22:26:41 +10:00
p = of_get_property ( dp , " dcr-mmio-stride " , NULL ) ;
2006-11-11 17:24:53 +11:00
stride = ( p = = NULL ) ? 0x10 : * p ;
/* XXX FIXME: Which property name is to use of the 2 following ? */
2007-04-03 22:26:41 +10:00
p = of_get_property ( dp , " dcr-mmio-range " , NULL ) ;
2006-11-11 17:24:53 +11:00
if ( p = = NULL )
2007-04-03 22:26:41 +10:00
p = of_get_property ( dp , " dcr-mmio-space " , NULL ) ;
2006-11-11 17:24:53 +11:00
if ( p = = NULL )
return OF_BAD_ADDR ;
/* Maybe could do some better range checking here */
ret = of_translate_address ( dp , p ) ;
if ( ret ! = OF_BAD_ADDR )
ret + = ( u64 ) ( stride ) * ( u64 ) dcr_n ;
if ( out_stride )
* out_stride = stride ;
return ret ;
}
dcr_host_t dcr_map ( struct device_node * dev , unsigned int dcr_n ,
unsigned int dcr_c )
{
2007-09-17 16:05:00 +10:00
dcr_host_t ret = { . token = NULL , . stride = 0 , . base = dcr_n } ;
2006-11-11 17:24:53 +11:00
u64 addr ;
pr_debug ( " dcr_map(%s, 0x%x, 0x%x) \n " ,
dev - > full_name , dcr_n , dcr_c ) ;
addr = of_translate_dcr_address ( dev , dcr_n , & ret . stride ) ;
pr_debug ( " translates to addr: 0x%lx, stride: 0x%x \n " ,
addr , ret . stride ) ;
if ( addr = = OF_BAD_ADDR )
return ret ;
pr_debug ( " mapping 0x%x bytes \n " , dcr_c * ret . stride ) ;
ret . token = ioremap ( addr , dcr_c * ret . stride ) ;
if ( ret . token = = NULL )
return ret ;
pr_debug ( " mapped at 0x%p -> base is 0x%p \n " ,
ret . token , ret . token - dcr_n * ret . stride ) ;
ret . token - = dcr_n * ret . stride ;
return ret ;
}
2007-08-09 07:46:49 +10:00
EXPORT_SYMBOL_GPL ( dcr_map ) ;
2006-11-11 17:24:53 +11:00
2007-10-15 19:34:37 +10:00
void dcr_unmap ( dcr_host_t host , unsigned int dcr_c )
2006-11-11 17:24:53 +11:00
{
dcr_host_t h = host ;
if ( h . token = = NULL )
return ;
2007-10-15 19:34:37 +10:00
h . token + = host . base * h . stride ;
2006-11-11 17:24:53 +11:00
iounmap ( h . token ) ;
h . token = NULL ;
}
2007-08-09 07:46:49 +10:00
EXPORT_SYMBOL_GPL ( dcr_unmap ) ;
2006-11-11 17:24:53 +11:00
# endif /* !defined(CONFIG_PPC_DCR_NATIVE) */