diff options
Diffstat (limited to 'sys/dev/ofw')
-rw-r--r-- | sys/dev/ofw/ofw_misc.c | 168 | ||||
-rw-r--r-- | sys/dev/ofw/ofw_misc.h | 58 |
2 files changed, 178 insertions, 48 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; + } } diff --git a/sys/dev/ofw/ofw_misc.h b/sys/dev/ofw/ofw_misc.h index 35a9b15c1a0..8dc20e9c33b 100644 --- a/sys/dev/ofw/ofw_misc.h +++ b/sys/dev/ofw/ofw_misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_misc.h,v 1.10 2020/02/21 15:46:16 patrick Exp $ */ +/* $OpenBSD: ofw_misc.h,v 1.11 2020/03/16 21:51:26 kettenis Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -129,24 +129,52 @@ void nvmem_register(struct nvmem_device *); int nvmem_read(uint32_t, bus_addr_t, void *, bus_size_t); int nvmem_read_cell(int, const char *name, void *, bus_size_t); -/* Video interface support */ +/* Port/endpoint interface support */ -struct drm_device; -struct video_device { - int vd_node; - void *vd_cookie; - int (*vd_read)(void *, bus_addr_t, void *, bus_size_t); +struct endpoint; - int (*vd_ep_activate)(void *, struct drm_device *); - void * (*vd_ep_get_data)(void *); +struct device_ports { + int dp_node; + void *dp_cookie; - LIST_ENTRY(video_device) vd_list; - uint32_t vd_phandle; + int (*dp_ep_activate)(void *, struct endpoint *, void *); + void *(*dp_ep_get_cookie)(void *, struct endpoint *); + + LIST_HEAD(, device_port) dp_ports; +}; + +struct device_port { + int dp_node; + uint32_t dp_phandle; + uint32_t dp_reg; + struct device_ports *dp_ports; + LIST_ENTRY(device_port) dp_list; + LIST_HEAD(, endpoint) dp_endpoints; +}; + +enum endpoint_type { + EP_DRM_BRIDGE = 1, /* struct drm_bridge */ + EP_DRM_CONNECTOR, /* struct drm_connector */ + EP_DRM_CRTC, /* struct drm_crtc */ + EP_DRM_ENCODER, /* struct drm_encoder */ + EP_DRM_PANEL, /* struct drm_panel */ +}; + +struct endpoint { + int ep_node; + uint32_t ep_phandle; + uint32_t ep_reg; + enum endpoint_type ep_type; + struct device_port *ep_port; + LIST_ENTRY(endpoint) ep_list; + LIST_ENTRY(endpoint) ep_plist; }; -void video_register(struct video_device *); -int video_port_activate(uint32_t, struct drm_device *); -int video_endpoint_activate(uint32_t, struct drm_device *); -void * video_endpoint_get_data(uint32_t); +void device_ports_register(struct device_ports *, enum endpoint_type); +void device_port_activate(uint32_t, void *); +struct endpoint *endpoint_byreg(struct device_ports *, uint32_t, uint32_t); +struct endpoint *endpoint_remote(struct endpoint *); +int endpoint_activate(struct endpoint *, void *); +void *endpoint_get_cookie(struct endpoint *); #endif /* _DEV_OFW_MISC_H_ */ |