From: Hai Li <hali@codeaurora.org>
To: dri-devel@lists.freedesktop.org
Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
robdclark@gmail.com, Hai Li <hali@codeaurora.org>
Subject: [PATCH 2/3] drm/msm/dsi: Enable PLL driver in MSM DSI
Date: Fri, 15 May 2015 13:04:05 -0400 [thread overview]
Message-ID: <1431709446-31429-3-git-send-email-hali@codeaurora.org> (raw)
In-Reply-To: <1431709446-31429-1-git-send-email-hali@codeaurora.org>
This change activates PLL driver for DSI to work with
common clock framework.
Signed-off-by: Hai Li <hali@codeaurora.org>
---
drivers/gpu/drm/msm/dsi/dsi.c | 14 +++++++
drivers/gpu/drm/msm/dsi/dsi.h | 43 ++++++++++++++++---
drivers/gpu/drm/msm/dsi/dsi_host.c | 60 ++++++++++++++++++++++----
drivers/gpu/drm/msm/dsi/dsi_manager.c | 79 +++++++++++++++++++++++++----------
drivers/gpu/drm/msm/dsi/dsi_phy.c | 68 ++++++++++++++++++++++++++++++
5 files changed, 229 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index ad50b80..beb26df 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -29,6 +29,12 @@ static void dsi_destroy(struct msm_dsi *msm_dsi)
return;
msm_dsi_manager_unregister(msm_dsi);
+
+ if (msm_dsi->phy) {
+ msm_dsi_phy_destroy(msm_dsi->phy);
+ msm_dsi->phy = NULL;
+ }
+
if (msm_dsi->host) {
msm_dsi_host_destroy(msm_dsi->host);
msm_dsi->host = NULL;
@@ -63,6 +69,14 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev)
if (ret)
goto fail;
+ /* Init dsi PHY */
+ msm_dsi->phy = msm_dsi_phy_init(pdev, msm_dsi->phy_type, msm_dsi->id);
+ if (!msm_dsi->phy) {
+ ret = -ENXIO;
+ pr_err("%s: phy init failed\n", __func__);
+ goto fail;
+ }
+
/* Register to dsi manager */
ret = msm_dsi_manager_register(msm_dsi);
if (ret)
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 321964a..8022814 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -38,6 +38,13 @@
#define DSI_ENCODER_MASTER DSI_1
#define DSI_ENCODER_SLAVE DSI_0
+enum msm_dsi_phy_type {
+ MSM_DSI_PHY_UNKNOWN,
+ MSM_DSI_PHY_28NM_HPM,
+ MSM_DSI_PHY_28NM_LP,
+ MSM_DSI_PHY_MAX
+};
+
struct msm_dsi {
struct drm_device *dev;
struct platform_device *pdev;
@@ -49,6 +56,8 @@ struct msm_dsi {
struct msm_dsi_phy *phy;
struct drm_panel *panel;
unsigned long panel_flags;
+
+ enum msm_dsi_phy_type phy_type;
bool phy_enabled;
/* the encoders we are hooked to (outside of dsi block) */
@@ -73,6 +82,29 @@ void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
/* msm dsi */
struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
+/* dsi pll */
+struct msm_dsi_pll;
+#ifdef CONFIG_DRM_MSM_DSI_PLL
+struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
+ enum msm_dsi_phy_type type, int dsi_id);
+void msm_dsi_pll_destroy(struct msm_dsi_pll *pll);
+int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
+ struct clk **byte_clk_provider, struct clk **pixel_clk_provider);
+#else
+static inline struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
+ enum msm_dsi_phy_type type, int id) {
+ return ERR_PTR(-ENODEV);
+}
+static inline void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
+{
+}
+static inline int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
+ struct clk **byte_clk_provider, struct clk **pixel_clk_provider)
+{
+ return -ENODEV;
+}
+#endif
+
/* dsi host */
int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg);
@@ -94,6 +126,8 @@ struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
unsigned long *panel_flags);
int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
void msm_dsi_host_unregister(struct mipi_dsi_host *host);
+int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
+ struct msm_dsi_pll *src_pll);
void msm_dsi_host_destroy(struct mipi_dsi_host *host);
int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
struct drm_device *dev);
@@ -101,18 +135,15 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi);
/* dsi phy */
struct msm_dsi_phy;
-enum msm_dsi_phy_type {
- MSM_DSI_PHY_UNKNOWN,
- MSM_DSI_PHY_28NM_HPM,
- MSM_DSI_PHY_28NM_LP,
- MSM_DSI_PHY_MAX
-};
struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
enum msm_dsi_phy_type type, int id);
+void msm_dsi_phy_destroy(struct msm_dsi_phy *phy);
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
const unsigned long bit_rate, const unsigned long esc_rate);
int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
u32 *clk_pre, u32 *clk_post);
+struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy);
+
#endif /* __DSI_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index f7ba890..1cf9f11 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -205,6 +205,9 @@ struct msm_dsi_host {
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
+ struct clk *byte_clk_src;
+ struct clk *pixel_clk_src;
+
u32 byte_clk_rate;
struct gpio_desc *disp_en_gpio;
@@ -463,6 +466,22 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host)
goto exit;
}
+ msm_host->byte_clk_src = devm_clk_get(dev, "byte_clk_src");
+ if (IS_ERR(msm_host->byte_clk_src)) {
+ ret = PTR_ERR(msm_host->byte_clk_src);
+ pr_err("%s: can't find byte_clk_src. ret=%d\n", __func__, ret);
+ msm_host->byte_clk_src = NULL;
+ goto exit;
+ }
+
+ msm_host->pixel_clk_src = devm_clk_get(dev, "pixel_clk_src");
+ if (IS_ERR(msm_host->pixel_clk_src)) {
+ ret = PTR_ERR(msm_host->pixel_clk_src);
+ pr_err("%s: can't find pixel_clk_src. ret=%d\n", __func__, ret);
+ msm_host->pixel_clk_src = NULL;
+ goto exit;
+ }
+
exit:
return ret;
}
@@ -1508,15 +1527,9 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
INIT_WORK(&msm_host->err_work, dsi_err_worker);
- msm_dsi->phy = msm_dsi_phy_init(pdev, msm_host->cfg->phy_type,
- msm_host->id);
- if (!msm_dsi->phy) {
- ret = -EINVAL;
- pr_err("%s: phy init failed\n", __func__);
- goto fail;
- }
msm_dsi->host = &msm_host->base;
msm_dsi->id = msm_host->id;
+ msm_dsi->phy_type = msm_host->cfg->phy_type;
DBG("Dsi Host %d initialized", msm_host->id);
return 0;
@@ -1824,6 +1837,39 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 iova, u32 len)
wmb();
}
+int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
+ struct msm_dsi_pll *src_pll)
+{
+ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+ struct clk *byte_clk_provider, *pixel_clk_provider;
+ int ret;
+
+ ret = msm_dsi_pll_get_clk_provider(src_pll,
+ &byte_clk_provider, &pixel_clk_provider);
+ if (ret) {
+ pr_info("%s: can't get provider from pll, don't set parent\n",
+ __func__);
+ return 0;
+ }
+
+ ret = clk_set_parent(msm_host->byte_clk_src, byte_clk_provider);
+ if (ret) {
+ pr_err("%s: can't set parent to byte_clk_src. ret=%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ ret = clk_set_parent(msm_host->pixel_clk_src, pixel_clk_provider);
+ if (ret) {
+ pr_err("%s: can't set parent to pixel_clk_src. ret=%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
int msm_dsi_host_enable(struct mipi_dsi_host *host)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 0a40f3c..87ac661 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -60,6 +60,53 @@ static int dsi_mgr_parse_dual_panel(struct device_node *np, int id)
return 0;
}
+static int dsi_mgr_host_register(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_pll *src_pll;
+ int ret;
+
+ if (!IS_DUAL_PANEL()) {
+ ret = msm_dsi_host_register(msm_dsi->host, true);
+ if (ret)
+ return ret;
+
+ 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_PANEL(id) ?
+ msm_dsi : other_dsi;
+ struct msm_dsi *sdsi = IS_MASTER_PANEL(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.
+ * Also, do not check defer for the slave host,
+ * 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);
+ if (ret)
+ return ret;
+ ret = msm_dsi_host_register(mdsi->host, true);
+ if (ret)
+ return ret;
+
+ /* PLL0 is to drive both 2 DSI link clocks in Dual DSI mode. */
+ 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)
+ return ret;
+ ret = msm_dsi_host_set_src_pll(other_dsi->host, src_pll);
+ }
+
+ return ret;
+}
+
struct dsi_connector {
struct drm_connector base;
int id;
@@ -652,7 +699,6 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
{
struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
int id = msm_dsi->id;
- struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
int ret;
if (id > DSI_MAX) {
@@ -670,31 +716,20 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
if (ret) {
pr_err("%s: failed to parse dual panel info\n", __func__);
- return ret;
+ goto fail;
}
- if (!IS_DUAL_PANEL()) {
- ret = msm_dsi_host_register(msm_dsi->host, true);
- } else if (!other_dsi) {
- return 0;
- } else {
- struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
- msm_dsi : other_dsi;
- struct msm_dsi *sdsi = IS_MASTER_PANEL(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.
- * Also, do not check defer for the slave host,
- * 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);
- if (ret)
- return ret;
- ret = msm_dsi_host_register(mdsi->host, true);
+ ret = dsi_mgr_host_register(id);
+ if (ret) {
+ pr_err("%s: failed to register mipi dsi host for DSI %d\n",
+ __func__, id);
+ goto fail;
}
+ return 0;
+
+fail:
+ msm_dsim->dsi[id] = NULL;
return ret;
}
diff --git a/drivers/gpu/drm/msm/dsi/dsi_phy.c b/drivers/gpu/drm/msm/dsi/dsi_phy.c
index fc11474..e313e52 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_phy.c
@@ -34,10 +34,18 @@ struct dsi_dphy_timing {
};
struct msm_dsi_phy {
+ struct platform_device *pdev;
void __iomem *base;
void __iomem *reg_base;
int id;
+
+ struct clk *ahb_clk;
+
struct dsi_dphy_timing timing;
+ enum msm_dsi_phy_type type;
+
+ struct msm_dsi_pll *pll;
+
int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel,
const unsigned long bit_rate, const unsigned long esc_rate);
int (*disable)(struct msm_dsi_phy *phy);
@@ -284,6 +292,27 @@ static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
return 0;
}
+static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
+{
+ int ret;
+
+ pm_runtime_get_sync(&phy->pdev->dev);
+
+ ret = clk_prepare_enable(phy->ahb_clk);
+ if (ret) {
+ pr_err("%s: can't enable ahb clk, %d\n", __func__, ret);
+ pm_runtime_put_sync(&phy->pdev->dev);
+ }
+
+ return ret;
+}
+
+static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
+{
+ clk_disable_unprepare(phy->ahb_clk);
+ pm_runtime_put_sync(&phy->pdev->dev);
+}
+
#define dsi_phy_func_init(name) \
do { \
phy->enable = dsi_##name##_phy_enable; \
@@ -294,6 +323,7 @@ struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
enum msm_dsi_phy_type type, int id)
{
struct msm_dsi_phy *phy;
+ int ret;
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
if (!phy)
@@ -320,11 +350,41 @@ struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
return NULL;
}
+ phy->type = type;
phy->id = id;
+ phy->pdev = pdev;
+
+ phy->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+ if (IS_ERR(phy->ahb_clk)) {
+ pr_err("%s: Unable to get ahb clk\n", __func__);
+ return NULL;
+ }
+
+ /* PLL init will call into clk_register which requires
+ * register access, so we need to enable power and ahb clock.
+ */
+ ret = dsi_phy_enable_resource(phy);
+ if (ret)
+ return NULL;
+
+ phy->pll = msm_dsi_pll_init(pdev, type, id);
+ if (!phy->pll)
+ pr_info("%s: pll init failed, need separate pll clk driver\n",
+ __func__);
+
+ dsi_phy_disable_resource(phy);
return phy;
}
+void msm_dsi_phy_destroy(struct msm_dsi_phy *phy)
+{
+ if (phy->pll) {
+ msm_dsi_pll_destroy(phy->pll);
+ phy->pll = NULL;
+ }
+}
+
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
const unsigned long bit_rate, const unsigned long esc_rate)
{
@@ -351,3 +411,11 @@ void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
*clk_post = phy->timing.clk_post;
}
+struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
+{
+ if (!phy)
+ return NULL;
+
+ return phy->pll;
+}
+
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
next prev parent reply other threads:[~2015-05-15 17:04 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-15 17:04 [PATCH 0/3] drm/msm/dsi: Add DSI PLL driver under common clock framework Hai Li
2015-05-15 17:04 ` Hai Li
2015-05-15 17:04 ` [PATCH 1/3] drm/msm/dsi: Add DSI PLL clock driver support Hai Li
2015-05-15 17:04 ` Hai Li
2015-05-15 17:04 ` Hai Li [this message]
2015-05-15 17:04 ` [PATCH 3/3] drm/msm/dsi: Separate PHY to another platform device Hai Li
2015-05-15 17:04 ` Hai Li
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1431709446-31429-3-git-send-email-hali@codeaurora.org \
--to=hali@codeaurora.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=robdclark@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.