xref: /openbsd-src/sys/dev/ofw/ofw_misc.c (revision 505ee9ea3b177e2387d907a91ca7da069f3f14d8)
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(&regmaps, rm, rm_list);
58 }
59 
60 struct regmap *
61 regmap_bycompatible(char *compatible)
62 {
63 	struct regmap *rm;
64 
65 	LIST_FOREACH(rm, &regmaps, 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, &regmaps, 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, &regmaps, 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