Commit 57bf4338 authored by Hai Li's avatar Hai Li Committed by Rob Clark

drm/msm/dsi: Pass down use case to PHY

For some new types of DSI PHY, more settings depend on
use cases controlled by DSI manager. This change allows
DSI manager to setup PHY with a use case.
Signed-off-by: default avatarHai Li <hali@codeaurora.org>
Signed-off-by: default avatarArchit Taneja <architt@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent dceac340
...@@ -37,6 +37,12 @@ enum msm_dsi_phy_type { ...@@ -37,6 +37,12 @@ enum msm_dsi_phy_type {
MSM_DSI_PHY_MAX MSM_DSI_PHY_MAX
}; };
enum msm_dsi_phy_usecase {
MSM_DSI_PHY_STANDALONE,
MSM_DSI_PHY_MASTER,
MSM_DSI_PHY_SLAVE,
};
#define DSI_DEV_REGULATOR_MAX 8 #define DSI_DEV_REGULATOR_MAX 8
#define DSI_BUS_CLK_MAX 4 #define DSI_BUS_CLK_MAX 4
...@@ -180,6 +186,8 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy); ...@@ -180,6 +186,8 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy);
void msm_dsi_phy_get_shared_timings(struct msm_dsi_phy *phy, void msm_dsi_phy_get_shared_timings(struct msm_dsi_phy *phy,
struct msm_dsi_phy_shared_timings *shared_timing); struct msm_dsi_phy_shared_timings *shared_timing);
struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy); struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy);
void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy,
enum msm_dsi_phy_usecase uc);
#endif /* __DSI_CONNECTOR_H__ */ #endif /* __DSI_CONNECTOR_H__ */
...@@ -72,11 +72,12 @@ static int dsi_mgr_parse_dual_dsi(struct device_node *np, int id) ...@@ -72,11 +72,12 @@ static int dsi_mgr_parse_dual_dsi(struct device_node *np, int id)
return 0; return 0;
} }
static int dsi_mgr_host_register(int id) static int dsi_mgr_setup_components(int id)
{ {
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id); struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
struct msm_dsi *clk_master_dsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER); struct msm_dsi *clk_master_dsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *clk_slave_dsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
struct msm_dsi_pll *src_pll; struct msm_dsi_pll *src_pll;
int ret; int ret;
...@@ -85,14 +86,15 @@ static int dsi_mgr_host_register(int id) ...@@ -85,14 +86,15 @@ static int dsi_mgr_host_register(int id)
if (ret) if (ret)
return ret; return ret;
msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
src_pll = msm_dsi_phy_get_pll(msm_dsi->phy); src_pll = msm_dsi_phy_get_pll(msm_dsi->phy);
ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
} else if (!other_dsi) { } else if (!other_dsi) {
ret = 0; ret = 0;
} else { } else {
struct msm_dsi *mdsi = IS_MASTER_DSI_LINK(id) ? struct msm_dsi *master_link_dsi = IS_MASTER_DSI_LINK(id) ?
msm_dsi : other_dsi; msm_dsi : other_dsi;
struct msm_dsi *sdsi = IS_MASTER_DSI_LINK(id) ? struct msm_dsi *slave_link_dsi = IS_MASTER_DSI_LINK(id) ?
other_dsi : msm_dsi; other_dsi : msm_dsi;
/* Register slave host first, so that slave DSI device /* Register slave host first, so that slave DSI device
* has a chance to probe, and do not block the master * has a chance to probe, and do not block the master
...@@ -101,14 +103,18 @@ static int dsi_mgr_host_register(int id) ...@@ -101,14 +103,18 @@ static int dsi_mgr_host_register(int id)
* because only master DSI device adds the panel to global * because only master DSI device adds the panel to global
* panel list. The panel's device is the master DSI device. * panel list. The panel's device is the master DSI device.
*/ */
ret = msm_dsi_host_register(sdsi->host, false); ret = msm_dsi_host_register(slave_link_dsi->host, false);
if (ret) if (ret)
return ret; return ret;
ret = msm_dsi_host_register(mdsi->host, true); ret = msm_dsi_host_register(master_link_dsi->host, true);
if (ret) if (ret)
return ret; return ret;
/* PLL0 is to drive both 2 DSI link clocks in Dual DSI mode. */ /* PLL0 is to drive both 2 DSI link clocks in Dual DSI mode. */
msm_dsi_phy_set_usecase(clk_master_dsi->phy,
MSM_DSI_PHY_MASTER);
msm_dsi_phy_set_usecase(clk_slave_dsi->phy,
MSM_DSI_PHY_SLAVE);
src_pll = msm_dsi_phy_get_pll(clk_master_dsi->phy); src_pll = msm_dsi_phy_get_pll(clk_master_dsi->phy);
ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
if (ret) if (ret)
...@@ -665,28 +671,12 @@ int msm_dsi_manager_phy_enable(int id, ...@@ -665,28 +671,12 @@ int msm_dsi_manager_phy_enable(int id,
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi_phy *phy = msm_dsi->phy; struct msm_dsi_phy *phy = msm_dsi->phy;
int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id; int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);
int ret; int ret;
ret = msm_dsi_phy_enable(phy, src_pll_id, bit_rate, esc_rate); ret = msm_dsi_phy_enable(phy, src_pll_id, bit_rate, esc_rate);
if (ret) if (ret)
return ret; return ret;
/*
* Reset DSI PHY silently changes its PLL registers to reset status,
* which will confuse clock driver and result in wrong output rate of
* link clocks. Restore PLL status if its PLL is being used as clock
* source.
*/
if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER)) {
ret = msm_dsi_pll_restore_state(pll);
if (ret) {
pr_err("%s: failed to restore pll state\n", __func__);
msm_dsi_phy_disable(phy);
return ret;
}
}
msm_dsi->phy_enabled = true; msm_dsi->phy_enabled = true;
msm_dsi_phy_get_shared_timings(phy, shared_timings); msm_dsi_phy_get_shared_timings(phy, shared_timings);
...@@ -699,11 +689,6 @@ void msm_dsi_manager_phy_disable(int id) ...@@ -699,11 +689,6 @@ void msm_dsi_manager_phy_disable(int id)
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER); struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE); struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
struct msm_dsi_phy *phy = msm_dsi->phy; struct msm_dsi_phy *phy = msm_dsi->phy;
struct msm_dsi_pll *pll = msm_dsi_phy_get_pll(msm_dsi->phy);
/* Save PLL status if it is a clock source */
if (!IS_DUAL_DSI() || (id == DSI_CLOCK_MASTER))
msm_dsi_pll_save_state(pll);
/* disable DSI phy /* disable DSI phy
* In dual-dsi configuration, the phy should be disabled for the * In dual-dsi configuration, the phy should be disabled for the
...@@ -834,7 +819,7 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi) ...@@ -834,7 +819,7 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
goto fail; goto fail;
} }
ret = dsi_mgr_host_register(id); ret = dsi_mgr_setup_components(id);
if (ret) { if (ret) {
pr_err("%s: failed to register mipi dsi host for DSI %d\n", pr_err("%s: failed to register mipi dsi host for DSI %d\n",
__func__, id); __func__, id);
......
...@@ -451,7 +451,24 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, ...@@ -451,7 +451,24 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
return ret; return ret;
} }
return 0; /*
* Resetting DSI PHY silently changes its PLL registers to reset status,
* which will confuse clock driver and result in wrong output rate of
* link clocks. Restore PLL status if its PLL is being used as clock
* source.
*/
if (phy->usecase != MSM_DSI_PHY_SLAVE) {
ret = msm_dsi_pll_restore_state(phy->pll);
if (ret) {
pr_err("%s: failed to restore pll state\n", __func__);
if (phy->cfg->ops.disable)
phy->cfg->ops.disable(phy);
dsi_phy_regulator_disable(phy);
return ret;
}
}
return ret;
} }
void msm_dsi_phy_disable(struct msm_dsi_phy *phy) void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
...@@ -459,6 +476,10 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy) ...@@ -459,6 +476,10 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
if (!phy || !phy->cfg->ops.disable) if (!phy || !phy->cfg->ops.disable)
return; return;
/* Save PLL status if it is a clock source */
if (phy->usecase != MSM_DSI_PHY_SLAVE)
msm_dsi_pll_save_state(phy->pll);
phy->cfg->ops.disable(phy); phy->cfg->ops.disable(phy);
dsi_phy_regulator_disable(phy); dsi_phy_regulator_disable(phy);
...@@ -479,3 +500,9 @@ struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy) ...@@ -479,3 +500,9 @@ struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
return phy->pll; return phy->pll;
} }
void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy,
enum msm_dsi_phy_usecase uc)
{
if (phy)
phy->usecase = uc;
}
...@@ -78,6 +78,7 @@ struct msm_dsi_phy { ...@@ -78,6 +78,7 @@ struct msm_dsi_phy {
struct msm_dsi_dphy_timing timing; struct msm_dsi_dphy_timing timing;
const struct msm_dsi_phy_cfg *cfg; const struct msm_dsi_phy_cfg *cfg;
enum msm_dsi_phy_usecase usecase;
bool regulator_ldo_mode; bool regulator_ldo_mode;
struct msm_dsi_pll *pll; struct msm_dsi_pll *pll;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment