Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm: dsi host: Use device graph parsing to parse connected panel

The dsi host looks for the connected panel node by parsing for a child
named 'panel'. This hierarchy isn't very flexible. The connected
panel is forced to be a child to the dsi host, and hence, a mipi dsi
device. This isn't suitable for dsi devices that don't use mipi dsi
as their control bus.

Follow the of_graph approach of creating ports and endpoints to
represent the connections between the dsi host and the panel connected
to it. In our case, the dsi host will only have one output port, linked
to the panel's input port.

Update DT binding documentation with device graph usage info.

v3:
- Fix return value checks of of_graph_* calls.
- Don't make port a mandatory DT property
- Fix defer check when no panel node specified
- Rename parse_dt func to align with other dsi_host funcs

Reviewed-by: Hai Li <hali@codeaurora.org>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>

authored by

Archit Taneja and committed by
Rob Clark
f7009d26 14bb28b0

+68 -19
+15
Documentation/devicetree/bindings/drm/msm/dsi.txt
··· 41 41 - pinctrl-names: the pin control state names; should contain "default" 42 42 - pinctrl-0: the default pinctrl state (active) 43 43 - pinctrl-n: the "sleep" pinctrl state 44 + - port: DSI controller output port. This contains one endpoint subnode, with its 45 + remote-endpoint set to the phandle of the connected panel's endpoint. 46 + See Documentation/devicetree/bindings/graph.txt for device graph info. 44 47 45 48 DSI PHY: 46 49 Required properties: ··· 116 113 117 114 power-supply = <...>; 118 115 backlight = <...>; 116 + 117 + port { 118 + panel_in: endpoint { 119 + remote-endpoint = <&dsi0_out>; 120 + }; 121 + }; 122 + }; 123 + 124 + port { 125 + dsi0_out: endpoint { 126 + remote-endpoint = <&panel_in>; 127 + }; 119 128 }; 120 129 }; 121 130
+53 -19
drivers/gpu/drm/msm/dsi/dsi_host.c
··· 21 21 #include <linux/of_gpio.h> 22 22 #include <linux/of_irq.h> 23 23 #include <linux/pinctrl/consumer.h> 24 + #include <linux/of_graph.h> 24 25 #include <linux/regulator/consumer.h> 25 26 #include <linux/spinlock.h> 26 27 #include <video/mipi_display.h> ··· 1403 1402 msm_host->format = dsi->format; 1404 1403 msm_host->mode_flags = dsi->mode_flags; 1405 1404 1406 - msm_host->panel_node = dsi->dev.of_node; 1405 + WARN_ON(dsi->dev.of_node != msm_host->panel_node); 1407 1406 1408 1407 /* Some gpios defined in panel DT need to be controlled by host */ 1409 1408 ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev); ··· 1453 1452 .transfer = dsi_host_transfer, 1454 1453 }; 1455 1454 1455 + static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) 1456 + { 1457 + struct device *dev = &msm_host->pdev->dev; 1458 + struct device_node *np = dev->of_node; 1459 + struct device_node *endpoint, *panel_node; 1460 + int ret; 1461 + 1462 + ret = of_property_read_u32(np, "qcom,dsi-host-index", &msm_host->id); 1463 + if (ret) { 1464 + dev_err(dev, "%s: host index not specified, ret=%d\n", 1465 + __func__, ret); 1466 + return ret; 1467 + } 1468 + 1469 + /* 1470 + * Get the first endpoint node. In our case, dsi has one output port 1471 + * to which the panel is connected. Don't return an error if a port 1472 + * isn't defined. It's possible that there is nothing connected to 1473 + * the dsi output. 1474 + */ 1475 + endpoint = of_graph_get_next_endpoint(np, NULL); 1476 + if (!endpoint) { 1477 + dev_dbg(dev, "%s: no endpoint\n", __func__); 1478 + return 0; 1479 + } 1480 + 1481 + /* Get panel node from the output port's endpoint data */ 1482 + panel_node = of_graph_get_remote_port_parent(endpoint); 1483 + if (!panel_node) { 1484 + dev_err(dev, "%s: no valid device\n", __func__); 1485 + of_node_put(endpoint); 1486 + return -ENODEV; 1487 + } 1488 + 1489 + of_node_put(endpoint); 1490 + of_node_put(panel_node); 1491 + 1492 + msm_host->panel_node = panel_node; 1493 + 1494 + return 0; 1495 + } 1496 + 1456 1497 int msm_dsi_host_init(struct msm_dsi *msm_dsi) 1457 1498 { 1458 1499 struct msm_dsi_host *msm_host = NULL; ··· 1509 1466 goto fail; 1510 1467 } 1511 1468 1512 - ret = of_property_read_u32(pdev->dev.of_node, 1513 - "qcom,dsi-host-index", &msm_host->id); 1469 + msm_host->pdev = pdev; 1470 + 1471 + ret = dsi_host_parse_dt(msm_host); 1514 1472 if (ret) { 1515 - dev_err(&pdev->dev, 1516 - "%s: host index not specified, ret=%d\n", 1517 - __func__, ret); 1473 + pr_err("%s: failed to parse dt\n", __func__); 1518 1474 goto fail; 1519 1475 } 1520 - msm_host->pdev = pdev; 1521 1476 1522 1477 ret = dsi_clk_init(msm_host); 1523 1478 if (ret) { ··· 1623 1582 int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer) 1624 1583 { 1625 1584 struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1626 - struct device_node *node; 1627 1585 int ret; 1628 1586 1629 1587 /* Register mipi dsi host */ ··· 1640 1600 * It makes sure panel is connected when fbcon detects 1641 1601 * connector status and gets the proper display mode to 1642 1602 * create framebuffer. 1603 + * Don't try to defer if there is nothing connected to the dsi 1604 + * output 1643 1605 */ 1644 - if (check_defer) { 1645 - node = of_get_child_by_name(msm_host->pdev->dev.of_node, 1646 - "panel"); 1647 - if (node) { 1648 - if (!of_drm_find_panel(node)) { 1649 - of_node_put(node); 1650 - return -EPROBE_DEFER; 1651 - } 1652 - 1653 - of_node_put(node); 1654 - } 1606 + if (check_defer && msm_host->panel_node) { 1607 + if (!of_drm_find_panel(msm_host->panel_node)) 1608 + return -EPROBE_DEFER; 1655 1609 } 1656 1610 } 1657 1611