2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2006-11-11 17:24:53 +11:00
/*
* ( c ) Copyright 2006 Benjamin Herrenschmidt , IBM Corp .
* < benh @ kernel . crashing . org >
*/
# undef DEBUG
# include <linux/kernel.h>
2011-05-27 10:46:24 -04:00
# include <linux/export.h>
2022-03-08 20:20:25 +01:00
# include <linux/of_address.h>
2006-11-11 17:24:53 +11:00
# include <asm/dcr.h>
2008-05-20 07:59:23 -05:00
# ifdef CONFIG_PPC_DCR_MMIO
2008-05-07 04:29:17 +10:00
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 ; ) {
if ( of_get_property ( par , " dcr-controller " , NULL ) )
break ;
p = of_get_property ( par , " dcr-parent " , NULL ) ;
tmp = par ;
if ( p = = NULL )
par = of_get_parent ( par ) ;
else
par = of_find_node_by_phandle ( * p ) ;
of_node_put ( tmp ) ;
}
return par ;
}
2008-05-20 07:59:23 -05:00
# endif
2008-05-07 04:29:17 +10:00
# if defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO)
bool dcr_map_ok_generic ( dcr_host_t host )
{
if ( host . type = = DCR_HOST_NATIVE )
return dcr_map_ok_native ( host . host . native ) ;
else if ( host . type = = DCR_HOST_MMIO )
return dcr_map_ok_mmio ( host . host . mmio ) ;
else
2015-03-30 16:46:04 -07:00
return false ;
2008-05-07 04:29:17 +10:00
}
EXPORT_SYMBOL_GPL ( dcr_map_ok_generic ) ;
dcr_host_t dcr_map_generic ( struct device_node * dev ,
unsigned int dcr_n ,
unsigned int dcr_c )
{
dcr_host_t host ;
struct device_node * dp ;
const char * prop ;
host . type = DCR_HOST_INVALID ;
dp = find_dcr_parent ( dev ) ;
if ( dp = = NULL )
return host ;
prop = of_get_property ( dp , " dcr-access-method " , NULL ) ;
pr_debug ( " dcr_map_generic(dcr-access-method = %s) \n " , prop ) ;
if ( ! strcmp ( prop , " native " ) ) {
host . type = DCR_HOST_NATIVE ;
host . host . native = dcr_map_native ( dev , dcr_n , dcr_c ) ;
} else if ( ! strcmp ( prop , " mmio " ) ) {
host . type = DCR_HOST_MMIO ;
host . host . mmio = dcr_map_mmio ( dev , dcr_n , dcr_c ) ;
}
of_node_put ( dp ) ;
return host ;
}
EXPORT_SYMBOL_GPL ( dcr_map_generic ) ;
void dcr_unmap_generic ( dcr_host_t host , unsigned int dcr_c )
{
if ( host . type = = DCR_HOST_NATIVE )
dcr_unmap_native ( host . host . native , dcr_c ) ;
else if ( host . type = = DCR_HOST_MMIO )
dcr_unmap_mmio ( host . host . mmio , dcr_c ) ;
else /* host.type == DCR_HOST_INVALID */
WARN_ON ( true ) ;
}
EXPORT_SYMBOL_GPL ( dcr_unmap_generic ) ;
u32 dcr_read_generic ( dcr_host_t host , unsigned int dcr_n )
{
if ( host . type = = DCR_HOST_NATIVE )
return dcr_read_native ( host . host . native , dcr_n ) ;
else if ( host . type = = DCR_HOST_MMIO )
return dcr_read_mmio ( host . host . mmio , dcr_n ) ;
else /* host.type == DCR_HOST_INVALID */
WARN_ON ( true ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( dcr_read_generic ) ;
void dcr_write_generic ( dcr_host_t host , unsigned int dcr_n , u32 value )
{
if ( host . type = = DCR_HOST_NATIVE )
dcr_write_native ( host . host . native , dcr_n , value ) ;
else if ( host . type = = DCR_HOST_MMIO )
dcr_write_mmio ( host . host . mmio , dcr_n , value ) ;
else /* host.type == DCR_HOST_INVALID */
WARN_ON ( true ) ;
}
EXPORT_SYMBOL_GPL ( dcr_write_generic ) ;
# endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
2008-12-19 08:17:54 +00:00
unsigned int dcr_resource_start ( const struct device_node * np ,
unsigned int index )
2006-11-11 17:24:53 +11:00
{
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
2008-12-19 08:17:54 +00:00
unsigned int dcr_resource_len ( const struct device_node * np , unsigned int index )
2006-11-11 17:24:53 +11:00
{
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
2008-05-07 04:29:17 +10:00
# ifdef CONFIG_PPC_DCR_MMIO
2006-11-11 17:24:53 +11:00
2014-05-23 07:50:50 +09:00
static u64 of_translate_dcr_address ( struct device_node * dev ,
unsigned int dcr_n ,
unsigned int * out_stride )
2006-11-11 17:24:53 +11:00
{
struct device_node * dp ;
const u32 * p ;
unsigned int stride ;
2008-05-07 04:29:17 +10:00
u64 ret = OF_BAD_ADDR ;
2006-11-11 17:24:53 +11:00
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 )
2008-05-07 04:29:17 +10:00
goto done ;
2006-11-11 17:24:53 +11:00
/* 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 ;
2008-05-07 04:29:17 +10:00
done :
of_node_put ( dp ) ;
2006-11-11 17:24:53 +11:00
return ret ;
}
2008-05-07 04:29:17 +10:00
dcr_host_mmio_t dcr_map_mmio ( struct device_node * dev ,
unsigned int dcr_n ,
unsigned int dcr_c )
2006-11-11 17:24:53 +11:00
{
2008-05-07 04:29:17 +10:00
dcr_host_mmio_t ret = { . token = NULL , . stride = 0 , . base = dcr_n } ;
2006-11-11 17:24:53 +11:00
u64 addr ;
2017-08-21 10:16:47 -05:00
pr_debug ( " dcr_map(%pOF, 0x%x, 0x%x) \n " ,
dev , dcr_n , dcr_c ) ;
2006-11-11 17:24:53 +11:00
addr = of_translate_dcr_address ( dev , dcr_n , & ret . stride ) ;
2008-05-07 04:29:17 +10:00
pr_debug ( " translates to addr: 0x%llx, stride: 0x%x \n " ,
( unsigned long long ) addr , ret . stride ) ;
2006-11-11 17:24:53 +11:00
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 ;
}
2008-05-07 04:29:17 +10:00
EXPORT_SYMBOL_GPL ( dcr_map_mmio ) ;
2006-11-11 17:24:53 +11:00
2008-05-07 04:29:17 +10:00
void dcr_unmap_mmio ( dcr_host_mmio_t host , unsigned int dcr_c )
2006-11-11 17:24:53 +11:00
{
2008-05-07 04:29:17 +10:00
dcr_host_mmio_t h = host ;
2006-11-11 17:24:53 +11:00
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 ;
}
2008-05-07 04:29:17 +10:00
EXPORT_SYMBOL_GPL ( dcr_unmap_mmio ) ;
# endif /* defined(CONFIG_PPC_DCR_MMIO) */
# ifdef CONFIG_PPC_DCR_NATIVE
2008-02-05 01:57:55 +11:00
DEFINE_SPINLOCK ( dcr_ind_lock ) ;
2014-08-19 23:24:15 -04:00
EXPORT_SYMBOL_GPL ( dcr_ind_lock ) ;
2008-05-07 04:29:17 +10:00
# endif /* defined(CONFIG_PPC_DCR_NATIVE) */