Loading drivers/video/msm/mdss/mdss_dsi.c +15 −209 Original line number Diff line number Diff line Loading @@ -430,7 +430,7 @@ static int mdss_dsi_off(struct mdss_panel_data *pdata) return ret; } static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) void mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; Loading Loading @@ -515,185 +515,16 @@ static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) } } int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable) void mdss_dsi_reset(struct mdss_dsi_ctrl_pdata *ctrl) { int ret = 0; struct mdss_panel_data *pdata = NULL; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 lane_status = 0, regval; u32 active_lanes = 0, clamp_reg; u32 clamp_reg_off, phyrst_reg_off; if (!ctrl_pdata) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } if (&ctrl_pdata->mmss_misc_io == NULL) { pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__); return -EINVAL; } pdata = &ctrl_pdata->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } pinfo = &pdata->panel_info; mipi = &pinfo->mipi; clamp_reg_off = ctrl_pdata->ulps_clamp_ctrl_off; phyrst_reg_off = ctrl_pdata->ulps_phyrst_ctrl_off; if (!mdss_dsi_ulps_feature_enabled(pdata)) { pr_debug("%s: ULPS feature not supported. enable=%d\n", __func__, enable); return -ENOTSUPP; } /* * 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__); return 0; } /* clock lane will always be programmed for ulps and will be clamped */ active_lanes = BIT(4); clamp_reg = BIT(8) | BIT(9); /* * make a note of all active data lanes for which ulps entry/exit * as well as DSI clamps are needed */ if (mipi->data_lane0) { active_lanes |= BIT(0); clamp_reg |= (BIT(0) | BIT(1)); } if (mipi->data_lane1) { active_lanes |= BIT(1); clamp_reg |= (BIT(2) | BIT(3)); } if (mipi->data_lane2) { active_lanes |= BIT(2); clamp_reg |= (BIT(4) | BIT(5)); } if (mipi->data_lane3) { active_lanes |= BIT(3); clamp_reg |= (BIT(6) | BIT(7)); } struct mdss_panel_data *pdata = &ctrl->panel_data; pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", __func__, (enable ? "on" : "off"), ctrl_pdata->ndx, active_lanes); if (enable && !ctrl_pdata->ulps) { /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Check to make sure that all active data lanes are in ULPS */ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); if (lane_status & (active_lanes << 8)) { pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n", __func__, ctrl_pdata->ndx, lane_status); ret = -EINVAL; goto error; } /* Enable MMSS DSI Clamps */ if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | clamp_reg); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg << 16)); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | ((clamp_reg << 16) | BIT(31))); } wmb(); /* * This register write ensures that DSI PHY will not be * reset when mdss ahb clock reset is asserted while coming * out of power collapse */ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + phyrst_reg_off, 0x1); ctrl_pdata->ulps = true; } else if (ctrl_pdata->ulps) { MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + phyrst_reg_off, 0x0); if (ctrl_pdata->ctrl_rev == MDSS_DSI_HW_REV_103) mdss_dsi_20nm_phy_init(pdata); else mdss_dsi_phy_init(pdata); pr_debug("%s: called for ctrl%d\n", __func__, ctrl->ndx); __mdss_dsi_ctrl_setup(pdata); /* DSI controller reset and init */ mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); /* * ULPS Entry Request. This is needed because, after power * collapse and reset, the DSI controller resets back to * idle state and not ULPS. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Disable MMSS DSI Clamps */ if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval & ~(clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval & ~((clamp_reg << 16) | BIT(31))); } /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8); usleep(1000); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0); /* * Wait for a short duration before enabling * data transmission */ usleep(100); lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); ctrl_pdata->ulps = false; } pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__, lane_status, enable ? "enabled" : "disabled"); error: return ret; mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); } static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, Loading Loading @@ -754,36 +585,13 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) return ret; } mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1); if (ret) { pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__, ret); ret = mdss_dsi_panel_power_on(pdata, 0); if (ret) { pr_err("%s: Panel reset failed. rc=%d\n", __func__, ret); return ret; } pdata->panel_info.panel_power_on = 0; return ret; } pdata->panel_info.panel_power_on = 1; ctrl_pdata->ctrl_rev = MIPI_INP(ctrl_pdata->ctrl_base); mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base)); if (ctrl_pdata->ctrl_rev == MDSS_DSI_HW_REV_103) mdss_dsi_20nm_phy_init(pdata); else mdss_dsi_phy_init(pdata); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); /* * Enable DSI clocks. * This is also enable the DSI core power block and reset/setup * DSI phy */ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); __mdss_dsi_ctrl_setup(pdata); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); pdata->panel_info.panel_power_on = 1; /* * Issue hardware reset line after enabling the DSI clocks and data Loading Loading @@ -992,9 +800,7 @@ int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata) WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT), "Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); mdss_dsi_op_mode_config(mipi->mode, pdata); mdss_dsi_reset(ctrl_pdata); pr_debug("%s-:End\n", __func__); return ret; } Loading drivers/video/msm/mdss/mdss_dsi.h +5 −2 Original line number Diff line number Diff line Loading @@ -336,9 +336,11 @@ struct mdss_dsi_ctrl_pdata { struct mutex mutex; struct mutex cmd_mutex; bool ulps; u32 ulps_clamp_ctrl_off; u32 ulps_phyrst_ctrl_off; bool ulps; bool core_power; bool mmss_clamp; struct dsi_buf tx_buf; struct dsi_buf rx_buf; Loading Loading @@ -410,7 +412,8 @@ void mdss_dsi_cmdlist_kickoff(int intf); int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl); int mdss_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl); bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type); int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable); void mdss_dsi_reset(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata); int mdss_dsi_panel_init(struct device_node *node, struct mdss_dsi_ctrl_pdata *ctrl_pdata, Loading drivers/video/msm/mdss/msm_mdss_io_8974.c +382 −38 Original line number Diff line number Diff line Loading @@ -484,6 +484,366 @@ static void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl) mdss_dsi_link_clk_unprepare(ctrl); } /** * mdss_dsi_ulps_config() - Program DSI lanes to enter/exit ULPS mode * @ctrl: pointer to DSI controller structure * @enable: 1 to enter ULPS, 0 to exit ULPS * * This function executes the necessary programming sequence to enter/exit * DSI Ultra-Low Power State (ULPS). This function assumes that the link and * bus clocks are already on. */ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { int ret = 0; struct mdss_panel_data *pdata = NULL; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 lane_status = 0; u32 active_lanes = 0; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } pinfo = &pdata->panel_info; mipi = &pinfo->mipi; if (!mdss_dsi_ulps_feature_enabled(pdata)) { pr_debug("%s: ULPS feature not supported. enable=%d\n", __func__, enable); return -ENOTSUPP; } /* * 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__); return 0; } /* clock lane will always be programmed for ulps */ active_lanes = BIT(4); /* * make a note of all active data lanes for which ulps entry/exit * is needed */ if (mipi->data_lane0) active_lanes |= BIT(0); if (mipi->data_lane1) active_lanes |= BIT(1); if (mipi->data_lane2) active_lanes |= BIT(2); if (mipi->data_lane3) active_lanes |= BIT(3); pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", __func__, (enable ? "on" : "off"), ctrl->ndx, active_lanes); if (enable && !ctrl->ulps) { /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Check to make sure that all active data lanes are in ULPS */ lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8); if (lane_status & (active_lanes << 8)) { pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n", __func__, ctrl->ndx, lane_status); ret = -EINVAL; goto error; } ctrl->ulps = true; } else if (!enable && ctrl->ulps) { /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms */ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes << 8); usleep(1000); MIPI_OUTP(ctrl->ctrl_base + 0x0AC, 0x0); /* * Wait for a short duration before enabling * data transmission */ usleep(100); lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8); ctrl->ulps = false; } else { pr_debug("%s: No change requested: %s -> %s\n", __func__, ctrl->ulps ? "enabled" : "disabled", enable ? "enabled" : "disabled"); } pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__, lane_status, enable ? "enabled" : "disabled"); error: return ret; } /** * mdss_dsi_clamp_ctrl() - Program DSI clamps for supporting power collapse * @ctrl: pointer to DSI controller structure * @enable: 1 to enable clamps, 0 to disable clamps * * For idle-screen usecases with command mode panels, MDSS can be power * collapsed. However, DSI phy needs to remain on. To avoid any mismatch * between the DSI controller state, DSI phy needs to be clamped before * power collapsing. This function executes the required programming * sequence to configure these DSI clamps. This function should only be called * when the DSI link clocks are disabled. */ static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { struct mipi_panel_info *mipi = NULL; u32 clamp_reg, regval = 0; u32 clamp_reg_off, phyrst_reg_off; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } if (!ctrl->mmss_misc_io.base) { pr_err("%s: mmss_misc_io not mapped\nn", __func__); return -EINVAL; } clamp_reg_off = ctrl->ulps_clamp_ctrl_off; phyrst_reg_off = ctrl->ulps_phyrst_ctrl_off; mipi = &ctrl->panel_data.panel_info.mipi; /* clock lane will always be clamped */ clamp_reg = BIT(9); if (ctrl->ulps) clamp_reg |= BIT(8); /* make a note of all active data lanes which need to be clamped */ if (mipi->data_lane0) { clamp_reg |= BIT(7); if (ctrl->ulps) clamp_reg |= BIT(6); } if (mipi->data_lane1) { clamp_reg |= BIT(5); if (ctrl->ulps) clamp_reg |= BIT(4); } if (mipi->data_lane2) { clamp_reg |= BIT(3); if (ctrl->ulps) clamp_reg |= BIT(2); } if (mipi->data_lane3) { clamp_reg |= BIT(1); if (ctrl->ulps) clamp_reg |= BIT(0); } pr_debug("%s: called for ctrl%d, enable=%d, clamp_reg=0x%08x\n", __func__, ctrl->ndx, enable, clamp_reg); if (enable && !ctrl->mmss_clamp) { /* Enable MMSS DSI Clamps */ if (ctrl->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | clamp_reg); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg | BIT(15))); } else if (ctrl->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg << 16)); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | ((clamp_reg << 16) | BIT(31))); } /* * This register write ensures that DSI PHY will not be * reset when mdss ahb clock reset is asserted while coming * out of power collapse */ MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off, 0x1); ctrl->mmss_clamp = true; } else if (!enable && ctrl->mmss_clamp) { MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off, 0x0); /* Disable MMSS DSI Clamps */ if (ctrl->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval & ~(clamp_reg | BIT(15))); } else if (ctrl->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval & ~((clamp_reg << 16) | BIT(31))); } ctrl->mmss_clamp = false; } else { pr_debug("%s: No change requested: %s -> %s\n", __func__, ctrl->mmss_clamp ? "enabled" : "disabled", enable ? "enabled" : "disabled"); } return 0; } /** * mdss_dsi_core_power_ctrl() - Enable/disable DSI core power * @ctrl: pointer to DSI controller structure * @enable: 1 to enable power, 0 to disable power * * When all DSI bus clocks are disabled, DSI core power module can be turned * off to save any leakage current. This function implements the necessary * programming sequence for the same. For command mode panels, the core power * can be turned off for idle-screen usecases, where additional programming is * needed to clamp DSI phy. */ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { int rc = 0; struct mdss_panel_data *pdata = NULL; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } if (enable) { if (!ctrl->core_power) { /* enable mdss gdsc */ pr_debug("%s: Enable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 1); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); goto error; } ctrl->core_power = true; } rc = mdss_dsi_bus_clk_start(ctrl); if (rc) { pr_err("%s: Failed to start bus clocks. rc=%d\n", __func__, rc); goto error_bus_clk_start; } /* * Phy software reset should not be done for idle screen power * collapse use-case. Issue a phy software reset only when * unblanking the panel. */ if (!pdata->panel_info.panel_power_on) mdss_dsi_phy_sw_reset(ctrl->ctrl_base); mdss_dsi_phy_init(pdata); mdss_dsi_ctrl_setup(pdata); if (ctrl->ulps) { /* * ULPS Entry Request. This is needed if the lanes were * in ULPS prior to power collapse, since after * power collapse and reset, the DSI controller resets * back to idle state and not ULPS. This ulps entry * request will transition the state of the DSI * controller to ULPS which will match the state of the * DSI phy. This needs to be done prior to disabling * the DSI clamps. */ rc = mdss_dsi_ulps_config(ctrl, 1); if (rc) { pr_err("%s: Failed to enter ULPS. rc=%d\n", __func__, rc); goto error_ulps; } } rc = mdss_dsi_clamp_ctrl(ctrl, 0); if (rc) { pr_err("%s: Failed to disable dsi clamps. rc=%d\n", __func__, rc); goto error_ulps; } } else { /* Enable DSI clamps only if entering idle power collapse */ if (ctrl->panel_data.panel_info.panel_power_on) { rc = mdss_dsi_clamp_ctrl(ctrl, 1); if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); } /* * disable bus clocks irrespective of whether dsi phy was * successfully clamped or not */ mdss_dsi_bus_clk_stop(ctrl); /* disable mdss gdsc only if dsi phy was successfully clamped*/ if (rc) { pr_debug("%s: leaving mdss gdsc on\n", __func__); } else { pr_debug("%s: Disable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); rc = 0; } else { ctrl->core_power = false; } } } return rc; error_ulps: mdss_dsi_bus_clk_stop(ctrl); error_bus_clk_start: if (msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0)) pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); else ctrl->core_power = false; error: return rc; } static int __mdss_dsi_update_clk_cnt(u32 *clk_cnt, int enable) { int changed = 0; Loading @@ -510,6 +870,7 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, { int rc = 0; struct mdss_panel_data *pdata; bool core_power_enabled = false; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); Loading @@ -523,41 +884,37 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, if (enable) { if (clk_type & DSI_BUS_CLKS) { /* enable mdss gdsc */ pr_debug("%s: Enable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 1); rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); pr_err("%s: Failed to enable core power. rc=%d\n", __func__, rc); goto error; } rc = mdss_dsi_bus_clk_start(ctrl); if (rc) { pr_err("Failed to start bus clocks. rc=%d\n", rc); goto error_vreg; } core_power_enabled = true; } if (clk_type & DSI_LINK_CLKS) { rc = mdss_dsi_link_clk_start(ctrl); if (rc) { pr_err("Failed to start link clocks. rc=%d\n", rc); pr_err("%s: Failed to start link clocks. rc=%d\n", __func__, rc); goto error_link_clk_start; } /* Disable ULPS, if enabled */ if (ctrl->ulps) { rc = mdss_dsi_ulps_config(ctrl, 0); if (rc) { pr_err("Failed to exit ulps. rc=%d\n", rc); pr_err("%s: Failed to exit ulps. rc=%d\n", __func__, rc); goto error_ulps_exit; } } /* * If we are coming out of idle power collapse, then * reset DSI controller state */ if (core_power_enabled) mdss_dsi_reset(ctrl); } } else { if (clk_type & DSI_LINK_CLKS) { Loading @@ -572,18 +929,10 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, mdss_dsi_link_clk_stop(ctrl); } if (clk_type & DSI_BUS_CLKS) { mdss_dsi_bus_clk_stop(ctrl); /* disable mdss gdsc */ pr_debug("%s: Disable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0); rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); rc = 0; pr_err("%s: Failed to disable core power. rc=%d\n", __func__, rc); } } } Loading @@ -593,15 +942,10 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, error_ulps_exit: mdss_dsi_link_clk_stop(ctrl); error_link_clk_start: if (clk_type & DSI_BUS_CLKS) mdss_dsi_bus_clk_stop(ctrl); error_vreg: if ((clk_type & DSI_BUS_CLKS) && (msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0))) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); } (mdss_dsi_core_power_ctrl(ctrl, !enable))) pr_warn("%s: Failed to disable core power. rc=%d\n", __func__, rc); error: return rc; } Loading Loading
drivers/video/msm/mdss/mdss_dsi.c +15 −209 Original line number Diff line number Diff line Loading @@ -430,7 +430,7 @@ static int mdss_dsi_off(struct mdss_panel_data *pdata) return ret; } static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) void mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; Loading Loading @@ -515,185 +515,16 @@ static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) } } int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable) void mdss_dsi_reset(struct mdss_dsi_ctrl_pdata *ctrl) { int ret = 0; struct mdss_panel_data *pdata = NULL; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 lane_status = 0, regval; u32 active_lanes = 0, clamp_reg; u32 clamp_reg_off, phyrst_reg_off; if (!ctrl_pdata) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } if (&ctrl_pdata->mmss_misc_io == NULL) { pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__); return -EINVAL; } pdata = &ctrl_pdata->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } pinfo = &pdata->panel_info; mipi = &pinfo->mipi; clamp_reg_off = ctrl_pdata->ulps_clamp_ctrl_off; phyrst_reg_off = ctrl_pdata->ulps_phyrst_ctrl_off; if (!mdss_dsi_ulps_feature_enabled(pdata)) { pr_debug("%s: ULPS feature not supported. enable=%d\n", __func__, enable); return -ENOTSUPP; } /* * 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__); return 0; } /* clock lane will always be programmed for ulps and will be clamped */ active_lanes = BIT(4); clamp_reg = BIT(8) | BIT(9); /* * make a note of all active data lanes for which ulps entry/exit * as well as DSI clamps are needed */ if (mipi->data_lane0) { active_lanes |= BIT(0); clamp_reg |= (BIT(0) | BIT(1)); } if (mipi->data_lane1) { active_lanes |= BIT(1); clamp_reg |= (BIT(2) | BIT(3)); } if (mipi->data_lane2) { active_lanes |= BIT(2); clamp_reg |= (BIT(4) | BIT(5)); } if (mipi->data_lane3) { active_lanes |= BIT(3); clamp_reg |= (BIT(6) | BIT(7)); } struct mdss_panel_data *pdata = &ctrl->panel_data; pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", __func__, (enable ? "on" : "off"), ctrl_pdata->ndx, active_lanes); if (enable && !ctrl_pdata->ulps) { /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Check to make sure that all active data lanes are in ULPS */ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); if (lane_status & (active_lanes << 8)) { pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n", __func__, ctrl_pdata->ndx, lane_status); ret = -EINVAL; goto error; } /* Enable MMSS DSI Clamps */ if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | clamp_reg); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg << 16)); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval | ((clamp_reg << 16) | BIT(31))); } wmb(); /* * This register write ensures that DSI PHY will not be * reset when mdss ahb clock reset is asserted while coming * out of power collapse */ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + phyrst_reg_off, 0x1); ctrl_pdata->ulps = true; } else if (ctrl_pdata->ulps) { MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + phyrst_reg_off, 0x0); if (ctrl_pdata->ctrl_rev == MDSS_DSI_HW_REV_103) mdss_dsi_20nm_phy_init(pdata); else mdss_dsi_phy_init(pdata); pr_debug("%s: called for ctrl%d\n", __func__, ctrl->ndx); __mdss_dsi_ctrl_setup(pdata); /* DSI controller reset and init */ mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); /* * ULPS Entry Request. This is needed because, after power * collapse and reset, the DSI controller resets back to * idle state and not ULPS. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Disable MMSS DSI Clamps */ if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval & ~(clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off, regval & ~((clamp_reg << 16) | BIT(31))); } /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8); usleep(1000); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0); /* * Wait for a short duration before enabling * data transmission */ usleep(100); lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); ctrl_pdata->ulps = false; } pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__, lane_status, enable ? "enabled" : "disabled"); error: return ret; mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); } static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, Loading Loading @@ -754,36 +585,13 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) return ret; } mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1); if (ret) { pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__, ret); ret = mdss_dsi_panel_power_on(pdata, 0); if (ret) { pr_err("%s: Panel reset failed. rc=%d\n", __func__, ret); return ret; } pdata->panel_info.panel_power_on = 0; return ret; } pdata->panel_info.panel_power_on = 1; ctrl_pdata->ctrl_rev = MIPI_INP(ctrl_pdata->ctrl_base); mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base)); if (ctrl_pdata->ctrl_rev == MDSS_DSI_HW_REV_103) mdss_dsi_20nm_phy_init(pdata); else mdss_dsi_phy_init(pdata); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); /* * Enable DSI clocks. * This is also enable the DSI core power block and reset/setup * DSI phy */ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); __mdss_dsi_ctrl_setup(pdata); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); pdata->panel_info.panel_power_on = 1; /* * Issue hardware reset line after enabling the DSI clocks and data Loading Loading @@ -992,9 +800,7 @@ int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata) WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT), "Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); mdss_dsi_op_mode_config(mipi->mode, pdata); mdss_dsi_reset(ctrl_pdata); pr_debug("%s-:End\n", __func__); return ret; } Loading
drivers/video/msm/mdss/mdss_dsi.h +5 −2 Original line number Diff line number Diff line Loading @@ -336,9 +336,11 @@ struct mdss_dsi_ctrl_pdata { struct mutex mutex; struct mutex cmd_mutex; bool ulps; u32 ulps_clamp_ctrl_off; u32 ulps_phyrst_ctrl_off; bool ulps; bool core_power; bool mmss_clamp; struct dsi_buf tx_buf; struct dsi_buf rx_buf; Loading Loading @@ -410,7 +412,8 @@ void mdss_dsi_cmdlist_kickoff(int intf); int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl); int mdss_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl); bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type); int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable); void mdss_dsi_reset(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata); int mdss_dsi_panel_init(struct device_node *node, struct mdss_dsi_ctrl_pdata *ctrl_pdata, Loading
drivers/video/msm/mdss/msm_mdss_io_8974.c +382 −38 Original line number Diff line number Diff line Loading @@ -484,6 +484,366 @@ static void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl) mdss_dsi_link_clk_unprepare(ctrl); } /** * mdss_dsi_ulps_config() - Program DSI lanes to enter/exit ULPS mode * @ctrl: pointer to DSI controller structure * @enable: 1 to enter ULPS, 0 to exit ULPS * * This function executes the necessary programming sequence to enter/exit * DSI Ultra-Low Power State (ULPS). This function assumes that the link and * bus clocks are already on. */ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { int ret = 0; struct mdss_panel_data *pdata = NULL; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 lane_status = 0; u32 active_lanes = 0; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } pinfo = &pdata->panel_info; mipi = &pinfo->mipi; if (!mdss_dsi_ulps_feature_enabled(pdata)) { pr_debug("%s: ULPS feature not supported. enable=%d\n", __func__, enable); return -ENOTSUPP; } /* * 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__); return 0; } /* clock lane will always be programmed for ulps */ active_lanes = BIT(4); /* * make a note of all active data lanes for which ulps entry/exit * is needed */ if (mipi->data_lane0) active_lanes |= BIT(0); if (mipi->data_lane1) active_lanes |= BIT(1); if (mipi->data_lane2) active_lanes |= BIT(2); if (mipi->data_lane3) active_lanes |= BIT(3); pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", __func__, (enable ? "on" : "off"), ctrl->ndx, active_lanes); if (enable && !ctrl->ulps) { /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Check to make sure that all active data lanes are in ULPS */ lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8); if (lane_status & (active_lanes << 8)) { pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n", __func__, ctrl->ndx, lane_status); ret = -EINVAL; goto error; } ctrl->ulps = true; } else if (!enable && ctrl->ulps) { /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms */ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes << 8); usleep(1000); MIPI_OUTP(ctrl->ctrl_base + 0x0AC, 0x0); /* * Wait for a short duration before enabling * data transmission */ usleep(100); lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8); ctrl->ulps = false; } else { pr_debug("%s: No change requested: %s -> %s\n", __func__, ctrl->ulps ? "enabled" : "disabled", enable ? "enabled" : "disabled"); } pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__, lane_status, enable ? "enabled" : "disabled"); error: return ret; } /** * mdss_dsi_clamp_ctrl() - Program DSI clamps for supporting power collapse * @ctrl: pointer to DSI controller structure * @enable: 1 to enable clamps, 0 to disable clamps * * For idle-screen usecases with command mode panels, MDSS can be power * collapsed. However, DSI phy needs to remain on. To avoid any mismatch * between the DSI controller state, DSI phy needs to be clamped before * power collapsing. This function executes the required programming * sequence to configure these DSI clamps. This function should only be called * when the DSI link clocks are disabled. */ static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { struct mipi_panel_info *mipi = NULL; u32 clamp_reg, regval = 0; u32 clamp_reg_off, phyrst_reg_off; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } if (!ctrl->mmss_misc_io.base) { pr_err("%s: mmss_misc_io not mapped\nn", __func__); return -EINVAL; } clamp_reg_off = ctrl->ulps_clamp_ctrl_off; phyrst_reg_off = ctrl->ulps_phyrst_ctrl_off; mipi = &ctrl->panel_data.panel_info.mipi; /* clock lane will always be clamped */ clamp_reg = BIT(9); if (ctrl->ulps) clamp_reg |= BIT(8); /* make a note of all active data lanes which need to be clamped */ if (mipi->data_lane0) { clamp_reg |= BIT(7); if (ctrl->ulps) clamp_reg |= BIT(6); } if (mipi->data_lane1) { clamp_reg |= BIT(5); if (ctrl->ulps) clamp_reg |= BIT(4); } if (mipi->data_lane2) { clamp_reg |= BIT(3); if (ctrl->ulps) clamp_reg |= BIT(2); } if (mipi->data_lane3) { clamp_reg |= BIT(1); if (ctrl->ulps) clamp_reg |= BIT(0); } pr_debug("%s: called for ctrl%d, enable=%d, clamp_reg=0x%08x\n", __func__, ctrl->ndx, enable, clamp_reg); if (enable && !ctrl->mmss_clamp) { /* Enable MMSS DSI Clamps */ if (ctrl->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | clamp_reg); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg | BIT(15))); } else if (ctrl->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | (clamp_reg << 16)); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval | ((clamp_reg << 16) | BIT(31))); } /* * This register write ensures that DSI PHY will not be * reset when mdss ahb clock reset is asserted while coming * out of power collapse */ MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off, 0x1); ctrl->mmss_clamp = true; } else if (!enable && ctrl->mmss_clamp) { MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off, 0x0); /* Disable MMSS DSI Clamps */ if (ctrl->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval & ~(clamp_reg | BIT(15))); } else if (ctrl->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl->mmss_misc_io.base + clamp_reg_off); MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off, regval & ~((clamp_reg << 16) | BIT(31))); } ctrl->mmss_clamp = false; } else { pr_debug("%s: No change requested: %s -> %s\n", __func__, ctrl->mmss_clamp ? "enabled" : "disabled", enable ? "enabled" : "disabled"); } return 0; } /** * mdss_dsi_core_power_ctrl() - Enable/disable DSI core power * @ctrl: pointer to DSI controller structure * @enable: 1 to enable power, 0 to disable power * * When all DSI bus clocks are disabled, DSI core power module can be turned * off to save any leakage current. This function implements the necessary * programming sequence for the same. For command mode panels, the core power * can be turned off for idle-screen usecases, where additional programming is * needed to clamp DSI phy. */ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { int rc = 0; struct mdss_panel_data *pdata = NULL; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } if (enable) { if (!ctrl->core_power) { /* enable mdss gdsc */ pr_debug("%s: Enable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 1); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); goto error; } ctrl->core_power = true; } rc = mdss_dsi_bus_clk_start(ctrl); if (rc) { pr_err("%s: Failed to start bus clocks. rc=%d\n", __func__, rc); goto error_bus_clk_start; } /* * Phy software reset should not be done for idle screen power * collapse use-case. Issue a phy software reset only when * unblanking the panel. */ if (!pdata->panel_info.panel_power_on) mdss_dsi_phy_sw_reset(ctrl->ctrl_base); mdss_dsi_phy_init(pdata); mdss_dsi_ctrl_setup(pdata); if (ctrl->ulps) { /* * ULPS Entry Request. This is needed if the lanes were * in ULPS prior to power collapse, since after * power collapse and reset, the DSI controller resets * back to idle state and not ULPS. This ulps entry * request will transition the state of the DSI * controller to ULPS which will match the state of the * DSI phy. This needs to be done prior to disabling * the DSI clamps. */ rc = mdss_dsi_ulps_config(ctrl, 1); if (rc) { pr_err("%s: Failed to enter ULPS. rc=%d\n", __func__, rc); goto error_ulps; } } rc = mdss_dsi_clamp_ctrl(ctrl, 0); if (rc) { pr_err("%s: Failed to disable dsi clamps. rc=%d\n", __func__, rc); goto error_ulps; } } else { /* Enable DSI clamps only if entering idle power collapse */ if (ctrl->panel_data.panel_info.panel_power_on) { rc = mdss_dsi_clamp_ctrl(ctrl, 1); if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); } /* * disable bus clocks irrespective of whether dsi phy was * successfully clamped or not */ mdss_dsi_bus_clk_stop(ctrl); /* disable mdss gdsc only if dsi phy was successfully clamped*/ if (rc) { pr_debug("%s: leaving mdss gdsc on\n", __func__); } else { pr_debug("%s: Disable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); rc = 0; } else { ctrl->core_power = false; } } } return rc; error_ulps: mdss_dsi_bus_clk_stop(ctrl); error_bus_clk_start: if (msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0)) pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); else ctrl->core_power = false; error: return rc; } static int __mdss_dsi_update_clk_cnt(u32 *clk_cnt, int enable) { int changed = 0; Loading @@ -510,6 +870,7 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, { int rc = 0; struct mdss_panel_data *pdata; bool core_power_enabled = false; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); Loading @@ -523,41 +884,37 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, if (enable) { if (clk_type & DSI_BUS_CLKS) { /* enable mdss gdsc */ pr_debug("%s: Enable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 1); rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); pr_err("%s: Failed to enable core power. rc=%d\n", __func__, rc); goto error; } rc = mdss_dsi_bus_clk_start(ctrl); if (rc) { pr_err("Failed to start bus clocks. rc=%d\n", rc); goto error_vreg; } core_power_enabled = true; } if (clk_type & DSI_LINK_CLKS) { rc = mdss_dsi_link_clk_start(ctrl); if (rc) { pr_err("Failed to start link clocks. rc=%d\n", rc); pr_err("%s: Failed to start link clocks. rc=%d\n", __func__, rc); goto error_link_clk_start; } /* Disable ULPS, if enabled */ if (ctrl->ulps) { rc = mdss_dsi_ulps_config(ctrl, 0); if (rc) { pr_err("Failed to exit ulps. rc=%d\n", rc); pr_err("%s: Failed to exit ulps. rc=%d\n", __func__, rc); goto error_ulps_exit; } } /* * If we are coming out of idle power collapse, then * reset DSI controller state */ if (core_power_enabled) mdss_dsi_reset(ctrl); } } else { if (clk_type & DSI_LINK_CLKS) { Loading @@ -572,18 +929,10 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, mdss_dsi_link_clk_stop(ctrl); } if (clk_type & DSI_BUS_CLKS) { mdss_dsi_bus_clk_stop(ctrl); /* disable mdss gdsc */ pr_debug("%s: Disable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0); rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); rc = 0; pr_err("%s: Failed to disable core power. rc=%d\n", __func__, rc); } } } Loading @@ -593,15 +942,10 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, error_ulps_exit: mdss_dsi_link_clk_stop(ctrl); error_link_clk_start: if (clk_type & DSI_BUS_CLKS) mdss_dsi_bus_clk_stop(ctrl); error_vreg: if ((clk_type & DSI_BUS_CLKS) && (msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0))) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); } (mdss_dsi_core_power_ctrl(ctrl, !enable))) pr_warn("%s: Failed to disable core power. rc=%d\n", __func__, rc); error: return rc; } Loading