xref: /openbmc/linux/arch/sparc/prom/tree_64.c (revision 917c3660d6d9a4b073a3db7c10f6989adae4e191)
15de18cdeSSam Ravnborg /*
25de18cdeSSam Ravnborg  * tree.c: Basic device tree traversal/scanning for the Linux
35de18cdeSSam Ravnborg  *         prom library.
45de18cdeSSam Ravnborg  *
55de18cdeSSam Ravnborg  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
65de18cdeSSam Ravnborg  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
75de18cdeSSam Ravnborg  */
85de18cdeSSam Ravnborg 
95de18cdeSSam Ravnborg #include <linux/string.h>
105de18cdeSSam Ravnborg #include <linux/types.h>
115de18cdeSSam Ravnborg #include <linux/kernel.h>
125de18cdeSSam Ravnborg #include <linux/sched.h>
13*917c3660SSam Ravnborg #include <linux/module.h>
145de18cdeSSam Ravnborg 
155de18cdeSSam Ravnborg #include <asm/openprom.h>
165de18cdeSSam Ravnborg #include <asm/oplib.h>
175de18cdeSSam Ravnborg #include <asm/ldc.h>
185de18cdeSSam Ravnborg 
195de18cdeSSam Ravnborg /* Return the child of node 'node' or zero if no this node has no
205de18cdeSSam Ravnborg  * direct descendent.
215de18cdeSSam Ravnborg  */
225de18cdeSSam Ravnborg inline int __prom_getchild(int node)
235de18cdeSSam Ravnborg {
245de18cdeSSam Ravnborg 	return p1275_cmd ("child", P1275_INOUT(1, 1), node);
255de18cdeSSam Ravnborg }
26*917c3660SSam Ravnborg EXPORT_SYMBOL(__prom_getchild);
275de18cdeSSam Ravnborg 
285de18cdeSSam Ravnborg inline int prom_getchild(int node)
295de18cdeSSam Ravnborg {
305de18cdeSSam Ravnborg 	int cnode;
315de18cdeSSam Ravnborg 
325de18cdeSSam Ravnborg 	if(node == -1) return 0;
335de18cdeSSam Ravnborg 	cnode = __prom_getchild(node);
345de18cdeSSam Ravnborg 	if(cnode == -1) return 0;
355de18cdeSSam Ravnborg 	return (int)cnode;
365de18cdeSSam Ravnborg }
37*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getchild);
385de18cdeSSam Ravnborg 
395de18cdeSSam Ravnborg inline int prom_getparent(int node)
405de18cdeSSam Ravnborg {
415de18cdeSSam Ravnborg 	int cnode;
425de18cdeSSam Ravnborg 
435de18cdeSSam Ravnborg 	if(node == -1) return 0;
445de18cdeSSam Ravnborg 	cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
455de18cdeSSam Ravnborg 	if(cnode == -1) return 0;
465de18cdeSSam Ravnborg 	return (int)cnode;
475de18cdeSSam Ravnborg }
485de18cdeSSam Ravnborg 
495de18cdeSSam Ravnborg /* Return the next sibling of node 'node' or zero if no more siblings
505de18cdeSSam Ravnborg  * at this level of depth in the tree.
515de18cdeSSam Ravnborg  */
525de18cdeSSam Ravnborg inline int __prom_getsibling(int node)
535de18cdeSSam Ravnborg {
545de18cdeSSam Ravnborg 	return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node);
555de18cdeSSam Ravnborg }
56*917c3660SSam Ravnborg EXPORT_SYMBOL(__prom_getsibling);
575de18cdeSSam Ravnborg 
585de18cdeSSam Ravnborg inline int prom_getsibling(int node)
595de18cdeSSam Ravnborg {
605de18cdeSSam Ravnborg 	int sibnode;
615de18cdeSSam Ravnborg 
625de18cdeSSam Ravnborg 	if (node == -1)
635de18cdeSSam Ravnborg 		return 0;
645de18cdeSSam Ravnborg 	sibnode = __prom_getsibling(node);
655de18cdeSSam Ravnborg 	if (sibnode == -1)
665de18cdeSSam Ravnborg 		return 0;
675de18cdeSSam Ravnborg 
685de18cdeSSam Ravnborg 	return sibnode;
695de18cdeSSam Ravnborg }
70*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getsibling);
715de18cdeSSam Ravnborg 
725de18cdeSSam Ravnborg /* Return the length in bytes of property 'prop' at node 'node'.
735de18cdeSSam Ravnborg  * Return -1 on error.
745de18cdeSSam Ravnborg  */
755de18cdeSSam Ravnborg inline int prom_getproplen(int node, const char *prop)
765de18cdeSSam Ravnborg {
775de18cdeSSam Ravnborg 	if((!node) || (!prop)) return -1;
785de18cdeSSam Ravnborg 	return p1275_cmd ("getproplen",
795de18cdeSSam Ravnborg 			  P1275_ARG(1,P1275_ARG_IN_STRING)|
805de18cdeSSam Ravnborg 			  P1275_INOUT(2, 1),
815de18cdeSSam Ravnborg 			  node, prop);
825de18cdeSSam Ravnborg }
83*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproplen);
845de18cdeSSam Ravnborg 
855de18cdeSSam Ravnborg /* Acquire a property 'prop' at node 'node' and place it in
865de18cdeSSam Ravnborg  * 'buffer' which has a size of 'bufsize'.  If the acquisition
875de18cdeSSam Ravnborg  * was successful the length will be returned, else -1 is returned.
885de18cdeSSam Ravnborg  */
895de18cdeSSam Ravnborg inline int prom_getproperty(int node, const char *prop,
905de18cdeSSam Ravnborg 			    char *buffer, int bufsize)
915de18cdeSSam Ravnborg {
925de18cdeSSam Ravnborg 	int plen;
935de18cdeSSam Ravnborg 
945de18cdeSSam Ravnborg 	plen = prom_getproplen(node, prop);
955de18cdeSSam Ravnborg 	if ((plen > bufsize) || (plen == 0) || (plen == -1)) {
965de18cdeSSam Ravnborg 		return -1;
975de18cdeSSam Ravnborg 	} else {
985de18cdeSSam Ravnborg 		/* Ok, things seem all right. */
995de18cdeSSam Ravnborg 		return p1275_cmd(prom_getprop_name,
1005de18cdeSSam Ravnborg 				 P1275_ARG(1,P1275_ARG_IN_STRING)|
1015de18cdeSSam Ravnborg 				 P1275_ARG(2,P1275_ARG_OUT_BUF)|
1025de18cdeSSam Ravnborg 				 P1275_INOUT(4, 1),
1035de18cdeSSam Ravnborg 				 node, prop, buffer, P1275_SIZE(plen));
1045de18cdeSSam Ravnborg 	}
1055de18cdeSSam Ravnborg }
106*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproperty);
1075de18cdeSSam Ravnborg 
1085de18cdeSSam Ravnborg /* Acquire an integer property and return its value.  Returns -1
1095de18cdeSSam Ravnborg  * on failure.
1105de18cdeSSam Ravnborg  */
1115de18cdeSSam Ravnborg inline int prom_getint(int node, const char *prop)
1125de18cdeSSam Ravnborg {
1135de18cdeSSam Ravnborg 	int intprop;
1145de18cdeSSam Ravnborg 
1155de18cdeSSam Ravnborg 	if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
1165de18cdeSSam Ravnborg 		return intprop;
1175de18cdeSSam Ravnborg 
1185de18cdeSSam Ravnborg 	return -1;
1195de18cdeSSam Ravnborg }
120*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getint);
1215de18cdeSSam Ravnborg 
1225de18cdeSSam Ravnborg /* Acquire an integer property, upon error return the passed default
1235de18cdeSSam Ravnborg  * integer.
1245de18cdeSSam Ravnborg  */
1255de18cdeSSam Ravnborg 
1265de18cdeSSam Ravnborg int prom_getintdefault(int node, const char *property, int deflt)
1275de18cdeSSam Ravnborg {
1285de18cdeSSam Ravnborg 	int retval;
1295de18cdeSSam Ravnborg 
1305de18cdeSSam Ravnborg 	retval = prom_getint(node, property);
1315de18cdeSSam Ravnborg 	if(retval == -1) return deflt;
1325de18cdeSSam Ravnborg 
1335de18cdeSSam Ravnborg 	return retval;
1345de18cdeSSam Ravnborg }
135*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getintdefault);
1365de18cdeSSam Ravnborg 
1375de18cdeSSam Ravnborg /* Acquire a boolean property, 1=TRUE 0=FALSE. */
1385de18cdeSSam Ravnborg int prom_getbool(int node, const char *prop)
1395de18cdeSSam Ravnborg {
1405de18cdeSSam Ravnborg 	int retval;
1415de18cdeSSam Ravnborg 
1425de18cdeSSam Ravnborg 	retval = prom_getproplen(node, prop);
1435de18cdeSSam Ravnborg 	if(retval == -1) return 0;
1445de18cdeSSam Ravnborg 	return 1;
1455de18cdeSSam Ravnborg }
146*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getbool);
1475de18cdeSSam Ravnborg 
1485de18cdeSSam Ravnborg /* Acquire a property whose value is a string, returns a null
1495de18cdeSSam Ravnborg  * string on error.  The char pointer is the user supplied string
1505de18cdeSSam Ravnborg  * buffer.
1515de18cdeSSam Ravnborg  */
1525de18cdeSSam Ravnborg void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
1535de18cdeSSam Ravnborg {
1545de18cdeSSam Ravnborg 	int len;
1555de18cdeSSam Ravnborg 
1565de18cdeSSam Ravnborg 	len = prom_getproperty(node, prop, user_buf, ubuf_size);
1575de18cdeSSam Ravnborg 	if(len != -1) return;
1585de18cdeSSam Ravnborg 	user_buf[0] = 0;
1595de18cdeSSam Ravnborg 	return;
1605de18cdeSSam Ravnborg }
161*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getstring);
1625de18cdeSSam Ravnborg 
1635de18cdeSSam Ravnborg /* Does the device at node 'node' have name 'name'?
1645de18cdeSSam Ravnborg  * YES = 1   NO = 0
1655de18cdeSSam Ravnborg  */
1665de18cdeSSam Ravnborg int prom_nodematch(int node, const char *name)
1675de18cdeSSam Ravnborg {
1685de18cdeSSam Ravnborg 	char namebuf[128];
1695de18cdeSSam Ravnborg 	prom_getproperty(node, "name", namebuf, sizeof(namebuf));
1705de18cdeSSam Ravnborg 	if(strcmp(namebuf, name) == 0) return 1;
1715de18cdeSSam Ravnborg 	return 0;
1725de18cdeSSam Ravnborg }
1735de18cdeSSam Ravnborg 
1745de18cdeSSam Ravnborg /* Search siblings at 'node_start' for a node with name
1755de18cdeSSam Ravnborg  * 'nodename'.  Return node if successful, zero if not.
1765de18cdeSSam Ravnborg  */
1775de18cdeSSam Ravnborg int prom_searchsiblings(int node_start, const char *nodename)
1785de18cdeSSam Ravnborg {
1795de18cdeSSam Ravnborg 
1805de18cdeSSam Ravnborg 	int thisnode, error;
1815de18cdeSSam Ravnborg 	char promlib_buf[128];
1825de18cdeSSam Ravnborg 
1835de18cdeSSam Ravnborg 	for(thisnode = node_start; thisnode;
1845de18cdeSSam Ravnborg 	    thisnode=prom_getsibling(thisnode)) {
1855de18cdeSSam Ravnborg 		error = prom_getproperty(thisnode, "name", promlib_buf,
1865de18cdeSSam Ravnborg 					 sizeof(promlib_buf));
1875de18cdeSSam Ravnborg 		/* Should this ever happen? */
1885de18cdeSSam Ravnborg 		if(error == -1) continue;
1895de18cdeSSam Ravnborg 		if(strcmp(nodename, promlib_buf)==0) return thisnode;
1905de18cdeSSam Ravnborg 	}
1915de18cdeSSam Ravnborg 
1925de18cdeSSam Ravnborg 	return 0;
1935de18cdeSSam Ravnborg }
194*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_searchsiblings);
1955de18cdeSSam Ravnborg 
1965de18cdeSSam Ravnborg /* Return the first property type for node 'node'.
1975de18cdeSSam Ravnborg  * buffer should be at least 32B in length
1985de18cdeSSam Ravnborg  */
1995de18cdeSSam Ravnborg inline char *prom_firstprop(int node, char *buffer)
2005de18cdeSSam Ravnborg {
2015de18cdeSSam Ravnborg 	*buffer = 0;
2025de18cdeSSam Ravnborg 	if(node == -1) return buffer;
2035de18cdeSSam Ravnborg 	p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)|
2045de18cdeSSam Ravnborg 			       P1275_INOUT(3, 0),
2055de18cdeSSam Ravnborg 			       node, (char *) 0x0, buffer);
2065de18cdeSSam Ravnborg 	return buffer;
2075de18cdeSSam Ravnborg }
208*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_firstprop);
2095de18cdeSSam Ravnborg 
2105de18cdeSSam Ravnborg /* Return the property type string after property type 'oprop'
2115de18cdeSSam Ravnborg  * at node 'node' .  Returns NULL string if no more
2125de18cdeSSam Ravnborg  * property types for this node.
2135de18cdeSSam Ravnborg  */
2145de18cdeSSam Ravnborg inline char *prom_nextprop(int node, const char *oprop, char *buffer)
2155de18cdeSSam Ravnborg {
2165de18cdeSSam Ravnborg 	char buf[32];
2175de18cdeSSam Ravnborg 
2185de18cdeSSam Ravnborg 	if(node == -1) {
2195de18cdeSSam Ravnborg 		*buffer = 0;
2205de18cdeSSam Ravnborg 		return buffer;
2215de18cdeSSam Ravnborg 	}
2225de18cdeSSam Ravnborg 	if (oprop == buffer) {
2235de18cdeSSam Ravnborg 		strcpy (buf, oprop);
2245de18cdeSSam Ravnborg 		oprop = buf;
2255de18cdeSSam Ravnborg 	}
2265de18cdeSSam Ravnborg 	p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
2275de18cdeSSam Ravnborg 				    P1275_ARG(2,P1275_ARG_OUT_32B)|
2285de18cdeSSam Ravnborg 				    P1275_INOUT(3, 0),
2295de18cdeSSam Ravnborg 				    node, oprop, buffer);
2305de18cdeSSam Ravnborg 	return buffer;
2315de18cdeSSam Ravnborg }
232*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_nextprop);
2335de18cdeSSam Ravnborg 
2345de18cdeSSam Ravnborg int
2355de18cdeSSam Ravnborg prom_finddevice(const char *name)
2365de18cdeSSam Ravnborg {
2375de18cdeSSam Ravnborg 	if (!name)
2385de18cdeSSam Ravnborg 		return 0;
2395de18cdeSSam Ravnborg 	return p1275_cmd(prom_finddev_name,
2405de18cdeSSam Ravnborg 			 P1275_ARG(0,P1275_ARG_IN_STRING)|
2415de18cdeSSam Ravnborg 			 P1275_INOUT(1, 1),
2425de18cdeSSam Ravnborg 			 name);
2435de18cdeSSam Ravnborg }
244*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_finddevice);
2455de18cdeSSam Ravnborg 
2465de18cdeSSam Ravnborg int prom_node_has_property(int node, const char *prop)
2475de18cdeSSam Ravnborg {
2485de18cdeSSam Ravnborg 	char buf [32];
2495de18cdeSSam Ravnborg 
2505de18cdeSSam Ravnborg 	*buf = 0;
2515de18cdeSSam Ravnborg 	do {
2525de18cdeSSam Ravnborg 		prom_nextprop(node, buf, buf);
2535de18cdeSSam Ravnborg 		if(!strcmp(buf, prop))
2545de18cdeSSam Ravnborg 			return 1;
2555de18cdeSSam Ravnborg 	} while (*buf);
2565de18cdeSSam Ravnborg 	return 0;
2575de18cdeSSam Ravnborg }
258*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_node_has_property);
2595de18cdeSSam Ravnborg 
2605de18cdeSSam Ravnborg /* Set property 'pname' at node 'node' to value 'value' which has a length
2615de18cdeSSam Ravnborg  * of 'size' bytes.  Return the number of bytes the prom accepted.
2625de18cdeSSam Ravnborg  */
2635de18cdeSSam Ravnborg int
2645de18cdeSSam Ravnborg prom_setprop(int node, const char *pname, char *value, int size)
2655de18cdeSSam Ravnborg {
2665de18cdeSSam Ravnborg 	if (size == 0)
2675de18cdeSSam Ravnborg 		return 0;
2685de18cdeSSam Ravnborg 	if ((pname == 0) || (value == 0))
2695de18cdeSSam Ravnborg 		return 0;
2705de18cdeSSam Ravnborg 
2715de18cdeSSam Ravnborg #ifdef CONFIG_SUN_LDOMS
2725de18cdeSSam Ravnborg 	if (ldom_domaining_enabled) {
2735de18cdeSSam Ravnborg 		ldom_set_var(pname, value);
2745de18cdeSSam Ravnborg 		return 0;
2755de18cdeSSam Ravnborg 	}
2765de18cdeSSam Ravnborg #endif
2775de18cdeSSam Ravnborg 	return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
2785de18cdeSSam Ravnborg 					  P1275_ARG(2,P1275_ARG_IN_BUF)|
2795de18cdeSSam Ravnborg 					  P1275_INOUT(4, 1),
2805de18cdeSSam Ravnborg 					  node, pname, value, P1275_SIZE(size));
2815de18cdeSSam Ravnborg }
282*917c3660SSam Ravnborg EXPORT_SYMBOL(prom_setprop);
2835de18cdeSSam Ravnborg 
2845de18cdeSSam Ravnborg inline int prom_inst2pkg(int inst)
2855de18cdeSSam Ravnborg {
2865de18cdeSSam Ravnborg 	int node;
2875de18cdeSSam Ravnborg 
2885de18cdeSSam Ravnborg 	node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst);
2895de18cdeSSam Ravnborg 	if (node == -1) return 0;
2905de18cdeSSam Ravnborg 	return node;
2915de18cdeSSam Ravnborg }
2925de18cdeSSam Ravnborg 
2935de18cdeSSam Ravnborg /* Return 'node' assigned to a particular prom 'path'
2945de18cdeSSam Ravnborg  * FIXME: Should work for v0 as well
2955de18cdeSSam Ravnborg  */
2965de18cdeSSam Ravnborg int
2975de18cdeSSam Ravnborg prom_pathtoinode(const char *path)
2985de18cdeSSam Ravnborg {
2995de18cdeSSam Ravnborg 	int node, inst;
3005de18cdeSSam Ravnborg 
3015de18cdeSSam Ravnborg 	inst = prom_devopen (path);
3025de18cdeSSam Ravnborg 	if (inst == 0) return 0;
3035de18cdeSSam Ravnborg 	node = prom_inst2pkg (inst);
3045de18cdeSSam Ravnborg 	prom_devclose (inst);
3055de18cdeSSam Ravnborg 	if (node == -1) return 0;
3065de18cdeSSam Ravnborg 	return node;
3075de18cdeSSam Ravnborg }
3085de18cdeSSam Ravnborg 
3095de18cdeSSam Ravnborg int prom_ihandle2path(int handle, char *buffer, int bufsize)
3105de18cdeSSam Ravnborg {
3115de18cdeSSam Ravnborg 	return p1275_cmd("instance-to-path",
3125de18cdeSSam Ravnborg 			 P1275_ARG(1,P1275_ARG_OUT_BUF)|
3135de18cdeSSam Ravnborg 			 P1275_INOUT(3, 1),
3145de18cdeSSam Ravnborg 			 handle, buffer, P1275_SIZE(bufsize));
3155de18cdeSSam Ravnborg }
316