From fc41001d97083fba638b9bbbf84c72db735c1680 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Sun, 16 Sep 2018 16:23:24 +0530 Subject: drm/i915/icl: Configure lane sequencing of combo phy transmitter This patch set the loadgen select and latency optimization for aux and transmit lanes of combo phy transmitters. It will be used for MIPI DSI HS operations. v2: Rebase v3: Add empty line to make code more legible (Ville). Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1537095223-5184-2-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 13830e43a4d1..1607cacccdb1 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -105,10 +105,49 @@ static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder) } } +static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 tmp; + int lane; + + /* Step 4b(i) set loadgen select for transmit and aux lanes */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port)); + tmp &= ~LOADGEN_SELECT; + I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp); + for (lane = 0; lane <= 3; lane++) { + tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane)); + tmp &= ~LOADGEN_SELECT; + if (lane != 2) + tmp |= LOADGEN_SELECT; + I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp); + } + } + + /* Step 4b(ii) set latency optimization for transmit and aux lanes */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port)); + tmp &= ~FRC_LATENCY_OPTIM_MASK; + tmp |= FRC_LATENCY_OPTIM_VAL(0x5); + I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp); + tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port)); + tmp &= ~FRC_LATENCY_OPTIM_MASK; + tmp |= FRC_LATENCY_OPTIM_VAL(0x5); + I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp); + } + +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) { /* step 4a: power up all lanes of the DDI used by DSI */ gen11_dsi_power_up_lanes(encoder); + + /* step 4b: configure lane sequencing of the Combo-PHY transmitters */ + gen11_dsi_config_phy_lanes_sequence(encoder); } static void __attribute__((unused)) -- cgit v1.2.3 From 3f4b9d9d02c6239f5d0eae6f59af5252ef8beefd Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Sun, 16 Sep 2018 16:23:25 +0530 Subject: drm/i915/icl: DSI vswing programming sequence This patch setup voltage swing before enabling combo PHY DDI (shared with DSI). Note that DSI voltage swing programming is for high speed data buffers. HW automatically handles the voltage swing for the low power data buffers. v2: Rebase v3: Address various review comments related to VSWING programming (Jani N) Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1537095223-5184-3-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 120 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 1607cacccdb1..e5c18a8e6458 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -27,6 +27,71 @@ #include "intel_dsi.h" +static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 tmp; + int lane; + + for_each_dsi_port(port, intel_dsi->ports) { + + /* + * Program voltage swing and pre-emphasis level values as per + * table in BSPEC under DDI buffer programing + */ + tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); + tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK); + tmp |= SCALING_MODE_SEL(0x2); + tmp |= TAP2_DISABLE | TAP3_DISABLE; + tmp |= RTERM_SELECT(0x6); + I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); + + tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); + tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK); + tmp |= SCALING_MODE_SEL(0x2); + tmp |= TAP2_DISABLE | TAP3_DISABLE; + tmp |= RTERM_SELECT(0x6); + I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); + + tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port)); + tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | + RCOMP_SCALAR_MASK); + tmp |= SWING_SEL_UPPER(0x2); + tmp |= SWING_SEL_LOWER(0x2); + tmp |= RCOMP_SCALAR(0x98); + I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp); + + tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port)); + tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | + RCOMP_SCALAR_MASK); + tmp |= SWING_SEL_UPPER(0x2); + tmp |= SWING_SEL_LOWER(0x2); + tmp |= RCOMP_SCALAR(0x98); + I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp); + + tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port)); + tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | + CURSOR_COEFF_MASK); + tmp |= POST_CURSOR_1(0x0); + tmp |= POST_CURSOR_2(0x0); + tmp |= CURSOR_COEFF(0x3f); + I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp); + + for (lane = 0; lane <= 3; lane++) { + /* Bspec: must not use GRP register for write */ + tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane)); + tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | + CURSOR_COEFF_MASK); + tmp |= POST_CURSOR_1(0x0); + tmp |= POST_CURSOR_2(0x0); + tmp |= CURSOR_COEFF(0x3f); + I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp); + } + } +} + static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -141,6 +206,58 @@ static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder) } +static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + u32 tmp; + enum port port; + + /* clear common keeper enable bit */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port)); + tmp &= ~COMMON_KEEPER_EN; + I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp); + tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port)); + tmp &= ~COMMON_KEEPER_EN; + I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp); + } + + /* + * Set SUS Clock Config bitfield to 11b + * Note: loadgen select program is done + * as part of lane phy sequence configuration + */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_PORT_CL_DW5(port)); + tmp |= SUS_CLOCK_CONFIG; + I915_WRITE(ICL_PORT_CL_DW5(port), tmp); + } + + /* Clear training enable to change swing values */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); + tmp &= ~TX_TRAINING_EN; + I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); + tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); + tmp &= ~TX_TRAINING_EN; + I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); + } + + /* Program swing and de-emphasis */ + dsi_program_swing_and_deemphasis(encoder); + + /* Set training enable to trigger update */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); + tmp |= TX_TRAINING_EN; + I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); + tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); + tmp |= TX_TRAINING_EN; + I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); + } +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) { /* step 4a: power up all lanes of the DDI used by DSI */ @@ -148,6 +265,9 @@ static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) /* step 4b: configure lane sequencing of the Combo-PHY transmitters */ gen11_dsi_config_phy_lanes_sequence(encoder); + + /* step 4c: configure voltage swing and skew */ + gen11_dsi_voltage_swing_program_seq(encoder); } static void __attribute__((unused)) -- cgit v1.2.3 From ba3df888be909a8850e695a3d9631cfb49afede2 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Sun, 16 Sep 2018 16:23:26 +0530 Subject: drm/i915/icl: Enable DDI Buffer This patch enables DDI buffer by writing to DDI_BUF_CTL register and wait for DDI status to be *not idle* for a port. v2: Rebase v3: Remove step hard coding comments (Jani N) Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1537095223-5184-4-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index e5c18a8e6458..190316c4c4c2 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -258,6 +258,25 @@ static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder) } } +static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + u32 tmp; + enum port port; + + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(DDI_BUF_CTL(port)); + tmp |= DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), tmp); + + if (wait_for_us(!(I915_READ(DDI_BUF_CTL(port)) & + DDI_BUF_IS_IDLE), + 500)) + DRM_ERROR("DDI port:%c buffer idle\n", port_name(port)); + } +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) { /* step 4a: power up all lanes of the DDI used by DSI */ @@ -268,6 +287,9 @@ static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) /* step 4c: configure voltage swing and skew */ gen11_dsi_voltage_swing_program_seq(encoder); + + /* enable DDI buffer */ + gen11_dsi_enable_ddi_buffer(encoder); } static void __attribute__((unused)) -- cgit v1.2.3 From 70a7b83628fa3f6599bd1a7c500f6a8fcdb81ab0 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Sun, 16 Sep 2018 16:23:27 +0530 Subject: drm/i915/icl: Program T_INIT_MASTER registers This patch programs the time (in escape clocks) to drive the link in the initialization (i.e. LP-11) state. v2: Rebase v3: Remove step hard coding comments (Jani N) Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1537095223-5184-5-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 190316c4c4c2..ff5b285ca495 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -277,6 +277,22 @@ static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder) } } +static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + u32 tmp; + enum port port; + + /* Program T-INIT master registers */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_DSI_T_INIT_MASTER(port)); + tmp &= ~MASTER_INIT_TIMER_MASK; + tmp |= intel_dsi->init_count; + I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp); + } +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) { /* step 4a: power up all lanes of the DDI used by DSI */ @@ -290,6 +306,9 @@ static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) /* enable DDI buffer */ gen11_dsi_enable_ddi_buffer(encoder); + + /* setup D-PHY timings */ + gen11_dsi_setup_dphy_timings(encoder); } static void __attribute__((unused)) -- cgit v1.2.3 From e72cce53101767230b7800c5b6e6341aaa451632 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:27:54 +0300 Subject: drm/i915/icl: Program DSI clock and data lane timing params This patch programs D-PHY timing parameters for the clock and data lane (in escape clocks) of DSI controller (DSI port 0 and 1). These programmed timings would be used by DSI Controller to calculate link transition latencies of the data and clock lanes. v2: Use newly defined bitfields for data and clock lane v3 by Jani: - Rebase on dphy abstraction - Reduce local variables - Remove unrelated comment changes (Ville) - Use the same style for range checks as VLV (Ville) - Assign, don't OR dphy_reg contents Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/70d491e2357f328a63b67ea3c43cb57a1d469c15.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index ff5b285ca495..9602b6532028 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -291,6 +291,24 @@ static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder) tmp |= intel_dsi->init_count; I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp); } + + /* Program DPHY clock lanes timings */ + for_each_dsi_port(port, intel_dsi->ports) { + I915_WRITE(DPHY_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg); + + /* shadow register inside display core */ + I915_WRITE(DSI_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg); + } + + /* Program DPHY data lanes timings */ + for_each_dsi_port(port, intel_dsi->ports) { + I915_WRITE(DPHY_DATA_TIMING_PARAM(port), + intel_dsi->dphy_data_lane_reg); + + /* shadow register inside display core */ + I915_WRITE(DSI_DATA_TIMING_PARAM(port), + intel_dsi->dphy_data_lane_reg); + } } static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) -- cgit v1.2.3 From 5fea8645585ff183e1421b8d1b46bc3bf99b0a87 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:27:55 +0300 Subject: drm/i915/icl: Program TA_TIMING_PARAM registers This patch programs D-PHY timing parameters for the bus turn around flow(in escape clocks) only if dsi link frequency <=800 MHz using DPHY_TA_TIMING_PARAM and its identical register DSI_TA_TIMING_PARAM (inside DSI Controller within the Display Core). v2: Changes - Don't use KHz() macro (Ville/Jani N) - Use newly defined bitfields v3 by Jani: - Use intel_dsi_bitrate() in favor of a new field - Remove redundant parens Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/2c777092a748dfc973714399d8c19ed7a8c31a10.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 9602b6532028..f9df3a7fa66b 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -309,6 +309,27 @@ static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder) I915_WRITE(DSI_DATA_TIMING_PARAM(port), intel_dsi->dphy_data_lane_reg); } + + /* + * If DSI link operating at or below an 800 MHz, + * TA_SURE should be override and programmed to + * a value '0' inside TA_PARAM_REGISTERS otherwise + * leave all fields at HW default values. + */ + if (intel_dsi_bitrate(intel_dsi) <= 800000) { + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(DPHY_TA_TIMING_PARAM(port)); + tmp &= ~TA_SURE_MASK; + tmp |= TA_SURE_OVERRIDE | TA_SURE(0); + I915_WRITE(DPHY_TA_TIMING_PARAM(port), tmp); + + /* shadow register inside display core */ + tmp = I915_READ(DSI_TA_TIMING_PARAM(port)); + tmp &= ~TA_SURE_MASK; + tmp |= TA_SURE_OVERRIDE | TA_SURE(0); + I915_WRITE(DSI_TA_TIMING_PARAM(port), tmp); + } + } } static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) -- cgit v1.2.3 From ca8fc99f2ac1b6c38e875cb23fd2ffc591240b19 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:27:56 +0300 Subject: drm/i915/icl: Get DSI transcoder for a given port This patch adds a helper function to retrieve DSI transcoder for a given DSI port using newly defined enum names for DSI transcoders. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/f88ff26fa10c68e37b7838bb7c8573c881474e73.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index f9df3a7fa66b..407c3065d08d 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -27,6 +27,14 @@ #include "intel_dsi.h" +static enum transcoder __attribute__((unused)) dsi_port_to_transcoder(enum port port) +{ + if (port == PORT_A) + return TRANSCODER_DSI_0; + else + return TRANSCODER_DSI_1; +} + static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); -- cgit v1.2.3 From d364dc66e2d5afdd825f79b70d8d81d287b2524a Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:27:59 +0300 Subject: drm/i915/icl: Configure DSI transcoders This patch programs DSI operation mode, pixel format, BGR info, link calibration etc for the DSI transcoder. This patch also extract BGR info of the DSI panel from VBT and save it inside struct intel_dsi which used for configuring DSI transcoder. v2: Rebase v3: Use newly defined bitfields. v4 by Jani: - Use intel_dsi_bitrate() - Make bgr_enabled bool - Use 0 instead of 0x0 - Replace DRM_ERROR() with MISSING_CASE() on pixel format and video mode - Use is_vid_mode() Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/7de4e39a4b2a18e53a2b9d9cea5b5b4c9d6eeb34.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 87 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 407c3065d08d..756c75d0c86c 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -27,7 +27,7 @@ #include "intel_dsi.h" -static enum transcoder __attribute__((unused)) dsi_port_to_transcoder(enum port port) +static enum transcoder dsi_port_to_transcoder(enum port port) { if (port == PORT_A) return TRANSCODER_DSI_0; @@ -340,6 +340,88 @@ static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder) } } +static void gen11_dsi_configure_transcoder(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + u32 tmp; + enum port port; + enum transcoder dsi_trans; + + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + tmp = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)); + + if (intel_dsi->eotp_pkt) + tmp &= ~EOTP_DISABLED; + else + tmp |= EOTP_DISABLED; + + /* enable link calibration if freq > 1.5Gbps */ + if (intel_dsi_bitrate(intel_dsi) >= 1500 * 1000) { + tmp &= ~LINK_CALIBRATION_MASK; + tmp |= CALIBRATION_ENABLED_INITIAL_ONLY; + } + + /* configure continuous clock */ + tmp &= ~CONTINUOUS_CLK_MASK; + if (intel_dsi->clock_stop) + tmp |= CLK_ENTER_LP_AFTER_DATA; + else + tmp |= CLK_HS_CONTINUOUS; + + /* configure buffer threshold limit to minimum */ + tmp &= ~PIX_BUF_THRESHOLD_MASK; + tmp |= PIX_BUF_THRESHOLD_1_4; + + /* set virtual channel to '0' */ + tmp &= ~PIX_VIRT_CHAN_MASK; + tmp |= PIX_VIRT_CHAN(0); + + /* program BGR transmission */ + if (intel_dsi->bgr_enabled) + tmp |= BGR_TRANSMISSION; + + /* select pixel format */ + tmp &= ~PIX_FMT_MASK; + switch (intel_dsi->pixel_format) { + default: + MISSING_CASE(intel_dsi->pixel_format); + /* fallthrough */ + case MIPI_DSI_FMT_RGB565: + tmp |= PIX_FMT_RGB565; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + tmp |= PIX_FMT_RGB666_PACKED; + break; + case MIPI_DSI_FMT_RGB666: + tmp |= PIX_FMT_RGB666_LOOSE; + break; + case MIPI_DSI_FMT_RGB888: + tmp |= PIX_FMT_RGB888; + break; + } + + /* program DSI operation mode */ + if (is_vid_mode(intel_dsi)) { + tmp &= ~OP_MODE_MASK; + switch (intel_dsi->video_mode_format) { + default: + MISSING_CASE(intel_dsi->video_mode_format); + /* fallthrough */ + case VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS: + tmp |= VIDEO_MODE_SYNC_EVENT; + break; + case VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE: + tmp |= VIDEO_MODE_SYNC_PULSE; + break; + } + } + + I915_WRITE(DSI_TRANS_FUNC_CONF(dsi_trans), tmp); + } +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) { /* step 4a: power up all lanes of the DDI used by DSI */ @@ -356,6 +438,9 @@ static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) /* setup D-PHY timings */ gen11_dsi_setup_dphy_timings(encoder); + + /* Step (4h, 4i, 4j, 4k): Configure transcoder */ + gen11_dsi_configure_transcoder(encoder); } static void __attribute__((unused)) -- cgit v1.2.3 From 70f4f502c47e9c541b0ae329440a7fe809cc5211 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:28:01 +0300 Subject: drm/i915/icl: Program TRANS_DDI_FUNC_CTL registers This patch select input PIPE for DSI, data lanes width, enable port sync mode and wait for DSI link to become ready. v2 by Jani: - Use MISSING_CASE with fallthrough instead of DRM_ERROR - minor stylistic changes Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/080320dc9a9e321dbe73567c6a7aa1dcff0f21c2.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 64 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 756c75d0c86c..87d5e6435791 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -340,10 +340,14 @@ static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder) } } -static void gen11_dsi_configure_transcoder(struct intel_encoder *encoder) +static void +gen11_dsi_configure_transcoder(struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc); + enum pipe pipe = intel_crtc->pipe; u32 tmp; enum port port; enum transcoder dsi_trans; @@ -420,9 +424,61 @@ static void gen11_dsi_configure_transcoder(struct intel_encoder *encoder) I915_WRITE(DSI_TRANS_FUNC_CONF(dsi_trans), tmp); } + + /* enable port sync mode if dual link */ + if (intel_dsi->dual_link) { + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans)); + tmp |= PORT_SYNC_MODE_ENABLE; + I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp); + } + + //TODO: configure DSS_CTL1 + } + + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + + /* select data lane width */ + tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans)); + tmp &= ~DDI_PORT_WIDTH_MASK; + tmp |= DDI_PORT_WIDTH(intel_dsi->lane_count); + + /* select input pipe */ + tmp &= ~TRANS_DDI_EDP_INPUT_MASK; + switch (pipe) { + default: + MISSING_CASE(pipe); + /* fallthrough */ + case PIPE_A: + tmp |= TRANS_DDI_EDP_INPUT_A_ON; + break; + case PIPE_B: + tmp |= TRANS_DDI_EDP_INPUT_B_ONOFF; + break; + case PIPE_C: + tmp |= TRANS_DDI_EDP_INPUT_C_ONOFF; + break; + } + + /* enable DDI buffer */ + tmp |= TRANS_DDI_FUNC_ENABLE; + I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp); + } + + /* wait for link ready */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + if (wait_for_us((I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)) & + LINK_READY), 2500)) + DRM_ERROR("DSI link not ready\n"); + } } -static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) +static void +gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config) { /* step 4a: power up all lanes of the DDI used by DSI */ gen11_dsi_power_up_lanes(encoder); @@ -440,7 +496,7 @@ static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) gen11_dsi_setup_dphy_timings(encoder); /* Step (4h, 4i, 4j, 4k): Configure transcoder */ - gen11_dsi_configure_transcoder(encoder); + gen11_dsi_configure_transcoder(encoder, pipe_config); } static void __attribute__((unused)) @@ -455,5 +511,5 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, gen11_dsi_program_esc_clk_div(encoder); /* step4: enable DSI port and DPHY */ - gen11_dsi_enable_port_and_phy(encoder); + gen11_dsi_enable_port_and_phy(encoder, pipe_config); } -- cgit v1.2.3 From d1aeb5f399d98443fd1f4b26480519379cb9cec8 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:28:03 +0300 Subject: drm/i915/icl: Configure DSI transcoder timings As part of DSI enable sequence, transcoder timings (horizontal & vertical) need to be set so that transcoder will generate the stream output as per those timings. This patch set required transcoder timings as per BSPEC. v2: Remove TRANS_TIMING_SHIFT usage v3 by Jani: - Rebase - Reduce temp variable use - Checkpatch fix Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/525949ae4e919a4f2b807d606234322534656048.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 118 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 87d5e6435791..f6ed57b28676 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -476,6 +476,121 @@ gen11_dsi_configure_transcoder(struct intel_encoder *encoder, } } +static void +gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + const struct drm_display_mode *adjusted_mode = + &pipe_config->base.adjusted_mode; + enum port port; + enum transcoder dsi_trans; + /* horizontal timings */ + u16 htotal, hactive, hsync_start, hsync_end, hsync_size; + u16 hfront_porch, hback_porch; + /* vertical timings */ + u16 vtotal, vactive, vsync_start, vsync_end, vsync_shift; + + hactive = adjusted_mode->crtc_hdisplay; + htotal = adjusted_mode->crtc_htotal; + hsync_start = adjusted_mode->crtc_hsync_start; + hsync_end = adjusted_mode->crtc_hsync_end; + hsync_size = hsync_end - hsync_start; + hfront_porch = (adjusted_mode->crtc_hsync_start - + adjusted_mode->crtc_hdisplay); + hback_porch = (adjusted_mode->crtc_htotal - + adjusted_mode->crtc_hsync_end); + vactive = adjusted_mode->crtc_vdisplay; + vtotal = adjusted_mode->crtc_vtotal; + vsync_start = adjusted_mode->crtc_vsync_start; + vsync_end = adjusted_mode->crtc_vsync_end; + vsync_shift = hsync_start - htotal / 2; + + if (intel_dsi->dual_link) { + hactive /= 2; + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) + hactive += intel_dsi->pixel_overlap; + htotal /= 2; + } + + /* minimum hactive as per bspec: 256 pixels */ + if (adjusted_mode->crtc_hdisplay < 256) + DRM_ERROR("hactive is less then 256 pixels\n"); + + /* if RGB666 format, then hactive must be multiple of 4 pixels */ + if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB666 && hactive % 4 != 0) + DRM_ERROR("hactive pixels are not multiple of 4\n"); + + /* program TRANS_HTOTAL register */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + I915_WRITE(HTOTAL(dsi_trans), + (hactive - 1) | ((htotal - 1) << 16)); + } + + /* TRANS_HSYNC register to be programmed only for video mode */ + if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) { + if (intel_dsi->video_mode_format == + VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE) { + /* BSPEC: hsync size should be atleast 16 pixels */ + if (hsync_size < 16) + DRM_ERROR("hsync size < 16 pixels\n"); + } + + if (hback_porch < 16) + DRM_ERROR("hback porch < 16 pixels\n"); + + if (intel_dsi->dual_link) { + hsync_start /= 2; + hsync_end /= 2; + } + + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + I915_WRITE(HSYNC(dsi_trans), + (hsync_start - 1) | ((hsync_end - 1) << 16)); + } + } + + /* program TRANS_VTOTAL register */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + /* + * FIXME: Programing this by assuming progressive mode, since + * non-interlaced info from VBT is not saved inside + * struct drm_display_mode. + * For interlace mode: program required pixel minus 2 + */ + I915_WRITE(VTOTAL(dsi_trans), + (vactive - 1) | ((vtotal - 1) << 16)); + } + + if (vsync_end < vsync_start || vsync_end > vtotal) + DRM_ERROR("Invalid vsync_end value\n"); + + if (vsync_start < vactive) + DRM_ERROR("vsync_start less than vactive\n"); + + /* program TRANS_VSYNC register */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + I915_WRITE(VSYNC(dsi_trans), + (vsync_start - 1) | ((vsync_end - 1) << 16)); + } + + /* + * FIXME: It has to be programmed only for interlaced + * modes. Put the check condition here once interlaced + * info available as described above. + * program TRANS_VSYNCSHIFT register + */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + I915_WRITE(VSYNCSHIFT(dsi_trans), vsync_shift); + } +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config) @@ -512,4 +627,7 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, /* step4: enable DSI port and DPHY */ gen11_dsi_enable_port_and_phy(encoder, pipe_config); + + /* step6c: configure transcoder timings */ + gen11_dsi_set_transcoder_timings(encoder, pipe_config); } -- cgit v1.2.3 From 303e347cebc3cd98326cd4fa66f4fd8219b9f603 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:28:05 +0300 Subject: drm/i915/icl: Enable DSI transcoders This patch enables DSI transcoders by writing to TRANS_CONF registers and wait for its state to be enabled. v2 by Jani: - Rebase Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/4b8ea0298ef9d6832a2dd69c923832d0b7b58184.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index f6ed57b28676..216a1753d246 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -591,6 +591,28 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, } } +static void gen11_dsi_enable_transcoder(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + enum transcoder dsi_trans; + u32 tmp; + + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + tmp = I915_READ(PIPECONF(dsi_trans)); + tmp |= PIPECONF_ENABLE; + I915_WRITE(PIPECONF(dsi_trans), tmp); + + /* wait for transcoder to be enabled */ + if (intel_wait_for_register(dev_priv, PIPECONF(dsi_trans), + I965_PIPECONF_ACTIVE, + I965_PIPECONF_ACTIVE, 10)) + DRM_ERROR("DSI transcoder not enabled\n"); + } +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config) @@ -630,4 +652,7 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, /* step6c: configure transcoder timings */ gen11_dsi_set_transcoder_timings(encoder, pipe_config); + + /* step6d: enable dsi transcoder */ + gen11_dsi_enable_transcoder(encoder); } -- cgit v1.2.3 From bfee32bfca82b69030b23177ebabfc2ade2f54fc Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:09 +0200 Subject: drm/i915/icl: Set max return packet size for DSI panel This patch programs maximum size of the payload transmitted from peripheral back to the host processor using short packet as a part of panel programming. v2: Rebase v3 by Jani: - Add FIXME note. Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/ed9df910326adf32eb2bc1cd1a5097d0dda94da8.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 216a1753d246..9c424adc8b75 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -25,6 +25,7 @@ * Jani Nikula */ +#include #include "intel_dsi.h" static enum transcoder dsi_port_to_transcoder(enum port port) @@ -636,6 +637,35 @@ gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, gen11_dsi_configure_transcoder(encoder, pipe_config); } +static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + struct mipi_dsi_device *dsi; + enum port port; + enum transcoder dsi_trans; + u32 tmp; + int ret; + + /* set maximum return packet size */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + + /* + * FIXME: This uses the number of DW's currently in the payload + * receive queue. This is probably not what we want here. + */ + tmp = I915_READ(DSI_CMD_RXCTL(dsi_trans)); + tmp &= NUMBER_RX_PLOAD_DW_MASK; + /* multiply "Number Rx Payload DW" by 4 to get max value */ + tmp = tmp * 4; + dsi = intel_dsi->dsi_hosts[port]->device; + ret = mipi_dsi_set_maximum_return_packet_size(dsi, tmp); + if (ret < 0) + DRM_ERROR("error setting max return pkt size%d\n", tmp); + } +} + static void __attribute__((unused)) gen11_dsi_pre_enable(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, @@ -650,6 +680,9 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, /* step4: enable DSI port and DPHY */ gen11_dsi_enable_port_and_phy(encoder, pipe_config); + /* step5: program and powerup panel */ + gen11_dsi_powerup_panel(encoder); + /* step6c: configure transcoder timings */ gen11_dsi_set_transcoder_timings(encoder, pipe_config); -- cgit v1.2.3 From c2661638e88655fef38bc3cc580e80457461f0a2 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:10 +0200 Subject: drm/i915/icl: Power on DSI panel This patch execute poweron, deassert reset, display on VBT sequences and send TURN_ON DSI command to panel for powering it up. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/8acb06fa634fe9637fdc09a3f5d2588b9138224f.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 9c424adc8b75..d9c91001f107 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -664,6 +664,13 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) if (ret < 0) DRM_ERROR("error setting max return pkt size%d\n", tmp); } + + /* panel power on related mipi dsi vbt sequences */ + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON); + intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); } static void __attribute__((unused)) -- cgit v1.2.3 From 32bbc3d450dcb7f45b343ee568892d746fe6dc1f Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:11 +0200 Subject: drm/i915/icl: Wait for header/payload credits release Driver needs payload/header credits for sending any command and data over DSI link. These credits are released once command or data sent to link. This patch adds functions to wait for releasing of payload and header credits. As per BSPEC, driver needs to ensure that all of commands/data has been dispatched to panel before the transcoder is enabled. This patch implement those steps i.e. sending NOP DCS command, wait for header/payload credit to be released etc. v2 by Jani: - squash the credit wait helpers patch with the first user - pass dev_priv to the credit wait helpers - bikeshed credit helper names - wait for *at least* the current maximum number of credits - indentation fix - add helpers for credits available Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/84bc509beabf2a2d1324a9f2a67ab4ebe05b10a6.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 74 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index d9c91001f107..0f0447b6b1be 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -28,6 +28,36 @@ #include #include "intel_dsi.h" +static inline int header_credits_available(struct drm_i915_private *dev_priv, + enum transcoder dsi_trans) +{ + return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_HEADER_CREDIT_MASK) + >> FREE_HEADER_CREDIT_SHIFT; +} + +static inline int payload_credits_available(struct drm_i915_private *dev_priv, + enum transcoder dsi_trans) +{ + return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_PLOAD_CREDIT_MASK) + >> FREE_PLOAD_CREDIT_SHIFT; +} + +static void wait_for_header_credits(struct drm_i915_private *dev_priv, + enum transcoder dsi_trans) +{ + if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >= + MAX_HEADER_CREDIT, 100)) + DRM_ERROR("DSI header credits not released\n"); +} + +static void wait_for_payload_credits(struct drm_i915_private *dev_priv, + enum transcoder dsi_trans) +{ + if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >= + MAX_PLOAD_CREDIT, 100)) + DRM_ERROR("DSI payload credits not released\n"); +} + static enum transcoder dsi_port_to_transcoder(enum port port) { if (port == PORT_A) @@ -36,6 +66,47 @@ static enum transcoder dsi_port_to_transcoder(enum port port) return TRANSCODER_DSI_1; } +static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + struct mipi_dsi_device *dsi; + enum port port; + enum transcoder dsi_trans; + int ret; + + /* wait for header/payload credits to be released */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + wait_for_header_credits(dev_priv, dsi_trans); + wait_for_payload_credits(dev_priv, dsi_trans); + } + + /* send nop DCS command */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi = intel_dsi->dsi_hosts[port]->device; + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + dsi->channel = 0; + ret = mipi_dsi_dcs_nop(dsi); + if (ret < 0) + DRM_ERROR("error sending DCS NOP command\n"); + } + + /* wait for header credits to be released */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + wait_for_header_credits(dev_priv, dsi_trans); + } + + /* wait for LP TX in progress bit to be cleared */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + if (wait_for_us(!(I915_READ(DSI_LP_MSG(dsi_trans)) & + LPTX_IN_PROGRESS), 20)) + DRM_ERROR("LPTX bit not cleared\n"); + } +} + static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -671,6 +742,9 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); + + /* ensure all panel commands dispatched before enabling transcoder */ + wait_for_cmds_dispatched_to_panel(encoder); } static void __attribute__((unused)) -- cgit v1.2.3 From 208013157a68e57fceffe463461c3d1eb83ea60a Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:12 +0200 Subject: drm/i915/icl: Turn ON panel backlight This patch enables backlight of DSI panel by using VBT BACKLIGHT_ON sequence and panel specific functions. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/05987eea297689af0b9defcf745a921f76f9011d.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 0f0447b6b1be..bffbb40cc0bc 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -752,6 +752,8 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + /* step2: enable IO power */ gen11_dsi_enable_io_power(encoder); @@ -769,4 +771,8 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, /* step6d: enable dsi transcoder */ gen11_dsi_enable_transcoder(encoder); + + /* step7: enable backlight */ + intel_panel_enable_backlight(pipe_config, conn_state); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); } -- cgit v1.2.3 From d9d996b6ca4393165e2ca5630fbdf3f7a2482028 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:13 +0200 Subject: drm/i915/icl: Turn OFF panel backlight This patch disbles backlight of DSI panel by using VBT BACKLIGHT_OFF sequence and panel specific disable functions. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/93cfbb198104deef4a281bbdef721385e4b6d954.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index bffbb40cc0bc..f7f48ff147d0 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -776,3 +776,15 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, intel_panel_enable_backlight(pipe_config, conn_state); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); } + +static void __attribute__((unused)) gen11_dsi_disable( + struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) +{ + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + + /* step1: turn off backlight */ + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF); + intel_panel_disable_backlight(old_conn_state); +} -- cgit v1.2.3 From 4e123bd3039d585deb989a84dec04f9e0acda9d3 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:14 +0200 Subject: drm/i915/icl: Disable DSI transcoders This patch disables transcoders by writing to TRANS_CONF registers for each DSI ports. v2 by Jani: - Wait for pipeconf active to go low Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/c76035309fa721322cf9c1ca7fc42b822937c2f3.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index f7f48ff147d0..644ad7475920 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -777,6 +777,29 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); } +static void gen11_dsi_disable_transcoder(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + enum transcoder dsi_trans; + u32 tmp; + + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + + /* disable transcoder */ + tmp = I915_READ(PIPECONF(dsi_trans)); + tmp &= ~PIPECONF_ENABLE; + I915_WRITE(PIPECONF(dsi_trans), tmp); + + /* wait for transcoder to be disabled */ + if (intel_wait_for_register(dev_priv, PIPECONF(dsi_trans), + I965_PIPECONF_ACTIVE, 0, 50)) + DRM_ERROR("DSI trancoder not disabled\n"); + } +} + static void __attribute__((unused)) gen11_dsi_disable( struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -787,4 +810,7 @@ static void __attribute__((unused)) gen11_dsi_disable( /* step1: turn off backlight */ intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF); intel_panel_disable_backlight(old_conn_state); + + /* step2d,e: disable transcoder and wait */ + gen11_dsi_disable_transcoder(encoder); } -- cgit v1.2.3 From 522cc3f717ac19a68847aee9831cb1e39f51f8dd Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:15 +0200 Subject: drm/i915/icl: Power down DSI panel This patch sends command and executes display off, assert reset, power off VBT seqeuences to power down DSI panel. Patch also adds high level function to wrap all the panel sepcific programming during DSI disabling. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/efdafbf6b4d31123738b87b2d8264a9b5553eb32.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 644ad7475920..a7b1a9eae04b 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -800,6 +800,18 @@ static void gen11_dsi_disable_transcoder(struct intel_encoder *encoder) } } +static void gen11_dsi_powerdown_panel(struct intel_encoder *encoder) +{ + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF); + + /* ensure cmds dispatched to panel */ + wait_for_cmds_dispatched_to_panel(encoder); +} + static void __attribute__((unused)) gen11_dsi_disable( struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -813,4 +825,7 @@ static void __attribute__((unused)) gen11_dsi_disable( /* step2d,e: disable transcoder and wait */ gen11_dsi_disable_transcoder(encoder); + + /* step2f,g: powerdown panel */ + gen11_dsi_powerdown_panel(encoder); } -- cgit v1.2.3 From 4769b598b94383bacd211caa2285e264c5e50498 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:16 +0200 Subject: drm/i915/icl: Put DSI link in ULPS As part of DSI disabling sequence, DSI link need to enter in ULPS by writing into DSI_LP_MSG register. This patch does the same using a wrapper function. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/50812f4bd37f95c053bef7eef4a95e5da029546f.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index a7b1a9eae04b..83c422d5976c 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -812,6 +812,29 @@ static void gen11_dsi_powerdown_panel(struct intel_encoder *encoder) wait_for_cmds_dispatched_to_panel(encoder); } +static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + enum transcoder dsi_trans; + u32 tmp; + + /* put dsi link in ULPS */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + tmp = I915_READ(DSI_LP_MSG(dsi_trans)); + tmp |= LINK_ENTER_ULPS; + tmp &= ~LINK_ULPS_TYPE_LP11; + I915_WRITE(DSI_LP_MSG(dsi_trans), tmp); + + if (wait_for_us((I915_READ(DSI_LP_MSG(dsi_trans)) & + LINK_IN_ULPS), + 10)) + DRM_ERROR("DSI link not in ULPS\n"); + } +} + static void __attribute__((unused)) gen11_dsi_disable( struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -828,4 +851,7 @@ static void __attribute__((unused)) gen11_dsi_disable( /* step2f,g: powerdown panel */ gen11_dsi_powerdown_panel(encoder); + + /* step2h,i,j: deconfig trancoder */ + gen11_dsi_deconfigure_trancoder(encoder); } -- cgit v1.2.3 From 7aa32f7c47c9c90eb0ad36a4ccc79418e48335b1 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:17 +0200 Subject: drm/i915/icl: Disable DDI function This patch disables DDI function by writing to TRANS_DDI_FUNC_CTL registers of DSI ports as part of DSI disable sequence. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/b0088d643247135ba96943fa14625f5a43f43633.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 83c422d5976c..0041f57d3c0b 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -833,6 +833,14 @@ static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder) 10)) DRM_ERROR("DSI link not in ULPS\n"); } + + /* disable ddi function */ + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans)); + tmp &= ~TRANS_DDI_FUNC_ENABLE; + I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp); + } } static void __attribute__((unused)) gen11_dsi_disable( -- cgit v1.2.3 From 9c83ab1bb384ebf72260b995c4c416bd86fd0e26 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:18 +0200 Subject: drm/i915/icl: Disable portsync mode This patch disables portsync mode if DSI link is operating in dual link mode by writing to TRANS_DDI_FUNC_CTL2 registers. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/3e608420b58930b6da478801bff018c6e964eb94.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 0041f57d3c0b..71092f116170 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -841,6 +841,16 @@ static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder) tmp &= ~TRANS_DDI_FUNC_ENABLE; I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp); } + + /* disable port sync mode if dual link */ + if (intel_dsi->dual_link) { + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans)); + tmp &= ~PORT_SYNC_MODE_ENABLE; + I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp); + } + } } static void __attribute__((unused)) gen11_dsi_disable( -- cgit v1.2.3 From 019cec36f3727daa811513221fa3b67bc4acec75 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:19 +0200 Subject: drm/i915/icl: Disable DSI ports This patch disables both DSI ports by writing to DDI_BUF_CTL registers as part of DSI encoder disable sequence. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/be9a7dc1ed89ad38679c67ff1c1552f0b4604494.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 71092f116170..44696848ffd7 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -853,6 +853,26 @@ static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder) } } +static void gen11_dsi_disable_port(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + u32 tmp; + enum port port; + + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(DDI_BUF_CTL(port)); + tmp &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), tmp); + + if (wait_for_us((I915_READ(DDI_BUF_CTL(port)) & + DDI_BUF_IS_IDLE), + 8)) + DRM_ERROR("DDI port:%c buffer not idle\n", + port_name(port)); + } +} + static void __attribute__((unused)) gen11_dsi_disable( struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -872,4 +892,7 @@ static void __attribute__((unused)) gen11_dsi_disable( /* step2h,i,j: deconfig trancoder */ gen11_dsi_deconfigure_trancoder(encoder); + + /* step3: disable port */ + gen11_dsi_disable_port(encoder); } -- cgit v1.2.3 From 0f0fe8497d968fef969c16f5dcff7062e85fb409 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:20 +0200 Subject: drm/i915/icl: Disable DSI IO power This patch configures mode of combo phy as DDI and disable IO power for DDI ports used by DSI. Signed-off-by: Madhav Chauhan Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/b68d767717a3b86c26042d0b16abb3943756fcc4.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 44696848ffd7..ac22c74ae146 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -873,6 +873,26 @@ static void gen11_dsi_disable_port(struct intel_encoder *encoder) } } +static void gen11_dsi_disable_io_power(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 tmp; + + intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_A_IO); + + if (intel_dsi->dual_link) + intel_display_power_put(dev_priv, POWER_DOMAIN_PORT_DDI_B_IO); + + /* set mode to DDI */ + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_DSI_IO_MODECTL(port)); + tmp &= ~COMBO_PHY_MODE_DSI; + I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp); + } +} + static void __attribute__((unused)) gen11_dsi_disable( struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -895,4 +915,7 @@ static void __attribute__((unused)) gen11_dsi_disable( /* step3: disable port */ gen11_dsi_disable_port(encoder); + + /* step4: disable IO power */ + gen11_dsi_disable_io_power(encoder); } -- cgit v1.2.3 From 5a4712f472bf67dc81b4d7cc571edca11cf52c87 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:22 +0200 Subject: drm/i915/icl: Program HS_TX_TIMEOUT/LP_RX_TIMEOUT/TA_TIMEOUT registers Program the timeout values (in escape clock) for HS TX, LP RX and TA timeout. HX TX: Ensure that host does not continuously transmit in the HS state. If this timer expires, then host will gracefully end its HS transmission and allow the link to enter into LP state. LP RX: Monitor the length of LP receptions from Peripheral. If timeout happens then host will drive the stop state onto all data lanes (only Data Lane 0 should be receiving anything from the Peripheral). This effectively takes back ownership of the bus transmit in the HS state. TA timeout: Timeout valuefor monitoring Bus Turn-Around (BTA) sequence. BTA sequence should complete within a bounded amount of time, with peripheral acknowledging BTA by driving the stop state. v2 by Jani: - Rebase - Use intel_dsi_bitrate() and intel_dsi_tlpx_ns(intel_dsi) - Squash HX TX, LP RX and TA timeout into one patch - Fix bspec mode set sequence reference - Add FIXME about two timeouts Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/60e610ccffe5f8c09dee1c65828f28f25227efce.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index ac22c74ae146..fd82f349ced9 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -685,6 +685,55 @@ static void gen11_dsi_enable_transcoder(struct intel_encoder *encoder) } } +static void gen11_dsi_setup_timeouts(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + enum transcoder dsi_trans; + u32 tmp, hs_tx_timeout, lp_rx_timeout, ta_timeout, divisor, mul; + + /* + * escape clock count calculation: + * BYTE_CLK_COUNT = TIME_NS/(8 * UI) + * UI (nsec) = (10^6)/Bitrate + * TIME_NS = (BYTE_CLK_COUNT * 8 * 10^6)/ Bitrate + * ESCAPE_CLK_COUNT = TIME_NS/ESC_CLK_NS + */ + divisor = intel_dsi_tlpx_ns(intel_dsi) * intel_dsi_bitrate(intel_dsi) * 1000; + mul = 8 * 1000000; + hs_tx_timeout = DIV_ROUND_UP(intel_dsi->hs_tx_timeout * mul, + divisor); + lp_rx_timeout = DIV_ROUND_UP(intel_dsi->lp_rx_timeout * mul, divisor); + ta_timeout = DIV_ROUND_UP(intel_dsi->turn_arnd_val * mul, divisor); + + for_each_dsi_port(port, intel_dsi->ports) { + dsi_trans = dsi_port_to_transcoder(port); + + /* program hst_tx_timeout */ + tmp = I915_READ(DSI_HSTX_TO(dsi_trans)); + tmp &= ~HSTX_TIMEOUT_VALUE_MASK; + tmp |= HSTX_TIMEOUT_VALUE(hs_tx_timeout); + I915_WRITE(DSI_HSTX_TO(dsi_trans), tmp); + + /* FIXME: DSI_CALIB_TO */ + + /* program lp_rx_host timeout */ + tmp = I915_READ(DSI_LPRX_HOST_TO(dsi_trans)); + tmp &= ~LPRX_TIMEOUT_VALUE_MASK; + tmp |= LPRX_TIMEOUT_VALUE(lp_rx_timeout); + I915_WRITE(DSI_LPRX_HOST_TO(dsi_trans), tmp); + + /* FIXME: DSI_PWAIT_TO */ + + /* program turn around timeout */ + tmp = I915_READ(DSI_TA_TO(dsi_trans)); + tmp &= ~TA_TIMEOUT_VALUE_MASK; + tmp |= TA_TIMEOUT_VALUE(ta_timeout); + I915_WRITE(DSI_TA_TO(dsi_trans), tmp); + } +} + static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config) @@ -704,6 +753,9 @@ gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, /* setup D-PHY timings */ gen11_dsi_setup_dphy_timings(encoder); + /* step 4h: setup DSI protocol timeouts */ + gen11_dsi_setup_timeouts(encoder); + /* Step (4h, 4i, 4j, 4k): Configure transcoder */ gen11_dsi_configure_transcoder(encoder, pipe_config); } -- cgit v1.2.3 From bf4d57ff411017468977203a009ce719aa83a93d Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:23 +0200 Subject: drm/i915/icl: Find DSI presence for ICL This patch detects DSI presence for ICL platform by reading VBT. DSI detection is done while initializing DSI using newly added function intel_gen11_dsi_init. v2 by Jani: - Preserve old behavour of intel_bios_is_dsi_present() - s/intel_gen11_dsi_init/icl_dsi_init/g Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/2324cdfc8918bda3165354e5e0d15053b1074f14.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915/icl_dsi.c') diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index fd82f349ced9..01f422df8c23 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -971,3 +971,11 @@ static void __attribute__((unused)) gen11_dsi_disable( /* step4: disable IO power */ gen11_dsi_disable_io_power(encoder); } + +void icl_dsi_init(struct drm_i915_private *dev_priv) +{ + enum port port; + + if (!intel_bios_is_dsi_present(dev_priv, &port)) + return; +} -- cgit v1.2.3