drm/msm/dsi: Pass down use case to PHY
authorHai Li <hali@codeaurora.org>
Thu, 15 Sep 2016 09:14:22 +0000 (14:44 +0530)
committerRob Clark <robdclark@gmail.com>
Mon, 6 Feb 2017 16:28:45 +0000 (11:28 -0500)
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: Hai Li <hali@codeaurora.org>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/dsi/dsi.h
drivers/gpu/drm/msm/dsi/dsi_manager.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy.h

index f5e4ccf..d516fe2 100644 (file)
@@ -37,6 +37,12 @@ enum msm_dsi_phy_type {
        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_BUS_CLK_MAX                4
 
@@ -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,
                        struct msm_dsi_phy_shared_timings *shared_timing);
 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__ */
 
index 423afa6..c040830 100644 (file)
@@ -72,11 +72,12 @@ static int dsi_mgr_parse_dual_dsi(struct device_node *np, int id)
        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 *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_slave_dsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
        struct msm_dsi_pll *src_pll;
        int ret;
 
@@ -85,15 +86,16 @@ static int dsi_mgr_host_register(int id)
                if (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);
                ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
        } else if (!other_dsi) {
                ret = 0;
        } else {
-               struct msm_dsi *mdsi = IS_MASTER_DSI_LINK(id) ?
-                                       msm_dsi : other_dsi;
-               struct msm_dsi *sdsi = IS_MASTER_DSI_LINK(id) ?
-                                       other_dsi : msm_dsi;
+               struct msm_dsi *master_link_dsi = IS_MASTER_DSI_LINK(id) ?
+                                                       msm_dsi : other_dsi;
+               struct msm_dsi *slave_link_dsi = IS_MASTER_DSI_LINK(id) ?
+                                                       other_dsi : msm_dsi;
                /* Register slave host first, so that slave DSI device
                 * has a chance to probe, and do not block the master
                 * DSI device's probe.
@@ -101,14 +103,18 @@ static int dsi_mgr_host_register(int id)
                 * because only master DSI device adds the panel to global
                 * 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)
                        return ret;
-               ret = msm_dsi_host_register(mdsi->host, true);
+               ret = msm_dsi_host_register(master_link_dsi->host, true);
                if (ret)
                        return ret;
 
                /* 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);
                ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
                if (ret)
@@ -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_phy *phy = msm_dsi->phy;
        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;
 
        ret = msm_dsi_phy_enable(phy, src_pll_id, bit_rate, esc_rate);
        if (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_get_shared_timings(phy, shared_timings);
 
@@ -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 *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
        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
         * 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)
                goto fail;
        }
 
-       ret = dsi_mgr_host_register(id);
+       ret = dsi_mgr_setup_components(id);
        if (ret) {
                pr_err("%s: failed to register mipi dsi host for DSI %d\n",
                        __func__, id);
index 51f7c66..1021c1c 100644 (file)
@@ -451,7 +451,24 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
                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)
@@ -459,6 +476,10 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
        if (!phy || !phy->cfg->ops.disable)
                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);
 
        dsi_phy_regulator_disable(phy);
@@ -479,3 +500,9 @@ struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
        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;
+}
index 7399934..e105742 100644 (file)
@@ -78,6 +78,7 @@ struct msm_dsi_phy {
        struct msm_dsi_dphy_timing timing;
        const struct msm_dsi_phy_cfg *cfg;
 
+       enum msm_dsi_phy_usecase usecase;
        bool regulator_ldo_mode;
 
        struct msm_dsi_pll *pll;