Loading drivers/video/msm/mdss/mdss_dsi.h +1 −0 Original line number Diff line number Diff line Loading @@ -570,6 +570,7 @@ void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, void mdss_dsi_controller_cfg(int enable, struct mdss_panel_data *pdata); void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool restore); int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl); irqreturn_t mdss_dsi_isr(int irq, void *ptr); irqreturn_t hw_vsync_handler(int irq, void *data); Loading drivers/video/msm/mdss/mdss_dsi_host.c +70 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,9 @@ #define DMA_TX_TIMEOUT 200 #define DMA_TPG_FIFO_LEN 64 #define FIFO_STATUS 0x0C #define LANE_STATUS 0xA8 struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX]; struct mdss_hw mdss_dsi0_hw = { Loading Loading @@ -517,6 +520,73 @@ void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl, bool restore) spin_unlock_irqrestore(&ctrl->mdp_lock, flag); } /** * mdss_dsi_wait_for_lane_idle() - Wait for DSI lanes to be idle * @ctrl: pointer to DSI controller structure * * This function waits for all the active DSI lanes to be idle by polling all * the *FIFO_EMPTY bits and polling the lane status to ensure that all the lanes * are in stop state. This function assumes that the bus clocks required to * access the registers are already turned on. */ int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl) { int rc; u32 val; u32 fifo_empty_mask = 0; u32 stop_state_mask = 0; struct mipi_panel_info *mipi; u32 const sleep_us = 10; u32 const timeout_us = 100; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } mipi = &ctrl->panel_data.panel_info.mipi; if (mipi->data_lane0) { stop_state_mask |= BIT(0); fifo_empty_mask |= (BIT(12) | BIT(16)); } if (mipi->data_lane1) { stop_state_mask |= BIT(1); fifo_empty_mask |= BIT(20); } if (mipi->data_lane2) { stop_state_mask |= BIT(2); fifo_empty_mask |= BIT(24); } if (mipi->data_lane3) { stop_state_mask |= BIT(3); fifo_empty_mask |= BIT(28); } pr_debug("%s: polling for fifo empty, mask=0x%08x\n", __func__, fifo_empty_mask); rc = readl_poll_timeout(ctrl->ctrl_base + FIFO_STATUS, val, (val & fifo_empty_mask), sleep_us, timeout_us); if (rc) { pr_err("%s: fifo not empty, FIFO_STATUS=0x%08x\n", __func__, val); goto error; } pr_debug("%s: polling for lanes to be in stop state, mask=0x%08x\n", __func__, stop_state_mask); rc = readl_poll_timeout(ctrl->ctrl_base + LANE_STATUS, val, (val & stop_state_mask), sleep_us, timeout_us); if (rc) { pr_err("%s: lanes not in stop state, LANE_STATUS=0x%08x\n", __func__, val); goto error; } error: return rc; } static void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u32 bits, int set) { Loading drivers/video/msm/mdss/msm_mdss_io_8974.c +95 −17 Original line number Diff line number Diff line Loading @@ -1502,6 +1502,67 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, return 0; } static bool mdss_dsi_is_ulps_req_valid(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { struct mdss_dsi_ctrl_pdata *octrl = NULL; struct mdss_panel_data *pdata = &ctrl->panel_data; struct mdss_panel_info *pinfo = &pdata->panel_info; pr_debug("%s: checking ulps req validity for ctrl%d\n", __func__, ctrl->ndx); if (!mdss_dsi_ulps_feature_enabled(pdata) && !pinfo->ulps_suspend_enabled) { pr_debug("%s: ULPS feature is not enabled\n", __func__); return false; } /* * No need to enter ULPS when transitioning from splash screen to * boot animation since it is expected that the clocks would be turned * right back on. */ if (enable && pinfo->cont_splash_enabled) { pr_debug("%s: skip ULPS config with splash screen enabled\n", __func__); return false; } /* * No need to enable ULPS if panel is not yet initialized. * However, this should be allowed in following usecases: * 1. If ULPS during suspend feature is enabled, where we * configure the lanes in ULPS after turning off the panel. * 2. When coming out of idle PC with clamps enabled, where we * transition the controller HW state back to ULPS prior to * disabling ULPS. */ if (enable && !ctrl->mmss_clamp && !(ctrl->ctrl_state & CTRL_STATE_PANEL_INIT) && !pdata->panel_info.ulps_suspend_enabled) { pr_debug("%s: panel not yet initialized\n", __func__); return false; } /* * For split-DSI usecase, wait till both controllers are initialized. * The same exceptions as above are applicable here too. */ if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) { octrl = mdss_dsi_get_other_ctrl(ctrl); if (enable && !ctrl->mmss_clamp && octrl && !(octrl->ctrl_state & CTRL_STATE_PANEL_INIT) && !pdata->panel_info.ulps_suspend_enabled) { pr_debug("%s: split-DSI, other ctrl not ready yet\n", __func__); return false; } } return true; } /** * mdss_dsi_ulps_config() - Program DSI lanes to enter/exit ULPS mode * @ctrl: pointer to DSI controller structure Loading Loading @@ -1534,20 +1595,9 @@ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, pinfo = &pdata->panel_info; mipi = &pinfo->mipi; if (!mdss_dsi_ulps_feature_enabled(pdata) && !pinfo->ulps_suspend_enabled) { pr_debug("%s: ULPS feature is not enabled\n", __func__); return 0; } /* * No need to enter ULPS when transitioning from splash screen to * boot animation since it is expected that the clocks would be turned * right back on. */ if (pinfo->cont_splash_enabled) { pr_debug("%s: skip ULPS config with splash screen enabled\n", __func__); if (!mdss_dsi_is_ulps_req_valid(ctrl, enable)) { pr_debug("%s: skiping ULPS config for ctrl%d, enable=%d\n", __func__, ctrl->ndx, enable); return 0; } Loading @@ -1566,11 +1616,31 @@ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, if (mipi->data_lane3) active_lanes |= BIT(3); pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x,clamps=%s\n", __func__, (enable ? "on" : "off"), ctrl->ndx, active_lanes); active_lanes, ctrl->mmss_clamp ? "enabled" : "disabled"); if (enable && !ctrl->ulps) { /* * Ensure that the lanes are idle prior to placing a ULPS entry * request. This is needed to ensure that there is no overlap * between any HS or LP commands being sent out on the lane and * a potential ULPS entry request. * * This check needs to be avoided when we are resuming from idle * power collapse and just restoring the controller state to * ULPS with the clamps still in place. */ if (!ctrl->mmss_clamp) { ret = mdss_dsi_wait_for_lane_idle(ctrl); if (ret) { pr_warn("%s: lanes not idle, skip ulps\n", __func__); ret = 0; goto error; } } /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes Loading Loading @@ -1913,7 +1983,6 @@ int mdss_dsi_pre_clkoff_cb(void *priv, } if ((clk & MDSS_DSI_CORE_CLK) && (new_state == MDSS_DSI_CLK_OFF)) { /* * Enable DSI clamps only if entering idle power collapse or * when ULPS during suspend is enabled. Loading @@ -1924,6 +1993,15 @@ int mdss_dsi_pre_clkoff_cb(void *priv, if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); } else { /* * Make sure that controller is not in ULPS state when * the DSI link is not active. */ rc = mdss_dsi_ulps_config(ctrl, 0); if (rc) pr_err("%s: failed to disable ulps. rc=%d\n", __func__, rc); } } Loading Loading
drivers/video/msm/mdss/mdss_dsi.h +1 −0 Original line number Diff line number Diff line Loading @@ -570,6 +570,7 @@ void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, void mdss_dsi_controller_cfg(int enable, struct mdss_panel_data *pdata); void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool restore); int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl); irqreturn_t mdss_dsi_isr(int irq, void *ptr); irqreturn_t hw_vsync_handler(int irq, void *data); Loading
drivers/video/msm/mdss/mdss_dsi_host.c +70 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,9 @@ #define DMA_TX_TIMEOUT 200 #define DMA_TPG_FIFO_LEN 64 #define FIFO_STATUS 0x0C #define LANE_STATUS 0xA8 struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX]; struct mdss_hw mdss_dsi0_hw = { Loading Loading @@ -517,6 +520,73 @@ void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl, bool restore) spin_unlock_irqrestore(&ctrl->mdp_lock, flag); } /** * mdss_dsi_wait_for_lane_idle() - Wait for DSI lanes to be idle * @ctrl: pointer to DSI controller structure * * This function waits for all the active DSI lanes to be idle by polling all * the *FIFO_EMPTY bits and polling the lane status to ensure that all the lanes * are in stop state. This function assumes that the bus clocks required to * access the registers are already turned on. */ int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl) { int rc; u32 val; u32 fifo_empty_mask = 0; u32 stop_state_mask = 0; struct mipi_panel_info *mipi; u32 const sleep_us = 10; u32 const timeout_us = 100; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } mipi = &ctrl->panel_data.panel_info.mipi; if (mipi->data_lane0) { stop_state_mask |= BIT(0); fifo_empty_mask |= (BIT(12) | BIT(16)); } if (mipi->data_lane1) { stop_state_mask |= BIT(1); fifo_empty_mask |= BIT(20); } if (mipi->data_lane2) { stop_state_mask |= BIT(2); fifo_empty_mask |= BIT(24); } if (mipi->data_lane3) { stop_state_mask |= BIT(3); fifo_empty_mask |= BIT(28); } pr_debug("%s: polling for fifo empty, mask=0x%08x\n", __func__, fifo_empty_mask); rc = readl_poll_timeout(ctrl->ctrl_base + FIFO_STATUS, val, (val & fifo_empty_mask), sleep_us, timeout_us); if (rc) { pr_err("%s: fifo not empty, FIFO_STATUS=0x%08x\n", __func__, val); goto error; } pr_debug("%s: polling for lanes to be in stop state, mask=0x%08x\n", __func__, stop_state_mask); rc = readl_poll_timeout(ctrl->ctrl_base + LANE_STATUS, val, (val & stop_state_mask), sleep_us, timeout_us); if (rc) { pr_err("%s: lanes not in stop state, LANE_STATUS=0x%08x\n", __func__, val); goto error; } error: return rc; } static void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u32 bits, int set) { Loading
drivers/video/msm/mdss/msm_mdss_io_8974.c +95 −17 Original line number Diff line number Diff line Loading @@ -1502,6 +1502,67 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, return 0; } static bool mdss_dsi_is_ulps_req_valid(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { struct mdss_dsi_ctrl_pdata *octrl = NULL; struct mdss_panel_data *pdata = &ctrl->panel_data; struct mdss_panel_info *pinfo = &pdata->panel_info; pr_debug("%s: checking ulps req validity for ctrl%d\n", __func__, ctrl->ndx); if (!mdss_dsi_ulps_feature_enabled(pdata) && !pinfo->ulps_suspend_enabled) { pr_debug("%s: ULPS feature is not enabled\n", __func__); return false; } /* * No need to enter ULPS when transitioning from splash screen to * boot animation since it is expected that the clocks would be turned * right back on. */ if (enable && pinfo->cont_splash_enabled) { pr_debug("%s: skip ULPS config with splash screen enabled\n", __func__); return false; } /* * No need to enable ULPS if panel is not yet initialized. * However, this should be allowed in following usecases: * 1. If ULPS during suspend feature is enabled, where we * configure the lanes in ULPS after turning off the panel. * 2. When coming out of idle PC with clamps enabled, where we * transition the controller HW state back to ULPS prior to * disabling ULPS. */ if (enable && !ctrl->mmss_clamp && !(ctrl->ctrl_state & CTRL_STATE_PANEL_INIT) && !pdata->panel_info.ulps_suspend_enabled) { pr_debug("%s: panel not yet initialized\n", __func__); return false; } /* * For split-DSI usecase, wait till both controllers are initialized. * The same exceptions as above are applicable here too. */ if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) { octrl = mdss_dsi_get_other_ctrl(ctrl); if (enable && !ctrl->mmss_clamp && octrl && !(octrl->ctrl_state & CTRL_STATE_PANEL_INIT) && !pdata->panel_info.ulps_suspend_enabled) { pr_debug("%s: split-DSI, other ctrl not ready yet\n", __func__); return false; } } return true; } /** * mdss_dsi_ulps_config() - Program DSI lanes to enter/exit ULPS mode * @ctrl: pointer to DSI controller structure Loading Loading @@ -1534,20 +1595,9 @@ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, pinfo = &pdata->panel_info; mipi = &pinfo->mipi; if (!mdss_dsi_ulps_feature_enabled(pdata) && !pinfo->ulps_suspend_enabled) { pr_debug("%s: ULPS feature is not enabled\n", __func__); return 0; } /* * No need to enter ULPS when transitioning from splash screen to * boot animation since it is expected that the clocks would be turned * right back on. */ if (pinfo->cont_splash_enabled) { pr_debug("%s: skip ULPS config with splash screen enabled\n", __func__); if (!mdss_dsi_is_ulps_req_valid(ctrl, enable)) { pr_debug("%s: skiping ULPS config for ctrl%d, enable=%d\n", __func__, ctrl->ndx, enable); return 0; } Loading @@ -1566,11 +1616,31 @@ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, if (mipi->data_lane3) active_lanes |= BIT(3); pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x,clamps=%s\n", __func__, (enable ? "on" : "off"), ctrl->ndx, active_lanes); active_lanes, ctrl->mmss_clamp ? "enabled" : "disabled"); if (enable && !ctrl->ulps) { /* * Ensure that the lanes are idle prior to placing a ULPS entry * request. This is needed to ensure that there is no overlap * between any HS or LP commands being sent out on the lane and * a potential ULPS entry request. * * This check needs to be avoided when we are resuming from idle * power collapse and just restoring the controller state to * ULPS with the clamps still in place. */ if (!ctrl->mmss_clamp) { ret = mdss_dsi_wait_for_lane_idle(ctrl); if (ret) { pr_warn("%s: lanes not idle, skip ulps\n", __func__); ret = 0; goto error; } } /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes Loading Loading @@ -1913,7 +1983,6 @@ int mdss_dsi_pre_clkoff_cb(void *priv, } if ((clk & MDSS_DSI_CORE_CLK) && (new_state == MDSS_DSI_CLK_OFF)) { /* * Enable DSI clamps only if entering idle power collapse or * when ULPS during suspend is enabled. Loading @@ -1924,6 +1993,15 @@ int mdss_dsi_pre_clkoff_cb(void *priv, if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); } else { /* * Make sure that controller is not in ULPS state when * the DSI link is not active. */ rc = mdss_dsi_ulps_config(ctrl, 0); if (rc) pr_err("%s: failed to disable ulps. rc=%d\n", __func__, rc); } } Loading