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

drm/exynos: move connector creation to attach callback

The current implementation assumes that the only possible peripheral
device for DSIM is a panel. Using an output bridge child device
should also be possible.

If an output bridge is available, don't create a new connector.
Instead, call drm_bridge_attach() and set encoder's bridge to NULL
in order to avoid an out bridge from being visible by the framework, as
the DSI bus needs control on enabling its child output bridge.

Such sequence is required by Toshiba TC358764 bridge, which is a DSI
peripheral bridge device.

changed in v5:
- detach bridge in mipi_dsi detach callback

Signed-off-by: Maciej Purski <m.purski@samsung.com>
[ a.hajda@samsung.com: v5 ]
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Manually merged due to merge conflict.
Signed-off-by: Inki Dae <inki.dae@samsung.com>

authored by

Maciej Purski and committed by
Inki Dae
6afb7721 2782622e

+32 -21
+32 -21
drivers/gpu/drm/exynos/exynos_drm_dsi.c
··· 255 255 struct mipi_dsi_host dsi_host; 256 256 struct drm_connector connector; 257 257 struct drm_panel *panel; 258 + struct drm_bridge *out_bridge; 258 259 struct device *dev; 259 260 260 261 void __iomem *reg_base; ··· 1500 1499 struct mipi_dsi_device *device) 1501 1500 { 1502 1501 struct exynos_dsi *dsi = host_to_dsi(host); 1503 - struct drm_device *drm = dsi->connector.dev; 1502 + struct drm_encoder *encoder = &dsi->encoder; 1503 + struct drm_device *drm = encoder->dev; 1504 + struct drm_bridge *out_bridge; 1505 + 1506 + out_bridge = of_drm_find_bridge(device->dev.of_node); 1507 + if (out_bridge) { 1508 + drm_bridge_attach(encoder, out_bridge, NULL); 1509 + dsi->out_bridge = out_bridge; 1510 + encoder->bridge = NULL; 1511 + } else { 1512 + int ret = exynos_dsi_create_connector(encoder); 1513 + 1514 + if (ret) { 1515 + DRM_ERROR("failed to create connector ret = %d\n", ret); 1516 + drm_encoder_cleanup(encoder); 1517 + return ret; 1518 + } 1519 + 1520 + dsi->panel = of_drm_find_panel(device->dev.of_node); 1521 + if (dsi->panel) { 1522 + drm_panel_attach(dsi->panel, &dsi->connector); 1523 + dsi->connector.status = connector_status_connected; 1524 + } 1525 + } 1504 1526 1505 1527 /* 1506 1528 * This is a temporary solution and should be made by more generic way. ··· 1542 1518 dsi->lanes = device->lanes; 1543 1519 dsi->format = device->format; 1544 1520 dsi->mode_flags = device->mode_flags; 1545 - dsi->panel = of_drm_find_panel(device->dev.of_node); 1546 - if (IS_ERR(dsi->panel)) 1547 - dsi->panel = NULL; 1548 - 1549 - if (dsi->panel) { 1550 - drm_panel_attach(dsi->panel, &dsi->connector); 1551 - dsi->connector.status = connector_status_connected; 1552 - } 1553 1521 exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode = 1554 1522 !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO); 1555 1523 ··· 1557 1541 struct mipi_dsi_device *device) 1558 1542 { 1559 1543 struct exynos_dsi *dsi = host_to_dsi(host); 1560 - struct drm_device *drm = dsi->connector.dev; 1561 - 1562 - mutex_lock(&drm->mode_config.mutex); 1544 + struct drm_device *drm = dsi->encoder.dev; 1563 1545 1564 1546 if (dsi->panel) { 1547 + mutex_lock(&drm->mode_config.mutex); 1565 1548 exynos_dsi_disable(&dsi->encoder); 1566 1549 drm_panel_detach(dsi->panel); 1567 1550 dsi->panel = NULL; 1568 1551 dsi->connector.status = connector_status_disconnected; 1552 + mutex_unlock(&drm->mode_config.mutex); 1553 + } else { 1554 + if (dsi->out_bridge->funcs->detach) 1555 + dsi->out_bridge->funcs->detach(dsi->out_bridge); 1556 + dsi->out_bridge = NULL; 1569 1557 } 1570 - 1571 - mutex_unlock(&drm->mode_config.mutex); 1572 1558 1573 1559 if (drm->mode_config.poll_enabled) 1574 1560 drm_kms_helper_hotplug_event(drm); ··· 1674 1656 ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); 1675 1657 if (ret < 0) 1676 1658 return ret; 1677 - 1678 - ret = exynos_dsi_create_connector(encoder); 1679 - if (ret) { 1680 - DRM_ERROR("failed to create connector ret = %d\n", ret); 1681 - drm_encoder_cleanup(encoder); 1682 - return ret; 1683 - } 1684 1659 1685 1660 if (dsi->in_bridge_node) { 1686 1661 in_bridge = of_drm_find_bridge(dsi->in_bridge_node);