msm: mdss: move ULPS configuration to DSI clock control
DSI Ultra Low Power State (ULPS) mode is property of the DSI data and clock lanes. Current implementation requires the MDP command interface to send explicit events to the DSI controller to config ULPS mode. However, it would be a lot more efficient if the DSI controller would independently decide to enter/exit ULPS based on whether the link clocks are enabled or not. This also ensures that if any DCS commands need to be sent when ULPS is enabled, the DSI controllers will exit ULPS accordingly. Change-Id: If8d5b7039b5e104bcee5304c7c0ddb3cdd5bbcbc Signed-off-by: Aravind Venkateswaran <aravindh@codeaurora.org>
This commit is contained in:
parent
fc0c415f2c
commit
802dc41de6
5 changed files with 241 additions and 253 deletions
|
@ -76,19 +76,21 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable)
|
||||||
panel_data);
|
panel_data);
|
||||||
pr_debug("%s: enable=%d\n", __func__, enable);
|
pr_debug("%s: enable=%d\n", __func__, enable);
|
||||||
|
|
||||||
if (pdata->panel_info.dynamic_switch_pending) {
|
/*
|
||||||
/*
|
* If a dynamic mode switch is pending, the regulators should not
|
||||||
* Current implementation of dynamic mode switch
|
* be turned off or on.
|
||||||
* relies on the GDSC to be disabled while switching.
|
*/
|
||||||
*/
|
if (pdata->panel_info.dynamic_switch_pending)
|
||||||
msm_dss_enable_vreg(
|
|
||||||
ctrl_pdata->power_data[DSI_CORE_PM].vreg_config,
|
|
||||||
ctrl_pdata->power_data[DSI_CORE_PM].num_vreg, enable);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
for (i = 0; i < DSI_MAX_PM; i++) {
|
for (i = 0; i < DSI_MAX_PM; i++) {
|
||||||
|
/*
|
||||||
|
* Core power module will be enabled when the
|
||||||
|
* clocks are enabled
|
||||||
|
*/
|
||||||
|
if (DSI_CORE_PM == i)
|
||||||
|
continue;
|
||||||
ret = msm_dss_enable_vreg(
|
ret = msm_dss_enable_vreg(
|
||||||
ctrl_pdata->power_data[i].vreg_config,
|
ctrl_pdata->power_data[i].vreg_config,
|
||||||
ctrl_pdata->power_data[i].num_vreg, 1);
|
ctrl_pdata->power_data[i].num_vreg, 1);
|
||||||
|
@ -121,6 +123,12 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable)
|
||||||
pr_debug("reset disable: pinctrl not enabled\n");
|
pr_debug("reset disable: pinctrl not enabled\n");
|
||||||
|
|
||||||
for (i = DSI_MAX_PM - 1; i >= 0; i--) {
|
for (i = DSI_MAX_PM - 1; i >= 0; i--) {
|
||||||
|
/*
|
||||||
|
* Core power module will be disabled when the
|
||||||
|
* clocks are disabled
|
||||||
|
*/
|
||||||
|
if (DSI_CORE_PM == i)
|
||||||
|
continue;
|
||||||
ret = msm_dss_enable_vreg(
|
ret = msm_dss_enable_vreg(
|
||||||
ctrl_pdata->power_data[i].vreg_config,
|
ctrl_pdata->power_data[i].vreg_config,
|
||||||
ctrl_pdata->power_data[i].num_vreg, 0);
|
ctrl_pdata->power_data[i].num_vreg, 0);
|
||||||
|
@ -483,85 +491,93 @@ static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool __mdss_dsi_ulps_feature_enabled(
|
int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable)
|
||||||
struct mdss_panel_data *pdata)
|
|
||||||
{
|
|
||||||
return pdata->panel_info.ulps_feature_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
|
||||||
int enable)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct mdss_panel_data *pdata = NULL;
|
struct mdss_panel_data *pdata = NULL;
|
||||||
struct mipi_panel_info *pinfo = NULL;
|
struct mdss_panel_info *pinfo;
|
||||||
u32 lane_status = 0;
|
struct mipi_panel_info *mipi;
|
||||||
u32 active_lanes = 0;
|
u32 lane_status = 0, regval;
|
||||||
u32 regval = 0;
|
u32 active_lanes = 0, clamp_reg;
|
||||||
|
|
||||||
if (!ctrl_pdata) {
|
if (!ctrl_pdata) {
|
||||||
pr_err("%s: invalid input\n", __func__);
|
pr_err("%s: invalid input\n", __func__);
|
||||||
return -EINVAL;
|
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;
|
pdata = &ctrl_pdata->panel_data;
|
||||||
if (!pdata) {
|
if (!pdata) {
|
||||||
pr_err("%s: Invalid panel data\n", __func__);
|
pr_err("%s: Invalid panel data\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
pinfo = &pdata->panel_info.mipi;
|
pinfo = &pdata->panel_info;
|
||||||
|
mipi = &pinfo->mipi;
|
||||||
|
|
||||||
if (!__mdss_dsi_ulps_feature_enabled(pdata)) {
|
if (!mdss_dsi_ulps_feature_enabled(pdata)) {
|
||||||
pr_debug("%s: ULPS feature not supported. enable=%d\n",
|
pr_debug("%s: ULPS feature not supported. enable=%d\n",
|
||||||
__func__, enable);
|
__func__, enable);
|
||||||
return -ENOTSUPP;
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if (enable && !ctrl_pdata->ulps) {
|
||||||
/* No need to configure ULPS mode when entering suspend state */
|
|
||||||
if (!pdata->panel_info.panel_power_on) {
|
|
||||||
pr_err("%s: panel off. returning\n", __func__);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__mdss_dsi_clk_enabled(ctrl_pdata, DSI_LINK_CLKS)) {
|
|
||||||
pr_err("%s: cannot enter ulps mode if dsi clocks are on\n",
|
|
||||||
__func__);
|
|
||||||
ret = -EPERM;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: Failed to enable clocks. rc=%d\n",
|
|
||||||
__func__, ret);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ULPS Entry Request.
|
* ULPS Entry Request.
|
||||||
* Wait for a short duration to ensure that the lanes
|
* Wait for a short duration to ensure that the lanes
|
||||||
* enter ULP state.
|
* enter ULP state.
|
||||||
*/
|
*/
|
||||||
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
|
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes);
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
|
||||||
/* Check to make sure that all active data lanes are in ULPS */
|
/* Check to make sure that all active data lanes are in ULPS */
|
||||||
if (pinfo->data_lane3)
|
|
||||||
active_lanes |= BIT(11);
|
|
||||||
if (pinfo->data_lane2)
|
|
||||||
active_lanes |= BIT(10);
|
|
||||||
if (pinfo->data_lane1)
|
|
||||||
active_lanes |= BIT(9);
|
|
||||||
if (pinfo->data_lane0)
|
|
||||||
active_lanes |= BIT(8);
|
|
||||||
active_lanes |= BIT(12); /* clock lane */
|
|
||||||
lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
|
lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
|
||||||
if (lane_status & active_lanes) {
|
if (lane_status & (active_lanes << 8)) {
|
||||||
pr_err("%s: ULPS entry req failed. Lane status=0x%08x\n",
|
pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n",
|
||||||
__func__, lane_status);
|
__func__, ctrl_pdata->ndx, lane_status);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,15 +585,15 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||||
if (ctrl_pdata->ndx == DSI_CTRL_0) {
|
if (ctrl_pdata->ndx == DSI_CTRL_0) {
|
||||||
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
||||||
regval | 0x3FF);
|
regval | clamp_reg);
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
||||||
regval | 0x83FF);
|
regval | (clamp_reg | BIT(15)));
|
||||||
} else if (ctrl_pdata->ndx == DSI_CTRL_1) {
|
} else if (ctrl_pdata->ndx == DSI_CTRL_1) {
|
||||||
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
||||||
regval | 0x3FF0000);
|
regval | (clamp_reg << 16));
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
||||||
regval | 0x83FF0000);
|
regval | ((clamp_reg << 16) | BIT(31)));
|
||||||
}
|
}
|
||||||
|
|
||||||
wmb();
|
wmb();
|
||||||
|
@ -588,19 +604,8 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||||
* out of power collapse
|
* out of power collapse
|
||||||
*/
|
*/
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1);
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1);
|
||||||
/* disable DSI controller */
|
|
||||||
mdss_dsi_controller_cfg(0, pdata);
|
|
||||||
|
|
||||||
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
|
|
||||||
ctrl_pdata->ulps = true;
|
ctrl_pdata->ulps = true;
|
||||||
} else if (ctrl_pdata->ulps) {
|
} else if (ctrl_pdata->ulps) {
|
||||||
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);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0);
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0);
|
||||||
mdss_dsi_phy_init(pdata);
|
mdss_dsi_phy_init(pdata);
|
||||||
|
|
||||||
|
@ -617,33 +622,26 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||||
* Wait for a short duration to ensure that the lanes
|
* Wait for a short duration to ensure that the lanes
|
||||||
* enter ULP state.
|
* enter ULP state.
|
||||||
*/
|
*/
|
||||||
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
|
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes);
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
|
||||||
/* Disable MMSS DSI Clamps */
|
/* Disable MMSS DSI Clamps */
|
||||||
if (ctrl_pdata->ndx == DSI_CTRL_0) {
|
if (ctrl_pdata->ndx == DSI_CTRL_0) {
|
||||||
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
||||||
regval & ~0x83FF);
|
regval & ~(clamp_reg | BIT(15)));
|
||||||
} else if (ctrl_pdata->ndx == DSI_CTRL_1) {
|
} else if (ctrl_pdata->ndx == DSI_CTRL_1) {
|
||||||
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14);
|
||||||
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14,
|
||||||
regval & ~0x83FF0000);
|
regval & ~((clamp_reg << 16) | BIT(31)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 1);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: Failed to enable link clocks. rc=%d\n",
|
|
||||||
__func__, ret);
|
|
||||||
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ULPS Exit Request
|
* ULPS Exit Request
|
||||||
* Hardware requirement is to wait for at least 1ms
|
* Hardware requirement is to wait for at least 1ms
|
||||||
*/
|
*/
|
||||||
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00);
|
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8);
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);
|
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);
|
||||||
|
|
||||||
|
@ -654,8 +652,6 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||||
usleep(100);
|
usleep(100);
|
||||||
|
|
||||||
lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
|
lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
|
||||||
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 0);
|
|
||||||
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
|
|
||||||
ctrl_pdata->ulps = false;
|
ctrl_pdata->ulps = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,78 +687,6 @@ static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
|
|
||||||
int enable)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
|
|
||||||
struct mdss_dsi_ctrl_pdata *sctrl = NULL;
|
|
||||||
|
|
||||||
if (&ctrl->mmss_misc_io == NULL) {
|
|
||||||
pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mdss_dsi_is_master_ctrl(ctrl)) {
|
|
||||||
if (enable) {
|
|
||||||
pr_debug("%s: skipping enable for master ctrl%d\n",
|
|
||||||
__func__, ctrl->ndx);
|
|
||||||
rc = 0;
|
|
||||||
goto error;
|
|
||||||
} else {
|
|
||||||
sctrl = mdss_dsi_get_slave_ctrl();
|
|
||||||
if (!sctrl) {
|
|
||||||
pr_err("%s: Unable to get slave control\n",
|
|
||||||
__func__);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mdss_dsi_is_slave_ctrl(ctrl)) {
|
|
||||||
if (enable) {
|
|
||||||
mctrl = mdss_dsi_get_master_ctrl();
|
|
||||||
if (!mctrl) {
|
|
||||||
pr_err("%s: Unable to get master control\n",
|
|
||||||
__func__);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pr_debug("%s: skipping disable for slave ctrl%d\n",
|
|
||||||
__func__, ctrl->ndx);
|
|
||||||
rc = 0;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mctrl) {
|
|
||||||
pr_debug("%s: configuring ulps (%s) for master ctrl%d\n",
|
|
||||||
__func__, (enable ? "on" : "off"), mctrl->ndx);
|
|
||||||
rc = mdss_dsi_ulps_config_sub(mctrl, enable);
|
|
||||||
if (rc)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("%s: configuring ulps (%s) for ctrl%d\n",
|
|
||||||
__func__, (enable ? "on" : "off"), ctrl->ndx);
|
|
||||||
rc = mdss_dsi_ulps_config_sub(ctrl, enable);
|
|
||||||
if (rc)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (sctrl) {
|
|
||||||
pr_debug("%s: configuring ulps (%s) for slave ctrl%d\n",
|
|
||||||
__func__, (enable ? "on" : "off"), sctrl->ndx);
|
|
||||||
rc = mdss_dsi_ulps_config_sub(sctrl, enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (rc)
|
|
||||||
pr_err("%s: Failed to configure ulps (%s) for ctrl%d\n",
|
|
||||||
__func__, (enable ? "on" : "off"), ctrl->ndx);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mdss_dsi_on(struct mdss_panel_data *pdata)
|
int mdss_dsi_on(struct mdss_panel_data *pdata)
|
||||||
{
|
{
|
||||||
|
@ -920,13 +844,15 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
|
||||||
panel_data);
|
panel_data);
|
||||||
mipi = &pdata->panel_info.mipi;
|
mipi = &pdata->panel_info.mipi;
|
||||||
|
|
||||||
|
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
|
||||||
|
|
||||||
if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
|
if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
|
||||||
if (!pdata->panel_info.dynamic_switch_pending) {
|
if (!pdata->panel_info.dynamic_switch_pending) {
|
||||||
ret = ctrl_pdata->on(pdata);
|
ret = ctrl_pdata->on(pdata);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("%s: unable to initialize the panel\n",
|
pr_err("%s: unable to initialize the panel\n",
|
||||||
__func__);
|
__func__);
|
||||||
return ret;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
|
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
|
||||||
|
@ -936,6 +862,8 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
|
||||||
mipi->vsync_enable && mipi->hw_vsync_mode)
|
mipi->vsync_enable && mipi->hw_vsync_mode)
|
||||||
mdss_dsi_set_tear_on(ctrl_pdata);
|
mdss_dsi_set_tear_on(ctrl_pdata);
|
||||||
|
|
||||||
|
error:
|
||||||
|
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
|
||||||
pr_debug("%s-:\n", __func__);
|
pr_debug("%s-:\n", __func__);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -958,16 +886,7 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata)
|
||||||
panel_data);
|
panel_data);
|
||||||
mipi = &pdata->panel_info.mipi;
|
mipi = &pdata->panel_info.mipi;
|
||||||
|
|
||||||
if (__mdss_dsi_ulps_feature_enabled(pdata) &&
|
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
|
||||||
(ctrl_pdata->ulps)) {
|
|
||||||
/* Disable ULPS mode before blanking the panel */
|
|
||||||
ret = mdss_dsi_ulps_config(ctrl_pdata, 0);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: failed to exit ULPS mode. rc=%d\n",
|
|
||||||
__func__, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdata->panel_info.type == MIPI_VIDEO_PANEL &&
|
if (pdata->panel_info.type == MIPI_VIDEO_PANEL &&
|
||||||
ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) {
|
ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) {
|
||||||
|
@ -997,12 +916,14 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata)
|
||||||
ret = ctrl_pdata->off(pdata);
|
ret = ctrl_pdata->off(pdata);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("%s: Panel OFF failed\n", __func__);
|
pr_err("%s: Panel OFF failed\n", __func__);
|
||||||
return ret;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
|
ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
|
||||||
pr_debug("%s-:End\n", __func__);
|
pr_debug("%s-:End\n", __func__);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1270,9 +1191,6 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
|
||||||
case MDSS_EVENT_DSI_STREAM_SIZE:
|
case MDSS_EVENT_DSI_STREAM_SIZE:
|
||||||
rc = mdss_dsi_set_stream_size(pdata);
|
rc = mdss_dsi_set_stream_size(pdata);
|
||||||
break;
|
break;
|
||||||
case MDSS_EVENT_DSI_ULPS_CTRL:
|
|
||||||
rc = mdss_dsi_ulps_config(ctrl_pdata, (int)(unsigned long) arg);
|
|
||||||
break;
|
|
||||||
case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
|
case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
|
||||||
rc = mdss_dsi_update_panel_config(ctrl_pdata,
|
rc = mdss_dsi_update_panel_config(ctrl_pdata,
|
||||||
(int)(unsigned long) arg);
|
(int)(unsigned long) arg);
|
||||||
|
|
|
@ -398,6 +398,7 @@ void mdss_dsi_cmdlist_kickoff(int intf);
|
||||||
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
|
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
|
||||||
int mdss_dsi_reg_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);
|
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);
|
||||||
|
|
||||||
int mdss_dsi_panel_init(struct device_node *node,
|
int mdss_dsi_panel_init(struct device_node *node,
|
||||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||||
|
@ -468,4 +469,11 @@ static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_by_index(int ndx)
|
||||||
|
|
||||||
return ctrl_list[ndx];
|
return ctrl_list[ndx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool mdss_dsi_ulps_feature_enabled(
|
||||||
|
struct mdss_panel_data *pdata)
|
||||||
|
{
|
||||||
|
return pdata->panel_info.ulps_feature_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* MDSS_DSI_H */
|
#endif /* MDSS_DSI_H */
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include "mdss_debug.h"
|
#include "mdss_debug.h"
|
||||||
#include "mdss_mdp_trace.h"
|
#include "mdss_mdp_trace.h"
|
||||||
|
|
||||||
#define VSYNC_EXPIRE_TICK 4
|
#define VSYNC_EXPIRE_TICK 6
|
||||||
|
|
||||||
#define MAX_SESSIONS 2
|
#define MAX_SESSIONS 2
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
#define KOFF_TIMEOUT msecs_to_jiffies(84)
|
#define KOFF_TIMEOUT msecs_to_jiffies(84)
|
||||||
|
|
||||||
#define STOP_TIMEOUT(hz) msecs_to_jiffies((1000 / hz) * (VSYNC_EXPIRE_TICK + 2))
|
#define STOP_TIMEOUT(hz) msecs_to_jiffies((1000 / hz) * (VSYNC_EXPIRE_TICK + 2))
|
||||||
#define ULPS_ENTER_TIME msecs_to_jiffies(100)
|
#define POWER_COLLAPSE_TIME msecs_to_jiffies(100)
|
||||||
|
|
||||||
struct mdss_mdp_cmd_ctx {
|
struct mdss_mdp_cmd_ctx {
|
||||||
struct mdss_mdp_ctl *ctl;
|
struct mdss_mdp_ctl *ctl;
|
||||||
|
@ -43,12 +43,12 @@ struct mdss_mdp_cmd_ctx {
|
||||||
struct mutex clk_mtx;
|
struct mutex clk_mtx;
|
||||||
spinlock_t clk_lock;
|
spinlock_t clk_lock;
|
||||||
struct work_struct clk_work;
|
struct work_struct clk_work;
|
||||||
struct delayed_work ulps_work;
|
struct delayed_work pc_work;
|
||||||
struct work_struct pp_done_work;
|
struct work_struct pp_done_work;
|
||||||
atomic_t pp_done_cnt;
|
atomic_t pp_done_cnt;
|
||||||
struct mdss_panel_recovery recovery;
|
struct mdss_panel_recovery recovery;
|
||||||
bool ulps;
|
|
||||||
struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
|
struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
|
||||||
|
bool idle_pc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
|
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
|
||||||
|
@ -195,17 +195,15 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
|
||||||
ctx->rdptr_enabled);
|
ctx->rdptr_enabled);
|
||||||
if (!ctx->clk_enabled) {
|
if (!ctx->clk_enabled) {
|
||||||
ctx->clk_enabled = 1;
|
ctx->clk_enabled = 1;
|
||||||
if (cancel_delayed_work_sync(&ctx->ulps_work))
|
if (cancel_delayed_work_sync(&ctx->pc_work))
|
||||||
pr_debug("deleted pending ulps work\n");
|
pr_debug("deleted pending power collapse work\n");
|
||||||
|
|
||||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
|
||||||
|
|
||||||
if (ctx->ulps) {
|
if (ctx->idle_pc) {
|
||||||
if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl))
|
if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl))
|
||||||
pr_warn("tearcheck setup failed\n");
|
pr_warn("tearcheck setup failed\n");
|
||||||
mdss_mdp_ctl_intf_event(ctx->ctl,
|
ctx->idle_pc = false;
|
||||||
MDSS_EVENT_DSI_ULPS_CTRL, (void *)0);
|
|
||||||
ctx->ulps = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mdss_mdp_ctl_intf_event
|
mdss_mdp_ctl_intf_event
|
||||||
|
@ -241,8 +239,9 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
|
||||||
mdss_mdp_ctl_intf_event
|
mdss_mdp_ctl_intf_event
|
||||||
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
|
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
|
||||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
|
||||||
if (ctx->panel_on)
|
if ((ctx->panel_on) && (mdata->idle_pc_enabled))
|
||||||
schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME);
|
schedule_delayed_work(&ctx->pc_work,
|
||||||
|
POWER_COLLAPSE_TIME);
|
||||||
}
|
}
|
||||||
mutex_unlock(&ctx->clk_mtx);
|
mutex_unlock(&ctx->clk_mtx);
|
||||||
}
|
}
|
||||||
|
@ -388,12 +387,11 @@ static void clk_ctrl_work(struct work_struct *work)
|
||||||
mdss_mdp_cmd_clk_off(ctx);
|
mdss_mdp_cmd_clk_off(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
|
static void __mdss_mdp_cmd_pc_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct delayed_work *dw = to_delayed_work(work);
|
struct delayed_work *dw = to_delayed_work(work);
|
||||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
|
||||||
struct mdss_mdp_cmd_ctx *ctx =
|
struct mdss_mdp_cmd_ctx *ctx =
|
||||||
container_of(dw, struct mdss_mdp_cmd_ctx, ulps_work);
|
container_of(dw, struct mdss_mdp_cmd_ctx, pc_work);
|
||||||
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
pr_err("%s: invalid ctx\n", __func__);
|
pr_err("%s: invalid ctx\n", __func__);
|
||||||
|
@ -401,19 +399,13 @@ static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx->panel_on) {
|
if (!ctx->panel_on) {
|
||||||
pr_err("Panel is off. skipping ULPS configuration\n");
|
pr_err("Panel is off. skipping power collapse\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_DSI_ULPS_CTRL,
|
ctx->idle_pc = true;
|
||||||
(void *)1)) {
|
ctx->ctl->play_cnt = 0;
|
||||||
ctx->ulps = true;
|
mdss_mdp_footswitch_ctrl_idle_pc(0, &ctx->ctl->mfd->pdev->dev);
|
||||||
if (mdata->idle_pc_enabled) {
|
|
||||||
ctx->ctl->play_cnt = 0;
|
|
||||||
mdss_mdp_footswitch_ctrl_idle_pc(0,
|
|
||||||
&ctx->ctl->mfd->pdev->dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
|
static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
|
||||||
|
@ -504,10 +496,10 @@ int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff)
|
||||||
|
|
||||||
pdata = ctl->panel_data;
|
pdata = ctl->panel_data;
|
||||||
|
|
||||||
pdata->panel_info.cont_splash_enabled = 0;
|
|
||||||
|
|
||||||
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
|
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
|
||||||
|
|
||||||
|
pdata->panel_info.cont_splash_enabled = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,8 +789,8 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
|
||||||
if (cancel_work_sync(&ctx->clk_work))
|
if (cancel_work_sync(&ctx->clk_work))
|
||||||
pr_debug("no pending clk work\n");
|
pr_debug("no pending clk work\n");
|
||||||
|
|
||||||
if (cancel_delayed_work_sync(&ctx->ulps_work))
|
if (cancel_delayed_work_sync(&ctx->pc_work))
|
||||||
pr_debug("deleted pending ulps work\n");
|
pr_debug("deleted pending power collapse work\n");
|
||||||
|
|
||||||
ctx->panel_on = 0;
|
ctx->panel_on = 0;
|
||||||
mdss_mdp_cmd_clk_off(ctx);
|
mdss_mdp_cmd_clk_off(ctx);
|
||||||
|
@ -811,9 +803,6 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
|
||||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
|
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
memset(ctx, 0, sizeof(*ctx));
|
|
||||||
ctl->priv_data = NULL;
|
|
||||||
|
|
||||||
if (ctl->num == 0) {
|
if (ctl->num == 0) {
|
||||||
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL);
|
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL);
|
||||||
WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
|
WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
|
||||||
|
@ -822,6 +811,9 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
|
||||||
WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
|
WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
|
ctl->priv_data = NULL;
|
||||||
|
|
||||||
ctl->stop_fnc = NULL;
|
ctl->stop_fnc = NULL;
|
||||||
ctl->display_fnc = NULL;
|
ctl->display_fnc = NULL;
|
||||||
ctl->wait_pingpong = NULL;
|
ctl->wait_pingpong = NULL;
|
||||||
|
@ -874,7 +866,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
|
||||||
spin_lock_init(&ctx->clk_lock);
|
spin_lock_init(&ctx->clk_lock);
|
||||||
mutex_init(&ctx->clk_mtx);
|
mutex_init(&ctx->clk_mtx);
|
||||||
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
|
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
|
||||||
INIT_DELAYED_WORK(&ctx->ulps_work, __mdss_mdp_cmd_ulps_work);
|
INIT_DELAYED_WORK(&ctx->pc_work, __mdss_mdp_cmd_pc_work);
|
||||||
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
|
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
|
||||||
atomic_set(&ctx->pp_done_cnt, 0);
|
atomic_set(&ctx->pp_done_cnt, 0);
|
||||||
INIT_LIST_HEAD(&ctx->vsync_handlers);
|
INIT_LIST_HEAD(&ctx->vsync_handlers);
|
||||||
|
|
|
@ -135,11 +135,6 @@ struct mdss_panel_recovery {
|
||||||
* @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
|
* @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
|
||||||
* @MDSS_EVENT_ENABLE_PARTIAL_ROI: Event to update ROI of the panel.
|
* @MDSS_EVENT_ENABLE_PARTIAL_ROI: Event to update ROI of the panel.
|
||||||
* @MDSS_EVENT_DSI_STREAM_SIZE: Event to update DSI controller's stream size
|
* @MDSS_EVENT_DSI_STREAM_SIZE: Event to update DSI controller's stream size
|
||||||
* @MDSS_EVENT_DSI_ULPS_CTRL: Event to configure Ultra Lower Power Saving
|
|
||||||
* mode for the DSI data and clock lanes. The
|
|
||||||
* event arguments can have one of these values:
|
|
||||||
* - 0: Disable ULPS mode
|
|
||||||
* - 1: Enable ULPS mode
|
|
||||||
* @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures
|
* @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures
|
||||||
* based on the dsi mode passed as argument.
|
* based on the dsi mode passed as argument.
|
||||||
* - 0: update to video mode
|
* - 0: update to video mode
|
||||||
|
@ -163,7 +158,6 @@ enum mdss_intf_events {
|
||||||
MDSS_EVENT_DSI_CMDLIST_KOFF,
|
MDSS_EVENT_DSI_CMDLIST_KOFF,
|
||||||
MDSS_EVENT_ENABLE_PARTIAL_ROI,
|
MDSS_EVENT_ENABLE_PARTIAL_ROI,
|
||||||
MDSS_EVENT_DSI_STREAM_SIZE,
|
MDSS_EVENT_DSI_STREAM_SIZE,
|
||||||
MDSS_EVENT_DSI_ULPS_CTRL,
|
|
||||||
MDSS_EVENT_DSI_DYNAMIC_SWITCH,
|
MDSS_EVENT_DSI_DYNAMIC_SWITCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -509,22 +509,37 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||||
u8 clk_type, int enable)
|
u8 clk_type, int enable)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
struct mdss_panel_data *pdata;
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
pr_err("%s: Invalid arg\n", __func__);
|
pr_err("%s: Invalid arg\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pdata = &ctrl->panel_data;
|
||||||
|
|
||||||
pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__,
|
pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__,
|
||||||
ctrl->ndx, clk_type, enable);
|
ctrl->ndx, clk_type, enable);
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
if (clk_type & DSI_BUS_CLKS) {
|
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);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("%s: failed to enable vregs for %s\n",
|
||||||
|
__func__,
|
||||||
|
__mdss_dsi_pm_name(DSI_CORE_PM));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
rc = mdss_dsi_bus_clk_start(ctrl);
|
rc = mdss_dsi_bus_clk_start(ctrl);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("Failed to start bus clocks. rc=%d\n",
|
pr_err("Failed to start bus clocks. rc=%d\n",
|
||||||
rc);
|
rc);
|
||||||
goto error;
|
goto error_vreg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (clk_type & DSI_LINK_CLKS) {
|
if (clk_type & DSI_LINK_CLKS) {
|
||||||
|
@ -532,18 +547,61 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("Failed to start link clocks. rc=%d\n",
|
pr_err("Failed to start link clocks. rc=%d\n",
|
||||||
rc);
|
rc);
|
||||||
if (clk_type & DSI_BUS_CLKS)
|
goto error_link_clk_start;
|
||||||
mdss_dsi_bus_clk_stop(ctrl);
|
}
|
||||||
goto error;
|
/* 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);
|
||||||
|
goto error_ulps_exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (clk_type & DSI_LINK_CLKS)
|
if (clk_type & DSI_LINK_CLKS) {
|
||||||
|
/*
|
||||||
|
* If ULPS feature is enabled, enter ULPS first.
|
||||||
|
* No need to enable ULPS when turning off clocks
|
||||||
|
* while blanking the panel.
|
||||||
|
*/
|
||||||
|
if ((mdss_dsi_ulps_feature_enabled(pdata)) &&
|
||||||
|
(pdata->panel_info.panel_power_on))
|
||||||
|
mdss_dsi_ulps_config(ctrl, 1);
|
||||||
mdss_dsi_link_clk_stop(ctrl);
|
mdss_dsi_link_clk_stop(ctrl);
|
||||||
if (clk_type & DSI_BUS_CLKS)
|
}
|
||||||
|
if (clk_type & DSI_BUS_CLKS) {
|
||||||
mdss_dsi_bus_clk_stop(ctrl);
|
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);
|
||||||
|
if (rc) {
|
||||||
|
pr_warn("%s: failed to disable vregs for %s\n",
|
||||||
|
__func__,
|
||||||
|
__mdss_dsi_pm_name(DSI_CORE_PM));
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
error:
|
error:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -569,7 +627,8 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||||
u8 clk_type, int enable)
|
u8 clk_type, int enable)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int changed = 0, m_changed = 0;
|
int link_changed = 0, bus_changed = 0;
|
||||||
|
int m_link_changed = 0, m_bus_changed = 0;
|
||||||
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
|
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
|
@ -588,62 +647,78 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||||
pr_warn("%s: Unable to get master control\n", __func__);
|
pr_warn("%s: Unable to get master control\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d",
|
pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d\n",
|
||||||
__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
|
__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
|
||||||
ctrl->link_clk_cnt);
|
ctrl->link_clk_cnt);
|
||||||
pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, enable=%d\n",
|
pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, enable=%d\n",
|
||||||
__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
|
__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
|
||||||
mctrl ? mctrl->link_clk_cnt : -1, enable);
|
mctrl ? mctrl->link_clk_cnt : -1, enable);
|
||||||
|
|
||||||
mutex_lock(&dsi_clk_lock);
|
mutex_lock(&dsi_clk_lock);
|
||||||
|
|
||||||
if (clk_type & DSI_BUS_CLKS) {
|
if (clk_type & DSI_BUS_CLKS) {
|
||||||
changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
|
bus_changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
|
||||||
enable);
|
enable);
|
||||||
if (changed && mctrl)
|
if (bus_changed && mctrl)
|
||||||
m_changed = __mdss_dsi_update_clk_cnt(
|
m_bus_changed = __mdss_dsi_update_clk_cnt(
|
||||||
&mctrl->bus_clk_cnt, enable);
|
&mctrl->bus_clk_cnt, enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clk_type & DSI_LINK_CLKS) {
|
if (clk_type & DSI_LINK_CLKS) {
|
||||||
changed += __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
|
link_changed = __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
|
||||||
enable);
|
enable);
|
||||||
if (changed && mctrl)
|
if (link_changed && mctrl)
|
||||||
m_changed += __mdss_dsi_update_clk_cnt(
|
m_link_changed = __mdss_dsi_update_clk_cnt(
|
||||||
&mctrl->link_clk_cnt, enable);
|
&mctrl->link_clk_cnt, enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (!link_changed && !bus_changed)
|
||||||
if (enable && m_changed) {
|
goto no_error; /* clk cnts updated, nothing else needed */
|
||||||
rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
|
|
||||||
if (rc) {
|
|
||||||
pr_err("Failed to start mctrl clocks. rc=%d\n",
|
|
||||||
rc);
|
|
||||||
goto error_mctrl_start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable);
|
/*
|
||||||
|
* If updating link clock, need to make sure that the bus
|
||||||
|
* clocks are enabled
|
||||||
|
*/
|
||||||
|
if (link_changed && (!bus_changed && !ctrl->bus_clk_cnt)) {
|
||||||
|
pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d",
|
||||||
|
__func__, mctrl->ndx);
|
||||||
|
goto error_mctrl_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_link_changed && (!m_bus_changed && !mctrl->bus_clk_cnt)) {
|
||||||
|
pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d",
|
||||||
|
__func__, ctrl->ndx);
|
||||||
|
goto error_mctrl_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable && (m_bus_changed || m_link_changed)) {
|
||||||
|
rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("Failed to %s ctrl clocks. rc=%d\n",
|
pr_err("Failed to start mctrl clocks. rc=%d\n", rc);
|
||||||
(enable ? "start" : "stop"), rc);
|
goto error_mctrl_start;
|
||||||
goto error_ctrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!enable && m_changed) {
|
|
||||||
rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
|
|
||||||
if (rc) {
|
|
||||||
pr_err("Failed to stop mctrl clocks. rc=%d\n",
|
|
||||||
rc);
|
|
||||||
goto error_mctrl_stop;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!enable && (m_bus_changed || m_link_changed)) {
|
||||||
|
rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("Failed to stop mctrl clocks. rc=%d\n", rc);
|
||||||
|
goto error_mctrl_stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("Failed to %s ctrl clocks. rc=%d\n",
|
||||||
|
(enable ? "start" : "stop"), rc);
|
||||||
|
goto error_ctrl;
|
||||||
|
}
|
||||||
|
|
||||||
goto no_error;
|
goto no_error;
|
||||||
|
|
||||||
error_mctrl_stop:
|
error_mctrl_stop:
|
||||||
mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1);
|
mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1);
|
||||||
error_ctrl:
|
error_ctrl:
|
||||||
if (enable && m_changed)
|
if (enable && (m_bus_changed || m_link_changed))
|
||||||
mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
|
mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
|
||||||
error_mctrl_start:
|
error_mctrl_start:
|
||||||
if (clk_type & DSI_BUS_CLKS) {
|
if (clk_type & DSI_BUS_CLKS) {
|
||||||
|
@ -661,12 +736,13 @@ error_mctrl_start:
|
||||||
|
|
||||||
no_error:
|
no_error:
|
||||||
mutex_unlock(&dsi_clk_lock);
|
mutex_unlock(&dsi_clk_lock);
|
||||||
pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d",
|
pr_debug("%s--: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d\n",
|
||||||
__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
|
__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
|
||||||
ctrl->link_clk_cnt, changed);
|
ctrl->link_clk_cnt, link_changed && bus_changed);
|
||||||
pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, m_changed=%d, enable=%d\n",
|
pr_debug("%s--: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, m_changed=%d, enable=%d\n",
|
||||||
__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
|
__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
|
||||||
mctrl ? mctrl->link_clk_cnt : -1, m_changed, enable);
|
mctrl ? mctrl->link_clk_cnt : -1,
|
||||||
|
m_link_changed && m_bus_changed, enable);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue