static int sun8i_mixer_of_get_id(struct device_node *node) { struct device_node *port, *ep; int ret = -EINVAL; /* output is port 1 */ port = of_graph_get_port_by_id(node, 1); if (!port) return -EINVAL; /* try to find downstream endpoint */ for_each_available_child_of_node(port, ep) { struct device_node *remote; u32 reg; remote = of_graph_get_remote_endpoint(ep); if (!remote) continue; ret = of_property_read_u32(remote, "reg", ®); if (!ret) { of_node_put(remote); of_node_put(ep); of_node_put(port); return reg; } of_node_put(remote); } of_node_put(port); return ret; }
static void sun4i_drv_traverse_endpoints(struct endpoint_list *list, struct device_node *node, int port_id) { struct device_node *ep, *remote, *port; port = of_graph_get_port_by_id(node, port_id); if (!port) { DRM_DEBUG_DRIVER("No output to bind on port %d\n", port_id); return; } for_each_available_child_of_node(port, ep) { remote = of_graph_get_remote_port_parent(ep); if (!remote) { DRM_DEBUG_DRIVER("Error retrieving the output node\n"); continue; } if (sun4i_drv_node_is_tcon(node)) { /* * TCON TOP is always probed before TCON. However, TCON * points back to TCON TOP when it is source for HDMI. * We have to skip it here to prevent infinite looping * between TCON TOP and TCON. */ if (sun4i_drv_node_is_tcon_top(remote)) { DRM_DEBUG_DRIVER("TCON output endpoint is TCON TOP... skipping\n"); of_node_put(remote); continue; } /* * If the node is our TCON with channel 0, the first * port is used for panel or bridges, and will not be * part of the component framework. */ if (sun4i_drv_node_is_tcon_with_ch0(node)) { struct of_endpoint endpoint; if (of_graph_parse_endpoint(ep, &endpoint)) { DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); of_node_put(remote); continue; } if (!endpoint.id) { DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); of_node_put(remote); continue; } } } kfifo_put(&list->fifo, remote); }
static int imx_pd_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = data; struct device_node *np = dev->of_node; struct device_node *port; const u8 *edidp; struct imx_parallel_display *imxpd; int ret; const char *fmt; imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); if (!imxpd) return -ENOMEM; edidp = of_get_property(np, "edid", &imxpd->edid_len); if (edidp) imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL); ret = of_property_read_string(np, "interface-pix-fmt", &fmt); if (!ret) { if (!strcmp(fmt, "rgb24")) imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24; else if (!strcmp(fmt, "rgb565")) imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16; else if (!strcmp(fmt, "bgr666")) imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18; else if (!strcmp(fmt, "lvds666")) imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; } /* port@1 is the output port */ port = of_graph_get_port_by_id(np, 1); if (port) { struct device_node *endpoint, *remote; endpoint = of_get_child_by_name(port, "endpoint"); if (endpoint) { remote = of_graph_get_remote_port_parent(endpoint); if (remote) imxpd->panel = of_drm_find_panel(remote); if (!imxpd->panel) return -EPROBE_DEFER; } } imxpd->dev = dev; ret = imx_pd_register(drm, imxpd); if (ret) return ret; dev_set_drvdata(dev, imxpd); return 0; }
static int rockchip_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *panel_node, *port, *endpoint; struct rockchip_dp_device *dp; struct drm_panel *panel; port = of_graph_get_port_by_id(dev->of_node, 1); if (!port) { dev_err(dev, "can't find output port\n"); return -EINVAL; } endpoint = of_get_child_by_name(port, "endpoint"); of_node_put(port); if (!endpoint) { dev_err(dev, "no output endpoint found\n"); return -EINVAL; } panel_node = of_graph_get_remote_port_parent(endpoint); of_node_put(endpoint); if (!panel_node) { dev_err(dev, "no output node found\n"); return -EINVAL; } panel = of_drm_find_panel(panel_node); if (!panel) { DRM_ERROR("failed to find panel\n"); of_node_put(panel_node); return -EPROBE_DEFER; } of_node_put(panel_node); dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); if (!dp) return -ENOMEM; dp->dev = dev; dp->plat_data.panel = panel; /* * We just use the drvdata until driver run into component * add function, and then we would set drvdata to null, so * that analogix dp driver could take charge of the drvdata. */ platform_set_drvdata(pdev, dp); return component_add(dev, &rockchip_dp_component_ops); }
static int imx7_csi_get_upstream_endpoint(struct imx7_csi *csi, struct v4l2_fwnode_endpoint *ep, bool skip_mux) { struct device_node *endpoint, *port; struct media_entity *src; struct v4l2_subdev *sd; struct media_pad *pad; if (!csi->src_sd) return -EPIPE; src = &csi->src_sd->entity; skip_video_mux: /* get source pad of entity directly upstream from src */ pad = imx_media_pipeline_pad(src, 0, 0, true); if (IS_ERR(pad)) return PTR_ERR(pad); sd = media_entity_to_v4l2_subdev(pad->entity); /* To get bus type we may need to skip video mux */ if (skip_mux && src->function == MEDIA_ENT_F_VID_MUX) { src = &sd->entity; goto skip_video_mux; } /* * NOTE: this assumes an OF-graph port id is the same as a * media pad index. */ port = of_graph_get_port_by_id(sd->dev->of_node, pad->index); if (!port) return -ENODEV; endpoint = of_get_next_child(port, NULL); of_node_put(port); if (!endpoint) return -ENODEV; v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), ep); of_node_put(endpoint); return 0; }
struct rockchip_rgb *rockchip_rgb_init(struct device *dev, struct drm_crtc *crtc, struct drm_device *drm_dev) { struct rockchip_rgb *rgb; struct drm_encoder *encoder; struct device_node *port, *endpoint; u32 endpoint_id; int ret = 0, child_count = 0; struct drm_panel *panel; struct drm_bridge *bridge; rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL); if (!rgb) return ERR_PTR(-ENOMEM); rgb->dev = dev; rgb->drm_dev = drm_dev; port = of_graph_get_port_by_id(dev->of_node, 0); if (!port) return ERR_PTR(-EINVAL); for_each_child_of_node(port, endpoint) { if (of_property_read_u32(endpoint, "reg", &endpoint_id)) endpoint_id = 0; if (rockchip_drm_endpoint_is_subdriver(endpoint) > 0) continue; child_count++; ret = drm_of_find_panel_or_bridge(dev->of_node, 0, endpoint_id, &panel, &bridge); if (!ret) { of_node_put(endpoint); break; } } of_node_put(port); /* if the rgb output is not connected to anything, just return */ if (!child_count) return NULL; if (ret < 0) { if (ret != -EPROBE_DEFER) DRM_DEV_ERROR(dev, "failed to find panel or bridge %d\n", ret); return ERR_PTR(ret); } encoder = &rgb->encoder; encoder->possible_crtcs = drm_crtc_mask(crtc); ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); if (ret < 0) { DRM_DEV_ERROR(drm_dev->dev, "failed to initialize encoder: %d\n", ret); return ERR_PTR(ret); } drm_encoder_helper_add(encoder, &rockchip_rgb_encoder_helper_funcs); if (panel) { bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_LVDS); if (IS_ERR(bridge)) return ERR_CAST(bridge); } rgb->bridge = bridge; ret = drm_bridge_attach(encoder, rgb->bridge, NULL); if (ret) { DRM_DEV_ERROR(drm_dev->dev, "failed to attach bridge: %d\n", ret); goto err_free_encoder; } return rgb; err_free_encoder: drm_encoder_cleanup(encoder); return ERR_PTR(ret); }
static int sun4i_drv_add_endpoints(struct device *dev, struct component_match **match, struct device_node *node) { struct device_node *port, *ep, *remote; int count = 0; /* * We don't support the frontend for now, so we will never * have a device bound. Just skip over it, but we still want * the rest our pipeline to be added. */ if (!sun4i_drv_node_is_frontend(node) && !of_device_is_available(node)) return 0; if (!sun4i_drv_node_is_frontend(node)) { /* Add current component */ DRM_DEBUG_DRIVER("Adding component %s\n", of_node_full_name(node)); drm_of_component_match_add(dev, match, compare_of, node); count++; } /* Inputs are listed first, then outputs */ port = of_graph_get_port_by_id(node, 1); if (!port) { DRM_DEBUG_DRIVER("No output to bind\n"); return count; } for_each_available_child_of_node(port, ep) { remote = of_graph_get_remote_port_parent(ep); if (!remote) { DRM_DEBUG_DRIVER("Error retrieving the output node\n"); of_node_put(remote); continue; } /* * If the node is our TCON, the first port is used for * panel or bridges, and will not be part of the * component framework. */ if (sun4i_drv_node_is_tcon(node)) { struct of_endpoint endpoint; if (of_graph_parse_endpoint(ep, &endpoint)) { DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); continue; } if (!endpoint.id) { DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); continue; } } /* Walk down our tree */ count += sun4i_drv_add_endpoints(dev, match, remote); of_node_put(remote); }
static int hdlcd_drm_bind(struct device *dev) { struct drm_device *drm; struct hdlcd_drm_private *hdlcd; int ret; hdlcd = devm_kzalloc(dev, sizeof(*hdlcd), GFP_KERNEL); if (!hdlcd) return -ENOMEM; drm = drm_dev_alloc(&hdlcd_driver, dev); if (IS_ERR(drm)) return PTR_ERR(drm); drm->dev_private = hdlcd; dev_set_drvdata(dev, drm); hdlcd_setup_mode_config(drm); ret = hdlcd_load(drm, 0); if (ret) goto err_free; /* Set the CRTC's port so that the encoder component can find it */ hdlcd->crtc.port = of_graph_get_port_by_id(dev->of_node, 0); ret = component_bind_all(dev, drm); if (ret) { DRM_ERROR("Failed to bind all components\n"); goto err_unload; } ret = pm_runtime_set_active(dev); if (ret) goto err_pm_active; pm_runtime_enable(dev); ret = drm_vblank_init(drm, drm->mode_config.num_crtc); if (ret < 0) { DRM_ERROR("failed to initialise vblank\n"); goto err_vblank; } drm_mode_config_reset(drm); drm_kms_helper_poll_init(drm); hdlcd->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_connector); if (IS_ERR(hdlcd->fbdev)) { ret = PTR_ERR(hdlcd->fbdev); hdlcd->fbdev = NULL; goto err_fbdev; } ret = drm_dev_register(drm, 0); if (ret) goto err_register; return 0; err_register: if (hdlcd->fbdev) { drm_fbdev_cma_fini(hdlcd->fbdev); hdlcd->fbdev = NULL; } err_fbdev: drm_kms_helper_poll_fini(drm); err_vblank: pm_runtime_disable(drm->dev); err_pm_active: component_unbind_all(dev, drm); err_unload: of_node_put(hdlcd->crtc.port); hdlcd->crtc.port = NULL; drm_irq_uninstall(drm); of_reserved_mem_device_release(drm->dev); err_free: drm_mode_config_cleanup(drm); dev_set_drvdata(dev, NULL); drm_dev_put(drm); return ret; }