1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2b00dc837SAdrian Bunk /*
31da177e4SLinus Torvalds * tree.c: Basic device tree traversal/scanning for the Linux
41da177e4SLinus Torvalds * prom library.
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
71da177e4SLinus Torvalds * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <linux/string.h>
111da177e4SLinus Torvalds #include <linux/types.h>
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/sched.h>
14917c3660SSam Ravnborg #include <linux/module.h>
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds #include <asm/openprom.h>
171da177e4SLinus Torvalds #include <asm/oplib.h>
18b3e13fbeSDavid S. Miller #include <asm/ldc.h>
191da177e4SLinus Torvalds
prom_node_to_node(const char * type,phandle node)208d125562SAndres Salomon static phandle prom_node_to_node(const char *type, phandle node)
2125edd694SDavid S. Miller {
2225edd694SDavid S. Miller unsigned long args[5];
2325edd694SDavid S. Miller
2425edd694SDavid S. Miller args[0] = (unsigned long) type;
2525edd694SDavid S. Miller args[1] = 1;
2625edd694SDavid S. Miller args[2] = 1;
2725edd694SDavid S. Miller args[3] = (unsigned int) node;
2825edd694SDavid S. Miller args[4] = (unsigned long) -1;
2925edd694SDavid S. Miller
3025edd694SDavid S. Miller p1275_cmd_direct(args);
3125edd694SDavid S. Miller
328d125562SAndres Salomon return (phandle) args[4];
3325edd694SDavid S. Miller }
3425edd694SDavid S. Miller
351da177e4SLinus Torvalds /* Return the child of node 'node' or zero if no this node has no
361da177e4SLinus Torvalds * direct descendent.
371da177e4SLinus Torvalds */
__prom_getchild(phandle node)388d125562SAndres Salomon inline phandle __prom_getchild(phandle node)
391da177e4SLinus Torvalds {
4025edd694SDavid S. Miller return prom_node_to_node("child", node);
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds
prom_getchild(phandle node)43dbebe0daSDenis Efremov phandle prom_getchild(phandle node)
441da177e4SLinus Torvalds {
458d125562SAndres Salomon phandle cnode;
461da177e4SLinus Torvalds
474a3a2552SAndres Salomon if ((s32)node == -1)
4825edd694SDavid S. Miller return 0;
491da177e4SLinus Torvalds cnode = __prom_getchild(node);
504a3a2552SAndres Salomon if ((s32)cnode == -1)
5125edd694SDavid S. Miller return 0;
5225edd694SDavid S. Miller return cnode;
531da177e4SLinus Torvalds }
54917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getchild);
551da177e4SLinus Torvalds
prom_getparent(phandle node)568d125562SAndres Salomon inline phandle prom_getparent(phandle node)
571da177e4SLinus Torvalds {
588d125562SAndres Salomon phandle cnode;
591da177e4SLinus Torvalds
604a3a2552SAndres Salomon if ((s32)node == -1)
6125edd694SDavid S. Miller return 0;
6225edd694SDavid S. Miller cnode = prom_node_to_node("parent", node);
634a3a2552SAndres Salomon if ((s32)cnode == -1)
6425edd694SDavid S. Miller return 0;
6525edd694SDavid S. Miller return cnode;
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds /* Return the next sibling of node 'node' or zero if no more siblings
691da177e4SLinus Torvalds * at this level of depth in the tree.
701da177e4SLinus Torvalds */
__prom_getsibling(phandle node)718d125562SAndres Salomon inline phandle __prom_getsibling(phandle node)
721da177e4SLinus Torvalds {
7325edd694SDavid S. Miller return prom_node_to_node(prom_peer_name, node);
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds
prom_getsibling(phandle node)76dbebe0daSDenis Efremov phandle prom_getsibling(phandle node)
771da177e4SLinus Torvalds {
788d125562SAndres Salomon phandle sibnode;
791da177e4SLinus Torvalds
804a3a2552SAndres Salomon if ((s32)node == -1)
81d82ace7dSDavid S. Miller return 0;
821da177e4SLinus Torvalds sibnode = __prom_getsibling(node);
834a3a2552SAndres Salomon if ((s32)sibnode == -1)
84d82ace7dSDavid S. Miller return 0;
85d82ace7dSDavid S. Miller
861da177e4SLinus Torvalds return sibnode;
871da177e4SLinus Torvalds }
88917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getsibling);
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds /* Return the length in bytes of property 'prop' at node 'node'.
911da177e4SLinus Torvalds * Return -1 on error.
921da177e4SLinus Torvalds */
prom_getproplen(phandle node,const char * prop)93dbebe0daSDenis Efremov int prom_getproplen(phandle node, const char *prop)
941da177e4SLinus Torvalds {
9525edd694SDavid S. Miller unsigned long args[6];
9625edd694SDavid S. Miller
9725edd694SDavid S. Miller if (!node || !prop)
9825edd694SDavid S. Miller return -1;
9925edd694SDavid S. Miller
10025edd694SDavid S. Miller args[0] = (unsigned long) "getproplen";
10125edd694SDavid S. Miller args[1] = 2;
10225edd694SDavid S. Miller args[2] = 1;
10325edd694SDavid S. Miller args[3] = (unsigned int) node;
10425edd694SDavid S. Miller args[4] = (unsigned long) prop;
10525edd694SDavid S. Miller args[5] = (unsigned long) -1;
10625edd694SDavid S. Miller
10725edd694SDavid S. Miller p1275_cmd_direct(args);
10825edd694SDavid S. Miller
10925edd694SDavid S. Miller return (int) args[5];
1101da177e4SLinus Torvalds }
111917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproplen);
1121da177e4SLinus Torvalds
1131da177e4SLinus Torvalds /* Acquire a property 'prop' at node 'node' and place it in
1141da177e4SLinus Torvalds * 'buffer' which has a size of 'bufsize'. If the acquisition
1151da177e4SLinus Torvalds * was successful the length will be returned, else -1 is returned.
1161da177e4SLinus Torvalds */
prom_getproperty(phandle node,const char * prop,char * buffer,int bufsize)117dbebe0daSDenis Efremov int prom_getproperty(phandle node, const char *prop,
118d979f179SDavid S. Miller char *buffer, int bufsize)
1191da177e4SLinus Torvalds {
12025edd694SDavid S. Miller unsigned long args[8];
1211da177e4SLinus Torvalds int plen;
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds plen = prom_getproplen(node, prop);
12425edd694SDavid S. Miller if ((plen > bufsize) || (plen == 0) || (plen == -1))
1251da177e4SLinus Torvalds return -1;
12625edd694SDavid S. Miller
12725edd694SDavid S. Miller args[0] = (unsigned long) prom_getprop_name;
12825edd694SDavid S. Miller args[1] = 4;
12925edd694SDavid S. Miller args[2] = 1;
13025edd694SDavid S. Miller args[3] = (unsigned int) node;
13125edd694SDavid S. Miller args[4] = (unsigned long) prop;
13225edd694SDavid S. Miller args[5] = (unsigned long) buffer;
13325edd694SDavid S. Miller args[6] = bufsize;
13425edd694SDavid S. Miller args[7] = (unsigned long) -1;
13525edd694SDavid S. Miller
13625edd694SDavid S. Miller p1275_cmd_direct(args);
13725edd694SDavid S. Miller
13825edd694SDavid S. Miller return (int) args[7];
1391da177e4SLinus Torvalds }
140917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproperty);
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds /* Acquire an integer property and return its value. Returns -1
1431da177e4SLinus Torvalds * on failure.
1441da177e4SLinus Torvalds */
prom_getint(phandle node,const char * prop)145dbebe0daSDenis Efremov int prom_getint(phandle node, const char *prop)
1461da177e4SLinus Torvalds {
1471da177e4SLinus Torvalds int intprop;
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
1501da177e4SLinus Torvalds return intprop;
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds return -1;
1531da177e4SLinus Torvalds }
154917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getint);
1551da177e4SLinus Torvalds
1561da177e4SLinus Torvalds /* Acquire an integer property, upon error return the passed default
1571da177e4SLinus Torvalds * integer.
1581da177e4SLinus Torvalds */
1591da177e4SLinus Torvalds
prom_getintdefault(phandle node,const char * property,int deflt)1608d125562SAndres Salomon int prom_getintdefault(phandle node, const char *property, int deflt)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds int retval;
1631da177e4SLinus Torvalds
1641da177e4SLinus Torvalds retval = prom_getint(node, property);
16525edd694SDavid S. Miller if (retval == -1)
16625edd694SDavid S. Miller return deflt;
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds return retval;
1691da177e4SLinus Torvalds }
170917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getintdefault);
1711da177e4SLinus Torvalds
1721da177e4SLinus Torvalds /* Acquire a boolean property, 1=TRUE 0=FALSE. */
prom_getbool(phandle node,const char * prop)1738d125562SAndres Salomon int prom_getbool(phandle node, const char *prop)
1741da177e4SLinus Torvalds {
1751da177e4SLinus Torvalds int retval;
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds retval = prom_getproplen(node, prop);
17825edd694SDavid S. Miller if (retval == -1)
17925edd694SDavid S. Miller return 0;
1801da177e4SLinus Torvalds return 1;
1811da177e4SLinus Torvalds }
182917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getbool);
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds /* Acquire a property whose value is a string, returns a null
1851da177e4SLinus Torvalds * string on error. The char pointer is the user supplied string
1861da177e4SLinus Torvalds * buffer.
1871da177e4SLinus Torvalds */
prom_getstring(phandle node,const char * prop,char * user_buf,int ubuf_size)1888d125562SAndres Salomon void prom_getstring(phandle node, const char *prop, char *user_buf,
1898d125562SAndres Salomon int ubuf_size)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds int len;
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds len = prom_getproperty(node, prop, user_buf, ubuf_size);
19425edd694SDavid S. Miller if (len != -1)
19525edd694SDavid S. Miller return;
1961da177e4SLinus Torvalds user_buf[0] = 0;
1971da177e4SLinus Torvalds }
198917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getstring);
1991da177e4SLinus Torvalds
2001da177e4SLinus Torvalds /* Does the device at node 'node' have name 'name'?
2011da177e4SLinus Torvalds * YES = 1 NO = 0
2021da177e4SLinus Torvalds */
prom_nodematch(phandle node,const char * name)2038d125562SAndres Salomon int prom_nodematch(phandle node, const char *name)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds char namebuf[128];
2061da177e4SLinus Torvalds prom_getproperty(node, "name", namebuf, sizeof(namebuf));
20725edd694SDavid S. Miller if (strcmp(namebuf, name) == 0)
20825edd694SDavid S. Miller return 1;
2091da177e4SLinus Torvalds return 0;
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds /* Search siblings at 'node_start' for a node with name
2131da177e4SLinus Torvalds * 'nodename'. Return node if successful, zero if not.
2141da177e4SLinus Torvalds */
prom_searchsiblings(phandle node_start,const char * nodename)2158d125562SAndres Salomon phandle prom_searchsiblings(phandle node_start, const char *nodename)
2161da177e4SLinus Torvalds {
2178d125562SAndres Salomon phandle thisnode;
2188d125562SAndres Salomon int error;
2191da177e4SLinus Torvalds char promlib_buf[128];
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds for(thisnode = node_start; thisnode;
2221da177e4SLinus Torvalds thisnode=prom_getsibling(thisnode)) {
2231da177e4SLinus Torvalds error = prom_getproperty(thisnode, "name", promlib_buf,
2241da177e4SLinus Torvalds sizeof(promlib_buf));
2251da177e4SLinus Torvalds /* Should this ever happen? */
2261da177e4SLinus Torvalds if(error == -1) continue;
2271da177e4SLinus Torvalds if(strcmp(nodename, promlib_buf)==0) return thisnode;
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds
2301da177e4SLinus Torvalds return 0;
2311da177e4SLinus Torvalds }
232917c3660SSam Ravnborg EXPORT_SYMBOL(prom_searchsiblings);
2331da177e4SLinus Torvalds
23425edd694SDavid S. Miller static const char *prom_nextprop_name = "nextprop";
23525edd694SDavid S. Miller
2361da177e4SLinus Torvalds /* Return the first property type for node 'node'.
2371da177e4SLinus Torvalds * buffer should be at least 32B in length
2381da177e4SLinus Torvalds */
prom_firstprop(phandle node,char * buffer)239dbebe0daSDenis Efremov char *prom_firstprop(phandle node, char *buffer)
2401da177e4SLinus Torvalds {
24125edd694SDavid S. Miller unsigned long args[7];
24225edd694SDavid S. Miller
2431da177e4SLinus Torvalds *buffer = 0;
2444a3a2552SAndres Salomon if ((s32)node == -1)
24525edd694SDavid S. Miller return buffer;
24625edd694SDavid S. Miller
24725edd694SDavid S. Miller args[0] = (unsigned long) prom_nextprop_name;
24825edd694SDavid S. Miller args[1] = 3;
24925edd694SDavid S. Miller args[2] = 1;
25025edd694SDavid S. Miller args[3] = (unsigned int) node;
25125edd694SDavid S. Miller args[4] = 0;
25225edd694SDavid S. Miller args[5] = (unsigned long) buffer;
25325edd694SDavid S. Miller args[6] = (unsigned long) -1;
25425edd694SDavid S. Miller
25525edd694SDavid S. Miller p1275_cmd_direct(args);
25625edd694SDavid S. Miller
2571da177e4SLinus Torvalds return buffer;
2581da177e4SLinus Torvalds }
259917c3660SSam Ravnborg EXPORT_SYMBOL(prom_firstprop);
2601da177e4SLinus Torvalds
2611da177e4SLinus Torvalds /* Return the property type string after property type 'oprop'
2621da177e4SLinus Torvalds * at node 'node' . Returns NULL string if no more
2631da177e4SLinus Torvalds * property types for this node.
2641da177e4SLinus Torvalds */
prom_nextprop(phandle node,const char * oprop,char * buffer)265dbebe0daSDenis Efremov char *prom_nextprop(phandle node, const char *oprop, char *buffer)
2661da177e4SLinus Torvalds {
26725edd694SDavid S. Miller unsigned long args[7];
2681da177e4SLinus Torvalds char buf[32];
2691da177e4SLinus Torvalds
2704a3a2552SAndres Salomon if ((s32)node == -1) {
2711da177e4SLinus Torvalds *buffer = 0;
2721da177e4SLinus Torvalds return buffer;
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds if (oprop == buffer) {
2751da177e4SLinus Torvalds strscpy(buf, oprop);
2761da177e4SLinus Torvalds oprop = buf;
2771da177e4SLinus Torvalds }
27825edd694SDavid S. Miller
27925edd694SDavid S. Miller args[0] = (unsigned long) prom_nextprop_name;
28025edd694SDavid S. Miller args[1] = 3;
28125edd694SDavid S. Miller args[2] = 1;
28225edd694SDavid S. Miller args[3] = (unsigned int) node;
28325edd694SDavid S. Miller args[4] = (unsigned long) oprop;
28425edd694SDavid S. Miller args[5] = (unsigned long) buffer;
28525edd694SDavid S. Miller args[6] = (unsigned long) -1;
28625edd694SDavid S. Miller
28725edd694SDavid S. Miller p1275_cmd_direct(args);
28825edd694SDavid S. Miller
2891da177e4SLinus Torvalds return buffer;
2901da177e4SLinus Torvalds }
291917c3660SSam Ravnborg EXPORT_SYMBOL(prom_nextprop);
2921da177e4SLinus Torvalds
prom_finddevice(const char * name)2938d125562SAndres Salomon phandle prom_finddevice(const char *name)
2941da177e4SLinus Torvalds {
29525edd694SDavid S. Miller unsigned long args[5];
29625edd694SDavid S. Miller
297bff06d55SDavid S. Miller if (!name)
298bff06d55SDavid S. Miller return 0;
29925edd694SDavid S. Miller args[0] = (unsigned long) "finddevice";
30025edd694SDavid S. Miller args[1] = 1;
30125edd694SDavid S. Miller args[2] = 1;
30225edd694SDavid S. Miller args[3] = (unsigned long) name;
30325edd694SDavid S. Miller args[4] = (unsigned long) -1;
30425edd694SDavid S. Miller
30525edd694SDavid S. Miller p1275_cmd_direct(args);
30625edd694SDavid S. Miller
30725edd694SDavid S. Miller return (int) args[4];
3081da177e4SLinus Torvalds }
309917c3660SSam Ravnborg EXPORT_SYMBOL(prom_finddevice);
3101da177e4SLinus Torvalds
prom_node_has_property(phandle node,const char * prop)3118d125562SAndres Salomon int prom_node_has_property(phandle node, const char *prop)
3121da177e4SLinus Torvalds {
3131da177e4SLinus Torvalds char buf [32];
3141da177e4SLinus Torvalds
3151da177e4SLinus Torvalds *buf = 0;
3161da177e4SLinus Torvalds do {
3171da177e4SLinus Torvalds prom_nextprop(node, buf, buf);
3181da177e4SLinus Torvalds if (!strcmp(buf, prop))
3191da177e4SLinus Torvalds return 1;
3201da177e4SLinus Torvalds } while (*buf);
3211da177e4SLinus Torvalds return 0;
3221da177e4SLinus Torvalds }
323917c3660SSam Ravnborg EXPORT_SYMBOL(prom_node_has_property);
3241da177e4SLinus Torvalds
3251da177e4SLinus Torvalds /* Set property 'pname' at node 'node' to value 'value' which has a length
3261da177e4SLinus Torvalds * of 'size' bytes. Return the number of bytes the prom accepted.
3271da177e4SLinus Torvalds */
3281da177e4SLinus Torvalds int
prom_setprop(phandle node,const char * pname,char * value,int size)3298d125562SAndres Salomon prom_setprop(phandle node, const char *pname, char *value, int size)
3301da177e4SLinus Torvalds {
33125edd694SDavid S. Miller unsigned long args[8];
33225edd694SDavid S. Miller
333b3e13fbeSDavid S. Miller if (size == 0)
334b3e13fbeSDavid S. Miller return 0;
335b3e13fbeSDavid S. Miller if ((pname == NULL) || (value == NULL))
336b3e13fbeSDavid S. Miller return 0;
3371da177e4SLinus Torvalds
338b3e13fbeSDavid S. Miller #ifdef CONFIG_SUN_LDOMS
339b3e13fbeSDavid S. Miller if (ldom_domaining_enabled) {
340b3e13fbeSDavid S. Miller ldom_set_var(pname, value);
341b3e13fbeSDavid S. Miller return 0;
342b3e13fbeSDavid S. Miller }
343b3e13fbeSDavid S. Miller #endif
34425edd694SDavid S. Miller args[0] = (unsigned long) "setprop";
34525edd694SDavid S. Miller args[1] = 4;
34625edd694SDavid S. Miller args[2] = 1;
34725edd694SDavid S. Miller args[3] = (unsigned int) node;
34825edd694SDavid S. Miller args[4] = (unsigned long) pname;
34925edd694SDavid S. Miller args[5] = (unsigned long) value;
35025edd694SDavid S. Miller args[6] = size;
35125edd694SDavid S. Miller args[7] = (unsigned long) -1;
35225edd694SDavid S. Miller
35325edd694SDavid S. Miller p1275_cmd_direct(args);
35425edd694SDavid S. Miller
35525edd694SDavid S. Miller return (int) args[7];
3561da177e4SLinus Torvalds }
357917c3660SSam Ravnborg EXPORT_SYMBOL(prom_setprop);
3581da177e4SLinus Torvalds
prom_inst2pkg(int inst)3598d125562SAndres Salomon inline phandle prom_inst2pkg(int inst)
3601da177e4SLinus Torvalds {
36125edd694SDavid S. Miller unsigned long args[5];
3628d125562SAndres Salomon phandle node;
3631da177e4SLinus Torvalds
36425edd694SDavid S. Miller args[0] = (unsigned long) "instance-to-package";
36525edd694SDavid S. Miller args[1] = 1;
36625edd694SDavid S. Miller args[2] = 1;
36725edd694SDavid S. Miller args[3] = (unsigned int) inst;
36825edd694SDavid S. Miller args[4] = (unsigned long) -1;
36925edd694SDavid S. Miller
37025edd694SDavid S. Miller p1275_cmd_direct(args);
37125edd694SDavid S. Miller
37225edd694SDavid S. Miller node = (int) args[4];
3734a3a2552SAndres Salomon if ((s32)node == -1)
37425edd694SDavid S. Miller return 0;
3751da177e4SLinus Torvalds return node;
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds
prom_ihandle2path(int handle,char * buffer,int bufsize)378c73fcc84SDavid S. Miller int prom_ihandle2path(int handle, char *buffer, int bufsize)
379c73fcc84SDavid S. Miller {
38025edd694SDavid S. Miller unsigned long args[7];
38125edd694SDavid S. Miller
38225edd694SDavid S. Miller args[0] = (unsigned long) "instance-to-path";
38325edd694SDavid S. Miller args[1] = 3;
38425edd694SDavid S. Miller args[2] = 1;
38525edd694SDavid S. Miller args[3] = (unsigned int) handle;
38625edd694SDavid S. Miller args[4] = (unsigned long) buffer;
38725edd694SDavid S. Miller args[5] = bufsize;
38825edd694SDavid S. Miller args[6] = (unsigned long) -1;
38925edd694SDavid S. Miller
39025edd694SDavid S. Miller p1275_cmd_direct(args);
39125edd694SDavid S. Miller
39225edd694SDavid S. Miller return (int) args[6];
393c73fcc84SDavid S. Miller }
394