ofw_subr.c revision 1.55 1 /* $NetBSD: ofw_subr.c,v 1.55 2021/01/27 04:55:42 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.55 2021/01/27 04:55:42 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_compatible_match(phandle, compat_data)
134 *
135 * This routine searches an array of device_compatible_entry structures
136 * for a matching "compatible" entry matching the supplied OFW node,
137 * and returns a weighted match value corresponding to which string
138 * from the "compatible" property was matched, which more weight given
139 * to the first string than the last.
140 *
141 * It should be used when determining whether a driver can drive
142 * a particular device.
143 *
144 * Arguments:
145 * phandle OFW phandle of device to be checked for
146 * compatibility.
147 * compat_data Array of possible compat entry strings and
148 * associated metadata. The last entry in the
149 * list should have a "compat" of NULL to terminate
150 * the list.
151 *
152 * Return Value:
153 * 0 if none of the strings are found in phandle's "compatibility"
154 * property, or a positive number based on the reverse index of the
155 * matching string in the phandle's "compatibility" property, plus 1.
156 *
157 * Side Effects:
158 * None.
159 */
160 int
161 of_compatible_match(int phandle,
162 const struct device_compatible_entry *compat_data)
163 {
164 char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
165 int proplen, match = 0;
166
167 proplen = OF_getproplen(phandle, "compatible");
168 if (proplen <= 0) {
169 return 0;
170 }
171
172 prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
173
174 if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
175 goto out;
176 }
177
178 match = device_compatible_match_strlist(prop, proplen, compat_data);
179
180 out:
181 kmem_tmpbuf_free(prop, proplen, propbuf);
182 return match;
183 }
184
185 /*
186 * const struct device_compatible_entry *of_compatible_lookup(phandle,
187 * compat_data)
188 *
189 * This routine searches an array of device_compatible_entry structures
190 * for a "compatible" entry matching the supplied OFW node.
191 *
192 * Arguments:
193 * phandle OFW phandle of device to be checked for
194 * compatibility.
195 * compat_data Array of possible compat entry strings and
196 * associated metadata. The last entry in the
197 * list should have a "compat" of NULL to terminate
198 * the list.
199 *
200 * Return Value:
201 * The first matching compat_data entry in the array. If no matches
202 * are found, NULL is returned.
203 *
204 * Side Effects:
205 * None.
206 */
207 const struct device_compatible_entry *
208 of_compatible_lookup(int phandle,
209 const struct device_compatible_entry *compat_data)
210 {
211 char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
212 const struct device_compatible_entry *match = NULL;
213 int proplen;
214
215 proplen = OF_getproplen(phandle, "compatible");
216 if (proplen <= 0) {
217 return 0;
218 }
219
220 prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
221
222 if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
223 goto out;
224 }
225
226 match = device_compatible_lookup_strlist(prop, proplen, compat_data);
227
228 out:
229 kmem_tmpbuf_free(prop, proplen, propbuf);
230 return match;
231 }
232
233 /*
234 * int of_packagename(phandle, buf, bufsize)
235 *
236 * This routine places the last component of an OFW node's name
237 * into a user-provided buffer.
238 *
239 * It can be used during autoconfiguration to make printing of
240 * device names more informative.
241 *
242 * Arguments:
243 * phandle OFW phandle of device whose name name is
244 * desired.
245 * buf Buffer to contain device name, provided by
246 * caller. (For now, must be at least 4
247 * bytes long.)
248 * bufsize Length of buffer referenced by 'buf', in
249 * bytes.
250 *
251 * Return Value:
252 * -1 if the device path name could not be obtained or would
253 * not fit in the allocated temporary buffer, or zero otherwise
254 * (meaning that the leaf node name was successfully extracted).
255 *
256 * Side Effects:
257 * If the leaf node name was successfully extracted, 'buf' is
258 * filled in with at most 'bufsize' bytes of the leaf node
259 * name. If the leaf node was not successfully extracted, a
260 * somewhat meaningful string is placed in the buffer. In
261 * either case, the contents of 'buf' will be NUL-terminated.
262 */
263 int
264 of_packagename(int phandle, char *buf, int bufsize)
265 {
266 char *pbuf;
267 const char *lastslash;
268 int l, rv;
269
270 pbuf = kmem_alloc(OFW_PATH_BUF_SIZE, KM_SLEEP);
271 l = OF_package_to_path(phandle, pbuf, OFW_PATH_BUF_SIZE);
272
273 /* check that we could get the name, and that it's not too long. */
274 if (l < 0 ||
275 (l == OFW_PATH_BUF_SIZE && pbuf[OFW_PATH_BUF_SIZE - 1] != '\0')) {
276 if (bufsize >= 25)
277 snprintf(buf, bufsize, "??? (phandle 0x%x)", phandle);
278 else if (bufsize >= 4)
279 strlcpy(buf, "???", bufsize);
280 else
281 panic("of_packagename: bufsize = %d is silly",
282 bufsize);
283 rv = -1;
284 } else {
285 pbuf[l] = '\0';
286 lastslash = strrchr(pbuf, '/');
287 strlcpy(buf, (lastslash == NULL) ? pbuf : (lastslash + 1),
288 bufsize);
289 rv = 0;
290 }
291
292 kmem_free(pbuf, OFW_PATH_BUF_SIZE);
293 return (rv);
294 }
295
296 /*
297 * Find the first child of a given node that matches name. Does not recurse.
298 */
299 int
300 of_find_firstchild_byname(int node, const char *name)
301 {
302 char namex[32];
303 int nn;
304
305 for (nn = OF_child(node); nn; nn = OF_peer(nn)) {
306 memset(namex, 0, sizeof(namex));
307 if (OF_getprop(nn, "name", namex, sizeof(namex)) == -1)
308 continue;
309 if (strcmp(name, namex) == 0)
310 return nn;
311 }
312 return -1;
313 }
314
315 /*
316 * Find a child node that is compatible with str. Recurses, starting at node.
317 */
318 int
319 of_find_bycompat(int node, const char *str)
320 {
321 const char * compatible[] = { str, NULL };
322 int child, ret;
323
324 for (child = OF_child(node); child; child = OF_peer(child)) {
325 if (of_compatible(child, compatible))
326 return child;
327 ret = of_find_bycompat(child, str);
328 if (ret != -1)
329 return ret;
330 }
331
332 return -1;
333 }
334
335 /*
336 * Find a give node by name. Recurses, and seems to walk upwards too.
337 */
338
339 int
340 of_getnode_byname(int start, const char *target)
341 {
342 int node, next;
343 char name[64];
344
345 if (start == 0)
346 start = OF_peer(0);
347
348 for (node = start; node; node = next) {
349 memset(name, 0, sizeof name);
350 OF_getprop(node, "name", name, sizeof name - 1);
351 if (strcmp(name, target) == 0)
352 break;
353
354 if ((next = OF_child(node)) != 0)
355 continue;
356
357 while (node) {
358 if ((next = OF_peer(node)) != 0)
359 break;
360 node = OF_parent(node);
361 }
362 }
363
364 /* XXX is this correct? */
365 return node;
366 }
367
368 /*
369 * Create a uint32_t integer property from an OFW node property.
370 */
371
372 bool
373 of_to_uint32_prop(prop_dictionary_t dict, int node, const char *ofname,
374 const char *propname)
375 {
376 uint32_t prop;
377
378 if (OF_getprop(node, ofname, &prop, sizeof(prop)) != sizeof(prop))
379 return FALSE;
380
381 return(prop_dictionary_set_uint32(dict, propname, prop));
382 }
383
384 /*
385 * Create a data property from an OFW node property. Max size of 256bytes.
386 */
387
388 bool
389 of_to_dataprop(prop_dictionary_t dict, int node, const char *ofname,
390 const char *propname)
391 {
392 int len;
393 uint8_t prop[256];
394
395 len = OF_getprop(node, ofname, prop, 256);
396 if (len < 1)
397 return FALSE;
398
399 return prop_dictionary_set_data(dict, propname, prop, len);
400 }
401
402 /*
403 * look at output-device, see if there's a Sun-typical video mode specifier as
404 * in screen:r1024x768x60 attached. If found copy it into *buffer, otherwise
405 * return NULL
406 */
407
408 char *
409 of_get_mode_string(char *buffer, int len)
410 {
411 int options;
412 char *pos, output_device[256];
413
414 /*
415 * finally, let's see if there's a video mode specified in
416 * output-device and pass it on so there's at least some way
417 * to program video modes
418 */
419 options = OF_finddevice("/options");
420 if ((options == 0) || (options == -1))
421 return NULL;
422 if (OF_getprop(options, "output-device", output_device, 256) == 0)
423 return NULL;
424
425 /* find the mode string if there is one */
426 pos = strstr(output_device, ":r");
427 if (pos == NULL)
428 return NULL;
429 strncpy(buffer, pos + 2, len);
430 return buffer;
431 }
432
433 /*
434 * Iterate over the subtree of a i2c controller node.
435 * Add all sub-devices into an array as part of the controller's
436 * device properties.
437 * This is used by the i2c bus attach code to do direct configuration.
438 */
439 void
440 of_enter_i2c_devs(prop_dictionary_t props, int ofnode, size_t cell_size,
441 int addr_shift)
442 {
443 int node, len;
444 char name[32];
445 uint64_t reg64;
446 uint32_t reg32;
447 uint64_t addr;
448 prop_array_t array = NULL;
449 prop_dictionary_t dev;
450
451 for (node = OF_child(ofnode); node; node = OF_peer(node)) {
452 if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
453 continue;
454 len = OF_getproplen(node, "reg");
455 addr = 0;
456 if (cell_size == 8 && len >= sizeof(reg64)) {
457 if (OF_getprop(node, "reg", ®64, sizeof(reg64))
458 < sizeof(reg64))
459 continue;
460 addr = be64toh(reg64);
461 /*
462 * The i2c bus number (0 or 1) is encoded in bit 33
463 * of the register, but we encode it in bit 8 of
464 * i2c_addr_t.
465 */
466 if (addr & 0x100000000)
467 addr = (addr & 0xff) | 0x100;
468 } else if (cell_size == 4 && len >= sizeof(reg32)) {
469 if (OF_getprop(node, "reg", ®32, sizeof(reg32))
470 < sizeof(reg32))
471 continue;
472 addr = be32toh(reg32);
473 } else {
474 continue;
475 }
476 addr >>= addr_shift;
477 if (addr == 0) continue;
478
479 if (array == NULL)
480 array = prop_array_create();
481
482 dev = prop_dictionary_create();
483 prop_dictionary_set_string(dev, "name", name);
484 prop_dictionary_set_uint32(dev, "addr", addr);
485 prop_dictionary_set_uint64(dev, "cookie", node);
486 prop_dictionary_set_uint32(dev, "cookietype", I2C_COOKIE_OF);
487 of_to_dataprop(dev, node, "compatible", "compatible");
488 prop_array_add(array, dev);
489 prop_object_release(dev);
490 }
491
492 if (array != NULL) {
493 prop_dictionary_set(props, "i2c-child-devices", array);
494 prop_object_release(array);
495 }
496 }
497
498 void
499 of_enter_spi_devs(prop_dictionary_t props, int ofnode, size_t cell_size)
500 {
501 int node, len;
502 char name[32];
503 uint64_t reg64;
504 uint32_t reg32;
505 uint32_t slave;
506 u_int32_t maxfreq;
507 prop_array_t array = NULL;
508 prop_dictionary_t dev;
509 int mode;
510
511 for (node = OF_child(ofnode); node; node = OF_peer(node)) {
512 if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
513 continue;
514 len = OF_getproplen(node, "reg");
515 slave = 0;
516 if (cell_size == 8 && len >= sizeof(reg64)) {
517 if (OF_getprop(node, "reg", ®64, sizeof(reg64))
518 < sizeof(reg64))
519 continue;
520 slave = be64toh(reg64);
521 } else if (cell_size == 4 && len >= sizeof(reg32)) {
522 if (OF_getprop(node, "reg", ®32, sizeof(reg32))
523 < sizeof(reg32))
524 continue;
525 slave = be32toh(reg32);
526 } else {
527 continue;
528 }
529 if (of_getprop_uint32(node, "spi-max-frequency", &maxfreq)) {
530 maxfreq = 0;
531 }
532 mode = ((int)of_hasprop(node, "cpol") << 1) | (int)of_hasprop(node, "cpha");
533
534 if (array == NULL)
535 array = prop_array_create();
536
537 dev = prop_dictionary_create();
538 prop_dictionary_set_string(dev, "name", name);
539 prop_dictionary_set_uint32(dev, "slave", slave);
540 prop_dictionary_set_uint32(dev, "mode", mode);
541 if (maxfreq > 0)
542 prop_dictionary_set_uint32(dev, "spi-max-frequency", maxfreq);
543 prop_dictionary_set_uint64(dev, "cookie", node);
544 of_to_dataprop(dev, node, "compatible", "compatible");
545 prop_array_add(array, dev);
546 prop_object_release(dev);
547 }
548
549 if (array != NULL) {
550 prop_dictionary_set(props, "spi-child-devices", array);
551 prop_object_release(array);
552 }
553 }
554
555
556 /*
557 * Returns true if the specified property is present.
558 */
559 bool
560 of_hasprop(int node, const char *prop)
561 {
562 return OF_getproplen(node, prop) >= 0;
563 }
564
565 /*
566 * Get the value of a uint32 property, compensating for host byte order.
567 * Returns 0 on success, non-zero on failure.
568 */
569 int
570 of_getprop_uint32(int node, const char *prop, uint32_t *val)
571 {
572 uint32_t v;
573 int len;
574
575 len = OF_getprop(node, prop, &v, sizeof(v));
576 if (len != sizeof(v))
577 return -1;
578
579 *val = be32toh(v);
580 return 0;
581 }
582
583 int
584 of_getprop_uint32_array(int node, const char *prop, uint32_t *array, int n)
585 {
586 uint32_t *v = array;
587 int len;
588
589 len = OF_getprop(node, prop, array, n * sizeof(*v));
590 if (len < (int)(n * sizeof(*v)))
591 return -1;
592
593 for (; n > 0; n--) {
594 BE32TOH(*v);
595 v++;
596 }
597
598 return 0;
599 }
600 /*
601 * Get the value of a uint64 property, compensating for host byte order.
602 * Returns 0 on success, non-zero on failure.
603 */
604 int
605 of_getprop_uint64(int node, const char *prop, uint64_t *val)
606 {
607 uint64_t v;
608 int len;
609
610 len = OF_getprop(node, prop, &v, sizeof(v));
611 if (len != sizeof(v))
612 return -1;
613
614 *val = be64toh(v);
615 return 0;
616 }
617