[Freedreno] [DPU PATCH 0/2] Connector virtualization for Dual-DSI

2018-04-10 Thread Chandan Uddaraju
This patch series adds support to DSI connector
virtualization for Dual-DSI configuration.

These changes have been tested using dual-dsi truly panel on sdm845 platform.

Additional changes that will be needed to have end-to-end functionality:
 --> DSI6G-v2 changes: https://patchwork.kernel.org/patch/10294605/
 --> truly panel patches: https://patchwork.kernel.org/patch/10327749/
 --> DPU changes that will be uploaded soon.


Chandan Uddaraju (2):
  drm/msm/dsi: adjust dsi timing for dual dsi mode
  drm/msm/dsi: Use one connector for dual DSI mode

 drivers/gpu/drm/msm/dsi/dsi.c |   3 +
 drivers/gpu/drm/msm/dsi/dsi.h |   2 +
 drivers/gpu/drm/msm/dsi/dsi_host.c|  17 +
 drivers/gpu/drm/msm/dsi/dsi_manager.c | 125 +++---
 4 files changed, 62 insertions(+), 85 deletions(-)

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [DPU PATCH v2 1/2] drm/msm/dsi: check video mode engine status before waiting

2018-04-10 Thread Abhinav Kumar
Make sure the video mode engine is on before waiting
for the video done interrupt.

Otherwise it leads to silent timeouts increasing display
turn ON time.

Changes in v2:
- Replace pr_err with dev_err
- Changed error message

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/dsi/dsi_host.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c 
b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 7a03a94..5b7b290 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -173,6 +173,7 @@ struct msm_dsi_host {
 
bool registered;
bool power_on;
+   bool enabled;
int irq;
 };
 
@@ -986,13 +987,19 @@ static void dsi_set_tx_power_mode(int mode, struct 
msm_dsi_host *msm_host)
 
 static void dsi_wait4video_done(struct msm_dsi_host *msm_host)
 {
+   u32 ret = 0;
+   struct device *dev = _host->pdev->dev;
+
dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 1);
 
reinit_completion(_host->video_comp);
 
-   wait_for_completion_timeout(_host->video_comp,
+   ret = wait_for_completion_timeout(_host->video_comp,
msecs_to_jiffies(70));
 
+   if (ret <= 0)
+   dev_err(dev, "wait for video done timed out\n");
+
dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, 0);
 }
 
@@ -1001,7 +1008,7 @@ static void dsi_wait4video_eng_busy(struct msm_dsi_host 
*msm_host)
if (!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO))
return;
 
-   if (msm_host->power_on) {
+   if (msm_host->power_on && msm_host->enabled) {
dsi_wait4video_done(msm_host);
/* delay 4 ms to skip BLLP */
usleep_range(2000, 4000);
@@ -2203,7 +2210,7 @@ int msm_dsi_host_enable(struct mipi_dsi_host *host)
 *  pm_runtime_put_autosuspend(_host->pdev->dev);
 * }
 */
-
+   msm_host->enabled = true;
return 0;
 }
 
@@ -2219,7 +2226,7 @@ int msm_dsi_host_disable(struct mipi_dsi_host *host)
 * Reset to disable video engine so that we can send off cmd.
 */
dsi_sw_reset(msm_host);
-
+   msm_host->enabled = false;
return 0;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


[Freedreno] [DPU PATCH 2/2] drm/msm/dsi: Use one connector for dual DSI mode

2018-04-10 Thread Chandan Uddaraju
Current DSI driver uses two connectors for dual DSI case even
though we only have one panel. Fix this by implementing one
connector/bridge for dual DSI use case. Use master DSI
controllers to register one connector/bridge.

Change-Id: I067b39f3b32eb3aa92d4155d4ca703ca7690645b
Signed-off-by: Chandan Uddaraju 
---
 drivers/gpu/drm/msm/dsi/dsi.c |   3 +
 drivers/gpu/drm/msm/dsi/dsi.h |   1 +
 drivers/gpu/drm/msm/dsi/dsi_manager.c | 110 --
 3 files changed, 29 insertions(+), 85 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index b744bcc..ff8164c 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -208,6 +208,9 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct 
drm_device *dev,
goto fail;
}
 
+   if (!msm_dsi_manager_validate_current_config(msm_dsi->id))
+   goto fail;
+
msm_dsi->encoder = encoder;
 
msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 4131b47..d487d94 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -100,6 +100,7 @@ struct msm_dsi {
 void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags);
 int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
 void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
+bool msm_dsi_manager_validate_current_config(u8 id);
 
 /* msm dsi */
 static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c 
b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 8ef1c3d..5817f59 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -305,67 +305,6 @@ static void dsi_mgr_connector_destroy(struct drm_connector 
*connector)
kfree(dsi_connector);
 }
 
-static void dsi_dual_connector_fix_modes(struct drm_connector *connector)
-{
-   struct drm_display_mode *mode, *m;
-
-   /* Only support left-right mode */
-   list_for_each_entry_safe(mode, m, >probed_modes, head) {
-   mode->clock >>= 1;
-   mode->hdisplay >>= 1;
-   mode->hsync_start >>= 1;
-   mode->hsync_end >>= 1;
-   mode->htotal >>= 1;
-   drm_mode_set_name(mode);
-   }
-}
-
-static int dsi_dual_connector_tile_init(
-   struct drm_connector *connector, int id)
-{
-   struct drm_display_mode *mode;
-   /* Fake topology id */
-   char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'};
-
-   if (connector->tile_group) {
-   DBG("Tile property has been initialized");
-   return 0;
-   }
-
-   /* Use the first mode only for now */
-   mode = list_first_entry(>probed_modes,
-   struct drm_display_mode,
-   head);
-   if (!mode)
-   return -EINVAL;
-
-   connector->tile_group = drm_mode_get_tile_group(
-   connector->dev, topo_id);
-   if (!connector->tile_group)
-   connector->tile_group = drm_mode_create_tile_group(
-   connector->dev, topo_id);
-   if (!connector->tile_group) {
-   pr_err("%s: failed to create tile group\n", __func__);
-   return -ENOMEM;
-   }
-
-   connector->has_tile = true;
-   connector->tile_is_single_monitor = true;
-
-   /* mode has been fixed */
-   connector->tile_h_size = mode->hdisplay;
-   connector->tile_v_size = mode->vdisplay;
-
-   /* Only support left-right mode */
-   connector->num_h_tile = 2;
-   connector->num_v_tile = 1;
-
-   connector->tile_v_loc = 0;
-   connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0;
-
-   return 0;
-}
-
 static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
 {
int id = dsi_mgr_connector_get_id(connector);
@@ -376,31 +315,15 @@ static int dsi_mgr_connector_get_modes(struct 
drm_connector *connector)
if (!panel)
return 0;
 
-   /* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
-* panel should not attach to any connector.
-* Only temporarily attach panel to the current connector here,
-* to let panel set mode to this connector.
+   /*
+* In dual DSI mode, we have one connector that can be
+* attached to the drm_panel.
 */
drm_panel_attach(panel, connector);
num = drm_panel_get_modes(panel);
-   drm_panel_detach(panel);
if (!num)
return 0;
 
-   if (IS_DUAL_DSI()) {
-   /* report half resolution to user */
-   dsi_dual_connector_fix_modes(connector);
-   ret = dsi_dual_connector_tile_init(connector, id);
-   

[Freedreno] [DPU PATCH v2 2/2] drm/msm/dsi: implement auto PHY timing calculator for 10nm PHY

2018-04-10 Thread Abhinav Kumar
Currently the DSI PHY timings are hard-coded for a specific panel
for the 10nm PHY.

Replace this with the auto PHY timing calculator which can calculate
the PHY timings for any panel.

Changes in v2:
- None

Reviewed-by: Archit Taneja 
Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/dsi/phy/dsi_phy.c  | 111 +
 drivers/gpu/drm/msm/dsi/phy/dsi_phy.h  |   2 +
 drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c |  28 
 3 files changed, 113 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c 
b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index 8e9d5c2..5b42885 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -265,6 +265,117 @@ int msm_dsi_dphy_timing_calc_v2(struct 
msm_dsi_dphy_timing *timing,
return 0;
 }
 
+int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
+  struct msm_dsi_phy_clk_request *clk_req)
+{
+   const unsigned long bit_rate = clk_req->bitclk_rate;
+   const unsigned long esc_rate = clk_req->escclk_rate;
+   s32 ui, ui_x8, lpx;
+   s32 tmax, tmin;
+   s32 pcnt0 = 50;
+   s32 pcnt1 = 50;
+   s32 pcnt2 = 10;
+   s32 pcnt3 = 30;
+   s32 pcnt4 = 10;
+   s32 pcnt5 = 2;
+   s32 coeff = 1000; /* Precision, should avoid overflow */
+   s32 hb_en, hb_en_ckln;
+   s32 temp;
+
+   if (!bit_rate || !esc_rate)
+   return -EINVAL;
+
+   timing->hs_halfbyte_en = 0;
+   hb_en = 0;
+   timing->hs_halfbyte_en_ckln = 0;
+   hb_en_ckln = 0;
+
+   ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
+   ui_x8 = ui << 3;
+   lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
+
+   temp = S_DIV_ROUND_UP(38 * coeff, ui_x8);
+   tmin = max_t(s32, temp, 0);
+   temp = (95 * coeff) / ui_x8;
+   tmax = max_t(s32, temp, 0);
+   timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
+
+
+   temp = 300 * coeff - (timing->clk_prepare << 3) * ui;
+   tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
+   tmax = (tmin > 255) ? 511 : 255;
+   timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
+
+   tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
+   temp = 105 * coeff + 12 * ui - 20 * coeff;
+   tmax = (temp + 3 * ui) / ui_x8;
+   timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
+
+   temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui, ui_x8);
+   tmin = max_t(s32, temp, 0);
+   temp = (85 * coeff + 6 * ui) / ui_x8;
+   tmax = max_t(s32, temp, 0);
+   timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
+
+   temp = 145 * coeff + 10 * ui - (timing->hs_prepare << 3) * ui;
+   tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
+   tmax = 255;
+   timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
+
+   tmin = DIV_ROUND_UP(60 * coeff + 4 * ui, ui_x8) - 1;
+   temp = 105 * coeff + 12 * ui - 20 * coeff;
+   tmax = (temp / ui_x8) - 1;
+   timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
+
+   temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
+   timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
+
+   tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
+   tmax = 255;
+   timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
+
+   temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
+   timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
+
+   temp = 60 * coeff + 52 * ui - 43 * ui;
+   tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
+   tmax = 63;
+   timing->shared_timings.clk_post =
+   linear_inter(tmax, tmin, pcnt2, 0, false);
+
+   temp = 8 * ui + (timing->clk_prepare << 3) * ui;
+   temp += (((timing->clk_zero + 3) << 3) + 11) * ui;
+   temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
+   (((timing->hs_rqst_ckln << 3) + 8) * ui);
+   tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
+   tmax = 63;
+   if (tmin > tmax) {
+   temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
+   timing->shared_timings.clk_pre = temp >> 1;
+   timing->shared_timings.clk_pre_inc_by_2 = 1;
+   } else {
+   timing->shared_timings.clk_pre =
+   linear_inter(tmax, tmin, pcnt2, 0, false);
+   timing->shared_timings.clk_pre_inc_by_2 = 0;
+   }
+
+   timing->ta_go = 3;
+   timing->ta_sure = 0;
+   timing->ta_get = 4;
+
+   DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
+   timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
+   timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
+   timing->clk_trail, timing->clk_prepare, timing->hs_exit,
+   timing->hs_zero, timing->hs_prepare, timing->hs_trail,
+