msm: mdss: Add support to selectively control bus and link clocks

DSI driver needs two different types of clocks for normal
operation - bus clocks and link clocks. The clock control function
enables/disables both these set of clocks together. However,
under certain circumstances, it is required to control just the
link clocks or the bus clocks. To support this, add separate
ref counts for link and bus clocks and modify the clock control
function to selectively control these clocks.

Change-Id: I25312131fc737b56dc15f4edf5e55a5824dad855
Signed-off-by: Aravind Venkateswaran <aravindh@codeaurora.org>
This commit is contained in:
Aravind Venkateswaran 2014-03-12 13:34:50 -07:00
parent 9133abcbd4
commit 5b70889f57
4 changed files with 116 additions and 68 deletions

View file

@ -321,7 +321,7 @@ static int mdss_dsi_off(struct mdss_panel_data *pdata)
ctrl_pdata, ctrl_pdata->ndx);
if (pdata->panel_info.type == MIPI_CMD_PANEL)
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
@ -329,7 +329,7 @@ static int mdss_dsi_off(struct mdss_panel_data *pdata)
/* disable DSI phy */
mdss_dsi_phy_disable(ctrl_pdata);
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
ret = mdss_dsi_panel_power_on(pdata, 0);
if (ret) {
@ -465,14 +465,14 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
goto error;
}
if (__mdss_dsi_clk_enabled(ctrl_pdata)) {
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;
}
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
/*
* ULPS Entry Request.
* Wait for a short duration to ensure that the lanes
@ -492,7 +492,7 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
mdss_dsi_controller_cfg(0, pdata);
lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
ctrl_pdata->ulps = true;
} else if (ctrl_pdata->ulps) {
mdss_dsi_phy_init(pdata);
@ -595,7 +595,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
return ret;
}
ret = mdss_dsi_bus_clk_start(ctrl_pdata);
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);
@ -612,9 +612,9 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
mdss_dsi_bus_clk_stop(ctrl_pdata);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
__mdss_dsi_ctrl_setup(pdata);
mdss_dsi_sw_reset(pdata);
@ -640,7 +640,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
}
if (pdata->panel_info.type == MIPI_CMD_PANEL)
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
pr_debug("%s-:\n", __func__);
return 0;
@ -902,8 +902,8 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
dsi_ctrl);
mdss_dsi_controller_cfg(true, pdata);
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
dsi_ctrl |= 0x2;
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
dsi_ctrl);
@ -1572,7 +1572,7 @@ int dsi_panel_device_register(struct device_node *pan_node,
return rc;
}
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
ctrl_pdata->ctrl_state |=
(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
} else {

View file

@ -230,6 +230,10 @@ enum {
#define DSI_CTRL_MASTER DSI_CTRL_0
#define DSI_CTRL_SLAVE DSI_CTRL_1
#define DSI_BUS_CLKS BIT(0)
#define DSI_LINK_CLKS BIT(1)
#define DSI_ALL_CLKS ((DSI_BUS_CLKS) | (DSI_LINK_CLKS))
#define DSI_EV_PLL_UNLOCKED 0x0001
#define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002
#define DSI_EV_MDP_BUSY_RELEASE 0x80000000
@ -247,7 +251,8 @@ struct mdss_dsi_ctrl_pdata {
struct dss_io_data mmss_misc_io;
struct dss_io_data phy_io;
int reg_size;
u32 clk_cnt;
u32 bus_clk_cnt;
u32 link_clk_cnt;
u32 flags;
struct clk *mdp_core_clk;
struct clk *ahb_clk;
@ -320,11 +325,8 @@ void mdp4_dsi_cmd_trigger(void);
void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
u8 clk_type, int enable);
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
int enable);
void mdss_dsi_controller_cfg(int enable,
@ -356,7 +358,7 @@ void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl);
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,

View file

@ -117,22 +117,26 @@ void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
mutex_unlock(&ctrl->cmd_mutex);
}
mdss_dsi_clk_ctrl(ctrl, enable);
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, enable);
}
void mdss_dsi_pll_relock(struct mdss_dsi_ctrl_pdata *ctrl)
{
int i, cnt;
cnt = ctrl->clk_cnt;
/*
* todo: this code does not work very well with dual
* dsi use cases. Need to fix this eventually.
*/
cnt = ctrl->link_clk_cnt;
/* disable dsi clk */
for (i = 0; i < cnt; i++)
mdss_dsi_clk_ctrl(ctrl, 0);
mdss_dsi_clk_ctrl(ctrl, DSI_LINK_CLKS, 0);
/* enable dsi clk */
for (i = 0; i < cnt; i++)
mdss_dsi_clk_ctrl(ctrl, 1);
mdss_dsi_clk_ctrl(ctrl, DSI_LINK_CLKS, 1);
}
void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
@ -618,7 +622,7 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
pr_debug("%s: Checking BTA status\n", __func__);
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
spin_lock_irqsave(&ctrl_pdata->mdp_lock, flag);
INIT_COMPLETION(ctrl_pdata->bta_comp);
mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM);
@ -633,7 +637,7 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
pr_err("%s: DSI BTA error: %i\n", __func__, ret);
}
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
return ret;
@ -1246,14 +1250,14 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
mdss_bus_bandwidth_ctrl(1);
pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
mdss_dsi_clk_ctrl(ctrl, 1);
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
if (req->flags & CMD_REQ_RX)
ret = mdss_dsi_cmdlist_rx(ctrl, req);
else
ret = mdss_dsi_cmdlist_tx(ctrl, req);
mdss_dsi_clk_ctrl(ctrl, 0);
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
mdss_bus_bandwidth_ctrl(0);
need_lock:

View file

@ -259,7 +259,7 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
return 0;
}
int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
static int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int rc = 0;
@ -303,7 +303,7 @@ error:
return rc;
}
void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
static void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
if (ctrl_pdata->mmss_misc_ahb_clk)
clk_disable_unprepare(ctrl_pdata->mmss_misc_ahb_clk);
@ -450,7 +450,7 @@ static void mdss_dsi_link_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
clk_disable(ctrl_pdata->byte_clk);
}
int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl)
static int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl)
{
int rc = 0;
@ -480,7 +480,7 @@ error:
return rc;
}
void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl)
static void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl)
{
mdss_dsi_link_clk_disable(ctrl);
mdss_dsi_link_clk_unprepare(ctrl);
@ -507,27 +507,38 @@ static int __mdss_dsi_update_clk_cnt(u32 *clk_cnt, int enable)
return changed;
}
static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
u8 clk_type, int enable)
{
int rc = 0;
pr_debug("%s: ndx=%d enable=%d\n", __func__, ctrl->ndx, enable);
pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__,
ctrl->ndx, clk_type, enable);
if (enable) {
rc = mdss_dsi_bus_clk_start(ctrl);
if (rc) {
pr_err("Failed to start bus clocks. rc=%d\n", rc);
goto error;
if (clk_type & DSI_BUS_CLKS) {
rc = mdss_dsi_bus_clk_start(ctrl);
if (rc) {
pr_err("Failed to start bus clocks. rc=%d\n",
rc);
goto error;
}
}
rc = mdss_dsi_link_clk_start(ctrl);
if (rc) {
pr_err("Failed to start link clocks. rc=%d\n", rc);
mdss_dsi_bus_clk_stop(ctrl);
goto error;
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);
if (clk_type & DSI_BUS_CLKS)
mdss_dsi_bus_clk_stop(ctrl);
goto error;
}
}
} else {
mdss_dsi_link_clk_stop(ctrl);
mdss_dsi_bus_clk_stop(ctrl);
if (clk_type & DSI_LINK_CLKS)
mdss_dsi_link_clk_stop(ctrl);
if (clk_type & DSI_BUS_CLKS)
mdss_dsi_bus_clk_stop(ctrl);
}
error:
@ -536,17 +547,23 @@ error:
static DEFINE_MUTEX(dsi_clk_lock); /* per system */
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl)
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type)
{
bool enabled;
bool bus_enabled = true;
bool link_enabled = true;
mutex_lock(&dsi_clk_lock);
enabled = ctrl->clk_cnt ? true : false;
if (clk_type & DSI_BUS_CLKS)
bus_enabled = ctrl->bus_clk_cnt ? true : false;
if (clk_type & DSI_LINK_CLKS)
link_enabled = ctrl->link_clk_cnt ? true : false;
mutex_unlock(&dsi_clk_lock);
return enabled;
return bus_enabled && link_enabled;
}
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
u8 clk_type, int enable)
{
int rc = 0;
int changed = 0, m_changed = 0;
@ -568,18 +585,33 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
pr_warn("%s: Unable to get master control\n", __func__);
}
pr_debug("%s++: ndx=%d clk_cnt=%d mctrl=%s m_clk_cnt=%d\n, enable=%d\n",
__func__, ctrl->ndx, ctrl->clk_cnt,
mctrl ? "yes" : "no", mctrl ? mctrl->clk_cnt : -1, enable);
pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d",
__func__, ctrl->ndx, clk_type, ctrl->bus_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",
__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
mctrl ? mctrl->link_clk_cnt : -1, enable);
mutex_lock(&dsi_clk_lock);
changed = __mdss_dsi_update_clk_cnt(&ctrl->clk_cnt, enable);
if (changed && mctrl)
m_changed = __mdss_dsi_update_clk_cnt(&mctrl->clk_cnt, enable);
if (clk_type & DSI_BUS_CLKS) {
changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
enable);
if (changed && mctrl)
m_changed = __mdss_dsi_update_clk_cnt(
&mctrl->bus_clk_cnt, enable);
}
if (clk_type & DSI_LINK_CLKS) {
changed += __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
enable);
if (changed && mctrl)
m_changed += __mdss_dsi_update_clk_cnt(
&mctrl->link_clk_cnt, enable);
}
if (changed) {
if (enable && m_changed) {
rc = mdss_dsi_clk_ctrl_sub(mctrl, enable);
rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
if (rc) {
pr_err("Failed to start mctrl clocks. rc=%d\n",
rc);
@ -587,7 +619,7 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
}
}
rc = mdss_dsi_clk_ctrl_sub(ctrl, enable);
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);
@ -595,7 +627,7 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
}
if (!enable && m_changed) {
rc = mdss_dsi_clk_ctrl_sub(mctrl, enable);
rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
if (rc) {
pr_err("Failed to stop mctrl clocks. rc=%d\n",
rc);
@ -603,24 +635,34 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
}
}
}
goto no_error;
error_mctrl_stop:
mdss_dsi_clk_ctrl_sub(ctrl, enable ? 0 : 1);
mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1);
error_ctrl:
mdss_dsi_clk_ctrl_sub(mctrl, 0);
mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
error_mctrl_start:
__mdss_dsi_update_clk_cnt(&mctrl->clk_cnt, enable ? 0 : 1);
__mdss_dsi_update_clk_cnt(&ctrl->clk_cnt, enable ? 0 : 1);
if (clk_type & DSI_BUS_CLKS) {
if (mctrl)
__mdss_dsi_update_clk_cnt(&mctrl->bus_clk_cnt,
enable ? 0 : 1);
__mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable ? 0 : 1);
}
if (clk_type & DSI_LINK_CLKS) {
if (mctrl)
__mdss_dsi_update_clk_cnt(&mctrl->link_clk_cnt,
enable ? 0 : 1);
__mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable ? 0 : 1);
}
no_error:
mutex_unlock(&dsi_clk_lock);
pr_debug("%s--: ndx=%d clk_cnt=%d changed=%d mctrl=%s m_clk_cnt=%d\n",
__func__, ctrl->ndx, ctrl->clk_cnt, changed,
mctrl ? "yes" : "no", mctrl ? mctrl->clk_cnt : -1);
pr_debug("%s--: m_changed=%d enable=%d\n", __func__,
mctrl ? m_changed : -1, enable);
pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d",
__func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
ctrl->link_clk_cnt, changed);
pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, m_changed=%d, enable=%d\n",
__func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
mctrl ? mctrl->link_clk_cnt : -1, m_changed, enable);
return rc;
}