diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index f8ecb01f355b2..5282429027168 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -272,6 +272,7 @@ struct dw_mipi_dsi { } vpg_defs; #endif /* CONFIG_DEBUG_FS */ + struct dw_mipi_dsi *dsi0; struct dw_mipi_dsi *master; /* dual-dsi master ptr */ struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */ @@ -408,6 +409,7 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, ctrl |= PHY_TXREQUESTCLKHS; } + ctrl |= PHY_TXREQUESTCLKHS; dsi_write(dsi, DSI_VID_MODE_CFG, val); dsi_write(dsi, DSI_LPCLK_CTRL, ctrl); } @@ -586,6 +588,7 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, unsigned long mode_flags) { + u32 val = 0; dsi_write(dsi, DSI_PWR_UP, RESET); if (mode_flags & MIPI_DSI_MODE_VIDEO) { @@ -595,6 +598,15 @@ static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); } + /* The high-speed clock is started before that the + * high-speed data is sent via the data lanes. + */ + val = dsi_read(dsi, DSI_LPCLK_CTRL); + if(((val & PHY_TXREQUESTCLKHS) != PHY_TXREQUESTCLKHS) + && (mode_flags & MIPI_DSI_MODE_VIDEO)) + val |= PHY_TXREQUESTCLKHS; + val |= PHY_TXREQUESTCLKHS; + dsi_write(dsi, DSI_PWR_UP, POWERUP); } @@ -605,6 +617,8 @@ static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi) dw_mipi_dsi_set_mode(dsi, 0); if (dsi->slave) dw_mipi_dsi_disable(dsi->slave); + if (dsi->dsi0) + dw_mipi_dsi_disable(dsi->dsi0); } static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) @@ -871,6 +885,8 @@ static void dw_mipi_dsi_post_disable(struct dw_mipi_dsi *dsi) if (dsi->slave) dw_mipi_dsi_post_disable(dsi->slave); + if (dsi->dsi0) + dw_mipi_dsi_set_mode(dsi->dsi0, 0); } static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, @@ -927,6 +943,8 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, if (dsi->slave) drm_mode_copy(&dsi->slave->mode, adjusted_mode); + if (dsi->dsi0) + drm_mode_copy(&dsi->dsi0->mode, adjusted_mode); } static void dw_mipi_dsi_pre_enable(struct dw_mipi_dsi *dsi) @@ -937,6 +955,8 @@ static void dw_mipi_dsi_pre_enable(struct dw_mipi_dsi *dsi) int ret; u32 lanes = dw_mipi_dsi_get_lanes(dsi); + if (dsi->dsi0) + dw_mipi_dsi_pre_enable(dsi->dsi0); if (dsi->apb_rst) { reset_control_assert(dsi->apb_rst); usleep_range(10, 20); @@ -1002,6 +1022,8 @@ static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi) u32 val; val = PHY_TXREQUESTCLKHS; + if (dsi->dsi0) + dw_mipi_dsi_enable(dsi->dsi0); if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) val |= AUTO_CLKLANE_CTRL; @@ -1264,6 +1286,19 @@ void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave) } EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave); +void dw_mipi_dsi_set_dsi0(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *dsi0) +{ + /* introduce controllers to each other */ + dsi->dsi0 = dsi0; + + /* migrate settings for already attached displays */ + dsi->dsi0->lanes = dsi->lanes; + dsi->dsi0->channel = dsi->channel; + dsi->dsi0->format = dsi->format; + dsi->dsi0->mode_flags = dsi->mode_flags; +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_dsi0); + /* * Probe/remove API, used from platforms based on the DRM bridge API. */ diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index bf4b3b536474a..0aee9a4abc3b0 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -317,6 +317,8 @@ struct dw_mipi_dsi_rockchip { /* dual-channel */ bool is_slave; + bool is_dsi0; + struct dw_mipi_dsi_rockchip *dsi0; struct dw_mipi_dsi_rockchip *slave; bool data_swap; @@ -883,6 +885,9 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) static void dw_mipi_dsi_rockchip_loader_protect(struct dw_mipi_dsi_rockchip *dsi, bool on) { + if (dsi->dsi0) + dw_mipi_dsi_rockchip_loader_protect(dsi->dsi0, on); + if (on) { pm_runtime_get_sync(dsi->dev); phy_init(dsi->phy); @@ -986,6 +991,31 @@ static struct device return NULL; } +static struct device +*dw_mipi_dsi_rockchip_find_dsi0(struct dw_mipi_dsi_rockchip *dsi) +{ + struct device_node *node = NULL; + struct platform_device *pdev; + struct dw_mipi_dsi_rockchip *dsi2; + + node = of_parse_phandle(dsi->dev->of_node, "rockchip,dsi-dsi0", 0); + if (node) { + pdev = of_find_device_by_node(node); + if (!pdev) + return ERR_PTR(-EPROBE_DEFER); + + dsi2 = platform_get_drvdata(pdev); + if (!dsi2) { + platform_device_put(pdev); + return ERR_PTR(-EPROBE_DEFER); + } + + return &pdev->dev; + } + + return NULL; +} + static int dw_mipi_dsi_get_dsc_info_from_sink(struct dw_mipi_dsi_rockchip *dsi, struct drm_panel *panel, struct drm_bridge *bridge) @@ -1075,6 +1105,27 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev, dw_mipi_dsi_set_slave(dsi->dmd, dsi->slave->dmd); put_device(second); } + if(!second){ + second = dw_mipi_dsi_rockchip_find_dsi0(dsi); + if (IS_ERR(second)) + return PTR_ERR(second); + + if (second) { + /* we are the slave in dual-DSI */ + dsi->dsi0 = dev_get_drvdata(second); + if (!dsi->dsi0) { + DRM_DEV_ERROR(dev, "could not get dsi0 data\n"); + return -ENODEV; + } + + dsi->dsi0->is_dsi0 = true; + dw_mipi_dsi_set_dsi0(dsi->dmd, dsi->dsi0->dmd); + put_device(second); + } else + dsi->is_dsi0 = of_property_read_bool(dev->of_node, "dsi1-only"); + } + if (dsi->is_dsi0) + return 0; if (dsi->is_slave) return 0; @@ -1123,6 +1174,8 @@ static void dw_mipi_dsi_rockchip_unbind(struct device *dev, { struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev); + if (dsi->is_dsi0) + return; if (dsi->is_slave) return; diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index 4844b7d011777..d55f0d290aea7 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -69,6 +69,7 @@ void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi); int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder); void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi); void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave); +void dw_mipi_dsi_set_dsi0(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave); struct drm_connector *dw_mipi_dsi_get_connector(struct dw_mipi_dsi *dsi); #endif /* __DW_MIPI_DSI__ */