drm/bridge/synopsys: dsi: add dual-dsi support

A patch from »drm/rockchip: migrate to common dw-mipi-dsi bridge and dual-dsi« in state Mainline for linux-kernel

From: Nickey Yang <nickey.yang@...> Date: Wed, 29 Nov 2017 19:59:51 +0800

Commit-Message

Allow to also drive a slave dw-mipi-dsi controller in a dual-dsi setup. This will require additional implementation-specific code to look up the slave instance and do specific setup. Also will probably need code in the specific crtcs as dual-dsi does not equal two separate dsi outputs. To activate, the implementation-specific code should set the slave using dw_mipi_dsi_set_slave() before calling __dw_mipi_dsi_bind(). Signed-off-by: Nickey Yang <nickey.yang@...> Signed-off-by: Heiko Stuebner <heiko@...>

Patch-Comment

drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 93 +++++++++++++++++-- include/drm/bridge/dw_mipi_dsi.h | 1 + 2 files changed, 86 insertions(+), 8 deletions(-)

Statistics

  • 86 lines added
  • 8 lines removed

Changes

---------------- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -----------------
index 1b4f6bb7ea59..f6fe52db4b02 100644
@@ -234,9 +234,17 @@ struct dw_mipi_dsi {
u32 format;
unsigned long mode_flags;
+ struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */
+ bool is_slave; /* dual-dsi slave state */
+
const struct dw_mipi_dsi_plat_data *plat_data;
};
+static inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi)
+{
+ return dsi->slave || dsi->is_slave;
+}
+
/*
* The controller should generate 2 frames before
* preparing the peripheral.
@@ -276,19 +284,37 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
struct dw_mipi_dsi *dsi = host_to_dsi(host);
struct drm_bridge *bridge;
struct drm_panel *panel;
+ struct device_node *np;
int ret;
+ int lanes = device->lanes;
+
+ /* check for dual-dsi */
+ np = of_mipi_dsi_find_second_host(dsi->dev->of_node, 1, 0);
+ if (IS_ERR(np))
+ return PTR_ERR(np);
+ if (np) {
+ of_node_put(np);
+ lanes /= 2;
+ }
- if (device->lanes > dsi->plat_data->max_data_lanes) {
+ if (lanes > dsi->plat_data->max_data_lanes) {
dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
device->lanes);
return -EINVAL;
}
- dsi->lanes = device->lanes;
+ dsi->lanes = lanes;
dsi->channel = device->channel;
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
+ if (dsi->slave) {
+ dsi->slave->lanes = dsi->lanes;
+ dsi->slave->channel = dsi->channel;
+ dsi->slave->format = dsi->format;
+ dsi->slave->mode_flags = dsi->mode_flags;
+ }
+
ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0,
&panel, &bridge);
if (ret)
@@ -445,10 +471,17 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
}
dw_mipi_message_config(dsi, msg);
+ if (dsi->slave)
+ dw_mipi_message_config(dsi->slave, msg);
ret = dw_mipi_dsi_write(dsi, &packet);
if (ret)
return ret;
+ if (dsi->slave) {
+ ret = dw_mipi_dsi_write(dsi->slave, &packet);
+ if (ret)
+ return ret;
+ }
if (msg->rx_buf && msg->rx_len) {
ret = dw_mipi_dsi_read(dsi, msg);
@@ -587,7 +620,15 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
* DSI_VNPCR.NPSIZE... especially because this driver supports
* non-burst video modes, see dw_mipi_dsi_video_mode_config()...
*/
- dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
+
+ int pkt_size;
+
+ if (dw_mipi_is_dual_mode(dsi))
+ pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
+ else
+ pkt_size = VID_PKT_SIZE(mode->hdisplay);
+
+ dsi_write(dsi, DSI_VID_PKT_SIZE, pkt_size);
}
static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
@@ -760,23 +801,33 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
dw_mipi_dsi_disable(dsi);
+ if (dsi->slave) {
+ dw_mipi_dsi_disable(dsi->slave);
+ clk_disable_unprepare(dsi->slave->pclk);
+ pm_runtime_put(dsi->slave->dev);
+ }
+
clk_disable_unprepare(dsi->pclk);
pm_runtime_put(dsi->dev);
}
-static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
+ struct drm_display_mode *mode)
{
- struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
void *priv_data = dsi->plat_data->priv_data;
int ret;
+ u32 lanes;
clk_prepare_enable(dsi->pclk);
+ if (dw_mipi_is_dual_mode(dsi))
+ lanes = dsi->lanes * 2;
+ else
+ lanes = dsi->lanes;
+
ret = phy_ops->get_lane_mbps(priv_data, mode, dsi->mode_flags,
- dsi->lanes, dsi->format, &dsi->lane_mbps);
+ lanes, dsi->format, &dsi->lane_mbps);
if (ret)
DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n");
@@ -808,12 +859,25 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
dw_mipi_dsi_set_mode(dsi, 0);
}
+static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
+
+ dw_mipi_dsi_mode_set(dsi, mode);
+ if (dsi->slave)
+ dw_mipi_dsi_mode_set(dsi->slave, mode);
+}
+
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
/* Switch to video mode for panel-bridge enable & panel enable */
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
+ if (dsi->slave)
+ dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
}
static enum drm_mode_status
@@ -953,6 +1017,19 @@ static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
pm_runtime_disable(dsi->dev);
}
+void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave)
+{
+ dsi->slave = slave;
+
+ /* migrate settings for already attached displays */
+ dsi->slave->is_slave = true;
+ dsi->slave->lanes = dsi->lanes;
+ dsi->slave->channel = dsi->channel;
+ dsi->slave->format = dsi->format;
+ dsi->slave->mode_flags = dsi->mode_flags;
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave);
+
/*
* Probe/remove API, used from platforms based on the DRM bridge API.
*/
----------------------- include/drm/bridge/dw_mipi_dsi.h -----------------------
index 6d7f8eb5d9f2..5fd997cdf281 100644
@@ -37,5 +37,6 @@ struct dw_mipi_dsi *dw_mipi_dsi_probe(struct platform_device *pdev,
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);
#endif /* __DW_MIPI_DSI__ */
 
 

Recent Patches

About Us

Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer.

Read More...