From 2bf3f59daeee6cfed79bd0d292aa9b4eded37c42 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 15 Oct 2018 17:27:50 +0300 Subject: drm/i915/dsi: refactor bitrate calculations in intel_dsi_vbt_init() Abstract bitrate calculation to a newly resurrected intel_dsi.c file that will contain common code for VLV and ICL DSI. No functional changes. Cc: Madhav Chauhan Cc: Ville Syrjala Reviewed-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/100e9721dfdec4f3987549ef24291bafc9cb0517.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dsi.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index ad7c1cb32983..68f14d8f1e18 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -129,6 +129,9 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) return container_of(encoder, struct intel_dsi, base.base); } +/* intel_dsi.c */ +int intel_dsi_bitrate(const struct intel_dsi *intel_dsi); + /* vlv_dsi.c */ void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); -- cgit v1.2.3 From 9ec9a87b1ee8ed96428a8ad284d25cdea5cf0706 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 15 Oct 2018 17:27:52 +0300 Subject: drm/i915/dsi: abstract intel_dsi_tlpx_ns() Will be needed in the future. No functional changes. Cc: Madhav Chauhan Cc: Ville Syrjala Reviewed-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/2cb427e5bc2ea88e4226bfcf162b3a6f307e32e1.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dsi.c | 13 +++++++++++++ drivers/gpu/drm/i915/intel_dsi.h | 1 + drivers/gpu/drm/i915/intel_dsi_vbt.c | 16 +--------------- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 4daa1da94047..a32cc1f4b384 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -15,3 +15,16 @@ int intel_dsi_bitrate(const struct intel_dsi *intel_dsi) return intel_dsi->pclk * bpp / intel_dsi->lane_count; } + +int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi) +{ + switch (intel_dsi->escape_clk_div) { + default: + case 0: + return 50; + case 1: + return 100; + case 2: + return 200; + } +} diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 68f14d8f1e18..0d911a4adfaa 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -131,6 +131,7 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) /* intel_dsi.c */ int intel_dsi_bitrate(const struct intel_dsi *intel_dsi); +int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi); /* vlv_dsi.c */ void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c index fdeba8386d53..b0d8548f0462 100644 --- a/drivers/gpu/drm/i915/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c @@ -512,21 +512,7 @@ static void vlv_dphy_param_init(struct intel_dsi *intel_dsi) u32 lp_to_hs_switch, hs_to_lp_switch; u32 mul; - switch (intel_dsi->escape_clk_div) { - case 0: - tlpx_ns = 50; - break; - case 1: - tlpx_ns = 100; - break; - - case 2: - tlpx_ns = 200; - break; - default: - tlpx_ns = 50; - break; - } + tlpx_ns = intel_dsi_tlpx_ns(intel_dsi); switch (intel_dsi->lane_count) { case 1: -- cgit v1.2.3 From b687c1984c4fbb40ba9058c5db9a604ffc466f5e Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Mon, 15 Oct 2018 17:27:53 +0300 Subject: drm/i915/icl: Make common DSI functions available This patch moves couple of legacy DSI functions to header and common DSI files so that they can be re-used by Gen11 DSI. No functional change. v2 by Jani: - Move intel_dsi_msleep() to intel_dsi_vbt.c Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/bd1f5f3e96d3e1de4d359f4fd1b750ac7e3c87d4.1539613303.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dsi.h | 11 +++++++++++ drivers/gpu/drm/i915/intel_dsi_vbt.c | 11 +++++++++++ drivers/gpu/drm/i915/vlv_dsi.c | 21 --------------------- 3 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 0d911a4adfaa..d7c0c599b52d 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -129,6 +129,16 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) return container_of(encoder, struct intel_dsi, base.base); } +static inline bool is_vid_mode(struct intel_dsi *intel_dsi) +{ + return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE; +} + +static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) +{ + return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE; +} + /* intel_dsi.c */ int intel_dsi_bitrate(const struct intel_dsi *intel_dsi); int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi); @@ -162,5 +172,6 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id); int intel_dsi_vbt_get_modes(struct intel_dsi *intel_dsi); void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, enum mipi_seq seq_id); +void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec); #endif /* _INTEL_DSI_H */ diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c index b0d8548f0462..5e16b4c5f531 100644 --- a/drivers/gpu/drm/i915/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c @@ -481,6 +481,17 @@ void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, } } +void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) +{ + struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); + + /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */ + if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3) + return; + + msleep(msec); +} + int intel_dsi_vbt_get_modes(struct intel_dsi *intel_dsi) { struct intel_connector *connector = intel_dsi->attached_connector; diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index dbca30460a6b..ee0cd5d0bf91 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -290,16 +290,6 @@ static void band_gap_reset(struct drm_i915_private *dev_priv) mutex_unlock(&dev_priv->sb_lock); } -static inline bool is_vid_mode(struct intel_dsi *intel_dsi) -{ - return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE; -} - -static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) -{ - return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE; -} - static bool intel_dsi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) @@ -746,17 +736,6 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder, const struct intel_crtc_state *pipe_config); static void intel_dsi_unprepare(struct intel_encoder *encoder); -static void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) -{ - struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); - - /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */ - if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3) - return; - - msleep(msec); -} - /* * Panel enable/disable sequences from the VBT spec. * -- 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 ++++++ drivers/gpu/drm/i915/intel_dsi.h | 3 + drivers/gpu/drm/i915/intel_dsi_vbt.c | 110 ++++++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') 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) diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index d7c0c599b52d..12b758ebefce 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -85,6 +85,9 @@ struct intel_dsi { u32 port_bits; u32 bw_timer; u32 dphy_reg; + + /* data lanes dphy timing */ + u32 dphy_data_lane_reg; u32 video_frmt_cfg_bits; u16 lp_byte_clk; diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c index 5e16b4c5f531..3035422aa0d6 100644 --- a/drivers/gpu/drm/i915/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c @@ -510,6 +510,111 @@ int intel_dsi_vbt_get_modes(struct intel_dsi *intel_dsi) return 1; } +#define ICL_PREPARE_CNT_MAX 0x7 +#define ICL_CLK_ZERO_CNT_MAX 0xf +#define ICL_TRAIL_CNT_MAX 0x7 +#define ICL_TCLK_PRE_CNT_MAX 0x3 +#define ICL_TCLK_POST_CNT_MAX 0x7 +#define ICL_HS_ZERO_CNT_MAX 0xf +#define ICL_EXIT_ZERO_CNT_MAX 0x7 + +static void icl_dphy_param_init(struct intel_dsi *intel_dsi) +{ + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; + u32 tlpx_ns; + u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt; + u32 ths_prepare_ns, tclk_trail_ns; + u32 hs_zero_cnt; + u32 tclk_pre_cnt, tclk_post_cnt; + + tlpx_ns = intel_dsi_tlpx_ns(intel_dsi); + + tclk_trail_ns = max(mipi_config->tclk_trail, mipi_config->ths_trail); + ths_prepare_ns = max(mipi_config->ths_prepare, + mipi_config->tclk_prepare); + + /* + * prepare cnt in escape clocks + * this field represents a hexadecimal value with a precision + * of 1.2 – i.e. the most significant bit is the integer + * and the least significant 2 bits are fraction bits. + * so, the field can represent a range of 0.25 to 1.75 + */ + prepare_cnt = DIV_ROUND_UP(ths_prepare_ns * 4, tlpx_ns); + if (prepare_cnt > ICL_PREPARE_CNT_MAX) { + DRM_DEBUG_KMS("prepare_cnt out of range (%d)\n", prepare_cnt); + prepare_cnt = ICL_PREPARE_CNT_MAX; + } + + /* clk zero count in escape clocks */ + clk_zero_cnt = DIV_ROUND_UP(mipi_config->tclk_prepare_clkzero - + ths_prepare_ns, tlpx_ns); + if (clk_zero_cnt > ICL_CLK_ZERO_CNT_MAX) { + DRM_DEBUG_KMS("clk_zero_cnt out of range (%d)\n", clk_zero_cnt); + clk_zero_cnt = ICL_CLK_ZERO_CNT_MAX; + } + + /* trail cnt in escape clocks*/ + trail_cnt = DIV_ROUND_UP(tclk_trail_ns, tlpx_ns); + if (trail_cnt > ICL_TRAIL_CNT_MAX) { + DRM_DEBUG_KMS("trail_cnt out of range (%d)\n", trail_cnt); + trail_cnt = ICL_TRAIL_CNT_MAX; + } + + /* tclk pre count in escape clocks */ + tclk_pre_cnt = DIV_ROUND_UP(mipi_config->tclk_pre, tlpx_ns); + if (tclk_pre_cnt > ICL_TCLK_PRE_CNT_MAX) { + DRM_DEBUG_KMS("tclk_pre_cnt out of range (%d)\n", tclk_pre_cnt); + tclk_pre_cnt = ICL_TCLK_PRE_CNT_MAX; + } + + /* tclk post count in escape clocks */ + tclk_post_cnt = DIV_ROUND_UP(mipi_config->tclk_post, tlpx_ns); + if (tclk_post_cnt > ICL_TCLK_POST_CNT_MAX) { + DRM_DEBUG_KMS("tclk_post_cnt out of range (%d)\n", tclk_post_cnt); + tclk_post_cnt = ICL_TCLK_POST_CNT_MAX; + } + + /* hs zero cnt in escape clocks */ + hs_zero_cnt = DIV_ROUND_UP(mipi_config->ths_prepare_hszero - + ths_prepare_ns, tlpx_ns); + if (hs_zero_cnt > ICL_HS_ZERO_CNT_MAX) { + DRM_DEBUG_KMS("hs_zero_cnt out of range (%d)\n", hs_zero_cnt); + hs_zero_cnt = ICL_HS_ZERO_CNT_MAX; + } + + /* hs exit zero cnt in escape clocks */ + exit_zero_cnt = DIV_ROUND_UP(mipi_config->ths_exit, tlpx_ns); + if (exit_zero_cnt > ICL_EXIT_ZERO_CNT_MAX) { + DRM_DEBUG_KMS("exit_zero_cnt out of range (%d)\n", exit_zero_cnt); + exit_zero_cnt = ICL_EXIT_ZERO_CNT_MAX; + } + + /* clock lane dphy timings */ + intel_dsi->dphy_reg = (CLK_PREPARE_OVERRIDE | + CLK_PREPARE(prepare_cnt) | + CLK_ZERO_OVERRIDE | + CLK_ZERO(clk_zero_cnt) | + CLK_PRE_OVERRIDE | + CLK_PRE(tclk_pre_cnt) | + CLK_POST_OVERRIDE | + CLK_POST(tclk_post_cnt) | + CLK_TRAIL_OVERRIDE | + CLK_TRAIL(trail_cnt)); + + /* data lanes dphy timings */ + intel_dsi->dphy_data_lane_reg = (HS_PREPARE_OVERRIDE | + HS_PREPARE(prepare_cnt) | + HS_ZERO_OVERRIDE | + HS_ZERO(hs_zero_cnt) | + HS_TRAIL_OVERRIDE | + HS_TRAIL(trail_cnt) | + HS_EXIT_OVERRIDE | + HS_EXIT(exit_zero_cnt)); +} + static void vlv_dphy_param_init(struct intel_dsi *intel_dsi) { struct drm_device *dev = intel_dsi->base.base.dev; @@ -743,7 +848,10 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) intel_dsi->burst_mode_ratio = burst_mode_ratio; - vlv_dphy_param_init(intel_dsi); + if (IS_ICELAKE(dev_priv)) + icl_dphy_param_init(intel_dsi); + else + vlv_dphy_param_init(intel_dsi); DRM_DEBUG_KMS("Pclk %d\n", intel_dsi->pclk); DRM_DEBUG_KMS("Pixel overlap %d\n", intel_dsi->pixel_overlap); -- 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 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_dsi.h | 3 ++ drivers/gpu/drm/i915/intel_dsi_vbt.c | 1 + 3 files changed, 90 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') 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)) diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 12b758ebefce..14567929de9a 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -81,6 +81,9 @@ struct intel_dsi { u16 dcs_backlight_ports; u16 dcs_cabc_ports; + /* RGB or BGR */ + bool bgr_enabled; + u8 pixel_overlap; u32 port_bits; u32 bw_timer; diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c index 3035422aa0d6..cca071406c25 100644 --- a/drivers/gpu/drm/i915/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c @@ -805,6 +805,7 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) intel_dsi->bw_timer = mipi_config->dbi_bw_timer; intel_dsi->video_frmt_cfg_bits = mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0; + intel_dsi->bgr_enabled = mipi_config->rgb_flip; /* Starting point, adjusted depending on dual link and burst mode */ intel_dsi->pclk = mode->clock; -- cgit v1.2.3 From 8e54d4fe79f0dbdf280bb5d5bbab669c592f9cc7 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:07 +0200 Subject: drm/i915/icl: Move dsi host init code to common file This patch moves intl_dsi_host_init() code to intel_dsi.c so that legacy and gen11 DSI code can share this code. v2 by Jani: - Move the shared stuff to intel_dsi.c Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1ee42b2d3c639e3f3c14a2c1595b8778901574d4.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dsi.c | 34 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dsi.h | 3 +++ drivers/gpu/drm/i915/vlv_dsi.c | 36 ++---------------------------------- 3 files changed, 39 insertions(+), 34 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index a32cc1f4b384..97e04c272612 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -28,3 +28,37 @@ int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi) return 200; } } + +struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi, + const struct mipi_dsi_host_ops *funcs, + enum port port) +{ + struct intel_dsi_host *host; + struct mipi_dsi_device *device; + + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) + return NULL; + + host->base.ops = funcs; + host->intel_dsi = intel_dsi; + host->port = port; + + /* + * We should call mipi_dsi_host_register(&host->base) here, but we don't + * have a host->dev, and we don't have OF stuff either. So just use the + * dsi framework as a library and hope for the best. Create the dsi + * devices by ourselves here too. Need to be careful though, because we + * don't initialize any of the driver model devices here. + */ + device = kzalloc(sizeof(*device), GFP_KERNEL); + if (!device) { + kfree(host); + return NULL; + } + + device->host = &host->base; + host->device = device; + + return host; +} diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 14567929de9a..09f0fa9ccc7d 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -152,6 +152,9 @@ int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi); /* vlv_dsi.c */ void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); +struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi, + const struct mipi_dsi_host_ops *funcs, + enum port port); /* vlv_dsi_pll.c */ int vlv_dsi_pll_compute(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index ee0cd5d0bf91..cbb935a9acf3 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -206,39 +206,6 @@ static const struct mipi_dsi_host_ops intel_dsi_host_ops = { .transfer = intel_dsi_host_transfer, }; -static struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi, - enum port port) -{ - struct intel_dsi_host *host; - struct mipi_dsi_device *device; - - host = kzalloc(sizeof(*host), GFP_KERNEL); - if (!host) - return NULL; - - host->base.ops = &intel_dsi_host_ops; - host->intel_dsi = intel_dsi; - host->port = port; - - /* - * We should call mipi_dsi_host_register(&host->base) here, but we don't - * have a host->dev, and we don't have OF stuff either. So just use the - * dsi framework as a library and hope for the best. Create the dsi - * devices by ourselves here too. Need to be careful though, because we - * don't initialize any of the driver model devices here. - */ - device = kzalloc(sizeof(*device), GFP_KERNEL); - if (!device) { - kfree(host); - return NULL; - } - - device->host = &host->base; - host->device = device; - - return host; -} - /* * send a video mode command * @@ -1768,7 +1735,8 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) for_each_dsi_port(port, intel_dsi->ports) { struct intel_dsi_host *host; - host = intel_dsi_host_init(intel_dsi, port); + host = intel_dsi_host_init(intel_dsi, &intel_dsi_host_ops, + port); if (!host) goto err; -- cgit v1.2.3 From 0d90c61ab9b043f49dcb544e170ab4411b6b3408 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan Date: Tue, 30 Oct 2018 13:56:08 +0200 Subject: drm/i915/dsi: move connector mode functions to common file Move DSI connector functions to intel_dsi.c and make them available to both legacy and ICL DSI. v2 by Jani: - Move the functions to intel_dsi.c - Don't reuse intel_dsi_connector_destroy() Signed-off-by: Madhav Chauhan Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/99244c6edf4a26ef2e279c7160d22dbbb5cd95f2.1540900289.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dsi.c | 47 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dsi.h | 3 +++ drivers/gpu/drm/i915/vlv_dsi.c | 48 ---------------------------------------- 3 files changed, 50 insertions(+), 48 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 97e04c272612..b9d5ef79015e 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -29,6 +29,53 @@ int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi) } } +int intel_dsi_get_modes(struct drm_connector *connector) +{ + struct intel_connector *intel_connector = to_intel_connector(connector); + struct drm_display_mode *mode; + + DRM_DEBUG_KMS("\n"); + + if (!intel_connector->panel.fixed_mode) { + DRM_DEBUG_KMS("no fixed mode\n"); + return 0; + } + + mode = drm_mode_duplicate(connector->dev, + intel_connector->panel.fixed_mode); + if (!mode) { + DRM_DEBUG_KMS("drm_mode_duplicate failed\n"); + return 0; + } + + drm_mode_probed_add(connector, mode); + return 1; +} + +enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct intel_connector *intel_connector = to_intel_connector(connector); + const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; + int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + + DRM_DEBUG_KMS("\n"); + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (fixed_mode) { + if (mode->hdisplay > fixed_mode->hdisplay) + return MODE_PANEL; + if (mode->vdisplay > fixed_mode->vdisplay) + return MODE_PANEL; + if (fixed_mode->clock > max_dotclk) + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi, const struct mipi_dsi_host_ops *funcs, enum port port) diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 09f0fa9ccc7d..10fd1582a8e2 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -152,6 +152,9 @@ int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi); /* vlv_dsi.c */ void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); +int intel_dsi_get_modes(struct drm_connector *connector); +enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode); struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi, const struct mipi_dsi_host_ops *funcs, enum port port); diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index cbb935a9acf3..bab87b62bc2d 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -1212,31 +1212,6 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, } } -static enum drm_mode_status -intel_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct intel_connector *intel_connector = to_intel_connector(connector); - const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; - int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; - - DRM_DEBUG_KMS("\n"); - - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - return MODE_NO_DBLESCAN; - - if (fixed_mode) { - if (mode->hdisplay > fixed_mode->hdisplay) - return MODE_PANEL; - if (mode->vdisplay > fixed_mode->vdisplay) - return MODE_PANEL; - if (fixed_mode->clock > max_dotclk) - return MODE_CLOCK_HIGH; - } - - return MODE_OK; -} - /* return txclkesc cycles in terms of divider and duration in us */ static u16 txclkesc(u32 divider, unsigned int us) { @@ -1559,29 +1534,6 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder) } } -static int intel_dsi_get_modes(struct drm_connector *connector) -{ - struct intel_connector *intel_connector = to_intel_connector(connector); - struct drm_display_mode *mode; - - DRM_DEBUG_KMS("\n"); - - if (!intel_connector->panel.fixed_mode) { - DRM_DEBUG_KMS("no fixed mode\n"); - return 0; - } - - mode = drm_mode_duplicate(connector->dev, - intel_connector->panel.fixed_mode); - if (!mode) { - DRM_DEBUG_KMS("drm_mode_duplicate failed\n"); - return 0; - } - - drm_mode_probed_add(connector, mode); - return 1; -} - static void intel_dsi_encoder_destroy(struct drm_encoder *encoder) { struct intel_dsi *intel_dsi = enc_to_intel_dsi(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 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dsi.h | 1 + drivers/gpu/drm/i915/intel_dsi_vbt.c | 1 + 3 files changed, 54 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') 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); } diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 10fd1582a8e2..f2a3ddedcc5d 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -95,6 +95,7 @@ struct intel_dsi { u16 lp_byte_clk; /* timeouts in byte clocks */ + u16 hs_tx_timeout; u16 lp_rx_timeout; u16 turn_arnd_val; u16 rst_timer_val; diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c index cca071406c25..80bd56e96143 100644 --- a/drivers/gpu/drm/i915/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c @@ -799,6 +799,7 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) intel_dsi->video_mode_format = mipi_config->video_transfer_mode; intel_dsi->escape_clk_div = mipi_config->byte_clk_sel; intel_dsi->lp_rx_timeout = mipi_config->lp_rx_timeout; + intel_dsi->hs_tx_timeout = mipi_config->hs_tx_timeout; intel_dsi->turn_arnd_val = mipi_config->turn_around_timeout; intel_dsi->rst_timer_val = mipi_config->device_reset_timer; intel_dsi->init_count = mipi_config->master_init_timer; -- cgit v1.2.3 From c1cd5b24d6cebfbfe5aca7e989ed98d773a696ed Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 22 Oct 2018 17:20:15 +0300 Subject: drm/i915: Determine DSI panel orientation from VBT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VBT appears to have two (or possibly three) ways to indicate the panel rotation. The first is in the MIPI config block, but that apparenly usually (maybe always?) indicates 0 degrees despite the actual panel orientation. The second way to indicate this is in the general features block, which can just indicate whether 180 degress rotation is used. The third might be a separate rotation data block, but that is not at all documented so who knows what it may contain. Let's try the first two. We first try the DSI specicic VBT information, and it it doesn't look trustworthy (ie. indicates 0 degrees) we fall back to the 180 degree thing. Just to avoid too many changes in one go we shall also keep the hardware readout path for now. If this works for more than just my VLV FFRD the question becomes how many of the panel orientation quirks are now redundant? v2: Move the code into intel_dsi.c (Jani) Cc: Hans de Goede Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181022142015.4026-1-ville.syrjala@linux.intel.com Tested-by: Hans de Goede --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_bios.c | 31 +++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dsi.c | 17 +++++++++++++++++ drivers/gpu/drm/i915/intel_dsi.h | 2 ++ drivers/gpu/drm/i915/vlv_dsi.c | 2 +- 5 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_dsi.h') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 08d25aa480f7..5d686b585a95 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1110,6 +1110,7 @@ struct intel_vbt_data { unsigned int panel_type:4; int lvds_ssc_freq; unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + enum drm_panel_orientation orientation; enum drrs_support_type drrs_type; @@ -1155,6 +1156,7 @@ struct intel_vbt_data { u8 *data; const u8 *sequence[MIPI_SEQ_MAX]; u8 *deassert_seq; /* Used by fixup_mipi_sequences() */ + enum drm_panel_orientation orientation; } dsi; int crt_ddc_pin; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 0ad2304457ab..bd7b2da71419 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -420,6 +420,13 @@ parse_general_features(struct drm_i915_private *dev_priv, intel_bios_ssc_frequency(dev_priv, general->ssc_freq); dev_priv->vbt.display_clock_mode = general->display_clock_mode; dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; + if (bdb->version >= 181) { + dev_priv->vbt.orientation = general->rotate_180 ? + DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP : + DRM_MODE_PANEL_ORIENTATION_NORMAL; + } else { + dev_priv->vbt.orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; + } DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", dev_priv->vbt.int_tv_support, dev_priv->vbt.int_crt_support, @@ -852,6 +859,30 @@ parse_mipi_config(struct drm_i915_private *dev_priv, parse_dsi_backlight_ports(dev_priv, bdb->version, port); + /* FIXME is the 90 vs. 270 correct? */ + switch (config->rotation) { + case ENABLE_ROTATION_0: + /* + * Most (all?) VBTs claim 0 degrees despite having + * an upside down panel, thus we do not trust this. + */ + dev_priv->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_UNKNOWN; + break; + case ENABLE_ROTATION_90: + dev_priv->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; + break; + case ENABLE_ROTATION_180: + dev_priv->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; + break; + case ENABLE_ROTATION_270: + dev_priv->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_LEFT_UP; + break; + } + /* We have mandatory mipi config blocks. Initialize as generic panel */ dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; } diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b9d5ef79015e..5fec02aceaed 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -109,3 +109,20 @@ struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi, return host; } + +enum drm_panel_orientation +intel_dsi_get_panel_orientation(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + enum drm_panel_orientation orientation; + + orientation = dev_priv->vbt.dsi.orientation; + if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) + return orientation; + + orientation = dev_priv->vbt.orientation; + if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) + return orientation; + + return DRM_MODE_PANEL_ORIENTATION_NORMAL; +} diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index f2a3ddedcc5d..ee93137f4433 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -149,6 +149,8 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) /* intel_dsi.c */ int intel_dsi_bitrate(const struct intel_dsi *intel_dsi); int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi); +enum drm_panel_orientation +intel_dsi_get_panel_orientation(struct intel_connector *connector); /* vlv_dsi.c */ void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index f1eedc974dbc..361e962a7969 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -1614,7 +1614,7 @@ vlv_dsi_get_panel_orientation(struct intel_connector *connector) return orientation; } - return DRM_MODE_PANEL_ORIENTATION_NORMAL; + return intel_dsi_get_panel_orientation(connector); } static void intel_dsi_add_properties(struct intel_connector *connector) -- cgit v1.2.3