1 /* $OpenBSD: ofw_misc.c,v 1.22 2020/06/25 12:35:21 patrick Exp $ */ 2 /* 3 * Copyright (c) 2017 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/systm.h> 20 #include <sys/malloc.h> 21 22 #include <machine/bus.h> 23 24 #include <dev/ofw/openfirm.h> 25 #include <dev/ofw/ofw_gpio.h> 26 #include <dev/ofw/ofw_misc.h> 27 #include <dev/ofw/ofw_regulator.h> 28 29 /* 30 * Register maps. 31 */ 32 33 struct regmap { 34 int rm_node; 35 uint32_t rm_phandle; 36 bus_space_tag_t rm_tag; 37 bus_space_handle_t rm_handle; 38 bus_size_t rm_size; 39 40 LIST_ENTRY(regmap) rm_list; 41 }; 42 43 LIST_HEAD(, regmap) regmaps = LIST_HEAD_INITIALIZER(regmap); 44 45 void 46 regmap_register(int node, bus_space_tag_t tag, bus_space_handle_t handle, 47 bus_size_t size) 48 { 49 struct regmap *rm; 50 51 rm = malloc(sizeof(struct regmap), M_DEVBUF, M_WAITOK); 52 rm->rm_node = node; 53 rm->rm_phandle = OF_getpropint(node, "phandle", 0); 54 rm->rm_tag = tag; 55 rm->rm_handle = handle; 56 rm->rm_size = size; 57 LIST_INSERT_HEAD(®maps, rm, rm_list); 58 } 59 60 struct regmap * 61 regmap_bycompatible(char *compatible) 62 { 63 struct regmap *rm; 64 65 LIST_FOREACH(rm, ®maps, rm_list) { 66 if (OF_is_compatible(rm->rm_node, compatible)) 67 return rm; 68 } 69 70 return NULL; 71 } 72 73 struct regmap * 74 regmap_bynode(int node) 75 { 76 struct regmap *rm; 77 78 LIST_FOREACH(rm, ®maps, rm_list) { 79 if (rm->rm_node == node) 80 return rm; 81 } 82 83 return NULL; 84 } 85 86 struct regmap * 87 regmap_byphandle(uint32_t phandle) 88 { 89 struct regmap *rm; 90 91 if (phandle == 0) 92 return NULL; 93 94 LIST_FOREACH(rm, ®maps, rm_list) { 95 if (rm->rm_phandle == phandle) 96 return rm; 97 } 98 99 return NULL; 100 } 101 102 void 103 regmap_write_4(struct regmap *rm, bus_size_t offset, uint32_t value) 104 { 105 KASSERT(offset <= rm->rm_size - sizeof(uint32_t)); 106 bus_space_write_4(rm->rm_tag, rm->rm_handle, offset, value); 107 } 108 109 uint32_t 110 regmap_read_4(struct regmap *rm, bus_size_t offset) 111 { 112 KASSERT(offset <= rm->rm_size - sizeof(uint32_t)); 113 return bus_space_read_4(rm->rm_tag, rm->rm_handle, offset); 114 } 115 116 117 /* 118 * PHY support. 119 */ 120 121 LIST_HEAD(, phy_device) phy_devices = 122 LIST_HEAD_INITIALIZER(phy_devices); 123 124 void 125 phy_register(struct phy_device *pd) 126 { 127 pd->pd_cells = OF_getpropint(pd->pd_node, "#phy-cells", 0); 128 pd->pd_phandle = OF_getpropint(pd->pd_node, "phandle", 0); 129 if (pd->pd_phandle == 0) 130 return; 131 132 LIST_INSERT_HEAD(&phy_devices, pd, pd_list); 133 } 134 135 int 136 phy_usb_nop_enable(int node) 137 { 138 uint32_t vcc_supply; 139 uint32_t *gpio; 140 int len; 141 142 vcc_supply = OF_getpropint(node, "vcc-supply", 0); 143 if (vcc_supply) 144 regulator_enable(vcc_supply); 145 146 len = OF_getproplen(node, "reset-gpios"); 147 if (len <= 0) 148 return 0; 149 150 /* There should only be a single GPIO pin. */ 151 gpio = malloc(len, M_TEMP, M_WAITOK); 152 OF_getpropintarray(node, "reset-gpios", gpio, len); 153 154 gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); 155 gpio_controller_set_pin(gpio, 1); 156 delay(10000); 157 gpio_controller_set_pin(gpio, 0); 158 159 free(gpio, M_TEMP, len); 160 161 return 0; 162 } 163 164 int 165 phy_enable_cells(uint32_t *cells) 166 { 167 struct phy_device *pd; 168 uint32_t phandle = cells[0]; 169 int node; 170 171 LIST_FOREACH(pd, &phy_devices, pd_list) { 172 if (pd->pd_phandle == phandle) 173 break; 174 } 175 176 if (pd && pd->pd_enable) 177 return pd->pd_enable(pd->pd_cookie, &cells[1]); 178 179 node = OF_getnodebyphandle(phandle); 180 if (node == 0) 181 return ENXIO; 182 183 if (OF_is_compatible(node, "usb-nop-xceiv")) 184 return phy_usb_nop_enable(node); 185 186 return ENXIO; 187 } 188 189 uint32_t * 190 phy_next_phy(uint32_t *cells) 191 { 192 uint32_t phandle = cells[0]; 193 int node, ncells; 194 195 node = OF_getnodebyphandle(phandle); 196 if (node == 0) 197 return NULL; 198 199 ncells = OF_getpropint(node, "#phy-cells", 0); 200 return cells + ncells + 1; 201 } 202 203 int 204 phy_enable_idx(int node, int idx) 205 { 206 uint32_t *phys; 207 uint32_t *phy; 208 int rv = -1; 209 int len; 210 211 len = OF_getproplen(node, "phys"); 212 if (len <= 0) 213 return -1; 214 215 phys = malloc(len, M_TEMP, M_WAITOK); 216 OF_getpropintarray(node, "phys", phys, len); 217 218 phy = phys; 219 while (phy && phy < phys + (len / sizeof(uint32_t))) { 220 if (idx <= 0) 221 rv = phy_enable_cells(phy); 222 if (idx == 0) 223 break; 224 phy = phy_next_phy(phy); 225 idx--; 226 } 227 228 free(phys, M_TEMP, len); 229 return rv; 230 } 231 232 int 233 phy_enable(int node, const char *name) 234 { 235 int idx; 236 237 idx = OF_getindex(node, name, "phy-names"); 238 if (idx == -1) 239 return -1; 240 241 return phy_enable_idx(node, idx); 242 } 243 244 /* 245 * I2C support. 246 */ 247 248 LIST_HEAD(, i2c_bus) i2c_busses = 249 LIST_HEAD_INITIALIZER(i2c_bus); 250 251 void 252 i2c_register(struct i2c_bus *ib) 253 { 254 ib->ib_phandle = OF_getpropint(ib->ib_node, "phandle", 0); 255 if (ib->ib_phandle == 0) 256 return; 257 258 LIST_INSERT_HEAD(&i2c_busses, ib, ib_list); 259 } 260 261 struct i2c_controller * 262 i2c_bynode(int node) 263 { 264 struct i2c_bus *ib; 265 266 LIST_FOREACH(ib, &i2c_busses, ib_list) { 267 if (ib->ib_node == node) 268 return ib->ib_ic; 269 } 270 271 return NULL; 272 } 273 274 struct i2c_controller * 275 i2c_byphandle(uint32_t phandle) 276 { 277 struct i2c_bus *ib; 278 279 if (phandle == 0) 280 return NULL; 281 282 LIST_FOREACH(ib, &i2c_busses, ib_list) { 283 if (ib->ib_phandle == phandle) 284 return ib->ib_ic; 285 } 286 287 return NULL; 288 } 289 290 /* 291 * SFP support. 292 */ 293 294 LIST_HEAD(, sfp_device) sfp_devices = 295 LIST_HEAD_INITIALIZER(sfp_devices); 296 297 void 298 sfp_register(struct sfp_device *sd) 299 { 300 sd->sd_phandle = OF_getpropint(sd->sd_node, "phandle", 0); 301 if (sd->sd_phandle == 0) 302 return; 303 304 LIST_INSERT_HEAD(&sfp_devices, sd, sd_list); 305 } 306 307 int 308 sfp_get_sffpage(uint32_t phandle, struct if_sffpage *sff) 309 { 310 struct sfp_device *sd; 311 312 if (phandle == 0) 313 return ENXIO; 314 315 LIST_FOREACH(sd, &sfp_devices, sd_list) { 316 if (sd->sd_phandle == phandle) 317 return sd->sd_get_sffpage(sd->sd_cookie, sff); 318 } 319 320 return ENXIO; 321 } 322 323 /* 324 * PWM support. 325 */ 326 327 LIST_HEAD(, pwm_device) pwm_devices = 328 LIST_HEAD_INITIALIZER(pwm_devices); 329 330 void 331 pwm_register(struct pwm_device *pd) 332 { 333 pd->pd_cells = OF_getpropint(pd->pd_node, "#pwm-cells", 0); 334 pd->pd_phandle = OF_getpropint(pd->pd_node, "phandle", 0); 335 if (pd->pd_phandle == 0) 336 return; 337 338 LIST_INSERT_HEAD(&pwm_devices, pd, pd_list); 339 340 } 341 342 int 343 pwm_init_state(uint32_t *cells, struct pwm_state *ps) 344 { 345 struct pwm_device *pd; 346 347 LIST_FOREACH(pd, &pwm_devices, pd_list) { 348 if (pd->pd_phandle == cells[0]) { 349 memset(ps, 0, sizeof(struct pwm_state)); 350 pd->pd_get_state(pd->pd_cookie, &cells[1], ps); 351 ps->ps_pulse_width = 0; 352 if (pd->pd_cells >= 2) 353 ps->ps_period = cells[2]; 354 if (pd->pd_cells >= 3) 355 ps->ps_flags = cells[3]; 356 return 0; 357 } 358 } 359 360 return ENXIO; 361 } 362 363 int 364 pwm_get_state(uint32_t *cells, struct pwm_state *ps) 365 { 366 struct pwm_device *pd; 367 368 LIST_FOREACH(pd, &pwm_devices, pd_list) { 369 if (pd->pd_phandle == cells[0]) 370 return pd->pd_get_state(pd->pd_cookie, &cells[1], ps); 371 } 372 373 return ENXIO; 374 } 375 376 int 377 pwm_set_state(uint32_t *cells, struct pwm_state *ps) 378 { 379 struct pwm_device *pd; 380 381 LIST_FOREACH(pd, &pwm_devices, pd_list) { 382 if (pd->pd_phandle == cells[0]) 383 return pd->pd_set_state(pd->pd_cookie, &cells[1], ps); 384 } 385 386 return ENXIO; 387 } 388 389 /* 390 * Non-volatile memory support. 391 */ 392 393 LIST_HEAD(, nvmem_device) nvmem_devices = 394 LIST_HEAD_INITIALIZER(nvmem_devices); 395 396 struct nvmem_cell { 397 uint32_t nc_phandle; 398 struct nvmem_device *nc_nd; 399 bus_addr_t nc_addr; 400 bus_size_t nc_size; 401 402 LIST_ENTRY(nvmem_cell) nc_list; 403 }; 404 405 LIST_HEAD(, nvmem_cell) nvmem_cells = 406 LIST_HEAD_INITIALIZER(nvmem_cells); 407 408 void 409 nvmem_register_child(int node, struct nvmem_device *nd) 410 { 411 struct nvmem_cell *nc; 412 uint32_t phandle; 413 uint32_t reg[2]; 414 415 phandle = OF_getpropint(node, "phandle", 0); 416 if (phandle == 0) 417 return; 418 419 if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg)) 420 return; 421 422 nc = malloc(sizeof(struct nvmem_cell), M_DEVBUF, M_WAITOK); 423 nc->nc_phandle = phandle; 424 nc->nc_nd = nd; 425 nc->nc_addr = reg[0]; 426 nc->nc_size = reg[1]; 427 LIST_INSERT_HEAD(&nvmem_cells, nc, nc_list); 428 } 429 430 void 431 nvmem_register(struct nvmem_device *nd) 432 { 433 int node; 434 435 nd->nd_phandle = OF_getpropint(nd->nd_node, "phandle", 0); 436 if (nd->nd_phandle) 437 LIST_INSERT_HEAD(&nvmem_devices, nd, nd_list); 438 439 for (node = OF_child(nd->nd_node); node; node = OF_peer(node)) 440 nvmem_register_child(node, nd); 441 } 442 443 int 444 nvmem_read(uint32_t phandle, bus_addr_t addr, void *data, bus_size_t size) 445 { 446 struct nvmem_device *nd; 447 448 if (phandle == 0) 449 return ENXIO; 450 451 LIST_FOREACH(nd, &nvmem_devices, nd_list) { 452 if (nd->nd_phandle == phandle) 453 return nd->nd_read(nd->nd_cookie, addr, data, size); 454 } 455 456 return ENXIO; 457 } 458 459 int 460 nvmem_read_cell(int node, const char *name, void *data, bus_size_t size) 461 { 462 struct nvmem_device *nd; 463 struct nvmem_cell *nc; 464 uint32_t phandle, *phandles; 465 int id, len; 466 467 id = OF_getindex(node, name, "nvmem-cell-names"); 468 if (id < 0) 469 return ENXIO; 470 471 len = OF_getproplen(node, "nvmem-cells"); 472 if (len <= 0) 473 return ENXIO; 474 475 phandles = malloc(len, M_TEMP, M_WAITOK); 476 OF_getpropintarray(node, "nvmem-cells", phandles, len); 477 phandle = phandles[id]; 478 free(phandles, M_TEMP, len); 479 480 LIST_FOREACH(nc, &nvmem_cells, nc_list) { 481 if (nc->nc_phandle == phandle) 482 break; 483 } 484 if (nc == NULL) 485 return ENXIO; 486 487 if (size > nc->nc_size) 488 return EINVAL; 489 490 nd = nc->nc_nd; 491 return nd->nd_read(nd->nd_cookie, nc->nc_addr, data, size); 492 } 493 494 /* Port/endpoint interface support */ 495 496 LIST_HEAD(, endpoint) endpoints = 497 LIST_HEAD_INITIALIZER(endpoints); 498 499 void 500 endpoint_register(int node, struct device_port *dp, enum endpoint_type type) 501 { 502 struct endpoint *ep; 503 504 ep = malloc(sizeof(*ep), M_DEVBUF, M_WAITOK); 505 ep->ep_node = node; 506 ep->ep_phandle = OF_getpropint(node, "phandle", 0); 507 ep->ep_reg = OF_getpropint(node, "reg", -1); 508 ep->ep_port = dp; 509 ep->ep_type = type; 510 511 LIST_INSERT_HEAD(&endpoints, ep, ep_list); 512 LIST_INSERT_HEAD(&dp->dp_endpoints, ep, ep_plist); 513 } 514 515 void 516 device_port_register(int node, struct device_ports *ports, 517 enum endpoint_type type) 518 { 519 struct device_port *dp; 520 521 dp = malloc(sizeof(*dp), M_DEVBUF, M_WAITOK); 522 dp->dp_node = node; 523 dp->dp_phandle = OF_getpropint(node, "phandle", 0); 524 dp->dp_reg = OF_getpropint(node, "reg", -1); 525 dp->dp_ports = ports; 526 LIST_INIT(&dp->dp_endpoints); 527 for (node = OF_child(node); node; node = OF_peer(node)) 528 endpoint_register(node, dp, type); 529 530 LIST_INSERT_HEAD(&ports->dp_ports, dp, dp_list); 531 } 532 533 void 534 device_ports_register(struct device_ports *ports, 535 enum endpoint_type type) 536 { 537 int node; 538 539 LIST_INIT(&ports->dp_ports); 540 541 node = OF_getnodebyname(ports->dp_node, "ports"); 542 if (node == 0) { 543 node = OF_getnodebyname(ports->dp_node, "port"); 544 if (node == 0) 545 return; 546 547 device_port_register(node, ports, type); 548 return; 549 } 550 551 for (node = OF_child(node); node; node = OF_peer(node)) 552 device_port_register(node, ports, type); 553 } 554 555 struct endpoint * 556 endpoint_byphandle(uint32_t phandle) 557 { 558 struct endpoint *ep; 559 560 if (phandle == 0) 561 return NULL; 562 563 LIST_FOREACH(ep, &endpoints, ep_list) { 564 if (ep->ep_phandle == phandle) 565 return ep; 566 } 567 568 return NULL; 569 } 570 571 struct endpoint * 572 endpoint_byreg(struct device_ports *ports, uint32_t dp_reg, uint32_t ep_reg) 573 { 574 struct device_port *dp; 575 struct endpoint *ep; 576 577 LIST_FOREACH(dp, &ports->dp_ports, dp_list) { 578 if (dp->dp_reg != dp_reg) 579 continue; 580 LIST_FOREACH(ep, &dp->dp_endpoints, ep_list) { 581 if (ep->ep_reg != ep_reg) 582 continue; 583 return ep; 584 } 585 } 586 587 return NULL; 588 } 589 590 struct endpoint * 591 endpoint_remote(struct endpoint *ep) 592 { 593 struct endpoint *rep; 594 int phandle; 595 596 phandle = OF_getpropint(ep->ep_node, "remote-endpoint", 0); 597 if (phandle == 0) 598 return NULL; 599 600 LIST_FOREACH(rep, &endpoints, ep_list) { 601 if (rep->ep_phandle == phandle) 602 return rep; 603 } 604 605 return NULL; 606 } 607 608 int 609 endpoint_activate(struct endpoint *ep, void *arg) 610 { 611 struct device_ports *ports = ep->ep_port->dp_ports; 612 return ports->dp_ep_activate(ports->dp_cookie, ep, arg); 613 } 614 615 void * 616 endpoint_get_cookie(struct endpoint *ep) 617 { 618 struct device_ports *ports = ep->ep_port->dp_ports; 619 return ports->dp_ep_get_cookie(ports->dp_cookie, ep); 620 } 621 622 int 623 device_port_activate(uint32_t phandle, void *arg) 624 { 625 struct device_port *dp = NULL; 626 struct endpoint *ep, *rep; 627 int count; 628 int error; 629 630 if (phandle == 0) 631 return ENXIO; 632 633 LIST_FOREACH(ep, &endpoints, ep_list) { 634 if (ep->ep_port->dp_phandle == phandle) { 635 dp = ep->ep_port; 636 break; 637 } 638 } 639 if (dp == NULL) 640 return ENXIO; 641 642 count = 0; 643 LIST_FOREACH(ep, &dp->dp_endpoints, ep_plist) { 644 rep = endpoint_remote(ep); 645 if (rep == NULL) 646 continue; 647 648 error = endpoint_activate(ep, arg); 649 if (error) 650 continue; 651 error = endpoint_activate(rep, arg); 652 if (error) 653 continue; 654 count++; 655 } 656 657 return count ? 0 : ENXIO; 658 } 659 660 /* Digital audio interface support */ 661 662 LIST_HEAD(, dai_device) dai_devices = 663 LIST_HEAD_INITIALIZER(dai_devices); 664 665 void 666 dai_register(struct dai_device *dd) 667 { 668 dd->dd_phandle = OF_getpropint(dd->dd_node, "phandle", 0); 669 if (dd->dd_phandle == 0) 670 return; 671 672 LIST_INSERT_HEAD(&dai_devices, dd, dd_list); 673 } 674 675 struct dai_device * 676 dai_byphandle(uint32_t phandle) 677 { 678 struct dai_device *dd; 679 680 if (phandle == 0) 681 return NULL; 682 683 LIST_FOREACH(dd, &dai_devices, dd_list) { 684 if (dd->dd_phandle == phandle) 685 return dd; 686 } 687 688 return NULL; 689 } 690 691 /* MII support */ 692 693 LIST_HEAD(, mii_bus) mii_busses = 694 LIST_HEAD_INITIALIZER(mii_busses); 695 696 void 697 mii_register(struct mii_bus *md) 698 { 699 LIST_INSERT_HEAD(&mii_busses, md, md_list); 700 } 701 702 struct mii_bus * 703 mii_byphandle(uint32_t phandle) 704 { 705 struct mii_bus *md; 706 int node; 707 708 if (phandle == 0) 709 return NULL; 710 711 node = OF_getnodebyphandle(phandle); 712 if (node == 0) 713 return NULL; 714 715 node = OF_parent(node); 716 if (node == 0) 717 return NULL; 718 719 LIST_FOREACH(md, &mii_busses, md_list) { 720 if (md->md_node == node) 721 return md; 722 } 723 724 return NULL; 725 } 726