@ -964,10 +964,21 @@ static void of_dump_addr(const char *s, const fdt32_t *addr, int na)
static void of_dump_addr ( const char * s , const fdt32_t * addr , int na ) { }
# endif
/* Callbacks for bus specific translators */
/**
* struct of_bus - Callbacks for bus specific translators
* @ match : Return non - zero if the node whose parent is at
* parentoffset in the FDT blob corresponds to a bus
* of this type , otherwise return zero . If NULL a match
* is assumed .
*
* Each bus type will include a struct of_bus in the of_busses array ,
* providing implementations of some or all of the functions used to
* match the bus & handle address translation for its children .
*/
struct of_bus {
const char * name ;
const char * addresses ;
int ( * match ) ( void * blob , int parentoffset ) ;
void ( * count_cells ) ( void * blob , int parentoffset ,
int * addrc , int * sizec ) ;
u64 ( * map ) ( fdt32_t * addr , const fdt32_t * range ,
@ -1022,8 +1033,70 @@ static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na)
return 0 ;
}
# ifdef CONFIG_OF_ISA_BUS
/* ISA bus translator */
static int of_bus_isa_match ( void * blob , int parentoffset )
{
const char * name ;
name = fdt_get_name ( blob , parentoffset , NULL ) ;
if ( ! name )
return 0 ;
return ! strcmp ( name , " isa " ) ;
}
static void of_bus_isa_count_cells ( void * blob , int parentoffset ,
int * addrc , int * sizec )
{
if ( addrc )
* addrc = 2 ;
if ( sizec )
* sizec = 1 ;
}
static u64 of_bus_isa_map ( fdt32_t * addr , const fdt32_t * range ,
int na , int ns , int pna )
{
u64 cp , s , da ;
/* Check address type match */
if ( ( addr [ 0 ] ^ range [ 0 ] ) & cpu_to_be32 ( 1 ) )
return OF_BAD_ADDR ;
cp = of_read_number ( range + 1 , na - 1 ) ;
s = of_read_number ( range + na + pna , ns ) ;
da = of_read_number ( addr + 1 , na - 1 ) ;
debug ( " OF: ISA map, cp=% " PRIu64 " , s=% " PRIu64
" , da=% " PRIu64 " \n " , cp , s , da ) ;
if ( da < cp | | da > = ( cp + s ) )
return OF_BAD_ADDR ;
return da - cp ;
}
static int of_bus_isa_translate ( fdt32_t * addr , u64 offset , int na )
{
return of_bus_default_translate ( addr + 1 , offset , na - 1 ) ;
}
# endif /* CONFIG_OF_ISA_BUS */
/* Array of bus specific translators */
static struct of_bus of_busses [ ] = {
# ifdef CONFIG_OF_ISA_BUS
/* 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 ,
} ,
# endif /* CONFIG_OF_ISA_BUS */
/* Default */
{
. name = " default " ,
@ -1034,6 +1107,28 @@ static struct of_bus of_busses[] = {
} ,
} ;
static struct of_bus * of_match_bus ( void * blob , int parentoffset )
{
struct of_bus * bus ;
if ( ARRAY_SIZE ( of_busses ) = = 1 )
return of_busses ;
for ( bus = of_busses ; bus ; bus + + ) {
if ( ! bus - > match | | bus - > match ( blob , parentoffset ) )
return bus ;
}
/*
* We should always have matched the default bus at least , since
* it has a NULL match field . If we didn ' t then it somehow isn ' t
* in the of_busses array or something equally catastrophic has
* gone wrong .
*/
assert ( 0 ) ;
return NULL ;
}
static int of_translate_one ( void * blob , int parent , struct of_bus * bus ,
struct of_bus * pbus , fdt32_t * addr ,
int na , int ns , int pna , const char * rprop )
@ -1113,7 +1208,7 @@ static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in
parent = fdt_parent_offset ( blob , node_offset ) ;
if ( parent < 0 )
goto bail ;
bus = & of_busses [ 0 ] ;
bus = of_match_bus ( blob , parent ) ;
/* Cound address cells & copy address locally */
bus - > count_cells ( blob , parent , & na , & ns ) ;
@ -1142,7 +1237,7 @@ static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in
}
/* Get new parent bus and counts */
pbus = & of_busses [ 0 ] ;
pbus = of_match_bus ( blob , parent ) ;
pbus - > count_cells ( blob , parent , & pna , & pns ) ;
if ( ! OF_CHECK_COUNTS ( pna , pns ) ) {
printf ( " %s: Bad cell count for %s \n " , __FUNCTION__ ,