2017-12-27 21:55:14 +03:00
// SPDX-License-Identifier: GPL-2.0+
2010-10-11 07:42:33 +04:00
/* pdt.c: OF PROM device tree support code.
2010-08-30 07:57:28 +04:00
*
* Paul Mackerras August 1996.
* Copyright ( C ) 1996 - 2005 Paul Mackerras .
*
* Adapted for 64 bit PowerPC by Dave Engebretsen and Peter Bergner .
* { engebret | bergner } @ us . ibm . com
*
* Adapted for sparc by David S . Miller davem @ davemloft . net
2010-10-11 07:42:33 +04:00
* Adapted for multiple architectures by Andres Salomon < dilinger @ queued . net >
2010-08-30 07:57:28 +04:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/of.h>
2010-10-11 07:42:33 +04:00
# include <linux/of_pdt.h>
2010-10-11 07:49:45 +04:00
static struct of_pdt_ops * of_pdt_prom_ops __initdata ;
2010-08-30 07:57:28 +04:00
2010-10-11 07:42:33 +04:00
# if defined(CONFIG_SPARC)
unsigned int of_pdt_unique_id __initdata ;
# define of_pdt_incr_unique_id(p) do { \
( p ) - > unique_id = of_pdt_unique_id + + ; \
} while ( 0 )
2011-02-24 09:38:22 +03:00
static char * __init of_pdt_build_full_name ( struct device_node * dp )
2010-10-11 07:42:33 +04:00
{
2018-11-17 00:06:55 +03:00
return build_path_component ( dp ) ;
2010-10-11 07:42:33 +04:00
}
2011-02-24 09:38:22 +03:00
# else /* CONFIG_SPARC */
2010-10-11 07:42:33 +04:00
static inline void of_pdt_incr_unique_id ( void * p ) { }
static inline void irq_trans_init ( struct device_node * dp ) { }
2011-02-24 09:38:22 +03:00
static char * __init of_pdt_build_full_name ( struct device_node * dp )
2010-10-11 07:42:33 +04:00
{
2011-02-24 09:38:22 +03:00
static int failsafe_id = 0 ; /* for generating unique names on failure */
2018-11-17 00:06:55 +03:00
const char * name ;
char path [ 256 ] ;
2011-02-24 09:38:22 +03:00
char * buf ;
int len ;
2018-11-17 00:06:55 +03:00
if ( ! of_pdt_prom_ops - > pkg2path ( dp - > phandle , path , sizeof ( path ) , & len ) ) {
name = kbasename ( path ) ;
buf = prom_early_alloc ( strlen ( name ) + 1 ) ;
strcpy ( buf , name ) ;
return buf ;
}
2011-02-24 09:38:22 +03:00
2018-11-17 00:06:55 +03:00
name = of_get_property ( dp , " name " , & len ) ;
buf = prom_early_alloc ( len + 16 ) ;
sprintf ( buf , " %s@unknown%i " , name , failsafe_id + + ) ;
2011-02-24 09:38:22 +03:00
pr_err ( " %s: pkg2path failed; assigning %s \n " , __func__ , buf ) ;
return buf ;
2010-10-11 07:42:33 +04:00
}
# endif /* !CONFIG_SPARC */
2010-08-30 07:57:28 +04:00
2010-10-11 07:51:25 +04:00
static struct property * __init of_pdt_build_one_prop ( phandle node , char * prev ,
2010-08-30 07:57:28 +04:00
char * special_name ,
void * special_val ,
int special_len )
{
static struct property * tmp = NULL ;
struct property * p ;
2010-10-11 07:49:45 +04:00
int err ;
2010-08-30 07:57:28 +04:00
if ( tmp ) {
p = tmp ;
memset ( p , 0 , sizeof ( * p ) + 32 ) ;
tmp = NULL ;
} else {
p = prom_early_alloc ( sizeof ( struct property ) + 32 ) ;
2010-10-11 07:42:33 +04:00
of_pdt_incr_unique_id ( p ) ;
2010-08-30 07:57:28 +04:00
}
p - > name = ( char * ) ( p + 1 ) ;
if ( special_name ) {
strcpy ( p - > name , special_name ) ;
p - > length = special_len ;
p - > value = prom_early_alloc ( special_len ) ;
memcpy ( p - > value , special_val , special_len ) ;
} else {
2010-10-11 07:49:45 +04:00
err = of_pdt_prom_ops - > nextprop ( node , prev , p - > name ) ;
if ( err ) {
2010-08-30 07:57:28 +04:00
tmp = p ;
return NULL ;
}
2010-10-11 07:49:45 +04:00
p - > length = of_pdt_prom_ops - > getproplen ( node , p - > name ) ;
2010-08-30 07:57:28 +04:00
if ( p - > length < = 0 ) {
p - > length = 0 ;
} else {
int len ;
p - > value = prom_early_alloc ( p - > length + 1 ) ;
2010-10-11 07:49:45 +04:00
len = of_pdt_prom_ops - > getproperty ( node , p - > name ,
p - > value , p - > length ) ;
2010-08-30 07:57:28 +04:00
if ( len < = 0 )
p - > length = 0 ;
( ( unsigned char * ) p - > value ) [ p - > length ] = ' \0 ' ;
}
}
return p ;
}
2010-10-11 07:51:25 +04:00
static struct property * __init of_pdt_build_prop_list ( phandle node )
2010-08-30 07:57:28 +04:00
{
struct property * head , * tail ;
2010-10-11 07:51:25 +04:00
head = tail = of_pdt_build_one_prop ( node , NULL ,
2010-08-30 07:57:28 +04:00
" .node " , & node , sizeof ( node ) ) ;
2010-10-11 07:51:25 +04:00
tail - > next = of_pdt_build_one_prop ( node , NULL , NULL , NULL , 0 ) ;
2010-08-30 07:57:28 +04:00
tail = tail - > next ;
while ( tail ) {
2010-10-11 07:51:25 +04:00
tail - > next = of_pdt_build_one_prop ( node , tail - > name ,
2010-08-30 07:57:28 +04:00
NULL , NULL , 0 ) ;
tail = tail - > next ;
}
return head ;
}
2010-10-11 07:51:25 +04:00
static char * __init of_pdt_get_one_property ( phandle node , const char * name )
2010-08-30 07:57:28 +04:00
{
char * buf = " <NULL> " ;
int len ;
2010-10-11 07:49:45 +04:00
len = of_pdt_prom_ops - > getproplen ( node , name ) ;
2010-08-30 07:57:28 +04:00
if ( len > 0 ) {
buf = prom_early_alloc ( len ) ;
2010-10-11 07:49:45 +04:00
len = of_pdt_prom_ops - > getproperty ( node , name , buf , len ) ;
2010-08-30 07:57:28 +04:00
}
return buf ;
}
2010-10-11 07:51:25 +04:00
static struct device_node * __init of_pdt_create_node ( phandle node ,
2010-08-30 07:57:28 +04:00
struct device_node * parent )
{
struct device_node * dp ;
if ( ! node )
return NULL ;
dp = prom_early_alloc ( sizeof ( * dp ) ) ;
2013-12-13 22:08:59 +04:00
of_node_init ( dp ) ;
2010-10-11 07:42:33 +04:00
of_pdt_incr_unique_id ( dp ) ;
2010-08-30 07:57:28 +04:00
dp - > parent = parent ;
2011-02-24 09:38:22 +03:00
dp - > name = of_pdt_get_one_property ( node , " name " ) ;
2010-08-30 07:57:28 +04:00
dp - > phandle = node ;
2010-10-11 07:51:25 +04:00
dp - > properties = of_pdt_build_prop_list ( node ) ;
2010-08-30 07:57:28 +04:00
2018-11-17 00:06:55 +03:00
dp - > full_name = of_pdt_build_full_name ( dp ) ;
2010-08-30 07:57:28 +04:00
irq_trans_init ( dp ) ;
return dp ;
}
2010-10-11 07:51:25 +04:00
static struct device_node * __init of_pdt_build_tree ( struct device_node * parent ,
2014-10-03 19:28:27 +04:00
phandle node )
2010-08-30 07:57:28 +04:00
{
struct device_node * ret = NULL , * prev_sibling = NULL ;
struct device_node * dp ;
while ( 1 ) {
2010-10-11 07:51:25 +04:00
dp = of_pdt_create_node ( node , parent ) ;
2010-08-30 07:57:28 +04:00
if ( ! dp )
break ;
if ( prev_sibling )
prev_sibling - > sibling = dp ;
if ( ! ret )
ret = dp ;
prev_sibling = dp ;
2014-10-03 19:28:27 +04:00
dp - > child = of_pdt_build_tree ( dp , of_pdt_prom_ops - > getchild ( node ) ) ;
2010-08-30 07:57:28 +04:00
2010-10-11 07:49:45 +04:00
node = of_pdt_prom_ops - > getsibling ( node ) ;
2010-08-30 07:57:28 +04:00
}
return ret ;
}
2011-12-28 01:58:40 +04:00
static void * __init kernel_tree_alloc ( u64 size , u64 align )
2011-08-15 11:28:14 +04:00
{
return prom_early_alloc ( size ) ;
}
2010-10-11 07:49:45 +04:00
void __init of_pdt_build_devicetree ( phandle root_node , struct of_pdt_ops * ops )
2010-08-30 07:57:28 +04:00
{
2010-10-11 07:49:45 +04:00
BUG_ON ( ! ops ) ;
of_pdt_prom_ops = ops ;
2014-10-03 19:28:27 +04:00
of_root = of_pdt_create_node ( root_node , NULL ) ;
of_root - > full_name = " / " ;
2010-08-30 07:57:28 +04:00
2014-10-03 19:28:27 +04:00
of_root - > child = of_pdt_build_tree ( of_root ,
of_pdt_prom_ops - > getchild ( of_root - > phandle ) ) ;
2011-08-15 11:28:14 +04:00
2013-05-30 13:38:08 +04:00
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
2011-08-15 11:28:14 +04:00
of_alias_scan ( kernel_tree_alloc ) ;
2010-08-30 07:57:28 +04:00
}