diff options
Diffstat (limited to 'sys/dev/ofw/ofw_misc.c')
-rw-r--r-- | sys/dev/ofw/ofw_misc.c | 168 |
1 files changed, 135 insertions, 33 deletions
diff --git a/sys/dev/ofw/ofw_misc.c b/sys/dev/ofw/ofw_misc.c index 880457d93d1..53f3aa89685 100644 --- a/sys/dev/ofw/ofw_misc.c +++ b/sys/dev/ofw/ofw_misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_misc.c,v 1.14 2020/03/01 18:00:12 kettenis Exp $ */ +/* $OpenBSD: ofw_misc.c,v 1.15 2020/03/16 21:51:26 kettenis Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -440,57 +440,159 @@ nvmem_read_cell(int node, const char *name, void *data, bus_size_t size) return nd->nd_read(nd->nd_cookie, nc->nc_addr, data, size); } -/* Video interface support */ +/* Port/endpoint interface support */ -LIST_HEAD(, video_device) video_devices = - LIST_HEAD_INITIALIZER(video_devices); +LIST_HEAD(, endpoint) endpoints = + LIST_HEAD_INITIALIZER(endpoints); void -video_register(struct video_device *vd) +endpoint_register(int node, struct device_port *dp, enum endpoint_type type) { - vd->vd_phandle = OF_getpropint(vd->vd_node, "phandle", 0); - if (vd->vd_phandle == 0) + struct endpoint *ep; + + ep = malloc(sizeof(*ep), M_DEVBUF, M_WAITOK); + ep->ep_node = node; + ep->ep_phandle = OF_getpropint(node, "phandle", 0); + ep->ep_reg = OF_getpropint(node, "reg", -1); + ep->ep_port = dp; + ep->ep_type = type; + + LIST_INSERT_HEAD(&endpoints, ep, ep_list); + LIST_INSERT_HEAD(&dp->dp_endpoints, ep, ep_plist); +} + +void +device_port_register(int node, struct device_ports *ports, + enum endpoint_type type) +{ + struct device_port *dp; + + dp = malloc(sizeof(*dp), M_DEVBUF, M_WAITOK); + dp->dp_node = node; + dp->dp_phandle = OF_getpropint(node, "phandle", 0); + dp->dp_reg = OF_getpropint(node, "reg", -1); + dp->dp_ports = ports; + LIST_INIT(&dp->dp_endpoints); + for (node = OF_child(node); node; node = OF_peer(node)) + endpoint_register(node, dp, type); + + LIST_INSERT_HEAD(&ports->dp_ports, dp, dp_list); +} + +void +device_ports_register(struct device_ports *ports, + enum endpoint_type type) +{ + int node; + + LIST_INIT(&ports->dp_ports); + + node = OF_getnodebyname(ports->dp_node, "ports"); + if (node == 0) { + node = OF_getnodebyname(ports->dp_node, "port"); + if (node == 0) + return; + + device_port_register(node, ports, type); return; - LIST_INSERT_HEAD(&video_devices, vd, vd_list); + } + + for (node = OF_child(node); node; node = OF_peer(node)) + device_port_register(node, ports, type); } -int -video_port_activate(uint32_t phandle, struct drm_device *ddev) +struct endpoint * +endpoint_byphandle(uint32_t phandle) { - uint32_t ep, rep; - int node, error; + struct endpoint *ep; - node = OF_getnodebyphandle(phandle); - if (node == 0) - return ENXIO; + LIST_FOREACH(ep, &endpoints, ep_list) { + if (ep->ep_phandle == phandle) + return ep; + } - for (node = OF_child(node); node; node = OF_peer(node)) { - ep = OF_getpropint(node, "phandle", 0); - rep = OF_getpropint(node, "remote-endpoint", 0); - if (ep == 0 || rep == 0) - continue; - error = video_endpoint_activate(ep, ddev); - if (error) - continue; - error = video_endpoint_activate(rep, ddev); - if (error) + return NULL; +} + +struct endpoint * +endpoint_byreg(struct device_ports *ports, uint32_t dp_reg, uint32_t ep_reg) +{ + struct device_port *dp; + struct endpoint *ep; + + LIST_FOREACH(dp, &ports->dp_ports, dp_list) { + if (dp->dp_reg != dp_reg) continue; + LIST_FOREACH(ep, &dp->dp_endpoints, ep_list) { + if (ep->ep_reg != ep_reg) + continue; + return ep; + } + } + + return NULL; +} + +struct endpoint * +endpoint_remote(struct endpoint *ep) +{ + struct endpoint *rep; + int phandle; + + phandle = OF_getpropint(ep->ep_node, "remote-endpoint", 0); + if (phandle == 0) + return NULL; + + LIST_FOREACH(rep, &endpoints, ep_list) { + if (rep->ep_phandle == phandle) + return rep; } - return 0; + return NULL; } int -video_endpoint_activate(uint32_t phandle, struct drm_device *ddev) +endpoint_activate(struct endpoint *ep, void *arg) +{ + struct device_ports *ports = ep->ep_port->dp_ports; + return ports->dp_ep_activate(ports->dp_cookie, ep, arg); +} + +void * +endpoint_get_cookie(struct endpoint *ep) { - struct video_device *vd; + struct device_ports *ports = ep->ep_port->dp_ports; + return ports->dp_ep_get_cookie(ports->dp_cookie, ep); +} - LIST_FOREACH(vd, &video_devices, vd_list) { - if (vd->vd_phandle == phandle) +void +device_port_activate(uint32_t phandle, void *arg) +{ + struct device_ports *ports; + struct device_port *dp; + struct endpoint *ep, *rep; + int error; + + LIST_FOREACH(ep, &endpoints, ep_list) { + if (ep->ep_port->dp_phandle == phandle) { + dp = ep->ep_port; break; + } } - if (vd == NULL) - return ENXIO; + if (dp == NULL) + return; - return vd->vd_ep_activate(vd->vd_cookie, ddev); + ports = dp->dp_ports; + LIST_FOREACH(ep, &dp->dp_endpoints, ep_plist) { + rep = endpoint_remote(ep); + if (rep == NULL) + continue; + + error = endpoint_activate(ep, arg); + if (error) + continue; + error = endpoint_activate(rep, arg); + if (error) + continue; + } } |