Home | History | Annotate | Line # | Download | only in ofw
ofw_subr.c revision 1.54
      1 /*	$NetBSD: ofw_subr.c,v 1.54 2021/01/27 03:10:21 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright 1998
      5  * Digital Equipment Corporation. All rights reserved.
      6  *
      7  * This software is furnished under license and may be used and
      8  * copied only in accordance with the following terms and conditions.
      9  * Subject to these conditions, you may download, copy, install,
     10  * use, modify and distribute this software in source and/or binary
     11  * form. No title or ownership is transferred hereby.
     12  *
     13  * 1) Any source code used, modified or distributed must reproduce
     14  *    and retain this copyright notice and list of conditions as
     15  *    they appear in the source file.
     16  *
     17  * 2) No right is granted to use any trade name, trademark, or logo of
     18  *    Digital Equipment Corporation. Neither the "Digital Equipment
     19  *    Corporation" name nor any trademark or logo of Digital Equipment
     20  *    Corporation may be used to endorse or promote products derived
     21  *    from this software without the prior written permission of
     22  *    Digital Equipment Corporation.
     23  *
     24  * 3) This software is provided "AS-IS" and any express or implied
     25  *    warranties, including but not limited to, any implied warranties
     26  *    of merchantability, fitness for a particular purpose, or
     27  *    non-infringement are disclaimed. In no event shall DIGITAL be
     28  *    liable for any damages whatsoever, and in particular, DIGITAL
     29  *    shall not be liable for special, indirect, consequential, or
     30  *    incidental damages or damages for lost profits, loss of
     31  *    revenue or loss of use, whether such damages arise in contract,
     32  *    negligence, tort, under statute, in equity, at law or otherwise,
     33  *    even if advised of the possibility of such damage.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: ofw_subr.c,v 1.54 2021/01/27 03:10:21 thorpej Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/device.h>
     41 #include <sys/kmem.h>
     42 #include <sys/systm.h>
     43 #include <dev/ofw/openfirm.h>
     44 #include <dev/i2c/i2cvar.h>
     45 
     46 #define	OFW_MAX_STACK_BUF_SIZE	256
     47 #define	OFW_PATH_BUF_SIZE	512
     48 
     49 /*
     50  * int of_decode_int(p)
     51  *
     52  * This routine converts OFW encoded-int datums
     53  * into the integer format of the host machine.
     54  *
     55  * It is primarily used to convert integer properties
     56  * returned by the OF_getprop routine.
     57  *
     58  * Arguments:
     59  *	p		pointer to unsigned char array which is an
     60  *			OFW-encoded integer.
     61  *
     62  * Return Value:
     63  *	Decoded integer value of argument p.
     64  *
     65  * Side Effects:
     66  *	None.
     67  */
     68 int
     69 of_decode_int(const unsigned char *p)
     70 {
     71 	unsigned int i = *p++ << 8;
     72 	i = (i + *p++) << 8;
     73 	i = (i + *p++) << 8;
     74 	return (i + *p);
     75 }
     76 
     77 /*
     78  * int of_compatible(phandle, strings)
     79  *
     80  * This routine checks an OFW node's "compatible" entry to see if
     81  * it matches any of the provided strings.
     82  *
     83  * of_compatible_match() is the preferred way to perform driver
     84  * compatibility match.  However, this routine that deals with
     85  * only strings is useful in some situations and is provided for
     86  * convenience.
     87  *
     88  * Arguments:
     89  *	phandle		OFW phandle of device to be checked for
     90  *			compatibility.
     91  *	strings		Array of containing expected "compatibility"
     92  *			property values, presence of any of which
     93  *			indicates compatibility.
     94  *
     95  * Return Value:
     96  *	0 if none of the strings are found in phandle's "compatibility"
     97  *	property, or the reverse index of the matching string in the
     98  *	phandle's "compatibility" property plus 1.
     99  *
    100  * Side Effects:
    101  *	None.
    102  */
    103 int
    104 of_compatible(int phandle, const char * const *strings)
    105 {
    106 	char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
    107 	const char *cp;
    108 	int proplen, match = 0;
    109 
    110 	proplen = OF_getproplen(phandle, "compatible");
    111 	if (proplen <= 0) {
    112 		return 0;
    113 	}
    114 
    115 	prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
    116 
    117 	if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
    118 		goto out;
    119 	}
    120 
    121 	for (; (cp = *strings) != NULL; strings++) {
    122 		if ((match = strlist_match(prop, proplen, cp)) != 0) {
    123 			break;
    124 		}
    125 	}
    126 
    127  out:
    128 	kmem_tmpbuf_free(prop, proplen, propbuf);
    129 	return match;
    130 }
    131 
    132 /*
    133  * int of_match_compatible(phandle, strings)
    134  *
    135  * This function is equivalent to of_compatible(), and its use
    136  * is deprecated.
    137  */
    138 int
    139 of_match_compatible(int phandle, const char * const *strings)
    140 {
    141 	return of_compatible(phandle, strings);
    142 }
    143 
    144 /*
    145  * int of_compatible_match(phandle, compat_data)
    146  *
    147  * This routine searches an array of device_compatible_entry structures
    148  * for a matching "compatible" entry matching the supplied OFW node,
    149  * and returns a weighted match value corresponding to which string
    150  * from the "compatible" property was matched, which more weight given
    151  * to the first string than the last.
    152  *
    153  * It should be used when determining whether a driver can drive
    154  * a particular device.
    155  *
    156  * Arguments:
    157  *	phandle		OFW phandle of device to be checked for
    158  *			compatibility.
    159  *	compat_data	Array of possible compat entry strings and
    160  *			associated metadata. The last entry in the
    161  *			list should have a "compat" of NULL to terminate
    162  *			the list.
    163  *
    164  * Return Value:
    165  *	0 if none of the strings are found in phandle's "compatibility"
    166  *	property, or a positive number based on the reverse index of the
    167  *	matching string in the phandle's "compatibility" property, plus 1.
    168  *
    169  * Side Effects:
    170  *	None.
    171  */
    172 int
    173 of_compatible_match(int phandle,
    174     const struct device_compatible_entry *compat_data)
    175 {
    176 	char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
    177 	int proplen, match = 0;
    178 
    179 	proplen = OF_getproplen(phandle, "compatible");
    180 	if (proplen <= 0) {
    181 		return 0;
    182 	}
    183 
    184 	prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
    185 
    186 	if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
    187 		goto out;
    188 	}
    189 
    190 	match = device_compatible_match_strlist(prop, proplen, compat_data);
    191 
    192  out:
    193 	kmem_tmpbuf_free(prop, proplen, propbuf);
    194 	return match;
    195 }
    196 
    197 /*
    198  * const struct device_compatible_entry *of_compatible_lookup(phandle,
    199  *							      compat_data)
    200  *
    201  * This routine searches an array of device_compatible_entry structures
    202  * for a "compatible" entry matching the supplied OFW node.
    203  *
    204  * Arguments:
    205  *	phandle		OFW phandle of device to be checked for
    206  *			compatibility.
    207  *	compat_data	Array of possible compat entry strings and
    208  *			associated metadata. The last entry in the
    209  *			list should have a "compat" of NULL to terminate
    210  *			the list.
    211  *
    212  * Return Value:
    213  *	The first matching compat_data entry in the array. If no matches
    214  *	are found, NULL is returned.
    215  *
    216  * Side Effects:
    217  *	None.
    218  */
    219 const struct device_compatible_entry *
    220 of_compatible_lookup(int phandle,
    221     const struct device_compatible_entry *compat_data)
    222 {
    223 	char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
    224 	const struct device_compatible_entry *match = NULL;
    225 	int proplen;
    226 
    227 	proplen = OF_getproplen(phandle, "compatible");
    228 	if (proplen <= 0) {
    229 		return 0;
    230 	}
    231 
    232 	prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
    233 
    234 	if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
    235 		goto out;
    236 	}
    237 
    238 	match = device_compatible_lookup_strlist(prop, proplen, compat_data);
    239 
    240  out:
    241 	kmem_tmpbuf_free(prop, proplen, propbuf);
    242 	return match;
    243 }
    244 
    245 /*
    246  * int of_packagename(phandle, buf, bufsize)
    247  *
    248  * This routine places the last component of an OFW node's name
    249  * into a user-provided buffer.
    250  *
    251  * It can be used during autoconfiguration to make printing of
    252  * device names more informative.
    253  *
    254  * Arguments:
    255  *	phandle		OFW phandle of device whose name name is
    256  *			desired.
    257  *	buf		Buffer to contain device name, provided by
    258  *			caller.  (For now, must be at least 4
    259  *			bytes long.)
    260  *	bufsize		Length of buffer referenced by 'buf', in
    261  *			bytes.
    262  *
    263  * Return Value:
    264  *	-1 if the device path name could not be obtained or would
    265  *	not fit in the allocated temporary buffer, or zero otherwise
    266  *	(meaning that the leaf node name was successfully extracted).
    267  *
    268  * Side Effects:
    269  *	If the leaf node name was successfully extracted, 'buf' is
    270  *	filled in with at most 'bufsize' bytes of the leaf node
    271  *	name.  If the leaf node was not successfully extracted, a
    272  *	somewhat meaningful string is placed in the buffer.  In
    273  *	either case, the contents of 'buf' will be NUL-terminated.
    274  */
    275 int
    276 of_packagename(int phandle, char *buf, int bufsize)
    277 {
    278 	char *pbuf;
    279 	const char *lastslash;
    280 	int l, rv;
    281 
    282 	pbuf = kmem_alloc(OFW_PATH_BUF_SIZE, KM_SLEEP);
    283 	l = OF_package_to_path(phandle, pbuf, OFW_PATH_BUF_SIZE);
    284 
    285 	/* check that we could get the name, and that it's not too long. */
    286 	if (l < 0 ||
    287 	    (l == OFW_PATH_BUF_SIZE && pbuf[OFW_PATH_BUF_SIZE - 1] != '\0')) {
    288 		if (bufsize >= 25)
    289 			snprintf(buf, bufsize, "??? (phandle 0x%x)", phandle);
    290 		else if (bufsize >= 4)
    291 			strlcpy(buf, "???", bufsize);
    292 		else
    293 			panic("of_packagename: bufsize = %d is silly",
    294 			    bufsize);
    295 		rv = -1;
    296 	} else {
    297 		pbuf[l] = '\0';
    298 		lastslash = strrchr(pbuf, '/');
    299 		strlcpy(buf, (lastslash == NULL) ? pbuf : (lastslash + 1),
    300 		    bufsize);
    301 		rv = 0;
    302 	}
    303 
    304 	kmem_free(pbuf, OFW_PATH_BUF_SIZE);
    305 	return (rv);
    306 }
    307 
    308 /*
    309  * Find the first child of a given node that matches name. Does not recurse.
    310  */
    311 int
    312 of_find_firstchild_byname(int node, const char *name)
    313 {
    314 	char namex[32];
    315 	int nn;
    316 
    317 	for (nn = OF_child(node); nn; nn = OF_peer(nn)) {
    318 		memset(namex, 0, sizeof(namex));
    319 		if (OF_getprop(nn, "name", namex, sizeof(namex)) == -1)
    320 			continue;
    321 		if (strcmp(name, namex) == 0)
    322 			return nn;
    323 	}
    324 	return -1;
    325 }
    326 
    327 /*
    328  * Find a child node that is compatible with str. Recurses, starting at node.
    329  */
    330 int
    331 of_find_bycompat(int node, const char *str)
    332 {
    333 	const char * compatible[] = { str, NULL };
    334 	int child, ret;
    335 
    336 	for (child = OF_child(node); child; child = OF_peer(child)) {
    337 		if (of_compatible(child, compatible))
    338 			return child;
    339 		ret = of_find_bycompat(child, str);
    340 		if (ret != -1)
    341 			return ret;
    342 	}
    343 
    344 	return -1;
    345 }
    346 
    347 /*
    348  * Find a give node by name.  Recurses, and seems to walk upwards too.
    349  */
    350 
    351 int
    352 of_getnode_byname(int start, const char *target)
    353 {
    354 	int node, next;
    355 	char name[64];
    356 
    357 	if (start == 0)
    358 		start = OF_peer(0);
    359 
    360 	for (node = start; node; node = next) {
    361 		memset(name, 0, sizeof name);
    362 		OF_getprop(node, "name", name, sizeof name - 1);
    363 		if (strcmp(name, target) == 0)
    364 			break;
    365 
    366 		if ((next = OF_child(node)) != 0)
    367 			continue;
    368 
    369 		while (node) {
    370 			if ((next = OF_peer(node)) != 0)
    371 				break;
    372 			node = OF_parent(node);
    373 		}
    374 	}
    375 
    376 	/* XXX is this correct? */
    377 	return node;
    378 }
    379 
    380 /*
    381  * Create a uint32_t integer property from an OFW node property.
    382  */
    383 
    384 bool
    385 of_to_uint32_prop(prop_dictionary_t dict, int node, const char *ofname,
    386     const char *propname)
    387 {
    388 	uint32_t prop;
    389 
    390 	if (OF_getprop(node, ofname, &prop, sizeof(prop)) != sizeof(prop))
    391 		return FALSE;
    392 
    393 	return(prop_dictionary_set_uint32(dict, propname, prop));
    394 }
    395 
    396 /*
    397  * Create a data property from an OFW node property.  Max size of 256bytes.
    398  */
    399 
    400 bool
    401 of_to_dataprop(prop_dictionary_t dict, int node, const char *ofname,
    402     const char *propname)
    403 {
    404 	int len;
    405 	uint8_t prop[256];
    406 
    407 	len = OF_getprop(node, ofname, prop, 256);
    408 	if (len < 1)
    409 		return FALSE;
    410 
    411 	return prop_dictionary_set_data(dict, propname, prop, len);
    412 }
    413 
    414 /*
    415  * look at output-device, see if there's a Sun-typical video mode specifier as
    416  * in screen:r1024x768x60 attached. If found copy it into *buffer, otherwise
    417  * return NULL
    418  */
    419 
    420 char *
    421 of_get_mode_string(char *buffer, int len)
    422 {
    423 	int options;
    424 	char *pos, output_device[256];
    425 
    426 	/*
    427 	 * finally, let's see if there's a video mode specified in
    428 	 * output-device and pass it on so there's at least some way
    429 	 * to program video modes
    430 	 */
    431 	options = OF_finddevice("/options");
    432 	if ((options == 0) || (options == -1))
    433 		return NULL;
    434 	if (OF_getprop(options, "output-device", output_device, 256) == 0)
    435 		return NULL;
    436 
    437 	/* find the mode string if there is one */
    438 	pos = strstr(output_device, ":r");
    439 	if (pos == NULL)
    440 		return NULL;
    441 	strncpy(buffer, pos + 2, len);
    442 	return buffer;
    443 }
    444 
    445 /*
    446  * Iterate over the subtree of a i2c controller node.
    447  * Add all sub-devices into an array as part of the controller's
    448  * device properties.
    449  * This is used by the i2c bus attach code to do direct configuration.
    450  */
    451 void
    452 of_enter_i2c_devs(prop_dictionary_t props, int ofnode, size_t cell_size,
    453     int addr_shift)
    454 {
    455 	int node, len;
    456 	char name[32];
    457 	uint64_t reg64;
    458 	uint32_t reg32;
    459 	uint64_t addr;
    460 	prop_array_t array = NULL;
    461 	prop_dictionary_t dev;
    462 
    463 	for (node = OF_child(ofnode); node; node = OF_peer(node)) {
    464 		if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
    465 			continue;
    466 		len = OF_getproplen(node, "reg");
    467 		addr = 0;
    468 		if (cell_size == 8 && len >= sizeof(reg64)) {
    469 			if (OF_getprop(node, "reg", &reg64, sizeof(reg64))
    470 			    < sizeof(reg64))
    471 				continue;
    472 			addr = be64toh(reg64);
    473 			/*
    474 			 * The i2c bus number (0 or 1) is encoded in bit 33
    475 			 * of the register, but we encode it in bit 8 of
    476 			 * i2c_addr_t.
    477 			 */
    478 			if (addr & 0x100000000)
    479 				addr = (addr & 0xff) | 0x100;
    480 		} else if (cell_size == 4 && len >= sizeof(reg32)) {
    481 			if (OF_getprop(node, "reg", &reg32, sizeof(reg32))
    482 			    < sizeof(reg32))
    483 				continue;
    484 			addr = be32toh(reg32);
    485 		} else {
    486 			continue;
    487 		}
    488 		addr >>= addr_shift;
    489 		if (addr == 0) continue;
    490 
    491 		if (array == NULL)
    492 			array = prop_array_create();
    493 
    494 		dev = prop_dictionary_create();
    495 		prop_dictionary_set_string(dev, "name", name);
    496 		prop_dictionary_set_uint32(dev, "addr", addr);
    497 		prop_dictionary_set_uint64(dev, "cookie", node);
    498 		prop_dictionary_set_uint32(dev, "cookietype", I2C_COOKIE_OF);
    499 		of_to_dataprop(dev, node, "compatible", "compatible");
    500 		prop_array_add(array, dev);
    501 		prop_object_release(dev);
    502 	}
    503 
    504 	if (array != NULL) {
    505 		prop_dictionary_set(props, "i2c-child-devices", array);
    506 		prop_object_release(array);
    507 	}
    508 }
    509 
    510 void
    511 of_enter_spi_devs(prop_dictionary_t props, int ofnode, size_t cell_size)
    512 {
    513 	int node, len;
    514 	char name[32];
    515 	uint64_t reg64;
    516 	uint32_t reg32;
    517 	uint32_t slave;
    518 	u_int32_t maxfreq;
    519 	prop_array_t array = NULL;
    520 	prop_dictionary_t dev;
    521 	int mode;
    522 
    523 	for (node = OF_child(ofnode); node; node = OF_peer(node)) {
    524 		if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
    525 			continue;
    526 		len = OF_getproplen(node, "reg");
    527 		slave = 0;
    528 		if (cell_size == 8 && len >= sizeof(reg64)) {
    529 			if (OF_getprop(node, "reg", &reg64, sizeof(reg64))
    530 			    < sizeof(reg64))
    531 				continue;
    532 			slave = be64toh(reg64);
    533 		} else if (cell_size == 4 && len >= sizeof(reg32)) {
    534 			if (OF_getprop(node, "reg", &reg32, sizeof(reg32))
    535 			    < sizeof(reg32))
    536 				continue;
    537 			slave = be32toh(reg32);
    538 		} else {
    539 			continue;
    540 		}
    541 		if (of_getprop_uint32(node, "spi-max-frequency", &maxfreq)) {
    542 			maxfreq = 0;
    543 		}
    544 		mode = ((int)of_hasprop(node, "cpol") << 1) | (int)of_hasprop(node, "cpha");
    545 
    546 		if (array == NULL)
    547 			array = prop_array_create();
    548 
    549 		dev = prop_dictionary_create();
    550 		prop_dictionary_set_string(dev, "name", name);
    551 		prop_dictionary_set_uint32(dev, "slave", slave);
    552 		prop_dictionary_set_uint32(dev, "mode", mode);
    553 		if (maxfreq > 0)
    554 			prop_dictionary_set_uint32(dev, "spi-max-frequency", maxfreq);
    555 		prop_dictionary_set_uint64(dev, "cookie", node);
    556 		of_to_dataprop(dev, node, "compatible", "compatible");
    557 		prop_array_add(array, dev);
    558 		prop_object_release(dev);
    559 	}
    560 
    561 	if (array != NULL) {
    562 		prop_dictionary_set(props, "spi-child-devices", array);
    563 		prop_object_release(array);
    564 	}
    565 }
    566 
    567 
    568 /*
    569  * Returns true if the specified property is present.
    570  */
    571 bool
    572 of_hasprop(int node, const char *prop)
    573 {
    574 	return OF_getproplen(node, prop) >= 0;
    575 }
    576 
    577 /*
    578  * Get the value of a uint32 property, compensating for host byte order.
    579  * Returns 0 on success, non-zero on failure.
    580  */
    581 int
    582 of_getprop_uint32(int node, const char *prop, uint32_t *val)
    583 {
    584 	uint32_t v;
    585 	int len;
    586 
    587 	len = OF_getprop(node, prop, &v, sizeof(v));
    588 	if (len != sizeof(v))
    589 		return -1;
    590 
    591 	*val = be32toh(v);
    592 	return 0;
    593 }
    594 
    595 int
    596 of_getprop_uint32_array(int node, const char *prop, uint32_t *array, int n)
    597 {
    598 	uint32_t *v = array;
    599 	int len;
    600 
    601 	len = OF_getprop(node, prop, array, n * sizeof(*v));
    602 	if (len < (int)(n * sizeof(*v)))
    603 		return -1;
    604 
    605 	for (; n > 0; n--) {
    606 		BE32TOH(*v);
    607 		v++;
    608 	}
    609 
    610 	return 0;
    611 }
    612 /*
    613  * Get the value of a uint64 property, compensating for host byte order.
    614  * Returns 0 on success, non-zero on failure.
    615  */
    616 int
    617 of_getprop_uint64(int node, const char *prop, uint64_t *val)
    618 {
    619 	uint64_t v;
    620 	int len;
    621 
    622 	len = OF_getprop(node, prop, &v, sizeof(v));
    623 	if (len != sizeof(v))
    624 		return -1;
    625 
    626 	*val = be64toh(v);
    627 	return 0;
    628 }
    629