/* * The encoder drivers use drm_of_find_possible_crtcs to get upstream * crtcs from the device tree using of_graph. For the results to be * correct, encoders must be probed/bound after _all_ crtcs have been * created. The existing code uses a depth first recursive traversal * of the of_graph, which means the encoders downstream of the TCON * get add right after the first TCON. The second TCON or CRTC will * never be properly associated with encoders connected to it. * * Also, in a dual display pipeline setup, both frontends can feed * either backend, and both backends can feed either TCON, we want * all components of the same type to be added before the next type * in the pipeline. Fortunately, the pipelines are perfectly symmetric, * i.e. components of the same type are at the same depth when counted * from the frontend. The only exception is the third pipeline in * the A80 SoC, which we do not support anyway. * * Hence we can use a breadth first search traversal order to add * components. We do not need to check for duplicates. The component * matching system handles this for us.
*/ struct endpoint_list {
DECLARE_KFIFO(fifo, struct device_node *, 16);
};
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;
}
}
}
/* * The frontend has been disabled in some of our old device * trees. If we find a node that is the frontend and is * disabled, we should just follow through and parse its * child, but without adding it to the component list. * Otherwise, we obviously want to add it to the list.
*/ if (!sun4i_drv_node_is_frontend(node) &&
!of_device_is_available(node)) return 0;
/* * The connectors will be the last nodes in our pipeline, we * can just bail out.
*/ if (sun4i_drv_node_is_connector(node)) return 0;
/* * If the device is either just a regular device, or an * enabled frontend supported by the driver, we add it to our * component list.
*/ if (!(sun4i_drv_node_is_frontend(node) ||
sun4i_drv_node_is_deu(node)) ||
(sun4i_drv_node_is_supported_frontend(node) &&
of_device_is_available(node))) { /* Add current component */
DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
drm_of_component_match_add(dev, match, component_compare_of, node);
count++;
}
/* each node has at least one output */
sun4i_drv_traverse_endpoints(list, node, 1);
/* TCON TOP has second and third output */ if (sun4i_drv_node_is_tcon_top(node)) {
sun4i_drv_traverse_endpoints(list, node, 3);
sun4i_drv_traverse_endpoints(list, node, 5);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.