From edef6ae0406008b3e4f23acdb353aa940c20204c Mon Sep 17 00:00:00 2001 From: Satya Rama Aditya Pinapala Date: Thu, 23 May 2019 09:48:41 -0700 Subject: [PATCH] disp: msm: dsi: snapshot of dsi from 4.14 to 4.19 This change is a snapshot of dsi files taken of 4.14 as of commit 764f7c2 (Merge remote-tracking branch 'quic/dev/msm-4.14-display' into msm-4.14) Change-Id: I8361a844c35a4450f7800964a8da2741676fd6c7 Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_catalog.c | 2 + msm/dsi/dsi_catalog.h | 2 + msm/dsi/dsi_clk_manager.c | 20 +--- msm/dsi/dsi_ctrl.c | 85 +++++++++----- msm/dsi/dsi_ctrl.h | 31 ++++- msm/dsi/dsi_ctrl_hw.h | 6 + msm/dsi/dsi_ctrl_hw_cmn.c | 48 ++++++++ msm/dsi/dsi_ctrl_reg.h | 1 + msm/dsi/dsi_display.c | 177 +++++++++++++++++++++++----- msm/dsi/dsi_panel.c | 208 +++++++++++++++++++++++++++------ msm/dsi/dsi_panel.h | 5 +- msm/dsi/dsi_phy.c | 22 +++- msm/dsi/dsi_phy.h | 10 +- msm/dsi/dsi_phy_hw.h | 9 ++ msm/dsi/dsi_phy_hw_v2_0.c | 113 +++++++++++------- msm/dsi/dsi_phy_hw_v4_0.c | 21 +++- msm/dsi/dsi_pwr.c | 13 +++ msm/dsi/dsi_pwr.h | 2 + msm/sde/sde_encoder_phys_cmd.c | 2 +- msm/sde/sde_kms.c | 23 ++-- msm/sde_dbg.c | 3 +- 21 files changed, 632 insertions(+), 171 deletions(-) diff --git a/msm/dsi/dsi_catalog.c b/msm/dsi/dsi_catalog.c index 0d6ba1bad2..d921c448cd 100644 --- a/msm/dsi/dsi_catalog.c +++ b/msm/dsi/dsi_catalog.c @@ -64,6 +64,7 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.set_continuous_clk = dsi_ctrl_hw_cmn_set_continuous_clk; ctrl->ops.wait4dynamic_refresh_done = dsi_ctrl_hw_cmn_wait4dynamic_refresh_done; + ctrl->ops.hs_req_sel = dsi_ctrl_hw_cmn_hs_req_sel; switch (version) { case DSI_CTRL_VERSION_1_4: @@ -261,6 +262,7 @@ static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy) dsi_phy_hw_v4_0_dyn_refresh_helper; phy->ops.dyn_refresh_ops.cache_phy_timings = dsi_phy_hw_v4_0_cache_phy_timings; + phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk; } /** diff --git a/msm/dsi/dsi_catalog.h b/msm/dsi/dsi_catalog.h index 124803b844..c4e47d878a 100644 --- a/msm/dsi/dsi_catalog.h +++ b/msm/dsi/dsi_catalog.h @@ -115,6 +115,7 @@ int dsi_phy_hw_timing_val_v4_0(struct dsi_phy_per_lane_cfgs *timing_cfg, int dsi_phy_hw_v4_0_lane_reset(struct dsi_phy_hw *phy); void dsi_phy_hw_v4_0_toggle_resync_fifo(struct dsi_phy_hw *phy); void dsi_phy_hw_v4_0_reset_clk_en_sel(struct dsi_phy_hw *phy); +void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable); /* DSI controller common ops */ u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl); @@ -239,6 +240,7 @@ void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable, enum dsi_clk_gate_type clk_selection); void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable); +void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy); /* dynamic refresh specific functions */ void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset); diff --git a/msm/dsi/dsi_clk_manager.c b/msm/dsi/dsi_clk_manager.c index 50276d8530..875b96c5b7 100644 --- a/msm/dsi/dsi_clk_manager.c +++ b/msm/dsi/dsi_clk_manager.c @@ -1272,23 +1272,15 @@ static int dsi_display_link_clk_force_update(void *client) goto error; } - rc = dsi_display_link_clk_disable(l_clks, - (DSI_LINK_LP_CLK | DSI_LINK_HS_CLK), - mngr->dsi_ctrl_count, mngr->master_ndx); - if (rc) { - pr_err("%s, failed to stop link clk, rc = %d\n", - __func__, rc); + rc = dsi_clk_update_link_clk_state(mngr, l_clks, (DSI_LINK_LP_CLK | + DSI_LINK_HS_CLK), DSI_CLK_OFF, false); + if (rc) goto error; - } - rc = dsi_display_link_clk_enable(l_clks, - (DSI_LINK_LP_CLK | DSI_LINK_HS_CLK), - mngr->dsi_ctrl_count, mngr->master_ndx); - if (rc) { - pr_err("%s, failed to start link clk rc= %d\n", - __func__, rc); + rc = dsi_clk_update_link_clk_state(mngr, l_clks, (DSI_LINK_LP_CLK | + DSI_LINK_HS_CLK), DSI_CLK_ON, true); + if (rc) goto error; - } error: mutex_unlock(&mngr->clk_mutex); diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 735d171751..0625fbd236 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -34,22 +34,6 @@ #define TICKS_IN_MICRO_SECOND 1000000 -/** - * enum dsi_ctrl_driver_ops - controller driver ops - */ -enum dsi_ctrl_driver_ops { - DSI_CTRL_OP_POWER_STATE_CHANGE, - DSI_CTRL_OP_CMD_ENGINE, - DSI_CTRL_OP_VID_ENGINE, - DSI_CTRL_OP_HOST_ENGINE, - DSI_CTRL_OP_CMD_TX, - DSI_CTRL_OP_HOST_INIT, - DSI_CTRL_OP_TPG, - DSI_CTRL_OP_PHY_SW_RESET, - DSI_CTRL_OP_ASYNC_TIMING, - DSI_CTRL_OP_MAX -}; - struct dsi_ctrl_list_item { struct dsi_ctrl *ctrl; struct list_head list; @@ -833,6 +817,7 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate; struct dsi_host_common_cfg *host_cfg = &config->common_config; + struct dsi_split_link_config *split_link = &host_cfg->split_link; struct dsi_mode_info *timing = &config->video_timing; u64 dsi_transfer_time_us = mode->priv_info->dsi_transfer_time_us; u64 min_dsi_clk_hz = mode->priv_info->min_dsi_clk_hz; @@ -850,6 +835,9 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, if (host_cfg->data_lanes & DSI_DATA_LANE_3) num_of_lanes++; + if (split_link->split_link_enabled) + num_of_lanes = split_link->lanes_per_sublink; + config->common_config.num_data_lanes = num_of_lanes; config->common_config.bpp = bpp; @@ -943,6 +931,7 @@ static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl, int rc = 0; u8 *buf = NULL; u32 len, i; + u8 cmd_type = 0; len = packet->size; len += 0x3; len &= ~0x03; /* Align to 32 bits */ @@ -965,7 +954,11 @@ static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl, /* send embedded BTA for read commands */ - if ((buf[2] & 0x3f) == MIPI_DSI_DCS_READ) + cmd_type = buf[2] & 0x3f; + if ((cmd_type == MIPI_DSI_DCS_READ) || + (cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || + (cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || + (cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM)) buf[3] |= BIT(5); *buffer = buf; @@ -1509,7 +1502,7 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, cmd = buff[0]; switch (cmd) { case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: - pr_err("Rx ACK_ERROR\n"); + pr_err("Rx ACK_ERROR 0x%x\n", cmd); rc = 0; break; case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: @@ -1525,7 +1518,7 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, rc = dsi_parse_long_read_resp(msg, buff); break; default: - pr_warn("Invalid response\n"); + pr_warn("Invalid response: 0x%x\n", cmd); rc = 0; } @@ -1601,6 +1594,18 @@ static int dsi_disable_ulps(struct dsi_ctrl *dsi_ctrl) return rc; } +static void dsi_ctrl_enable_error_interrupts(struct dsi_ctrl *dsi_ctrl) +{ + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && + !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && + !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, + 0xFF00A0); + else + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, + 0xFF00E0); +} + static int dsi_ctrl_drv_state_init(struct dsi_ctrl *dsi_ctrl) { int rc = 0; @@ -1730,6 +1735,9 @@ static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->null_insertion_enabled = of_property_read_bool(of_node, "qcom,null-insertion-enabled"); + dsi_ctrl->split_link_supported = of_property_read_bool(of_node, + "qcom,split-link-supported"); + rc = of_property_read_u32(of_node, "frame-threshold-time-us", &frame_threshold_time_us); if (rc) { @@ -2217,7 +2225,7 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) } dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); + dsi_ctrl_enable_error_interrupts(dsi_ctrl); dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); mutex_unlock(&dsi_ctrl->ctrl_lock); @@ -2340,6 +2348,12 @@ static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl, if (error & 0x3000E00) pr_err("dsi PHY contention error: 0x%lx\n", error); + /* ignore TX timeout if blpp_lp11 is disabled */ + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && + !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && + !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) + error &= ~DSI_HS_TX_TIMEOUT; + /* TX timeout error */ if (error & 0xE0) { if (error & 0xA0) { @@ -2637,27 +2651,34 @@ int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl) } /** - * dsi_ctrl_update_host_init_state() - Update the host initialization state. + * dsi_ctrl_update_host_state() - Update the host initialization state. * @dsi_ctrl: DSI controller handle. + * @op: ctrl driver ops * @enable: boolean signifying host state. * - * Update the host initialization status only while exiting from ulps during - * suspend state. + * Update the host status only while exiting from ulps during suspend state. * * Return: error code. */ -int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool enable) +int dsi_ctrl_update_host_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_ctrl_driver_ops op, bool enable) { int rc = 0; u32 state = enable ? 0x1 : 0x0; - rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state); + if (!dsi_ctrl) + return rc; + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl_check_state(dsi_ctrl, op, state); if (rc) { pr_err("[DSI_%d] Controller state check failed, rc=%d\n", dsi_ctrl->cell_index, rc); + mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } - dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, state); + + dsi_ctrl_update_state(dsi_ctrl, op, state); + mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } @@ -2720,7 +2741,7 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled) } dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); - dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); + dsi_ctrl_enable_error_interrupts(dsi_ctrl); pr_debug("[DSI_%d]Host initialization complete, continuous splash status:%d\n", dsi_ctrl->cell_index, is_splash_enabled); @@ -2749,6 +2770,16 @@ void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable) mutex_unlock(&dsi_ctrl->ctrl_lock); } +void dsi_ctrl_hs_req_sel(struct dsi_ctrl *dsi_ctrl, bool sel_phy) +{ + if (!dsi_ctrl) + return; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->hw.ops.hs_req_sel(&dsi_ctrl->hw, sel_phy); + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + void dsi_ctrl_set_continuous_clk(struct dsi_ctrl *dsi_ctrl, bool enable) { if (!dsi_ctrl) diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index 242f47eb97..8144f6d531 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -75,6 +75,22 @@ enum dsi_engine_state { DSI_CTRL_ENGINE_MAX, }; +/** + * enum dsi_ctrl_driver_ops - controller driver ops + */ +enum dsi_ctrl_driver_ops { + DSI_CTRL_OP_POWER_STATE_CHANGE, + DSI_CTRL_OP_CMD_ENGINE, + DSI_CTRL_OP_VID_ENGINE, + DSI_CTRL_OP_HOST_ENGINE, + DSI_CTRL_OP_CMD_TX, + DSI_CTRL_OP_HOST_INIT, + DSI_CTRL_OP_TPG, + DSI_CTRL_OP_PHY_SW_RESET, + DSI_CTRL_OP_ASYNC_TIMING, + DSI_CTRL_OP_MAX +}; + /** * struct dsi_ctrl_power_info - digital and analog power supplies for dsi host * @digital: Digital power supply required to turn on DSI controller hardware. @@ -212,6 +228,7 @@ struct dsi_ctrl_interrupts { * @null_insertion_enabled: A boolean property to allow dsi controller to * insert null packet. * @modeupdated: Boolean to send new roi if mode is updated. + * @split_link_supported: Boolean to check if hw supports split link. */ struct dsi_ctrl { struct platform_device *pdev; @@ -267,6 +284,7 @@ struct dsi_ctrl { bool phy_isolation_enabled; bool null_insertion_enabled; bool modeupdated; + bool split_link_supported; }; /** @@ -786,15 +804,24 @@ int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, */ int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl); /** - * dsi_ctrl_update_host_init_state() - Set the host initialization state + * dsi_ctrl_update_host_state() - Set the host state */ -int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool en); +int dsi_ctrl_update_host_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_ctrl_driver_ops op, bool en); /** * dsi_ctrl_pixel_format_to_bpp() - returns number of bits per pxl */ int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format); +/** + * dsi_ctrl_hs_req_sel() - API to enable continuous clk support through phy + * @dsi_ctrl: DSI controller handle. + * @sel_phy: Boolean to control whether to select phy or + * controller + */ +void dsi_ctrl_hs_req_sel(struct dsi_ctrl *dsi_ctrl, bool sel_phy); + /** * dsi_ctrl_set_continuous_clk() - API to set/unset force clock lane HS request. * @dsi_ctrl: DSI controller handle. diff --git a/msm/dsi/dsi_ctrl_hw.h b/msm/dsi/dsi_ctrl_hw.h index 711acd76a7..01ebdc6ccb 100644 --- a/msm/dsi/dsi_ctrl_hw.h +++ b/msm/dsi/dsi_ctrl_hw.h @@ -823,6 +823,12 @@ struct dsi_ctrl_hw_ops { * @ctrl: Pointer to the controller host hardware. */ int (*wait4dynamic_refresh_done)(struct dsi_ctrl_hw *ctrl); + /** + * hw.ops.hs_req_sel() - enable continuous clk support through phy + * @ctrl: Pointer to the controller host hardware. + * @sel_phy: Bool to control whether to select phy or controller + */ + void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy); }; /* diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index 177c00463b..c0803a24e9 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -19,6 +19,8 @@ #define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21)) #define DSI_CTRL_CMD_MISR_ENABLE BIT(28) #define DSI_CTRL_VIDEO_MISR_ENABLE BIT(16) +#define DSI_CTRL_DMA_LINK_SEL (BIT(12)|BIT(13)) +#define DSI_CTRL_MDP0_LINK_SEL (BIT(20)|BIT(22)) /* Unsupported formats default to RGB888 */ static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { @@ -26,6 +28,38 @@ static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { static const u8 video_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { 0x0, 0x1, 0x2, 0x3, 0x3, 0x3, 0x3 }; +/** + * dsi_split_link_setup() - setup dsi split link configurations + * @ctrl: Pointer to the controller host hardware. + * @cfg: DSI host configuration that is common to both video and + * command modes. + */ +static void dsi_split_link_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *cfg) +{ + u32 reg; + + if (!cfg->split_link.split_link_enabled) + return; + + reg = DSI_R32(ctrl, DSI_SPLIT_LINK); + + /* DMA_LINK_SEL */ + reg &= ~(0x7 << 12); + reg |= DSI_CTRL_DMA_LINK_SEL; + + /* MDP0_LINK_SEL */ + reg &= ~(0x7 << 20); + reg |= DSI_CTRL_MDP0_LINK_SEL; + + /* EN */ + reg |= 0x1; + + /* DSI_SPLIT_LINK */ + DSI_W32(ctrl, DSI_SPLIT_LINK, reg); + wmb(); /* make sure split link is asserted */ +} + /** * dsi_setup_trigger_controls() - setup dsi trigger configurations * @ctrl: Pointer to the controller host hardware. @@ -57,6 +91,7 @@ void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl, u32 reg_value = 0; dsi_setup_trigger_controls(ctrl, cfg); + dsi_split_link_setup(ctrl, cfg); /* Setup clocking timing controls */ reg_value = ((cfg->t_clk_post & 0x3F) << 8); @@ -1533,6 +1568,19 @@ int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl) return rc; } +void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_LANE_CTRL); + if (sel_phy) + reg &= ~BIT(24); + else + reg |= BIT(24); + DSI_W32(ctrl, DSI_LANE_CTRL, reg); + wmb(); /* make sure request is set */ +} + void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable) { u32 reg = 0; diff --git a/msm/dsi/dsi_ctrl_reg.h b/msm/dsi/dsi_ctrl_reg.h index bf93887fb5..d27d4ffe24 100644 --- a/msm/dsi/dsi_ctrl_reg.h +++ b/msm/dsi/dsi_ctrl_reg.h @@ -145,6 +145,7 @@ #define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0) #define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4) #define DSI_LOGICAL_LANE_SWAP_CTRL (0x0310) +#define DSI_SPLIT_LINK (0x0330) #endif /* _DSI_CTRL_REG_H_ */ diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index cb1f10bf4a..a3eb4fa8b9 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -78,6 +78,11 @@ static int dsi_display_config_clk_gating(struct dsi_display *display, return -EINVAL; } + if (display->panel->host_config.force_hs_clk_lane) { + pr_debug("no dsi clock gating for continuous clock mode\n"); + return 0; + } + mctrl = &display->ctrl[display->clk_master_idx]; if (!mctrl) { pr_err("Invalid controller\n"); @@ -586,8 +591,11 @@ static bool dsi_display_validate_reg_read(struct dsi_panel *panel) for (j = 0; j < config->groups; ++j) { for (i = 0; i < len; ++i) { if (config->return_buf[i] != - config->status_value[group + i]) + config->status_value[group + i]) { + DRM_ERROR("mismatch: 0x%x\n", + config->return_buf[i]); break; + } } if (i == len) @@ -828,6 +836,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, if (te_check_override && gpio_is_valid(dsi_display->disp_te_gpio)) status_mode = ESD_MODE_PANEL_TE; + if (status_mode == ESD_MODE_PANEL_TE) { + rc = dsi_display_status_check_te(dsi_display); + goto exit; + } + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); @@ -843,23 +856,25 @@ int dsi_display_check_status(struct drm_connector *connector, void *display, } else if (status_mode == ESD_MODE_PANEL_TE) { rc = dsi_display_status_check_te(dsi_display); } else { - pr_warn("unsupported check status mode\n"); + pr_warn("Unsupported check status mode: %d\n", status_mode); panel->esd_config.esd_enabled = false; } - /* Unmask error interrupts */ + /* Unmask error interrupts if check passed*/ if (rc > 0) { dsi_display_set_ctrl_esd_check_flag(dsi_display, false); dsi_display_mask_ctrl_error_interrupts(dsi_display, mask, false); - } else { - /* Handle Panel failures during display disable sequence */ - atomic_set(&panel->esd_recovery_pending, 1); } dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); +exit: + /* Handle Panel failures during display disable sequence */ + if (rc <=0) + atomic_set(&panel->esd_recovery_pending, 1); + release_panel_lock: dsi_panel_release_panel_lock(panel); SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); @@ -1620,12 +1635,25 @@ static int dsi_display_debugfs_deinit(struct dsi_display *display) static void adjust_timing_by_ctrl_count(const struct dsi_display *display, struct dsi_display_mode *mode) { - mode->timing.h_active /= display->ctrl_count; - mode->timing.h_front_porch /= display->ctrl_count; - mode->timing.h_sync_width /= display->ctrl_count; - mode->timing.h_back_porch /= display->ctrl_count; - mode->timing.h_skew /= display->ctrl_count; - mode->pixel_clk_khz /= display->ctrl_count; + struct dsi_host_common_cfg *host = &display->panel->host_config; + bool is_split_link = host->split_link.split_link_enabled; + u32 sublinks_count = host->split_link.num_sublinks; + + if (is_split_link && sublinks_count > 1) { + mode->timing.h_active /= sublinks_count; + mode->timing.h_front_porch /= sublinks_count; + mode->timing.h_sync_width /= sublinks_count; + mode->timing.h_back_porch /= sublinks_count; + mode->timing.h_skew /= sublinks_count; + mode->pixel_clk_khz /= sublinks_count; + } else { + mode->timing.h_active /= display->ctrl_count; + mode->timing.h_front_porch /= display->ctrl_count; + mode->timing.h_sync_width /= display->ctrl_count; + mode->timing.h_back_porch /= display->ctrl_count; + mode->timing.h_skew /= display->ctrl_count; + mode->pixel_clk_khz /= display->ctrl_count; + } } static int dsi_display_is_ulps_req_valid(struct dsi_display *display, @@ -2366,7 +2394,9 @@ static int dsi_display_ctrl_init(struct dsi_display *display) } else { display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; - rc = dsi_ctrl_update_host_init_state(ctrl->ctrl, true); + rc = dsi_ctrl_update_host_state(ctrl->ctrl, + DSI_CTRL_OP_HOST_INIT, + true); if (rc) pr_debug("host init update failed rc=%d\n", rc); } @@ -2450,6 +2480,25 @@ static int dsi_display_ctrl_host_disable(struct dsi_display *display) struct dsi_display_ctrl *m_ctrl, *ctrl; m_ctrl = &display->ctrl[display->cmd_master_idx]; + /* + * For platforms where ULPS is controlled by DSI controller block, + * do not disable dsi controller block if lanes are to be + * kept in ULPS during suspend. So just update the SW state + * and return early. + */ + if (display->panel->ulps_suspend_enabled && + !m_ctrl->phy->hw.ops.ulps_ops.ulps_request) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_update_host_state(ctrl->ctrl, + DSI_CTRL_OP_HOST_ENGINE, + false); + if (rc) + pr_debug("host state update failed %d\n", rc); + } + return rc; + } + display_for_each_ctrl(i, display) { ctrl = &display->ctrl[i]; if (!ctrl->ctrl || (ctrl == m_ctrl)) @@ -4609,6 +4658,42 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display) return rc; } +static int dsi_display_validate_split_link(struct dsi_display *display) +{ + int i, rc = 0; + struct dsi_display_ctrl *ctrl; + struct dsi_host_common_cfg *host = &display->panel->host_config; + + if (!host->split_link.split_link_enabled) + return 0; + + if (display->panel->panel_mode == DSI_OP_CMD_MODE) { + pr_err("[%s] split link is not supported in command mode\n", + display->name); + rc = -ENOTSUPP; + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl->split_link_supported) { + pr_err("[%s] split link is not supported by hw\n", + display->name); + rc = -ENOTSUPP; + goto error; + } + + set_bit(DSI_PHY_SPLIT_LINK, ctrl->phy->hw.feature_map); + } + + pr_debug("Split link is enabled\n"); + return 0; + +error: + host->split_link.split_link_enabled = false; + return rc; +} + /** * dsi_display_bind - bind dsi device with controlling device * @dev: Pointer to base of platform device @@ -4649,8 +4734,28 @@ static int dsi_display_bind(struct device *dev, if (!display->fw) display->name = display->panel_node->name; + + /* defer bind if ext bridge driver is not loaded */ + if (display->panel && display->panel->host_config.ext_bridge_mode) { + for (i = 0; i < display->ext_bridge_cnt; i++) { + if (!of_drm_find_bridge( + display->ext_bridge[i].node_of)) { + pr_debug("defer for bridge[%d] %s\n", i, + display->ext_bridge[i].node_of->full_name); + return -EPROBE_DEFER; + } + } + } + mutex_lock(&display->display_lock); + rc = dsi_display_validate_split_link(display); + if (rc) { + pr_err("[%s] split link validation failed, rc=%d\n", + display->name, rc); + goto error; + } + rc = dsi_display_debugfs_init(display); if (rc) { pr_err("[%s] debugfs init failed, rc=%d\n", display->name, rc); @@ -5273,7 +5378,7 @@ static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge( sde_conn = to_sde_connector(conn_iter); if (sde_conn->encoder == bridge->encoder) { display = sde_conn->display; - for (i = 0; i < display->ctrl_count; i++) { + display_for_each_ctrl(i, display) { if (display->ext_bridge[i].bridge == bridge) return &display->ext_bridge[i]; } @@ -5440,6 +5545,9 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display, struct drm_bridge *prev_bridge = bridge; int rc = 0, i; + if (display->panel && !display->panel->host_config.ext_bridge_mode) + return 0; + for (i = 0; i < display->ext_bridge_cnt; i++) { struct dsi_display_ext_bridge *ext_bridge_info = &display->ext_bridge[i]; @@ -5750,8 +5858,10 @@ int dsi_display_get_modes(struct dsi_display *display, { struct dsi_dfps_capabilities dfps_caps; struct dsi_display_ctrl *ctrl; + struct dsi_host_common_cfg *host = &display->panel->host_config; + bool is_split_link; u32 num_dfps_rates, panel_mode_count, total_mode_count; - u32 mode_idx, array_idx = 0; + u32 sublinks_count, mode_idx, array_idx = 0; struct dsi_dyn_clk_caps *dyn_clk_caps; int i, start, end, rc = -EINVAL; @@ -5827,15 +5937,25 @@ int dsi_display_get_modes(struct dsi_display *display, panel_mode.timing.dsi_transfer_time_us; } - panel_mode.timing.h_active *= display->ctrl_count; - panel_mode.timing.h_front_porch *= display->ctrl_count; - panel_mode.timing.h_sync_width *= display->ctrl_count; - panel_mode.timing.h_back_porch *= display->ctrl_count; - panel_mode.timing.h_skew *= display->ctrl_count; - panel_mode.pixel_clk_khz *= display->ctrl_count; + is_split_link = host->split_link.split_link_enabled; + sublinks_count = host->split_link.num_sublinks; + if (is_split_link && sublinks_count > 1) { + panel_mode.timing.h_active *= sublinks_count; + panel_mode.timing.h_front_porch *= sublinks_count; + panel_mode.timing.h_sync_width *= sublinks_count; + panel_mode.timing.h_back_porch *= sublinks_count; + panel_mode.timing.h_skew *= sublinks_count; + panel_mode.pixel_clk_khz *= sublinks_count; + } else { + panel_mode.timing.h_active *= display->ctrl_count; + panel_mode.timing.h_front_porch *= display->ctrl_count; + panel_mode.timing.h_sync_width *= display->ctrl_count; + panel_mode.timing.h_back_porch *= display->ctrl_count; + panel_mode.timing.h_skew *= display->ctrl_count; + panel_mode.pixel_clk_khz *= display->ctrl_count; + } start = array_idx; - for (i = 0; i < num_dfps_rates; i++) { struct dsi_display_mode *sub_mode = &display->modes[array_idx]; @@ -5886,6 +6006,7 @@ int dsi_display_get_panel_vfp(void *dsi_display, u32 count, refresh_rate = 0; struct dsi_dfps_capabilities dfps_caps; struct dsi_display *display = (struct dsi_display *)dsi_display; + struct dsi_host_common_cfg *host; if (!display) return -EINVAL; @@ -5909,7 +6030,11 @@ int dsi_display_get_panel_vfp(void *dsi_display, return -EINVAL; } - h_active *= display->ctrl_count; + host = &display->panel->host_config; + if (host->split_link.split_link_enabled) + h_active *= host->split_link.num_sublinks; + else + h_active *= display->ctrl_count; for (i = 0; i < count; i++) { struct dsi_display_mode *m = &display->modes[i]; @@ -6574,7 +6699,8 @@ int dsi_display_prepare(struct dsi_display *display) if (display->is_cont_splash_enabled && display->config.panel_mode == DSI_OP_VIDEO_MODE) { pr_err("DMS not supported on first frame\n"); - return -EINVAL; + rc = -EINVAL; + goto error; } /* update dsi ctrl for new mode */ @@ -6771,8 +6897,7 @@ static int dsi_display_qsync(struct dsi_display *display, bool enable) mutex_lock(&display->display_lock); - for (i = 0; i < display->ctrl_count; i++) { - + display_for_each_ctrl(i, display) { if (enable) { /* send the commands to enable qsync */ rc = dsi_panel_send_qsync_on_dcs(display->panel, i); diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 9ca58a6a37..dea93b0790 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -8,6 +8,7 @@ #include #include #include +#include #include