2010-06-08 17:48:09 +04:00
2012-04-11 21:30:11 +04:00
# include <linux/device.h>
2010-06-08 17:48:09 +04:00
# include <linux/io.h>
# include <linux/ioport.h>
2010-06-08 17:48:10 +04:00
# include <linux/module.h>
2010-06-08 17:48:09 +04:00
# include <linux/of_address.h>
2010-06-08 17:48:10 +04:00
# include <linux/pci_regs.h>
# include <linux/string.h>
2010-06-08 17:48:09 +04:00
2010-06-08 17:48:10 +04:00
/* Max address size we deal with */
# define OF_MAX_ADDR_CELLS 4
# define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
( ns ) > 0 )
static struct of_bus * of_match_bus ( struct device_node * np ) ;
2010-12-01 12:54:46 +03:00
static int __of_address_to_resource ( struct device_node * dev ,
const __be32 * addrp , u64 size , unsigned int flags ,
2011-12-05 18:23:55 +04:00
const char * name , struct resource * r ) ;
2010-06-08 17:48:10 +04:00
/* Debug utility */
# ifdef DEBUG
2010-12-01 12:54:46 +03:00
static void of_dump_addr ( const char * s , const __be32 * addr , int na )
2010-06-08 17:48:10 +04:00
{
printk ( KERN_DEBUG " %s " , s ) ;
while ( na - - )
2010-06-08 17:48:11 +04:00
printk ( " %08x " , be32_to_cpu ( * ( addr + + ) ) ) ;
2010-06-08 17:48:10 +04:00
printk ( " \n " ) ;
}
# else
2010-12-01 12:54:46 +03:00
static void of_dump_addr ( const char * s , const __be32 * addr , int na ) { }
2010-06-08 17:48:10 +04:00
# endif
/* Callbacks for bus specific translators */
struct of_bus {
const char * name ;
const char * addresses ;
int ( * match ) ( struct device_node * parent ) ;
void ( * count_cells ) ( struct device_node * child ,
int * addrc , int * sizec ) ;
2010-12-01 12:54:46 +03:00
u64 ( * map ) ( u32 * addr , const __be32 * range ,
2010-06-08 17:48:10 +04:00
int na , int ns , int pna ) ;
int ( * translate ) ( u32 * addr , u64 offset , int na ) ;
2010-12-01 12:54:46 +03:00
unsigned int ( * get_flags ) ( const __be32 * addr ) ;
2010-06-08 17:48:10 +04:00
} ;
/*
* Default translator ( generic bus )
*/
static void of_bus_default_count_cells ( struct device_node * dev ,
int * addrc , int * sizec )
{
if ( addrc )
* addrc = of_n_addr_cells ( dev ) ;
if ( sizec )
* sizec = of_n_size_cells ( dev ) ;
}
2010-12-01 12:54:46 +03:00
static u64 of_bus_default_map ( u32 * addr , const __be32 * range ,
2010-06-08 17:48:10 +04:00
int na , int ns , int pna )
{
u64 cp , s , da ;
cp = of_read_number ( range , na ) ;
s = of_read_number ( range + na + pna , ns ) ;
da = of_read_number ( addr , na ) ;
pr_debug ( " OF: default map, cp=%llx, s=%llx, da=%llx \n " ,
( unsigned long long ) cp , ( unsigned long long ) s ,
( unsigned long long ) da ) ;
if ( da < cp | | da > = ( cp + s ) )
return OF_BAD_ADDR ;
return da - cp ;
}
static int of_bus_default_translate ( u32 * addr , u64 offset , int na )
{
u64 a = of_read_number ( addr , na ) ;
memset ( addr , 0 , na * 4 ) ;
a + = offset ;
if ( na > 1 )
2010-06-08 17:48:11 +04:00
addr [ na - 2 ] = cpu_to_be32 ( a > > 32 ) ;
addr [ na - 1 ] = cpu_to_be32 ( a & 0xffffffffu ) ;
2010-06-08 17:48:10 +04:00
return 0 ;
}
2010-12-01 12:54:46 +03:00
static unsigned int of_bus_default_get_flags ( const __be32 * addr )
2010-06-08 17:48:10 +04:00
{
return IORESOURCE_MEM ;
}
# ifdef CONFIG_PCI
/*
* PCI bus specific translator
*/
static int of_bus_pci_match ( struct device_node * np )
{
/* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
return ! strcmp ( np - > type , " pci " ) | | ! strcmp ( np - > type , " vci " ) ;
}
static void of_bus_pci_count_cells ( struct device_node * np ,
int * addrc , int * sizec )
{
if ( addrc )
* addrc = 3 ;
if ( sizec )
* sizec = 2 ;
}
2010-12-01 12:54:46 +03:00
static unsigned int of_bus_pci_get_flags ( const __be32 * addr )
2010-06-08 17:48:10 +04:00
{
unsigned int flags = 0 ;
2010-12-01 12:54:46 +03:00
u32 w = be32_to_cpup ( addr ) ;
2010-06-08 17:48:10 +04:00
switch ( ( w > > 24 ) & 0x03 ) {
case 0x01 :
flags | = IORESOURCE_IO ;
break ;
case 0x02 : /* 32 bits */
case 0x03 : /* 64 bits */
flags | = IORESOURCE_MEM ;
break ;
}
if ( w & 0x40000000 )
flags | = IORESOURCE_PREFETCH ;
return flags ;
}
2010-12-01 12:54:46 +03:00
static u64 of_bus_pci_map ( u32 * addr , const __be32 * range , int na , int ns ,
int pna )
2010-06-08 17:48:10 +04:00
{
u64 cp , s , da ;
unsigned int af , rf ;
af = of_bus_pci_get_flags ( addr ) ;
rf = of_bus_pci_get_flags ( range ) ;
/* Check address type match */
if ( ( af ^ rf ) & ( IORESOURCE_MEM | IORESOURCE_IO ) )
return OF_BAD_ADDR ;
/* Read address values, skipping high cell */
cp = of_read_number ( range + 1 , na - 1 ) ;
s = of_read_number ( range + na + pna , ns ) ;
da = of_read_number ( addr + 1 , na - 1 ) ;
pr_debug ( " OF: PCI map, cp=%llx, s=%llx, da=%llx \n " ,
( unsigned long long ) cp , ( unsigned long long ) s ,
( unsigned long long ) da ) ;
if ( da < cp | | da > = ( cp + s ) )
return OF_BAD_ADDR ;
return da - cp ;
}
static int of_bus_pci_translate ( u32 * addr , u64 offset , int na )
{
return of_bus_default_translate ( addr + 1 , offset , na - 1 ) ;
}
2010-12-01 12:54:46 +03:00
const __be32 * of_get_pci_address ( struct device_node * dev , int bar_no , u64 * size ,
2010-06-08 17:48:10 +04:00
unsigned int * flags )
{
2010-10-11 07:24:10 +04:00
const __be32 * prop ;
2010-06-08 17:48:10 +04:00
unsigned int psize ;
struct device_node * parent ;
struct of_bus * bus ;
int onesize , i , na , ns ;
/* Get parent & match bus type */
parent = of_get_parent ( dev ) ;
if ( parent = = NULL )
return NULL ;
bus = of_match_bus ( parent ) ;
if ( strcmp ( bus - > name , " pci " ) ) {
of_node_put ( parent ) ;
return NULL ;
}
bus - > count_cells ( dev , & na , & ns ) ;
of_node_put ( parent ) ;
if ( ! OF_CHECK_COUNTS ( na , ns ) )
return NULL ;
/* Get "reg" or "assigned-addresses" property */
prop = of_get_property ( dev , bus - > addresses , & psize ) ;
if ( prop = = NULL )
return NULL ;
psize / = 4 ;
onesize = na + ns ;
2010-06-08 17:48:11 +04:00
for ( i = 0 ; psize > = onesize ; psize - = onesize , prop + = onesize , i + + ) {
u32 val = be32_to_cpu ( prop [ 0 ] ) ;
if ( ( val & 0xff ) = = ( ( bar_no * 4 ) + PCI_BASE_ADDRESS_0 ) ) {
2010-06-08 17:48:10 +04:00
if ( size )
* size = of_read_number ( prop + na , ns ) ;
if ( flags )
* flags = bus - > get_flags ( prop ) ;
return prop ;
}
2010-06-08 17:48:11 +04:00
}
2010-06-08 17:48:10 +04:00
return NULL ;
}
EXPORT_SYMBOL ( of_get_pci_address ) ;
int of_pci_address_to_resource ( struct device_node * dev , int bar ,
struct resource * r )
{
2010-12-01 12:54:46 +03:00
const __be32 * addrp ;
2010-06-08 17:48:10 +04:00
u64 size ;
unsigned int flags ;
addrp = of_get_pci_address ( dev , bar , & size , & flags ) ;
if ( addrp = = NULL )
return - EINVAL ;
2011-12-05 18:23:55 +04:00
return __of_address_to_resource ( dev , addrp , size , flags , NULL , r ) ;
2010-06-08 17:48:10 +04:00
}
EXPORT_SYMBOL_GPL ( of_pci_address_to_resource ) ;
# endif /* CONFIG_PCI */
/*
* ISA bus specific translator
*/
static int of_bus_isa_match ( struct device_node * np )
{
return ! strcmp ( np - > name , " isa " ) ;
}
static void of_bus_isa_count_cells ( struct device_node * child ,
int * addrc , int * sizec )
{
if ( addrc )
* addrc = 2 ;
if ( sizec )
* sizec = 1 ;
}
2010-12-01 12:54:46 +03:00
static u64 of_bus_isa_map ( u32 * addr , const __be32 * range , int na , int ns ,
int pna )
2010-06-08 17:48:10 +04:00
{
u64 cp , s , da ;
/* Check address type match */
2010-12-01 12:54:46 +03:00
if ( ( addr [ 0 ] ^ range [ 0 ] ) & cpu_to_be32 ( 1 ) )
2010-06-08 17:48:10 +04:00
return OF_BAD_ADDR ;
/* Read address values, skipping high cell */
cp = of_read_number ( range + 1 , na - 1 ) ;
s = of_read_number ( range + na + pna , ns ) ;
da = of_read_number ( addr + 1 , na - 1 ) ;
pr_debug ( " OF: ISA map, cp=%llx, s=%llx, da=%llx \n " ,
( unsigned long long ) cp , ( unsigned long long ) s ,
( unsigned long long ) da ) ;
if ( da < cp | | da > = ( cp + s ) )
return OF_BAD_ADDR ;
return da - cp ;
}
static int of_bus_isa_translate ( u32 * addr , u64 offset , int na )
{
return of_bus_default_translate ( addr + 1 , offset , na - 1 ) ;
}
2010-12-01 12:54:46 +03:00
static unsigned int of_bus_isa_get_flags ( const __be32 * addr )
2010-06-08 17:48:10 +04:00
{
unsigned int flags = 0 ;
2010-12-01 12:54:46 +03:00
u32 w = be32_to_cpup ( addr ) ;
2010-06-08 17:48:10 +04:00
if ( w & 1 )
flags | = IORESOURCE_IO ;
else
flags | = IORESOURCE_MEM ;
return flags ;
}
/*
* Array of bus specific translators
*/
static struct of_bus of_busses [ ] = {
# ifdef CONFIG_PCI
/* PCI */
{
. name = " pci " ,
. addresses = " assigned-addresses " ,
. match = of_bus_pci_match ,
. count_cells = of_bus_pci_count_cells ,
. map = of_bus_pci_map ,
. translate = of_bus_pci_translate ,
. get_flags = of_bus_pci_get_flags ,
} ,
# endif /* CONFIG_PCI */
/* ISA */
{
. name = " isa " ,
. addresses = " reg " ,
. match = of_bus_isa_match ,
. count_cells = of_bus_isa_count_cells ,
. map = of_bus_isa_map ,
. translate = of_bus_isa_translate ,
. get_flags = of_bus_isa_get_flags ,
} ,
/* Default */
{
. name = " default " ,
. addresses = " reg " ,
. match = NULL ,
. count_cells = of_bus_default_count_cells ,
. map = of_bus_default_map ,
. translate = of_bus_default_translate ,
. get_flags = of_bus_default_get_flags ,
} ,
} ;
static struct of_bus * of_match_bus ( struct device_node * np )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( of_busses ) ; i + + )
if ( ! of_busses [ i ] . match | | of_busses [ i ] . match ( np ) )
return & of_busses [ i ] ;
BUG ( ) ;
return NULL ;
}
static int of_translate_one ( struct device_node * parent , struct of_bus * bus ,
struct of_bus * pbus , u32 * addr ,
int na , int ns , int pna , const char * rprop )
{
2010-12-01 12:54:46 +03:00
const __be32 * ranges ;
2010-06-08 17:48:10 +04:00
unsigned int rlen ;
int rone ;
u64 offset = OF_BAD_ADDR ;
/* Normally, an absence of a "ranges" property means we are
* crossing a non - translatable boundary , and thus the addresses
* below the current not cannot be converted to CPU physical ones .
* Unfortunately , while this is very clear in the spec , it ' s not
* what Apple understood , and they do have things like / uni - n or
* / ht nodes with no " ranges " property and a lot of perfectly
* useable mapped devices below them . Thus we treat the absence of
* " ranges " as equivalent to an empty " ranges " property which means
* a 1 : 1 translation at that level . It ' s up to the caller not to try
* to translate addresses that aren ' t supposed to be translated in
* the first place . - - BenH .
2010-06-08 17:48:11 +04:00
*
* As far as we know , this damage only exists on Apple machines , so
* This code is only enabled on powerpc . - - gcl
2010-06-08 17:48:10 +04:00
*/
ranges = of_get_property ( parent , rprop , & rlen ) ;
2010-06-08 17:48:11 +04:00
# if !defined(CONFIG_PPC)
if ( ranges = = NULL ) {
pr_err ( " OF: no ranges; cannot translate \n " ) ;
return 1 ;
}
# endif /* !defined(CONFIG_PPC) */
2010-06-08 17:48:10 +04:00
if ( ranges = = NULL | | rlen = = 0 ) {
offset = of_read_number ( addr , na ) ;
memset ( addr , 0 , pna * 4 ) ;
2010-06-08 17:48:11 +04:00
pr_debug ( " OF: empty ranges; 1:1 translation \n " ) ;
2010-06-08 17:48:10 +04:00
goto finish ;
}
pr_debug ( " OF: walking ranges... \n " ) ;
/* Now walk through the ranges */
rlen / = 4 ;
rone = na + pna + ns ;
for ( ; rlen > = rone ; rlen - = rone , ranges + = rone ) {
offset = bus - > map ( addr , ranges , na , ns , pna ) ;
if ( offset ! = OF_BAD_ADDR )
break ;
}
if ( offset = = OF_BAD_ADDR ) {
pr_debug ( " OF: not found ! \n " ) ;
return 1 ;
}
memcpy ( addr , ranges + na , 4 * pna ) ;
finish :
of_dump_addr ( " OF: parent translation for: " , addr , pna ) ;
pr_debug ( " OF: with offset: %llx \n " , ( unsigned long long ) offset ) ;
/* Translate it into parent bus space */
return pbus - > translate ( addr , offset , pna ) ;
}
/*
* Translate an address from the device - tree into a CPU physical address ,
* this walks up the tree and applies the various bus mappings on the
* way .
*
* Note : We consider that crossing any level with # size - cells = = 0 to mean
* that translation is impossible ( that is we are not dealing with a value
* that can be mapped to a cpu physical address ) . This is not really specified
* that way , but this is traditionally the way IBM at least do things
*/
2010-12-01 12:54:46 +03:00
u64 __of_translate_address ( struct device_node * dev , const __be32 * in_addr ,
2010-06-08 17:48:10 +04:00
const char * rprop )
{
struct device_node * parent = NULL ;
struct of_bus * bus , * pbus ;
u32 addr [ OF_MAX_ADDR_CELLS ] ;
int na , ns , pna , pns ;
u64 result = OF_BAD_ADDR ;
pr_debug ( " OF: ** translation for device %s ** \n " , dev - > full_name ) ;
/* Increase refcount at current level */
of_node_get ( dev ) ;
/* Get parent & match bus type */
parent = of_get_parent ( dev ) ;
if ( parent = = NULL )
goto bail ;
bus = of_match_bus ( parent ) ;
/* Cound address cells & copy address locally */
bus - > count_cells ( dev , & na , & ns ) ;
if ( ! OF_CHECK_COUNTS ( na , ns ) ) {
printk ( KERN_ERR " prom_parse: Bad cell count for %s \n " ,
dev - > full_name ) ;
goto bail ;
}
memcpy ( addr , in_addr , na * 4 ) ;
pr_debug ( " OF: bus is %s (na=%d, ns=%d) on %s \n " ,
bus - > name , na , ns , parent - > full_name ) ;
of_dump_addr ( " OF: translating address: " , addr , na ) ;
/* Translate */
for ( ; ; ) {
/* Switch to parent bus */
of_node_put ( dev ) ;
dev = parent ;
parent = of_get_parent ( dev ) ;
/* If root, we have finished */
if ( parent = = NULL ) {
pr_debug ( " OF: reached root node \n " ) ;
result = of_read_number ( addr , na ) ;
break ;
}
/* Get new parent bus and counts */
pbus = of_match_bus ( parent ) ;
pbus - > count_cells ( dev , & pna , & pns ) ;
if ( ! OF_CHECK_COUNTS ( pna , pns ) ) {
printk ( KERN_ERR " prom_parse: Bad cell count for %s \n " ,
dev - > full_name ) ;
break ;
}
pr_debug ( " OF: parent bus is %s (na=%d, ns=%d) on %s \n " ,
pbus - > name , pna , pns , parent - > full_name ) ;
/* Apply bus translation */
if ( of_translate_one ( dev , bus , pbus , addr , na , ns , pna , rprop ) )
break ;
/* Complete the move up one level */
na = pna ;
ns = pns ;
bus = pbus ;
of_dump_addr ( " OF: one level translation: " , addr , na ) ;
}
bail :
of_node_put ( parent ) ;
of_node_put ( dev ) ;
return result ;
}
2010-12-01 12:54:46 +03:00
u64 of_translate_address ( struct device_node * dev , const __be32 * in_addr )
2010-06-08 17:48:10 +04:00
{
return __of_translate_address ( dev , in_addr , " ranges " ) ;
}
EXPORT_SYMBOL ( of_translate_address ) ;
2010-12-01 12:54:46 +03:00
u64 of_translate_dma_address ( struct device_node * dev , const __be32 * in_addr )
2010-06-08 17:48:10 +04:00
{
return __of_translate_address ( dev , in_addr , " dma-ranges " ) ;
}
EXPORT_SYMBOL ( of_translate_dma_address ) ;
2010-12-01 12:54:46 +03:00
const __be32 * of_get_address ( struct device_node * dev , int index , u64 * size ,
2010-06-08 17:48:10 +04:00
unsigned int * flags )
{
2010-12-01 12:54:46 +03:00
const __be32 * prop ;
2010-06-08 17:48:10 +04:00
unsigned int psize ;
struct device_node * parent ;
struct of_bus * bus ;
int onesize , i , na , ns ;
/* Get parent & match bus type */
parent = of_get_parent ( dev ) ;
if ( parent = = NULL )
return NULL ;
bus = of_match_bus ( parent ) ;
bus - > count_cells ( dev , & na , & ns ) ;
of_node_put ( parent ) ;
if ( ! OF_CHECK_COUNTS ( na , ns ) )
return NULL ;
/* Get "reg" or "assigned-addresses" property */
prop = of_get_property ( dev , bus - > addresses , & psize ) ;
if ( prop = = NULL )
return NULL ;
psize / = 4 ;
onesize = na + ns ;
for ( i = 0 ; psize > = onesize ; psize - = onesize , prop + = onesize , i + + )
if ( i = = index ) {
if ( size )
* size = of_read_number ( prop + na , ns ) ;
if ( flags )
* flags = bus - > get_flags ( prop ) ;
return prop ;
}
return NULL ;
}
EXPORT_SYMBOL ( of_get_address ) ;
2010-12-01 12:54:46 +03:00
static int __of_address_to_resource ( struct device_node * dev ,
const __be32 * addrp , u64 size , unsigned int flags ,
2011-12-05 18:23:55 +04:00
const char * name , struct resource * r )
2010-06-08 17:48:09 +04:00
{
u64 taddr ;
if ( ( flags & ( IORESOURCE_IO | IORESOURCE_MEM ) ) = = 0 )
return - EINVAL ;
taddr = of_translate_address ( dev , addrp ) ;
if ( taddr = = OF_BAD_ADDR )
return - EINVAL ;
memset ( r , 0 , sizeof ( struct resource ) ) ;
if ( flags & IORESOURCE_IO ) {
unsigned long port ;
port = pci_address_to_pio ( taddr ) ;
if ( port = = ( unsigned long ) - 1 )
return - EINVAL ;
r - > start = port ;
r - > end = port + size - 1 ;
} else {
r - > start = taddr ;
r - > end = taddr + size - 1 ;
}
r - > flags = flags ;
2011-12-05 18:23:55 +04:00
r - > name = name ? name : dev - > full_name ;
2010-06-08 17:48:09 +04:00
return 0 ;
}
/**
* of_address_to_resource - Translate device tree address and return as resource
*
* Note that if your address is a PIO address , the conversion will fail if
* the physical address can ' t be internally converted to an IO token with
* pci_address_to_pio ( ) , that is because it ' s either called to early or it
* can ' t be matched to any host bridge IO space
*/
int of_address_to_resource ( struct device_node * dev , int index ,
struct resource * r )
{
2010-12-01 12:54:46 +03:00
const __be32 * addrp ;
2010-06-08 17:48:09 +04:00
u64 size ;
unsigned int flags ;
2011-12-05 18:23:55 +04:00
const char * name = NULL ;
2010-06-08 17:48:09 +04:00
addrp = of_get_address ( dev , index , & size , & flags ) ;
if ( addrp = = NULL )
return - EINVAL ;
2011-12-05 18:23:55 +04:00
/* Get optional "reg-names" property to add a name to a resource */
of_property_read_string_index ( dev , " reg-names " , index , & name ) ;
return __of_address_to_resource ( dev , addrp , size , flags , name , r ) ;
2010-06-08 17:48:09 +04:00
}
EXPORT_SYMBOL_GPL ( of_address_to_resource ) ;
2011-07-06 09:42:28 +04:00
struct device_node * of_find_matching_node_by_address ( struct device_node * from ,
const struct of_device_id * matches ,
u64 base_address )
{
struct device_node * dn = of_find_matching_node ( from , matches ) ;
struct resource res ;
while ( dn ) {
if ( of_address_to_resource ( dn , 0 , & res ) )
continue ;
if ( res . start = = base_address )
return dn ;
dn = of_find_matching_node ( dn , matches ) ;
}
return NULL ;
}
2010-06-08 17:48:09 +04:00
2010-06-08 17:48:09 +04:00
/**
* of_iomap - Maps the memory mapped IO for a given device_node
* @ device : the device whose io range will be mapped
* @ index : index of the io range
*
* Returns a pointer to the mapped memory
*/
void __iomem * of_iomap ( struct device_node * np , int index )
{
struct resource res ;
if ( of_address_to_resource ( np , index , & res ) )
return NULL ;
2011-07-22 23:47:21 +04:00
return ioremap ( res . start , resource_size ( & res ) ) ;
2010-06-08 17:48:09 +04:00
}
EXPORT_SYMBOL ( of_iomap ) ;