1 /* $NetBSD: ofw_subr.c,v 1.30 2017/07/03 00:47:34 jmcneill 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.30 2017/07/03 00:47:34 jmcneill Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/malloc.h> 42 #include <dev/ofw/openfirm.h> 43 44 #define OFW_MAX_STACK_BUF_SIZE 256 45 #define OFW_PATH_BUF_SIZE 512 46 47 /* 48 * int of_decode_int(p) 49 * 50 * This routine converts OFW encoded-int datums 51 * into the integer format of the host machine. 52 * 53 * It is primarily used to convert integer properties 54 * returned by the OF_getprop routine. 55 * 56 * Arguments: 57 * p pointer to unsigned char array which is an 58 * OFW-encoded integer. 59 * 60 * Return Value: 61 * Decoded integer value of argument p. 62 * 63 * Side Effects: 64 * None. 65 */ 66 int 67 of_decode_int(const unsigned char *p) 68 { 69 unsigned int i = *p++ << 8; 70 i = (i + *p++) << 8; 71 i = (i + *p++) << 8; 72 return (i + *p); 73 } 74 75 /* 76 * int of_compatible(phandle, strings) 77 * 78 * This routine checks an OFW node's "compatible" entry to see if 79 * it matches any of the provided strings. 80 * 81 * It should be used when determining whether a driver can drive 82 * a particular device. 83 * 84 * Arguments: 85 * phandle OFW phandle of device to be checked for 86 * compatibility. 87 * strings Array of containing expected "compatibility" 88 * property values, presence of any of which 89 * indicates compatibility. 90 * 91 * Return Value: 92 * -1 if none of the strings are found in phandle's "compatibility" 93 * property, or the reverse index of the matching string in the 94 * phandle's "compatibility" property. 95 * 96 * Side Effects: 97 * None. 98 */ 99 int 100 of_compatible(int phandle, const char * const *strings) 101 { 102 103 int len, olen, allocated, nstr, cstr, rv; 104 char *buf; 105 const char *sp, *nsp; 106 107 len = OF_getproplen(phandle, "compatible"); 108 if (len <= 0) 109 return (-1); 110 111 if (len > OFW_MAX_STACK_BUF_SIZE) { 112 buf = malloc(len, M_TEMP, M_WAITOK); 113 allocated = 1; 114 } else { 115 buf = alloca(len); 116 allocated = 0; 117 } 118 119 /* 'compatible' size should not change. */ 120 if (OF_getprop(phandle, "compatible", buf, len) != len) { 121 rv = -1; 122 goto out; 123 } 124 125 /* count 'compatible' strings */ 126 sp = buf; 127 nstr = 0; 128 olen = len; 129 while (len && (nsp = memchr(sp, 0, len)) != NULL) { 130 nsp++; /* skip over NUL char */ 131 len -= (nsp - sp); 132 sp = nsp; 133 nstr++; 134 } 135 len = olen; 136 137 sp = buf; 138 rv = nstr; 139 while (len && (nsp = memchr(sp, 0, len)) != NULL) { 140 rv--; 141 /* look for a match among the strings provided */ 142 for (cstr = 0; strings[cstr] != NULL; cstr++) 143 if (strcmp(sp, strings[cstr]) == 0) 144 goto out; 145 146 nsp++; /* skip over NUL char */ 147 len -= (nsp - sp); 148 sp = nsp; 149 } 150 rv = -1; 151 152 out: 153 if (allocated) 154 free(buf, M_TEMP); 155 return (rv); 156 } 157 158 /* 159 * int of_match_compatible(phandle, strings) 160 * 161 * This routine checks an OFW node's "compatible" entry to see if 162 * it matches any of the provided strings. 163 * 164 * It should be used when determining whether a driver can drive 165 * a particular device. 166 * 167 * Arguments: 168 * phandle OFW phandle of device to be checked for 169 * compatibility. 170 * strings Array of containing expected "compatibility" 171 * property values, presence of any of which 172 * indicates compatibility. 173 * 174 * Return Value: 175 * 0 if none of the strings are found in phandle's "compatibility" 176 * property, or a positive number based on the reverse index of the 177 * matching string in the phandle's "compatibility" property, plus 1. 178 * 179 * Side Effects: 180 * None. 181 */ 182 int 183 of_match_compatible(int phandle, const char * const *strings) 184 { 185 return of_compatible(phandle, strings) + 1; 186 } 187 188 /* 189 * int of_match_compat_data(phandle, compat_data) 190 * 191 * This routine searches an array of compat_data structures for a 192 * matching "compatible" entry matching the supplied OFW node. 193 * 194 * It should be used when determining whether a driver can drive 195 * a particular device. 196 * 197 * Arguments: 198 * phandle OFW phandle of device to be checked for 199 * compatibility. 200 * compat_data Array of possible compat entry strings and 201 * associated metadata. The last entry in the 202 * list should have a "compat" of NULL to terminate 203 * the list. 204 * 205 * Return Value: 206 * 0 if none of the strings are found in phandle's "compatibility" 207 * property, or a positive number based on the reverse index of the 208 * matching string in the phandle's "compatibility" property, plus 1. 209 * 210 * Side Effects: 211 * None. 212 */ 213 int 214 of_match_compat_data(int phandle, const struct of_compat_data *compat_data) 215 { 216 for (; compat_data->compat != NULL; compat_data++) { 217 const char *compat[] = { compat_data->compat, NULL }; 218 const int match = of_match_compatible(phandle, compat); 219 if (match) 220 return match; 221 } 222 return 0; 223 } 224 225 /* 226 * const struct of_compat_data *of_search_compatible(phandle, compat_data) 227 * 228 * This routine searches an array of compat_data structures for a 229 * matching "compatible" entry matching the supplied OFW node. 230 * 231 * Arguments: 232 * phandle OFW phandle of device to be checked for 233 * compatibility. 234 * compat_data Array of possible compat entry strings and 235 * associated metadata. The last entry in the 236 * list should have a "compat" of NULL to terminate 237 * the list. 238 * 239 * Return Value: 240 * The first matching compat_data entry in the array. If no matches 241 * are found, the terminating ("compat" of NULL) record is returned. 242 * 243 * Side Effects: 244 * None. 245 */ 246 const struct of_compat_data * 247 of_search_compatible(int phandle, const struct of_compat_data *compat_data) 248 { 249 for (; compat_data->compat != NULL; compat_data++) { 250 const char *compat[] = { compat_data->compat, NULL }; 251 if (of_match_compatible(phandle, compat)) 252 break; 253 } 254 return compat_data; 255 } 256 257 /* 258 * int of_packagename(phandle, buf, bufsize) 259 * 260 * This routine places the last component of an OFW node's name 261 * into a user-provided buffer. 262 * 263 * It can be used during autoconfiguration to make printing of 264 * device names more informative. 265 * 266 * Arguments: 267 * phandle OFW phandle of device whose name name is 268 * desired. 269 * buf Buffer to contain device name, provided by 270 * caller. (For now, must be at least 4 271 * bytes long.) 272 * bufsize Length of buffer referenced by 'buf', in 273 * bytes. 274 * 275 * Return Value: 276 * -1 if the device path name could not be obtained or would 277 * not fit in the allocated temporary buffer, or zero otherwise 278 * (meaning that the leaf node name was successfully extracted). 279 * 280 * Side Effects: 281 * If the leaf node name was successfully extracted, 'buf' is 282 * filled in with at most 'bufsize' bytes of the leaf node 283 * name. If the leaf node was not successfully extracted, a 284 * somewhat meaningful string is placed in the buffer. In 285 * either case, the contents of 'buf' will be NUL-terminated. 286 */ 287 int 288 of_packagename(int phandle, char *buf, int bufsize) 289 { 290 char *pbuf; 291 const char *lastslash; 292 int l, rv; 293 294 pbuf = malloc(OFW_PATH_BUF_SIZE, M_TEMP, M_WAITOK); 295 l = OF_package_to_path(phandle, pbuf, OFW_PATH_BUF_SIZE); 296 297 /* check that we could get the name, and that it's not too long. */ 298 if (l < 0 || 299 (l == OFW_PATH_BUF_SIZE && pbuf[OFW_PATH_BUF_SIZE - 1] != '\0')) { 300 if (bufsize >= 25) 301 snprintf(buf, bufsize, "??? (phandle 0x%x)", phandle); 302 else if (bufsize >= 4) 303 strlcpy(buf, "???", bufsize); 304 else 305 panic("of_packagename: bufsize = %d is silly", 306 bufsize); 307 rv = -1; 308 } else { 309 pbuf[l] = '\0'; 310 lastslash = strrchr(pbuf, '/'); 311 strlcpy(buf, (lastslash == NULL) ? pbuf : (lastslash + 1), 312 bufsize); 313 rv = 0; 314 } 315 316 free(pbuf, M_TEMP); 317 return (rv); 318 } 319 320 /* 321 * Find the first child of a given node that matches name. Does not recurse. 322 */ 323 int 324 of_find_firstchild_byname(int node, const char *name) 325 { 326 char namex[32]; 327 int nn; 328 329 for (nn = OF_child(node); nn; nn = OF_peer(nn)) { 330 memset(namex, 0, sizeof(namex)); 331 if (OF_getprop(nn, "name", namex, sizeof(namex)) == -1) 332 continue; 333 if (strcmp(name, namex) == 0) 334 return nn; 335 } 336 return -1; 337 } 338 339 /* 340 * Find a give node by name. Recurses, and seems to walk upwards too. 341 */ 342 343 int 344 of_getnode_byname(int start, const char *target) 345 { 346 int node, next; 347 char name[64]; 348 349 if (start == 0) 350 start = OF_peer(0); 351 352 for (node = start; node; node = next) { 353 memset(name, 0, sizeof name); 354 OF_getprop(node, "name", name, sizeof name - 1); 355 if (strcmp(name, target) == 0) 356 break; 357 358 if ((next = OF_child(node)) != 0) 359 continue; 360 361 while (node) { 362 if ((next = OF_peer(node)) != 0) 363 break; 364 node = OF_parent(node); 365 } 366 } 367 368 /* XXX is this correct? */ 369 return node; 370 } 371 372 /* 373 * Create a uint32_t integer property from an OFW node property. 374 */ 375 376 boolean_t 377 of_to_uint32_prop(prop_dictionary_t dict, int node, const char *ofname, 378 const char *propname) 379 { 380 uint32_t prop; 381 382 if (OF_getprop(node, ofname, &prop, sizeof(prop)) != sizeof(prop)) 383 return FALSE; 384 385 return(prop_dictionary_set_uint32(dict, propname, prop)); 386 } 387 388 /* 389 * Create a data property from an OFW node property. Max size of 256bytes. 390 */ 391 392 boolean_t 393 of_to_dataprop(prop_dictionary_t dict, int node, const char *ofname, 394 const char *propname) 395 { 396 prop_data_t data; 397 int len; 398 uint8_t prop[256]; 399 boolean_t res; 400 401 len = OF_getprop(node, ofname, prop, 256); 402 if (len < 1) 403 return FALSE; 404 405 data = prop_data_create_data(prop, len); 406 res = prop_dictionary_set(dict, propname, data); 407 prop_object_release(data); 408 return res; 409 } 410 411 /* 412 * look at output-device, see if there's a Sun-typical video mode specifier as 413 * in screen:r1024x768x60 attached. If found copy it into *buffer, otherwise 414 * return NULL 415 */ 416 417 char * 418 of_get_mode_string(char *buffer, int len) 419 { 420 int options; 421 char *pos, output_device[256]; 422 423 /* 424 * finally, let's see if there's a video mode specified in 425 * output-device and pass it on so there's at least some way 426 * to program video modes 427 */ 428 options = OF_finddevice("/options"); 429 if ((options == 0) || (options == -1)) 430 return NULL; 431 if (OF_getprop(options, "output-device", output_device, 256) == 0) 432 return NULL; 433 434 /* find the mode string if there is one */ 435 pos = strstr(output_device, ":r"); 436 if (pos == NULL) 437 return NULL; 438 strncpy(buffer, pos + 2, len); 439 return buffer; 440 } 441 442 /* 443 * Iterate over the subtree of a i2c controller node. 444 * Add all sub-devices into an array as part of the controller's 445 * device properties. 446 * This is used by the i2c bus attach code to do direct configuration. 447 */ 448 void 449 of_enter_i2c_devs(prop_dictionary_t props, int ofnode, size_t cell_size, 450 int addr_shift) 451 { 452 int node, len; 453 char name[32], compatible[32]; 454 uint64_t reg64; 455 uint32_t reg32; 456 uint64_t addr; 457 prop_array_t array = NULL; 458 prop_dictionary_t dev; 459 460 for (node = OF_child(ofnode); node; node = OF_peer(node)) { 461 if (OF_getprop(node, "name", name, sizeof(name)) <= 0) 462 continue; 463 len = OF_getproplen(node, "reg"); 464 addr = 0; 465 if (cell_size == 8 && len >= sizeof(reg64)) { 466 if (OF_getprop(node, "reg", ®64, sizeof(reg64)) 467 < sizeof(reg64)) 468 continue; 469 addr = be64toh(reg64); 470 /* 471 * The i2c bus number (0 or 1) is encoded in bit 33 472 * of the register, but we encode it in bit 8 of 473 * i2c_addr_t. 474 */ 475 if (addr & 0x100000000) 476 addr = (addr & 0xff) | 0x100; 477 } else if (cell_size == 4 && len >= sizeof(reg32)) { 478 if (OF_getprop(node, "reg", ®32, sizeof(reg32)) 479 < sizeof(reg32)) 480 continue; 481 addr = be32toh(reg32); 482 } else { 483 continue; 484 } 485 addr >>= addr_shift; 486 if (addr == 0) continue; 487 488 if (array == NULL) 489 array = prop_array_create(); 490 491 dev = prop_dictionary_create(); 492 prop_dictionary_set_cstring(dev, "name", name); 493 prop_dictionary_set_uint32(dev, "addr", addr); 494 prop_dictionary_set_uint64(dev, "cookie", node); 495 of_to_dataprop(dev, node, "compatible", "compatible"); 496 if (OF_getprop(node, "compatible", compatible, 497 sizeof(compatible)) > 0) { 498 /* Set size for EEPROM's that we know about */ 499 if (strcmp(compatible, "i2c-at24c64") == 0) 500 prop_dictionary_set_uint32(dev, "size", 8192); 501 if (strcmp(compatible, "i2c-at34c02") == 0) 502 prop_dictionary_set_uint32(dev, "size", 256); 503 } 504 prop_array_add(array, dev); 505 prop_object_release(dev); 506 } 507 508 if (array != NULL) { 509 prop_dictionary_set(props, "i2c-child-devices", array); 510 prop_object_release(array); 511 } 512 513 prop_dictionary_set_bool(props, "i2c-indirect-config", false); 514 } 515 516 /* 517 * Returns true if the specified property is present. 518 */ 519 bool 520 of_hasprop(int node, const char *prop) 521 { 522 return OF_getproplen(node, prop) >= 0; 523 } 524 525 /* 526 * Get the value of a uint32 property, compensating for host byte order. 527 * Returns 0 on success, non-zero on failure. 528 */ 529 int 530 of_getprop_uint32(int node, const char *prop, uint32_t *val) 531 { 532 uint32_t v; 533 int len; 534 535 len = OF_getprop(node, prop, &v, sizeof(v)); 536 if (len != sizeof(v)) 537 return -1; 538 539 *val = be32toh(v); 540 return 0; 541 } 542