drm: msm: dsi-staging: add support for DSI clock manager
Add support for DSI clock manager driver. This includes
refactor of the DSI power module, ULPS, PHY clamping,
DSI controller/PHY re-initialisation, and adds support
for enable/disable of DSI clocks during static screen.
The DSI clock manager maintains three state of the DSI
clocks namely ON/OFF/ECG.
CRs-Fixed: 2008002
Change-Id: I15bcf8531be6596c4a9dc52690c4971de46f387d
Signed-off-by: Padmanabhan Komanduru <pkomandu@codeaurora.org>
Signed-off-by: Shashank Babu Chinta Venkata <sbchin@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 1ccbbe7..4249ac4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,7 +25,8 @@
#include "msm_gpu.h"
#include "dsi_phy.h"
#include "dsi_phy_hw.h"
-#include "dsi_clk_pwr.h"
+#include "dsi_clk.h"
+#include "dsi_pwr.h"
#include "dsi_catalog.h"
#define DSI_PHY_DEFAULT_LABEL "MDSS PHY CTRL"
@@ -104,65 +105,6 @@
return 0;
}
-static int dsi_phy_clocks_deinit(struct msm_dsi_phy *phy)
-{
- int rc = 0;
- struct dsi_core_clk_info *core = &phy->clks.core_clks;
-
- if (core->mdp_core_clk)
- devm_clk_put(&phy->pdev->dev, core->mdp_core_clk);
- if (core->iface_clk)
- devm_clk_put(&phy->pdev->dev, core->iface_clk);
- if (core->core_mmss_clk)
- devm_clk_put(&phy->pdev->dev, core->core_mmss_clk);
- if (core->bus_clk)
- devm_clk_put(&phy->pdev->dev, core->bus_clk);
-
- memset(core, 0x0, sizeof(*core));
-
- return rc;
-}
-
-static int dsi_phy_clocks_init(struct platform_device *pdev,
- struct msm_dsi_phy *phy)
-{
- int rc = 0;
- struct dsi_core_clk_info *core = &phy->clks.core_clks;
-
- core->mdp_core_clk = devm_clk_get(&pdev->dev, "mdp_core_clk");
- if (IS_ERR(core->mdp_core_clk)) {
- rc = PTR_ERR(core->mdp_core_clk);
- pr_err("failed to get mdp_core_clk, rc=%d\n", rc);
- goto fail;
- }
-
- core->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
- if (IS_ERR(core->iface_clk)) {
- rc = PTR_ERR(core->iface_clk);
- pr_err("failed to get iface_clk, rc=%d\n", rc);
- goto fail;
- }
-
- core->core_mmss_clk = devm_clk_get(&pdev->dev, "core_mmss_clk");
- if (IS_ERR(core->core_mmss_clk)) {
- rc = PTR_ERR(core->core_mmss_clk);
- pr_err("failed to get core_mmss_clk, rc=%d\n", rc);
- goto fail;
- }
-
- core->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
- if (IS_ERR(core->bus_clk)) {
- rc = PTR_ERR(core->bus_clk);
- pr_err("failed to get bus_clk, rc=%d\n", rc);
- goto fail;
- }
-
- return rc;
-fail:
- dsi_phy_clocks_deinit(phy);
- return rc;
-}
-
static int dsi_phy_supplies_init(struct platform_device *pdev,
struct msm_dsi_phy *phy)
{
@@ -182,7 +124,7 @@
ARRAY_SIZE(regs->vregs[i].vreg_name),
"%s", "gdsc");
- rc = dsi_clk_pwr_get_dt_vreg_data(&pdev->dev,
+ rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
&phy->pwr_info.phy_pwr,
"qcom,phy-supply-entries");
if (rc) {
@@ -404,16 +346,10 @@
goto fail;
}
- rc = dsi_phy_clocks_init(pdev, dsi_phy);
- if (rc) {
- pr_err("failed to parse clock information, rc = %d\n", rc);
- goto fail_regmap;
- }
-
rc = dsi_phy_supplies_init(pdev, dsi_phy);
if (rc) {
pr_err("failed to parse voltage supplies, rc = %d\n", rc);
- goto fail_clks;
+ goto fail_regmap;
}
rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version,
@@ -446,8 +382,6 @@
fail_supplies:
(void)dsi_phy_supplies_deinit(dsi_phy);
-fail_clks:
- (void)dsi_phy_clocks_deinit(dsi_phy);
fail_regmap:
(void)dsi_phy_regmap_deinit(dsi_phy);
fail:
@@ -489,10 +423,6 @@
if (rc)
pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
- rc = dsi_phy_clocks_deinit(phy);
- if (rc)
- pr_err("failed to deinitialize clocks, rc=%d\n", rc);
-
rc = dsi_phy_regmap_deinit(phy);
if (rc)
pr_err("failed to deinitialize regmap, rc=%d\n", rc);
@@ -622,6 +552,19 @@
return 0;
}
+int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy,
+ struct clk_ctrl_cb *clk_cb)
+{
+ if (!dsi_phy || !clk_cb) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ dsi_phy->clk_cb.priv = clk_cb->priv;
+ dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
+ return 0;
+}
+
/**
* dsi_phy_validate_mode() - validate a display mode
* @dsi_phy: DSI PHY handle.
@@ -679,22 +622,27 @@
pr_err("failed to enable digital regulator\n");
goto error;
}
- rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.phy_pwr, true);
- if (rc) {
- pr_err("failed to enable phy power\n");
- (void)dsi_pwr_enable_regulator(
- &dsi_phy->pwr_info.digital,
- false
- );
- goto error;
+
+ if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
+ rc = dsi_pwr_enable_regulator(
+ &dsi_phy->pwr_info.phy_pwr, true);
+ if (rc) {
+ pr_err("failed to enable phy power\n");
+ (void)dsi_pwr_enable_regulator(
+ &dsi_phy->pwr_info.digital, false);
+ goto error;
+ }
}
} else {
- rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.phy_pwr,
- false);
- if (rc) {
- pr_err("failed to enable digital regulator\n");
- goto error;
+ if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
+ rc = dsi_pwr_enable_regulator(
+ &dsi_phy->pwr_info.phy_pwr, false);
+ if (rc) {
+ pr_err("failed to enable digital regulator\n");
+ goto error;
+ }
}
+
rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital,
false);
if (rc) {
@@ -726,23 +674,28 @@
bool skip_validation)
{
int rc = 0;
+ struct dsi_clk_ctrl_info clk_info;
if (!phy || !config) {
pr_err("Invalid params\n");
return -EINVAL;
}
+ clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
+ clk_info.clk_type = DSI_CORE_CLK;
+ clk_info.clk_state = DSI_CLK_ON;
+
+ rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
+ if (rc) {
+ pr_err("failed to enable DSI core clocks\n");
+ return rc;
+ }
+
mutex_lock(&phy->phy_lock);
if (!skip_validation)
pr_debug("[PHY_%d] TODO: perform validation\n", phy->index);
- rc = dsi_clk_enable_core_clks(&phy->clks.core_clks, true);
- if (rc) {
- pr_err("failed to enable core clocks, rc=%d\n", rc);
- goto error;
- }
-
memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
phy->data_lanes = config->common_config.data_lanes;
phy->dst_format = config->common_config.dst_format;
@@ -755,19 +708,19 @@
&phy->cfg.timing);
if (rc) {
pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
- goto error_disable_clks;
+ goto error;
}
dsi_phy_enable_hw(phy);
+ phy->dsi_phy_state = DSI_PHY_ENGINE_ON;
-error_disable_clks:
- rc = dsi_clk_enable_core_clks(&phy->clks.core_clks, false);
- if (rc) {
- pr_err("failed to disable clocks, skip phy disable\n");
- goto error;
- }
error:
mutex_unlock(&phy->phy_lock);
+
+ clk_info.clk_state = DSI_CLK_OFF;
+ rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
+ if (rc)
+ pr_err("failed to disable DSI core clocks\n");
return rc;
}
@@ -780,31 +733,67 @@
int dsi_phy_disable(struct msm_dsi_phy *phy)
{
int rc = 0;
+ struct dsi_clk_ctrl_info clk_info;
if (!phy) {
pr_err("Invalid params\n");
return -EINVAL;
}
+ clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
+ clk_info.clk_type = DSI_CORE_CLK;
+ clk_info.clk_state = DSI_CLK_ON;
+
+ rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
+ if (rc) {
+ pr_err("failed to enable DSI core clocks\n");
+ return rc;
+ }
+
mutex_lock(&phy->phy_lock);
-
- rc = dsi_clk_enable_core_clks(&phy->clks.core_clks, true);
- if (rc) {
- pr_err("failed to enable core clocks, rc=%d\n", rc);
- goto error;
- }
-
dsi_phy_disable_hw(phy);
+ phy->dsi_phy_state = DSI_PHY_ENGINE_OFF;
+ mutex_unlock(&phy->phy_lock);
- rc = dsi_clk_enable_core_clks(&phy->clks.core_clks, false);
- if (rc) {
- pr_err("failed to disable core clocks, rc=%d\n", rc);
- goto error;
+ clk_info.clk_state = DSI_CLK_OFF;
+
+ rc = phy->clk_cb.dsi_clk_cb(phy->clk_cb.priv, clk_info);
+ if (rc)
+ pr_err("failed to disable DSI core clocks\n");
+
+ return rc;
+}
+
+/**
+ * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
+ * @phy: DSI PHY handle
+ * @enable: boolean to specify PHY enable/disable.
+ *
+ * Return: error code.
+ */
+
+int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable)
+{
+ if (!phy) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
}
-error:
+ mutex_lock(&phy->phy_lock);
+ if (enable) {
+ if (phy->hw.ops.phy_idle_on)
+ phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg);
+
+ if (phy->hw.ops.regulator_enable)
+ phy->hw.ops.regulator_enable(&phy->hw,
+ &phy->cfg.regulators);
+ } else {
+ if (phy->hw.ops.phy_idle_off)
+ phy->hw.ops.phy_idle_off(&phy->hw);
+ }
mutex_unlock(&phy->phy_lock);
- return rc;
+
+ return 0;
}
/**