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