summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/dsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dsi')
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h60
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_cfg.c6
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c6
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c30
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.c161
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.h41
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c747
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c939
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c16
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c654
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c479
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c774
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.c184
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.h132
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c881
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c1096
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c643
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c526
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c913
19 files changed, 3636 insertions, 4652 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 78ef5d4ed922..7abfeab08165 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -23,18 +23,6 @@
struct msm_dsi_phy_shared_timings;
struct msm_dsi_phy_clk_request;
-enum msm_dsi_phy_type {
- MSM_DSI_PHY_28NM_HPM,
- MSM_DSI_PHY_28NM_LP,
- MSM_DSI_PHY_20NM,
- MSM_DSI_PHY_28NM_8960,
- MSM_DSI_PHY_14NM,
- MSM_DSI_PHY_10NM,
- MSM_DSI_PHY_7NM,
- MSM_DSI_PHY_7NM_V4_1,
- MSM_DSI_PHY_MAX
-};
-
enum msm_dsi_phy_usecase {
MSM_DSI_PHY_STANDALONE,
MSM_DSI_PHY_MASTER,
@@ -104,45 +92,6 @@ static inline bool msm_dsi_device_connected(struct 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);
-void msm_dsi_pll_save_state(struct msm_dsi_pll *pll);
-int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll);
-int msm_dsi_pll_set_usecase(struct msm_dsi_pll *pll,
- enum msm_dsi_phy_usecase uc);
-#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;
-}
-static inline void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
-{
-}
-static inline int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
-{
- return 0;
-}
-static inline int msm_dsi_pll_set_usecase(struct msm_dsi_pll *pll,
- enum msm_dsi_phy_usecase uc)
-{
- return -ENODEV;
-}
-#endif
-
/* dsi host */
struct msm_dsi_host;
int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
@@ -169,7 +118,7 @@ struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
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);
+ struct msm_dsi_phy *src_phy);
void msm_dsi_host_reset_phy(struct mipi_dsi_host *host);
void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host,
struct msm_dsi_phy_clk_request *clk_req,
@@ -213,14 +162,17 @@ struct msm_dsi_phy_clk_request {
void msm_dsi_phy_driver_register(void);
void msm_dsi_phy_driver_unregister(void);
-int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req);
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);
+int msm_dsi_phy_get_clk_provider(struct msm_dsi_phy *phy,
+ struct clk **byte_clk_provider, struct clk **pixel_clk_provider);
+void msm_dsi_phy_pll_save_state(struct msm_dsi_phy *phy);
+int msm_dsi_phy_pll_restore_state(struct msm_dsi_phy *phy);
#endif /* __DSI_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
index b2ff68a15791..f3f1c03c7db9 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
@@ -106,12 +106,8 @@ static const struct msm_dsi_config msm8994_dsi_cfg = {
.num_dsi = 2,
};
-/*
- * TODO: core_mmss_clk fails to enable for some reason, but things work fine
- * without it too. Figure out why it doesn't enable and uncomment below
- */
static const char * const dsi_8996_bus_clk_names[] = {
- "mdp_core", "iface", "bus", /* "core_mmss", */
+ "mdp_core", "iface", "bus", "core_mmss",
};
static const struct msm_dsi_config msm8996_dsi_cfg = {
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index ab281cba0f08..8a10e4343281 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -1826,8 +1826,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
if (!msm_host) {
- pr_err("%s: FAILED: cannot alloc dsi host\n",
- __func__);
ret = -ENOMEM;
goto fail;
}
@@ -2226,13 +2224,13 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 dma_base,
}
int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
- struct msm_dsi_pll *src_pll)
+ struct msm_dsi_phy *src_phy)
{
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,
+ ret = msm_dsi_phy_get_clk_provider(src_phy,
&byte_clk_provider, &pixel_clk_provider);
if (ret) {
pr_info("%s: can't get provider from pll, don't set parent\n",
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 1d28dfba2c9b..cd016576e8c5 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -70,7 +70,6 @@ static int dsi_mgr_setup_components(int 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;
if (!IS_DUAL_DSI()) {
@@ -79,10 +78,7 @@ static int dsi_mgr_setup_components(int id)
return ret;
msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
- src_pll = msm_dsi_phy_get_pll(msm_dsi->phy);
- if (IS_ERR(src_pll))
- return PTR_ERR(src_pll);
- ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
+ ret = msm_dsi_host_set_src_pll(msm_dsi->host, msm_dsi->phy);
} else if (!other_dsi) {
ret = 0;
} else {
@@ -109,19 +105,16 @@ static int dsi_mgr_setup_components(int id)
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);
- if (IS_ERR(src_pll))
- return PTR_ERR(src_pll);
- ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll);
+ ret = msm_dsi_host_set_src_pll(msm_dsi->host, clk_master_dsi->phy);
if (ret)
return ret;
- ret = msm_dsi_host_set_src_pll(other_dsi->host, src_pll);
+ ret = msm_dsi_host_set_src_pll(other_dsi->host, clk_master_dsi->phy);
}
return ret;
}
-static int enable_phy(struct msm_dsi *msm_dsi, int src_pll_id,
+static int enable_phy(struct msm_dsi *msm_dsi,
struct msm_dsi_phy_shared_timings *shared_timings)
{
struct msm_dsi_phy_clk_request clk_req;
@@ -130,7 +123,7 @@ static int enable_phy(struct msm_dsi *msm_dsi, int src_pll_id,
msm_dsi_host_get_phy_clk_req(msm_dsi->host, &clk_req, is_dual_dsi);
- ret = msm_dsi_phy_enable(msm_dsi->phy, src_pll_id, &clk_req);
+ ret = msm_dsi_phy_enable(msm_dsi->phy, &clk_req);
msm_dsi_phy_get_shared_timings(msm_dsi->phy, shared_timings);
return ret;
@@ -143,7 +136,6 @@ dsi_mgr_phy_enable(int id,
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
- int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
int ret;
/* In case of dual DSI, some registers in PHY1 have been programmed
@@ -156,11 +148,11 @@ dsi_mgr_phy_enable(int id,
msm_dsi_host_reset_phy(mdsi->host);
msm_dsi_host_reset_phy(sdsi->host);
- ret = enable_phy(mdsi, src_pll_id,
+ ret = enable_phy(mdsi,
&shared_timings[DSI_CLOCK_MASTER]);
if (ret)
return ret;
- ret = enable_phy(sdsi, src_pll_id,
+ ret = enable_phy(sdsi,
&shared_timings[DSI_CLOCK_SLAVE]);
if (ret) {
msm_dsi_phy_disable(mdsi->phy);
@@ -169,7 +161,7 @@ dsi_mgr_phy_enable(int id,
}
} else {
msm_dsi_host_reset_phy(msm_dsi->host);
- ret = enable_phy(msm_dsi, src_pll_id, &shared_timings[id]);
+ ret = enable_phy(msm_dsi, &shared_timings[id]);
if (ret)
return ret;
}
@@ -505,7 +497,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
struct mipi_dsi_host *host = msm_dsi->host;
struct drm_panel *panel = msm_dsi->panel;
- struct msm_dsi_pll *src_pll;
bool is_dual_dsi = IS_DUAL_DSI();
int ret;
@@ -539,9 +530,8 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
id, ret);
}
- /* Save PLL status if it is a clock source */
- src_pll = msm_dsi_phy_get_pll(msm_dsi->phy);
- msm_dsi_pll_save_state(src_pll);
+ /* Save PHY status if it is a clock source */
+ msm_dsi_phy_pll_save_state(msm_dsi->phy);
ret = msm_dsi_host_power_off(host);
if (ret)
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index e8c1a727179c..f0a2ddf96a4b 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -3,6 +3,7 @@
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*/
+#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include "dsi_phy.h"
@@ -460,23 +461,6 @@ int msm_dsi_dphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing,
return 0;
}
-void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
- u32 bit_mask)
-{
- int phy_id = phy->id;
- u32 val;
-
- if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
- return;
-
- val = dsi_phy_read(phy->base + reg);
-
- if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
- dsi_phy_write(phy->base + reg, val | bit_mask);
- else
- dsi_phy_write(phy->base + reg, val & (~bit_mask));
-}
-
static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
{
struct regulator_bulk_data *s = phy->supplies;
@@ -637,24 +621,6 @@ static int dsi_phy_get_id(struct msm_dsi_phy *phy)
return -EINVAL;
}
-int msm_dsi_phy_init_common(struct msm_dsi_phy *phy)
-{
- struct platform_device *pdev = phy->pdev;
- int ret = 0;
-
- phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
- "DSI_PHY_REG");
- if (IS_ERR(phy->reg_base)) {
- DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy regulator base\n",
- __func__);
- ret = -ENOMEM;
- goto fail;
- }
-
-fail:
- return ret;
-}
-
static int dsi_phy_driver_probe(struct platform_device *pdev)
{
struct msm_dsi_phy *phy;
@@ -670,6 +636,14 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
if (!match)
return -ENODEV;
+ phy->provided_clocks = devm_kzalloc(dev,
+ struct_size(phy->provided_clocks, hws, NUM_PROVIDED_CLKS),
+ GFP_KERNEL);
+ if (!phy->provided_clocks)
+ return -ENOMEM;
+
+ phy->provided_clocks->num = NUM_PROVIDED_CLKS;
+
phy->cfg = match->data;
phy->pdev = pdev;
@@ -691,6 +665,31 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
goto fail;
}
+ phy->pll_base = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
+ if (IS_ERR(phy->pll_base)) {
+ DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (phy->cfg->has_phy_lane) {
+ phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane", "DSI_PHY_LANE");
+ if (IS_ERR(phy->lane_base)) {
+ DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (phy->cfg->has_phy_regulator) {
+ phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
+ if (IS_ERR(phy->reg_base)) {
+ DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy regulator base\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+ }
+
ret = dsi_phy_regulator_init(phy);
if (ret)
goto fail;
@@ -702,12 +701,6 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
goto fail;
}
- if (phy->cfg->ops.init) {
- ret = phy->cfg->ops.init(phy);
- if (ret)
- goto fail;
- }
-
/* PLL init will call into clk_register which requires
* register access, so we need to enable power and ahb clock.
*/
@@ -715,12 +708,21 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
if (ret)
goto fail;
- phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
- if (IS_ERR_OR_NULL(phy->pll)) {
- DRM_DEV_INFO(dev,
- "%s: pll init failed: %ld, need separate pll clk driver\n",
- __func__, PTR_ERR(phy->pll));
- phy->pll = NULL;
+ if (phy->cfg->ops.pll_init) {
+ ret = phy->cfg->ops.pll_init(phy);
+ if (ret) {
+ DRM_DEV_INFO(dev,
+ "%s: pll init failed: %d, need separate pll clk driver\n",
+ __func__, ret);
+ goto fail;
+ }
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ phy->provided_clocks);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);
+ goto fail;
}
dsi_phy_disable_resource(phy);
@@ -733,23 +735,8 @@ fail:
return ret;
}
-static int dsi_phy_driver_remove(struct platform_device *pdev)
-{
- struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
-
- if (phy && phy->pll) {
- msm_dsi_pll_destroy(phy->pll);
- phy->pll = NULL;
- }
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
static struct platform_driver dsi_phy_platform_driver = {
.probe = dsi_phy_driver_probe,
- .remove = dsi_phy_driver_remove,
.driver = {
.name = "msm_dsi_phy",
.of_match_table = dsi_phy_dt_match,
@@ -766,7 +753,7 @@ void __exit msm_dsi_phy_driver_unregister(void)
platform_driver_unregister(&dsi_phy_platform_driver);
}
-int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+int msm_dsi_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req)
{
struct device *dev = &phy->pdev->dev;
@@ -789,7 +776,7 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
goto reg_en_fail;
}
- ret = phy->cfg->ops.enable(phy, src_pll_id, clk_req);
+ ret = phy->cfg->ops.enable(phy, clk_req);
if (ret) {
DRM_DEV_ERROR(dev, "%s: phy enable failed, %d\n", __func__, ret);
goto phy_en_fail;
@@ -802,9 +789,9 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
* source.
*/
if (phy->usecase != MSM_DSI_PHY_SLAVE) {
- ret = msm_dsi_pll_restore_state(phy->pll);
+ ret = msm_dsi_phy_pll_restore_state(phy);
if (ret) {
- DRM_DEV_ERROR(dev, "%s: failed to restore pll state, %d\n",
+ DRM_DEV_ERROR(dev, "%s: failed to restore phy state, %d\n",
__func__, ret);
goto pll_restor_fail;
}
@@ -841,17 +828,43 @@ void msm_dsi_phy_get_shared_timings(struct msm_dsi_phy *phy,
sizeof(*shared_timings));
}
-struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
-{
- if (!phy)
- return NULL;
-
- 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;
}
+
+int msm_dsi_phy_get_clk_provider(struct msm_dsi_phy *phy,
+ struct clk **byte_clk_provider, struct clk **pixel_clk_provider)
+{
+ if (byte_clk_provider)
+ *byte_clk_provider = phy->provided_clocks->hws[DSI_BYTE_PLL_CLK]->clk;
+ if (pixel_clk_provider)
+ *pixel_clk_provider = phy->provided_clocks->hws[DSI_PIXEL_PLL_CLK]->clk;
+
+ return -EINVAL;
+}
+
+void msm_dsi_phy_pll_save_state(struct msm_dsi_phy *phy)
+{
+ if (phy->cfg->ops.save_pll_state) {
+ phy->cfg->ops.save_pll_state(phy);
+ phy->state_saved = true;
+ }
+}
+
+int msm_dsi_phy_pll_restore_state(struct msm_dsi_phy *phy)
+{
+ int ret;
+
+ if (phy->cfg->ops.restore_pll_state && phy->state_saved) {
+ ret = phy->cfg->ops.restore_pll_state(phy);
+ if (ret)
+ return ret;
+
+ phy->state_saved = false;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
index d2bd74b6f357..94a77ac364d3 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
@@ -6,37 +6,38 @@
#ifndef __DSI_PHY_H__
#define __DSI_PHY_H__
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include "dsi.h"
#define dsi_phy_read(offset) msm_readl((offset))
#define dsi_phy_write(offset, data) msm_writel((data), (offset))
-
-/* v3.0.0 10nm implementation that requires the old timings settings */
-#define V3_0_0_10NM_OLD_TIMINGS_QUIRK BIT(0)
+#define dsi_phy_write_udelay(offset, data, delay_us) { msm_writel((data), (offset)); udelay(delay_us); }
+#define dsi_phy_write_ndelay(offset, data, delay_ns) { msm_writel((data), (offset)); ndelay(delay_ns); }
struct msm_dsi_phy_ops {
- int (*init) (struct msm_dsi_phy *phy);
- int (*enable)(struct msm_dsi_phy *phy, int src_pll_id,
+ int (*pll_init)(struct msm_dsi_phy *phy);
+ int (*enable)(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req);
void (*disable)(struct msm_dsi_phy *phy);
+ void (*save_pll_state)(struct msm_dsi_phy *phy);
+ int (*restore_pll_state)(struct msm_dsi_phy *phy);
};
struct msm_dsi_phy_cfg {
- enum msm_dsi_phy_type type;
struct dsi_reg_config reg_cfg;
struct msm_dsi_phy_ops ops;
- /*
- * Each cell {phy_id, pll_id} of the truth table indicates
- * if the source PLL selection bit should be set for each PHY.
- * Fill default H/W values in illegal cells, eg. cell {0, 1}.
- */
- bool src_pll_truthtable[DSI_MAX][DSI_MAX];
+ unsigned long min_pll_rate;
+ unsigned long max_pll_rate;
+
const resource_size_t io_start[DSI_MAX];
const int num_dsi_phy;
const int quirks;
+ bool has_phy_regulator;
+ bool has_phy_lane;
};
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs;
@@ -74,9 +75,14 @@ struct msm_dsi_dphy_timing {
u8 hs_halfbyte_en_ckln;
};
+#define DSI_BYTE_PLL_CLK 0
+#define DSI_PIXEL_PLL_CLK 1
+#define NUM_PROVIDED_CLKS 2
+
struct msm_dsi_phy {
struct platform_device *pdev;
void __iomem *base;
+ void __iomem *pll_base;
void __iomem *reg_base;
void __iomem *lane_base;
int id;
@@ -90,7 +96,12 @@ struct msm_dsi_phy {
enum msm_dsi_phy_usecase usecase;
bool regulator_ldo_mode;
- struct msm_dsi_pll *pll;
+ struct clk_hw *vco_hw;
+ bool pll_on;
+
+ struct clk_hw_onecell_data *provided_clocks;
+
+ bool state_saved;
};
/*
@@ -104,9 +115,5 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
struct msm_dsi_phy_clk_request *clk_req);
int msm_dsi_dphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing,
struct msm_dsi_phy_clk_request *clk_req);
-void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
- u32 bit_mask);
-int msm_dsi_phy_init_common(struct msm_dsi_phy *phy);
#endif /* __DSI_PHY_H__ */
-
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
index d1b92d4dc197..34bc93548fcf 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
@@ -3,11 +3,715 @@
* Copyright (c) 2018, The Linux Foundation
*/
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/iopoll.h>
#include "dsi_phy.h"
#include "dsi.xml.h"
+/*
+ * DSI PLL 10nm - clock diagram (eg: DSI0):
+ *
+ * dsi0_pll_out_div_clk dsi0_pll_bit_clk
+ * | |
+ * | |
+ * +---------+ | +----------+ | +----+
+ * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0_phy_pll_out_byteclk
+ * +---------+ | +----------+ | +----+
+ * | |
+ * | | dsi0_pll_by_2_bit_clk
+ * | | |
+ * | | +----+ | |\ dsi0_pclk_mux
+ * | |--| /2 |--o--| \ |
+ * | | +----+ | \ | +---------+
+ * | --------------| |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk
+ * |------------------------------| / +---------+
+ * | +-----+ | /
+ * -----------| /4? |--o----------|/
+ * +-----+ | |
+ * | |dsiclk_sel
+ * |
+ * dsi0_pll_post_out_div_clk
+ */
+
+#define VCO_REF_CLK_RATE 19200000
+#define FRAC_BITS 18
+
+/* v3.0.0 10nm implementation that requires the old timings settings */
+#define DSI_PHY_10NM_QUIRK_OLD_TIMINGS BIT(0)
+
+struct dsi_pll_config {
+ bool enable_ssc;
+ bool ssc_center;
+ u32 ssc_freq;
+ u32 ssc_offset;
+ u32 ssc_adj_per;
+
+ /* out */
+ u32 pll_prop_gain_rate;
+ u32 decimal_div_start;
+ u32 frac_div_start;
+ u32 pll_clock_inverters;
+ u32 ssc_stepsize;
+ u32 ssc_div_per;
+};
+
+struct pll_10nm_cached_state {
+ unsigned long vco_rate;
+ u8 bit_clk_div;
+ u8 pix_clk_div;
+ u8 pll_out_div;
+ u8 pll_mux;
+};
+
+struct dsi_pll_10nm {
+ struct clk_hw clk_hw;
+
+ struct msm_dsi_phy *phy;
+
+ u64 vco_current_rate;
+
+ /* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */
+ spinlock_t postdiv_lock;
+
+ struct pll_10nm_cached_state cached_state;
+
+ struct dsi_pll_10nm *slave;
+};
+
+#define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, clk_hw)
+
+/*
+ * Global list of private DSI PLL struct pointers. We need this for Dual DSI
+ * mode, where the master PLL's clk_ops needs access the slave's private data
+ */
+static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX];
+
+static void dsi_pll_setup_config(struct dsi_pll_config *config)
+{
+ config->ssc_freq = 31500;
+ config->ssc_offset = 5000;
+ config->ssc_adj_per = 2;
+
+ config->enable_ssc = false;
+ config->ssc_center = false;
+}
+
+static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll, struct dsi_pll_config *config)
+{
+ u64 fref = VCO_REF_CLK_RATE;
+ u64 pll_freq;
+ u64 divider;
+ u64 dec, dec_multiple;
+ u32 frac;
+ u64 multiplier;
+
+ pll_freq = pll->vco_current_rate;
+
+ divider = fref * 2;
+
+ multiplier = 1 << FRAC_BITS;
+ dec_multiple = div_u64(pll_freq * multiplier, divider);
+ dec = div_u64_rem(dec_multiple, multiplier, &frac);
+
+ if (pll_freq <= 1900000000UL)
+ config->pll_prop_gain_rate = 8;
+ else if (pll_freq <= 3000000000UL)
+ config->pll_prop_gain_rate = 10;
+ else
+ config->pll_prop_gain_rate = 12;
+ if (pll_freq < 1100000000UL)
+ config->pll_clock_inverters = 8;
+ else
+ config->pll_clock_inverters = 0;
+
+ config->decimal_div_start = dec;
+ config->frac_div_start = frac;
+}
+
+#define SSC_CENTER BIT(0)
+#define SSC_EN BIT(1)
+
+static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll, struct dsi_pll_config *config)
+{
+ u32 ssc_per;
+ u32 ssc_mod;
+ u64 ssc_step_size;
+ u64 frac;
+
+ if (!config->enable_ssc) {
+ DBG("SSC not enabled\n");
+ return;
+ }
+
+ ssc_per = DIV_ROUND_CLOSEST(VCO_REF_CLK_RATE, config->ssc_freq) / 2 - 1;
+ ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
+ ssc_per -= ssc_mod;
+
+ frac = config->frac_div_start;
+ ssc_step_size = config->decimal_div_start;
+ ssc_step_size *= (1 << FRAC_BITS);
+ ssc_step_size += frac;
+ ssc_step_size *= config->ssc_offset;
+ ssc_step_size *= (config->ssc_adj_per + 1);
+ ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
+ ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
+
+ config->ssc_div_per = ssc_per;
+ config->ssc_stepsize = ssc_step_size;
+
+ pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n",
+ config->decimal_div_start, frac, FRAC_BITS);
+ pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n",
+ ssc_per, (u32)ssc_step_size, config->ssc_adj_per);
+}
+
+static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll, struct dsi_pll_config *config)
+{
+ void __iomem *base = pll->phy->pll_base;
+
+ if (config->enable_ssc) {
+ pr_debug("SSC is enabled\n");
+
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1,
+ config->ssc_stepsize & 0xff);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1,
+ config->ssc_stepsize >> 8);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1,
+ config->ssc_div_per & 0xff);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1,
+ config->ssc_div_per >> 8);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1,
+ config->ssc_adj_per & 0xff);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1,
+ config->ssc_adj_per >> 8);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL,
+ SSC_EN | (config->ssc_center ? SSC_CENTER : 0));
+ }
+}
+
+static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll)
+{
+ void __iomem *base = pll->phy->pll_base;
+
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE,
+ 0xba);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1,
+ 0x4c);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f);
+}
+
+static void dsi_pll_commit(struct dsi_pll_10nm *pll, struct dsi_pll_config *config)
+{
+ void __iomem *base = pll->phy->pll_base;
+
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1,
+ config->decimal_div_start);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1,
+ config->frac_div_start & 0xff);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1,
+ (config->frac_div_start & 0xff00) >> 8);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1,
+ (config->frac_div_start & 0x30000) >> 16);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 64);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10);
+ dsi_phy_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS,
+ config->pll_clock_inverters);
+}
+
+static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(hw);
+ struct dsi_pll_config config;
+
+ DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->phy->id, rate,
+ parent_rate);
+
+ pll_10nm->vco_current_rate = rate;
+
+ dsi_pll_setup_config(&config);
+
+ dsi_pll_calc_dec_frac(pll_10nm, &config);
+
+ dsi_pll_calc_ssc(pll_10nm, &config);
+
+ dsi_pll_commit(pll_10nm, &config);
+
+ dsi_pll_config_hzindep_reg(pll_10nm);
+
+ dsi_pll_ssc_commit(pll_10nm, &config);
+
+ /* flush, ensure all register writes are done*/
+ wmb();
+
+ return 0;
+}
+
+static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll)
+{
+ struct device *dev = &pll->phy->pdev->dev;
+ int rc;
+ u32 status = 0;
+ u32 const delay_us = 100;
+ u32 const timeout_us = 5000;
+
+ rc = readl_poll_timeout_atomic(pll->phy->pll_base +
+ REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE,
+ status,
+ ((status & BIT(0)) > 0),
+ delay_us,
+ timeout_us);
+ if (rc)
+ DRM_DEV_ERROR(dev, "DSI PLL(%d) lock failed, status=0x%08x\n",
+ pll->phy->id, status);
+
+ return rc;
+}
+
+static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll)
+{
+ u32 data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0);
+
+ dsi_phy_write(pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0);
+ dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0,
+ data & ~BIT(5));
+ ndelay(250);
+}
+
+static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll)
+{
+ u32 data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0);
+
+ dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CTRL_0,
+ data | BIT(5));
+ dsi_phy_write(pll->phy->pll_base + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0);
+ ndelay(250);
+}
+
+static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll)
+{
+ u32 data;
+
+ data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+ dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1,
+ data & ~BIT(5));
+}
+
+static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll)
+{
+ u32 data;
+
+ data = dsi_phy_read(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+ dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_CLK_CFG1,
+ data | BIT(5));
+}
+
+static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(hw);
+ struct device *dev = &pll_10nm->phy->pdev->dev;
+ int rc;
+
+ dsi_pll_enable_pll_bias(pll_10nm);
+ if (pll_10nm->slave)
+ dsi_pll_enable_pll_bias(pll_10nm->slave);
+
+ rc = dsi_pll_10nm_vco_set_rate(hw,pll_10nm->vco_current_rate, 0);
+ if (rc) {
+ DRM_DEV_ERROR(dev, "vco_set_rate failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Start PLL */
+ dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL,
+ 0x01);
+
+ /*
+ * ensure all PLL configurations are written prior to checking
+ * for PLL lock.
+ */
+ wmb();
+
+ /* Check for PLL lock */
+ rc = dsi_pll_10nm_lock_status(pll_10nm);
+ if (rc) {
+ DRM_DEV_ERROR(dev, "PLL(%d) lock failed\n", pll_10nm->phy->id);
+ goto error;
+ }
+
+ pll_10nm->phy->pll_on = true;
+
+ dsi_pll_enable_global_clk(pll_10nm);
+ if (pll_10nm->slave)
+ dsi_pll_enable_global_clk(pll_10nm->slave);
+
+ dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL,
+ 0x01);
+ if (pll_10nm->slave)
+ dsi_phy_write(pll_10nm->slave->phy->base +
+ REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01);
+
+error:
+ return rc;
+}
+
+static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll)
+{
+ dsi_phy_write(pll->phy->base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0);
+ dsi_pll_disable_pll_bias(pll);
+}
+
+static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(hw);
+
+ /*
+ * To avoid any stray glitches while abruptly powering down the PLL
+ * make sure to gate the clock using the clock enable bit before
+ * powering down the PLL
+ */
+ dsi_pll_disable_global_clk(pll_10nm);
+ dsi_phy_write(pll_10nm->phy->base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0);
+ dsi_pll_disable_sub(pll_10nm);
+ if (pll_10nm->slave) {
+ dsi_pll_disable_global_clk(pll_10nm->slave);
+ dsi_pll_disable_sub(pll_10nm->slave);
+ }
+ /* flush, ensure all register writes are done */
+ wmb();
+ pll_10nm->phy->pll_on = false;
+}
+
+static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(hw);
+ void __iomem *base = pll_10nm->phy->pll_base;
+ u64 ref_clk = VCO_REF_CLK_RATE;
+ u64 vco_rate = 0x0;
+ u64 multiplier;
+ u32 frac;
+ u32 dec;
+ u64 pll_freq, tmp64;
+
+ dec = dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1);
+ dec &= 0xff;
+
+ frac = dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1);
+ frac |= ((dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) &
+ 0xff) << 8);
+ frac |= ((dsi_phy_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) &
+ 0x3) << 16);
+
+ /*
+ * TODO:
+ * 1. Assumes prescaler is disabled
+ */
+ multiplier = 1 << FRAC_BITS;
+ pll_freq = dec * (ref_clk * 2);
+ tmp64 = (ref_clk * 2 * frac);
+ pll_freq += div_u64(tmp64, multiplier);
+
+ vco_rate = pll_freq;
+
+ DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
+ pll_10nm->phy->id, (unsigned long)vco_rate, dec, frac);
+
+ return (unsigned long)vco_rate;
+}
+
+static long dsi_pll_10nm_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *parent_rate)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(hw);
+
+ if (rate < pll_10nm->phy->cfg->min_pll_rate)
+ return pll_10nm->phy->cfg->min_pll_rate;
+ else if (rate > pll_10nm->phy->cfg->max_pll_rate)
+ return pll_10nm->phy->cfg->max_pll_rate;
+ else
+ return rate;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_10nm_vco = {
+ .round_rate = dsi_pll_10nm_clk_round_rate,
+ .set_rate = dsi_pll_10nm_vco_set_rate,
+ .recalc_rate = dsi_pll_10nm_vco_recalc_rate,
+ .prepare = dsi_pll_10nm_vco_prepare,
+ .unprepare = dsi_pll_10nm_vco_unprepare,
+};
+
+/*
+ * PLL Callbacks
+ */
+
+static void dsi_10nm_pll_save_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(phy->vco_hw);
+ struct pll_10nm_cached_state *cached = &pll_10nm->cached_state;
+ void __iomem *phy_base = pll_10nm->phy->base;
+ u32 cmn_clk_cfg0, cmn_clk_cfg1;
+
+ cached->pll_out_div = dsi_phy_read(pll_10nm->phy->pll_base +
+ REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE);
+ cached->pll_out_div &= 0x3;
+
+ cmn_clk_cfg0 = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0);
+ cached->bit_clk_div = cmn_clk_cfg0 & 0xf;
+ cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4;
+
+ cmn_clk_cfg1 = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+ cached->pll_mux = cmn_clk_cfg1 & 0x3;
+
+ DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x",
+ pll_10nm->phy->id, cached->pll_out_div, cached->bit_clk_div,
+ cached->pix_clk_div, cached->pll_mux);
+}
+
+static int dsi_10nm_pll_restore_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(phy->vco_hw);
+ struct pll_10nm_cached_state *cached = &pll_10nm->cached_state;
+ void __iomem *phy_base = pll_10nm->phy->base;
+ u32 val;
+ int ret;
+
+ val = dsi_phy_read(pll_10nm->phy->pll_base + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE);
+ val &= ~0x3;
+ val |= cached->pll_out_div;
+ dsi_phy_write(pll_10nm->phy->pll_base + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val);
+
+ dsi_phy_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0,
+ cached->bit_clk_div | (cached->pix_clk_div << 4));
+
+ val = dsi_phy_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
+ val &= ~0x3;
+ val |= cached->pll_mux;
+ dsi_phy_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val);
+
+ ret = dsi_pll_10nm_vco_set_rate(phy->vco_hw,
+ pll_10nm->vco_current_rate,
+ VCO_REF_CLK_RATE);
+ if (ret) {
+ DRM_DEV_ERROR(&pll_10nm->phy->pdev->dev,
+ "restore vco rate failed. ret=%d\n", ret);
+ return ret;
+ }
+
+ DBG("DSI PLL%d", pll_10nm->phy->id);
+
+ return 0;
+}
+
+static int dsi_10nm_set_usecase(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_10nm *pll_10nm = to_pll_10nm(phy->vco_hw);
+ void __iomem *base = phy->base;
+ u32 data = 0x0; /* internal PLL */
+
+ DBG("DSI PLL%d", pll_10nm->phy->id);
+
+ switch (phy->usecase) {
+ case MSM_DSI_PHY_STANDALONE:
+ break;
+ case MSM_DSI_PHY_MASTER:
+ pll_10nm->slave = pll_10nm_list[(pll_10nm->phy->id + 1) % DSI_MAX];
+ break;
+ case MSM_DSI_PHY_SLAVE:
+ data = 0x1; /* external PLL */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set PLL src */
+ dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2));
+
+ return 0;
+}
+
+/*
+ * The post dividers and mux clocks are created using the standard divider and
+ * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux
+ * state to follow the master PLL's divider/mux state. Therefore, we don't
+ * require special clock ops that also configure the slave PLL registers
+ */
+static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm, struct clk_hw **provided_clocks)
+{
+ char clk_name[32], parent[32], vco_name[32];
+ char parent2[32], parent3[32], parent4[32];
+ struct clk_init_data vco_init = {
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .name = vco_name,
+ .flags = CLK_IGNORE_UNUSED,
+ .ops = &clk_ops_dsi_pll_10nm_vco,
+ };
+ struct device *dev = &pll_10nm->phy->pdev->dev;
+ struct clk_hw *hw;
+ int ret;
+
+ DBG("DSI%d", pll_10nm->phy->id);
+
+ snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->phy->id);
+ pll_10nm->clk_hw.init = &vco_init;
+
+ ret = devm_clk_hw_register(dev, &pll_10nm->clk_hw);
+ if (ret)
+ return ret;
+
+ snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id);
+ snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->phy->id);
+
+ hw = devm_clk_hw_register_divider(dev, clk_name,
+ parent, CLK_SET_RATE_PARENT,
+ pll_10nm->phy->pll_base +
+ REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE,
+ 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id);
+
+ /* BIT CLK: DIV_CTRL_3_0 */
+ hw = devm_clk_hw_register_divider(dev, clk_name, parent,
+ CLK_SET_RATE_PARENT,
+ pll_10nm->phy->base +
+ REG_DSI_10nm_PHY_CMN_CLK_CFG0,
+ 0, 4, CLK_DIVIDER_ONE_BASED,
+ &pll_10nm->postdiv_lock);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id);
+
+ /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent,
+ CLK_SET_RATE_PARENT, 1, 8);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ provided_clocks[DSI_BYTE_PLL_CLK] = hw;
+
+ snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id);
+
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent,
+ 0, 1, 2);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id);
+
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent,
+ 0, 1, 4);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->phy->id);
+ snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->phy->id);
+ snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->phy->id);
+ snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->phy->id);
+
+ hw = devm_clk_hw_register_mux(dev, clk_name,
+ ((const char *[]){
+ parent, parent2, parent3, parent4
+ }), 4, 0, pll_10nm->phy->base +
+ REG_DSI_10nm_PHY_CMN_CLK_CFG1,
+ 0, 2, 0, NULL);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->phy->id);
+
+ /* PIX CLK DIV : DIV_CTRL_7_4*/
+ hw = devm_clk_hw_register_divider(dev, clk_name, parent,
+ 0, pll_10nm->phy->base +
+ REG_DSI_10nm_PHY_CMN_CLK_CFG0,
+ 4, 4, CLK_DIVIDER_ONE_BASED,
+ &pll_10nm->postdiv_lock);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ provided_clocks[DSI_PIXEL_PLL_CLK] = hw;
+
+ return 0;
+
+fail:
+
+ return ret;
+}
+
+static int dsi_pll_10nm_init(struct msm_dsi_phy *phy)
+{
+ struct platform_device *pdev = phy->pdev;
+ struct dsi_pll_10nm *pll_10nm;
+ int ret;
+
+ pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL);
+ if (!pll_10nm)
+ return -ENOMEM;
+
+ DBG("DSI PLL%d", phy->id);
+
+ pll_10nm_list[phy->id] = pll_10nm;
+
+ spin_lock_init(&pll_10nm->postdiv_lock);
+
+ pll_10nm->phy = phy;
+
+ ret = pll_10nm_register(pll_10nm, phy->provided_clocks->hws);
+ if (ret) {
+ DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
+ return ret;
+ }
+
+ phy->vco_hw = &pll_10nm->clk_hw;
+
+ /* TODO: Remove this when we have proper display handover support */
+ msm_dsi_phy_pll_save_state(phy);
+
+ return 0;
+}
+
static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy)
{
void __iomem *base = phy->base;
@@ -42,7 +746,7 @@ static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy)
u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 };
void __iomem *lane_base = phy->lane_base;
- if (phy->cfg->quirks & V3_0_0_10NM_OLD_TIMINGS_QUIRK)
+ if (phy->cfg->quirks & DSI_PHY_10NM_QUIRK_OLD_TIMINGS)
tx_dctrl[3] = 0x02;
/* Strength ctrl settings */
@@ -77,14 +781,14 @@ static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy)
tx_dctrl[i]);
}
- if (!(phy->cfg->quirks & V3_0_0_10NM_OLD_TIMINGS_QUIRK)) {
+ if (!(phy->cfg->quirks & DSI_PHY_10NM_QUIRK_OLD_TIMINGS)) {
/* Toggle BIT 0 to release freeze I/0 */
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05);
dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04);
}
}
-static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req)
{
int ret;
@@ -175,7 +879,7 @@ static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
/* Select full-rate mode */
dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_2, 0x40);
- ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase);
+ ret = dsi_10nm_set_usecase(phy);
if (ret) {
DRM_DEV_ERROR(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
__func__, ret);
@@ -216,24 +920,8 @@ static void dsi_10nm_phy_disable(struct msm_dsi_phy *phy)
DBG("DSI%d PHY disabled", phy->id);
}
-static int dsi_10nm_phy_init(struct msm_dsi_phy *phy)
-{
- struct platform_device *pdev = phy->pdev;
-
- phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane",
- "DSI_PHY_LANE");
- if (IS_ERR(phy->lane_base)) {
- DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n",
- __func__);
- return -ENOMEM;
- }
-
- return 0;
-}
-
const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = {
- .type = MSM_DSI_PHY_10NM,
- .src_pll_truthtable = { {false, false}, {true, false} },
+ .has_phy_lane = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -243,15 +931,18 @@ const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs = {
.ops = {
.enable = dsi_10nm_phy_enable,
.disable = dsi_10nm_phy_disable,
- .init = dsi_10nm_phy_init,
+ .pll_init = dsi_pll_10nm_init,
+ .save_pll_state = dsi_10nm_pll_save_state,
+ .restore_pll_state = dsi_10nm_pll_restore_state,
},
+ .min_pll_rate = 1000000000UL,
+ .max_pll_rate = 3500000000UL,
.io_start = { 0xae94400, 0xae96400 },
.num_dsi_phy = 2,
};
const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs = {
- .type = MSM_DSI_PHY_10NM,
- .src_pll_truthtable = { {false, false}, {true, false} },
+ .has_phy_lane = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -261,9 +952,13 @@ const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs = {
.ops = {
.enable = dsi_10nm_phy_enable,
.disable = dsi_10nm_phy_disable,
- .init = dsi_10nm_phy_init,
+ .pll_init = dsi_pll_10nm_init,
+ .save_pll_state = dsi_10nm_pll_save_state,
+ .restore_pll_state = dsi_10nm_pll_restore_state,
},
+ .min_pll_rate = 1000000000UL,
+ .max_pll_rate = 3500000000UL,
.io_start = { 0xc994400, 0xc996400 },
.num_dsi_phy = 2,
- .quirks = V3_0_0_10NM_OLD_TIMINGS_QUIRK,
+ .quirks = DSI_PHY_10NM_QUIRK_OLD_TIMINGS,
};
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
index 519400501bcd..65d68eb9e3cb 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
@@ -3,6 +3,8 @@
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
*/
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include "dsi_phy.h"
@@ -10,6 +12,895 @@
#define PHY_14NM_CKLN_IDX 4
+/*
+ * DSI PLL 14nm - clock diagram (eg: DSI0):
+ *
+ * dsi0n1_postdiv_clk
+ * |
+ * |
+ * +----+ | +----+
+ * dsi0vco_clk ---| n1 |--o--| /8 |-- dsi0pllbyte
+ * +----+ | +----+
+ * | dsi0n1_postdivby2_clk
+ * | +----+ |
+ * o---| /2 |--o--|\
+ * | +----+ | \ +----+
+ * | | |--| n2 |-- dsi0pll
+ * o--------------| / +----+
+ * |/
+ */
+
+#define POLL_MAX_READS 15
+#define POLL_TIMEOUT_US 1000
+
+#define VCO_REF_CLK_RATE 19200000
+#define VCO_MIN_RATE 1300000000UL
+#define VCO_MAX_RATE 2600000000UL
+
+struct dsi_pll_config {
+ u64 vco_current_rate;
+
+ u32 ssc_en; /* SSC enable/disable */
+
+ /* fixed params */
+ u32 plllock_cnt;
+ u32 ssc_center;
+ u32 ssc_adj_period;
+ u32 ssc_spread;
+ u32 ssc_freq;
+
+ /* calculated */
+ u32 dec_start;
+ u32 div_frac_start;
+ u32 ssc_period;
+ u32 ssc_step_size;
+ u32 plllock_cmp;
+ u32 pll_vco_div_ref;
+ u32 pll_vco_count;
+ u32 pll_kvco_div_ref;
+ u32 pll_kvco_count;
+};
+
+struct pll_14nm_cached_state {
+ unsigned long vco_rate;
+ u8 n2postdiv;
+ u8 n1postdiv;
+};
+
+struct dsi_pll_14nm {
+ struct clk_hw clk_hw;
+
+ struct msm_dsi_phy *phy;
+
+ /* protects REG_DSI_14nm_PHY_CMN_CLK_CFG0 register */
+ spinlock_t postdiv_lock;
+
+ struct pll_14nm_cached_state cached_state;
+
+ struct dsi_pll_14nm *slave;
+};
+
+#define to_pll_14nm(x) container_of(x, struct dsi_pll_14nm, clk_hw)
+
+/*
+ * Private struct for N1/N2 post-divider clocks. These clocks are similar to
+ * the generic clk_divider class of clocks. The only difference is that it
+ * also sets the slave DSI PLL's post-dividers if in Dual DSI mode
+ */
+struct dsi_pll_14nm_postdiv {
+ struct clk_hw hw;
+
+ /* divider params */
+ u8 shift;
+ u8 width;
+ u8 flags; /* same flags as used by clk_divider struct */
+
+ struct dsi_pll_14nm *pll;
+};
+
+#define to_pll_14nm_postdiv(_hw) container_of(_hw, struct dsi_pll_14nm_postdiv, hw)
+
+/*
+ * Global list of private DSI PLL struct pointers. We need this for Dual DSI
+ * mode, where the master PLL's clk_ops needs access the slave's private data
+ */
+static struct dsi_pll_14nm *pll_14nm_list[DSI_MAX];
+
+static bool pll_14nm_poll_for_ready(struct dsi_pll_14nm *pll_14nm,
+ u32 nb_tries, u32 timeout_us)
+{
+ bool pll_locked = false;
+ void __iomem *base = pll_14nm->phy->pll_base;
+ u32 tries, val;
+
+ tries = nb_tries;
+ while (tries--) {
+ val = dsi_phy_read(base +
+ REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS);
+ pll_locked = !!(val & BIT(5));
+
+ if (pll_locked)
+ break;
+
+ udelay(timeout_us);
+ }
+
+ if (!pll_locked) {
+ tries = nb_tries;
+ while (tries--) {
+ val = dsi_phy_read(base +
+ REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS);
+ pll_locked = !!(val & BIT(0));
+
+ if (pll_locked)
+ break;
+
+ udelay(timeout_us);
+ }
+ }
+
+ DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
+
+ return pll_locked;
+}
+
+static void dsi_pll_14nm_config_init(struct dsi_pll_config *pconf)
+{
+ /* fixed input */
+ pconf->plllock_cnt = 1;
+
+ /*
+ * SSC is enabled by default. We might need DT props for configuring
+ * some SSC params like PPM and center/down spread etc.
+ */
+ pconf->ssc_en = 1;
+ pconf->ssc_center = 0; /* down spread by default */
+ pconf->ssc_spread = 5; /* PPM / 1000 */
+ pconf->ssc_freq = 31500; /* default recommended */
+ pconf->ssc_adj_period = 37;
+}
+
+#define CEIL(x, y) (((x) + ((y) - 1)) / (y))
+
+static void pll_14nm_ssc_calc(struct dsi_pll_14nm *pll, struct dsi_pll_config *pconf)
+{
+ u32 period, ssc_period;
+ u32 ref, rem;
+ u64 step_size;
+
+ DBG("vco=%lld ref=%d", pconf->vco_current_rate, VCO_REF_CLK_RATE);
+
+ ssc_period = pconf->ssc_freq / 500;
+ period = (u32)VCO_REF_CLK_RATE / 1000;
+ ssc_period = CEIL(period, ssc_period);
+ ssc_period -= 1;
+ pconf->ssc_period = ssc_period;
+
+ DBG("ssc freq=%d spread=%d period=%d", pconf->ssc_freq,
+ pconf->ssc_spread, pconf->ssc_period);
+
+ step_size = (u32)pconf->vco_current_rate;
+ ref = VCO_REF_CLK_RATE;
+ ref /= 1000;
+ step_size = div_u64(step_size, ref);
+ step_size <<= 20;
+ step_size = div_u64(step_size, 1000);
+ step_size *= pconf->ssc_spread;
+ step_size = div_u64(step_size, 1000);
+ step_size *= (pconf->ssc_adj_period + 1);
+
+ rem = 0;
+ step_size = div_u64_rem(step_size, ssc_period + 1, &rem);
+ if (rem)
+ step_size++;
+
+ DBG("step_size=%lld", step_size);
+
+ step_size &= 0x0ffff; /* take lower 16 bits */
+
+ pconf->ssc_step_size = step_size;
+}
+
+static void pll_14nm_dec_frac_calc(struct dsi_pll_14nm *pll, struct dsi_pll_config *pconf)
+{
+ u64 multiplier = BIT(20);
+ u64 dec_start_multiple, dec_start, pll_comp_val;
+ u32 duration, div_frac_start;
+ u64 vco_clk_rate = pconf->vco_current_rate;
+ u64 fref = VCO_REF_CLK_RATE;
+
+ DBG("vco_clk_rate=%lld ref_clk_rate=%lld", vco_clk_rate, fref);
+
+ dec_start_multiple = div_u64(vco_clk_rate * multiplier, fref);
+ div_u64_rem(dec_start_multiple, multiplier, &div_frac_start);
+
+ dec_start = div_u64(dec_start_multiple, multiplier);
+
+ pconf->dec_start = (u32)dec_start;
+ pconf->div_frac_start = div_frac_start;
+
+ if (pconf->plllock_cnt == 0)
+ duration = 1024;
+ else if (pconf->plllock_cnt == 1)
+ duration = 256;
+ else if (pconf->plllock_cnt == 2)
+ duration = 128;
+ else
+ duration = 32;
+
+ pll_comp_val = duration * dec_start_multiple;
+ pll_comp_val = div_u64(pll_comp_val, multiplier);
+ do_div(pll_comp_val, 10);
+
+ pconf->plllock_cmp = (u32)pll_comp_val;
+}
+
+static u32 pll_14nm_kvco_slop(u32 vrate)
+{
+ u32 slop = 0;
+
+ if (vrate > VCO_MIN_RATE && vrate <= 1800000000UL)
+ slop = 600;
+ else if (vrate > 1800000000UL && vrate < 2300000000UL)
+ slop = 400;
+ else if (vrate > 2300000000UL && vrate < VCO_MAX_RATE)
+ slop = 280;
+
+ return slop;
+}
+
+static void pll_14nm_calc_vco_count(struct dsi_pll_14nm *pll, struct dsi_pll_config *pconf)
+{
+ u64 vco_clk_rate = pconf->vco_current_rate;
+ u64 fref = VCO_REF_CLK_RATE;
+ u32 vco_measure_time = 5;
+ u32 kvco_measure_time = 5;
+ u64 data;
+ u32 cnt;
+
+ data = fref * vco_measure_time;
+ do_div(data, 1000000);
+ data &= 0x03ff; /* 10 bits */
+ data -= 2;
+ pconf->pll_vco_div_ref = data;
+
+ data = div_u64(vco_clk_rate, 1000000); /* unit is Mhz */
+ data *= vco_measure_time;
+ do_div(data, 10);
+ pconf->pll_vco_count = data;
+
+ data = fref * kvco_measure_time;
+ do_div(data, 1000000);
+ data &= 0x03ff; /* 10 bits */
+ data -= 1;
+ pconf->pll_kvco_div_ref = data;
+
+ cnt = pll_14nm_kvco_slop(vco_clk_rate);
+ cnt *= 2;
+ cnt /= 100;
+ cnt *= kvco_measure_time;
+ pconf->pll_kvco_count = cnt;
+}
+
+static void pll_db_commit_ssc(struct dsi_pll_14nm *pll, struct dsi_pll_config *pconf)
+{
+ void __iomem *base = pll->phy->pll_base;
+ u8 data;
+
+ data = pconf->ssc_adj_period;
+ data &= 0x0ff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER1, data);
+ data = (pconf->ssc_adj_period >> 8);
+ data &= 0x03;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER2, data);
+
+ data = pconf->ssc_period;
+ data &= 0x0ff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER1, data);
+ data = (pconf->ssc_period >> 8);
+ data &= 0x0ff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER2, data);
+
+ data = pconf->ssc_step_size;
+ data &= 0x0ff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE1, data);
+ data = (pconf->ssc_step_size >> 8);
+ data &= 0x0ff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE2, data);
+
+ data = (pconf->ssc_center & 0x01);
+ data <<= 1;
+ data |= 0x01; /* enable */
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SSC_EN_CENTER, data);
+
+ wmb(); /* make sure register committed */
+}
+
+static void pll_db_commit_common(struct dsi_pll_14nm *pll,
+ struct dsi_pll_config *pconf)
+{
+ void __iomem *base = pll->phy->pll_base;
+ u8 data;
+
+ /* confgiure the non frequency dependent pll registers */
+ data = 0;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_SYSCLK_EN_RESET, data);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_TXCLK_EN, 1);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL, 48);
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL2, 4 << 3); /* bandgap_timer */
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL5, 5); /* pll_wakeup_timer */
+
+ data = pconf->pll_vco_div_ref & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF1, data);
+ data = (pconf->pll_vco_div_ref >> 8) & 0x3;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF2, data);
+
+ data = pconf->pll_kvco_div_ref & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF1, data);
+ data = (pconf->pll_kvco_div_ref >> 8) & 0x3;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF2, data);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_MISC1, 16);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_IE_TRIM, 4);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_IP_TRIM, 4);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_CP_SET_CUR, 1 << 3 | 1);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPCSET, 0 << 3 | 0);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPMSET, 0 << 3 | 0);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICP_SET, 4 << 3 | 4);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF1, 1 << 4 | 11);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_IPTAT_TRIM, 7);
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_CRCTRL, 1 << 4 | 2);
+}
+
+static void pll_14nm_software_reset(struct dsi_pll_14nm *pll_14nm)
+{
+ void __iomem *cmn_base = pll_14nm->phy->base;
+
+ /* de assert pll start and apply pll sw reset */
+
+ /* stop pll */
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0);
+
+ /* pll sw reset */
+ dsi_phy_write_udelay(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0x20, 10);
+ wmb(); /* make sure register committed */
+
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0);
+ wmb(); /* make sure register committed */
+}
+
+static void pll_db_commit_14nm(struct dsi_pll_14nm *pll,
+ struct dsi_pll_config *pconf)
+{
+ void __iomem *base = pll->phy->pll_base;
+ void __iomem *cmn_base = pll->phy->base;
+ u8 data;
+
+ DBG("DSI%d PLL", pll->phy->id);
+
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_LDO_CNTRL, 0x3c);
+
+ pll_db_commit_common(pll, pconf);
+
+ pll_14nm_software_reset(pll);
+
+ /* Use the /2 path in Mux */
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG1, 1);
+
+ data = 0xff; /* data, clk, pll normal operation */
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_0, data);
+
+ /* configure the frequency dependent pll registers */
+ data = pconf->dec_start;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_DEC_START, data);
+
+ data = pconf->div_frac_start & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1, data);
+ data = (pconf->div_frac_start >> 8) & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2, data);
+ data = (pconf->div_frac_start >> 16) & 0xf;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3, data);
+
+ data = pconf->plllock_cmp & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP1, data);
+
+ data = (pconf->plllock_cmp >> 8) & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP2, data);
+
+ data = (pconf->plllock_cmp >> 16) & 0x3;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP3, data);
+
+ data = pconf->plllock_cnt << 1 | 0 << 3; /* plllock_rng */
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP_EN, data);
+
+ data = pconf->pll_vco_count & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT1, data);
+ data = (pconf->pll_vco_count >> 8) & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT2, data);
+
+ data = pconf->pll_kvco_count & 0xff;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT1, data);
+ data = (pconf->pll_kvco_count >> 8) & 0x3;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT2, data);
+
+ /*
+ * High nibble configures the post divider internal to the VCO. It's
+ * fixed to divide by 1 for now.
+ *
+ * 0: divided by 1
+ * 1: divided by 2
+ * 2: divided by 4
+ * 3: divided by 8
+ */
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF2_POSTDIV, 0 << 4 | 3);
+
+ if (pconf->ssc_en)
+ pll_db_commit_ssc(pll, pconf);
+
+ wmb(); /* make sure register committed */
+}
+
+/*
+ * VCO clock Callbacks
+ */
+static int dsi_pll_14nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(hw);
+ struct dsi_pll_config conf;
+
+ DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_14nm->phy->id, rate,
+ parent_rate);
+
+ dsi_pll_14nm_config_init(&conf);
+ conf.vco_current_rate = rate;
+
+ pll_14nm_dec_frac_calc(pll_14nm, &conf);
+
+ if (conf.ssc_en)
+ pll_14nm_ssc_calc(pll_14nm, &conf);
+
+ pll_14nm_calc_vco_count(pll_14nm, &conf);
+
+ /* commit the slave DSI PLL registers if we're master. Note that we
+ * don't lock the slave PLL. We just ensure that the PLL/PHY registers
+ * of the master and slave are identical
+ */
+ if (pll_14nm->phy->usecase == MSM_DSI_PHY_MASTER) {
+ struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave;
+
+ pll_db_commit_14nm(pll_14nm_slave, &conf);
+ }
+
+ pll_db_commit_14nm(pll_14nm, &conf);
+
+ return 0;
+}
+
+static unsigned long dsi_pll_14nm_vco_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(hw);
+ void __iomem *base = pll_14nm->phy->pll_base;
+ u64 vco_rate, multiplier = BIT(20);
+ u32 div_frac_start;
+ u32 dec_start;
+ u64 ref_clk = parent_rate;
+
+ dec_start = dsi_phy_read(base + REG_DSI_14nm_PHY_PLL_DEC_START);
+ dec_start &= 0x0ff;
+
+ DBG("dec_start = %x", dec_start);
+
+ div_frac_start = (dsi_phy_read(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3)
+ & 0xf) << 16;
+ div_frac_start |= (dsi_phy_read(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2)
+ & 0xff) << 8;
+ div_frac_start |= dsi_phy_read(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1)
+ & 0xff;
+
+ DBG("div_frac_start = %x", div_frac_start);
+
+ vco_rate = ref_clk * dec_start;
+
+ vco_rate += ((ref_clk * div_frac_start) / multiplier);
+
+ /*
+ * Recalculating the rate from dec_start and frac_start doesn't end up
+ * the rate we originally set. Convert the freq to KHz, round it up and
+ * convert it back to MHz.
+ */
+ vco_rate = DIV_ROUND_UP_ULL(vco_rate, 1000) * 1000;
+
+ DBG("returning vco rate = %lu", (unsigned long)vco_rate);
+
+ return (unsigned long)vco_rate;
+}
+
+static int dsi_pll_14nm_vco_prepare(struct clk_hw *hw)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(hw);
+ void __iomem *base = pll_14nm->phy->pll_base;
+ void __iomem *cmn_base = pll_14nm->phy->base;
+ bool locked;
+
+ DBG("");
+
+ if (unlikely(pll_14nm->phy->pll_on))
+ return 0;
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_VREF_CFG1, 0x10);
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 1);
+
+ locked = pll_14nm_poll_for_ready(pll_14nm, POLL_MAX_READS,
+ POLL_TIMEOUT_US);
+
+ if (unlikely(!locked)) {
+ DRM_DEV_ERROR(&pll_14nm->phy->pdev->dev, "DSI PLL lock failed\n");
+ return -EINVAL;
+ }
+
+ DBG("DSI PLL lock success");
+ pll_14nm->phy->pll_on = true;
+
+ return 0;
+}
+
+static void dsi_pll_14nm_vco_unprepare(struct clk_hw *hw)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(hw);
+ void __iomem *cmn_base = pll_14nm->phy->base;
+
+ DBG("");
+
+ if (unlikely(!pll_14nm->phy->pll_on))
+ return;
+
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0);
+
+ pll_14nm->phy->pll_on = false;
+}
+
+static long dsi_pll_14nm_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *parent_rate)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(hw);
+
+ if (rate < pll_14nm->phy->cfg->min_pll_rate)
+ return pll_14nm->phy->cfg->min_pll_rate;
+ else if (rate > pll_14nm->phy->cfg->max_pll_rate)
+ return pll_14nm->phy->cfg->max_pll_rate;
+ else
+ return rate;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_14nm_vco = {
+ .round_rate = dsi_pll_14nm_clk_round_rate,
+ .set_rate = dsi_pll_14nm_vco_set_rate,
+ .recalc_rate = dsi_pll_14nm_vco_recalc_rate,
+ .prepare = dsi_pll_14nm_vco_prepare,
+ .unprepare = dsi_pll_14nm_vco_unprepare,
+};
+
+/*
+ * N1 and N2 post-divider clock callbacks
+ */
+#define div_mask(width) ((1 << (width)) - 1)
+static unsigned long dsi_pll_14nm_postdiv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw);
+ struct dsi_pll_14nm *pll_14nm = postdiv->pll;
+ void __iomem *base = pll_14nm->phy->base;
+ u8 shift = postdiv->shift;
+ u8 width = postdiv->width;
+ u32 val;
+
+ DBG("DSI%d PLL parent rate=%lu", pll_14nm->phy->id, parent_rate);
+
+ val = dsi_phy_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0) >> shift;
+ val &= div_mask(width);
+
+ return divider_recalc_rate(hw, parent_rate, val, NULL,
+ postdiv->flags, width);
+}
+
+static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *prate)
+{
+ struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw);
+ struct dsi_pll_14nm *pll_14nm = postdiv->pll;
+
+ DBG("DSI%d PLL parent rate=%lu", pll_14nm->phy->id, rate);
+
+ return divider_round_rate(hw, rate, prate, NULL,
+ postdiv->width,
+ postdiv->flags);
+}
+
+static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw);
+ struct dsi_pll_14nm *pll_14nm = postdiv->pll;
+ void __iomem *base = pll_14nm->phy->base;
+ spinlock_t *lock = &pll_14nm->postdiv_lock;
+ u8 shift = postdiv->shift;
+ u8 width = postdiv->width;
+ unsigned int value;
+ unsigned long flags = 0;
+ u32 val;
+
+ DBG("DSI%d PLL parent rate=%lu parent rate %lu", pll_14nm->phy->id, rate,
+ parent_rate);
+
+ value = divider_get_val(rate, parent_rate, NULL, postdiv->width,
+ postdiv->flags);
+
+ spin_lock_irqsave(lock, flags);
+
+ val = dsi_phy_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0);
+ val &= ~(div_mask(width) << shift);
+
+ val |= value << shift;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val);
+
+ /* If we're master in dual DSI mode, then the slave PLL's post-dividers
+ * follow the master's post dividers
+ */
+ if (pll_14nm->phy->usecase == MSM_DSI_PHY_MASTER) {
+ struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave;
+ void __iomem *slave_base = pll_14nm_slave->phy->base;
+
+ dsi_phy_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val);
+ }
+
+ spin_unlock_irqrestore(lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_14nm_postdiv = {
+ .recalc_rate = dsi_pll_14nm_postdiv_recalc_rate,
+ .round_rate = dsi_pll_14nm_postdiv_round_rate,
+ .set_rate = dsi_pll_14nm_postdiv_set_rate,
+};
+
+/*
+ * PLL Callbacks
+ */
+
+static void dsi_14nm_pll_save_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(phy->vco_hw);
+ struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state;
+ void __iomem *cmn_base = pll_14nm->phy->base;
+ u32 data;
+
+ data = dsi_phy_read(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0);
+
+ cached_state->n1postdiv = data & 0xf;
+ cached_state->n2postdiv = (data >> 4) & 0xf;
+
+ DBG("DSI%d PLL save state %x %x", pll_14nm->phy->id,
+ cached_state->n1postdiv, cached_state->n2postdiv);
+
+ cached_state->vco_rate = clk_hw_get_rate(phy->vco_hw);
+}
+
+static int dsi_14nm_pll_restore_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(phy->vco_hw);
+ struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state;
+ void __iomem *cmn_base = pll_14nm->phy->base;
+ u32 data;
+ int ret;
+
+ ret = dsi_pll_14nm_vco_set_rate(phy->vco_hw,
+ cached_state->vco_rate, 0);
+ if (ret) {
+ DRM_DEV_ERROR(&pll_14nm->phy->pdev->dev,
+ "restore vco rate failed. ret=%d\n", ret);
+ return ret;
+ }
+
+ data = cached_state->n1postdiv | (cached_state->n2postdiv << 4);
+
+ DBG("DSI%d PLL restore state %x %x", pll_14nm->phy->id,
+ cached_state->n1postdiv, cached_state->n2postdiv);
+
+ dsi_phy_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data);
+
+ /* also restore post-dividers for slave DSI PLL */
+ if (phy->usecase == MSM_DSI_PHY_MASTER) {
+ struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave;
+ void __iomem *slave_base = pll_14nm_slave->phy->base;
+
+ dsi_phy_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data);
+ }
+
+ return 0;
+}
+
+static int dsi_14nm_set_usecase(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_14nm *pll_14nm = to_pll_14nm(phy->vco_hw);
+ void __iomem *base = phy->pll_base;
+ u32 clkbuflr_en, bandgap = 0;
+
+ switch (phy->usecase) {
+ case MSM_DSI_PHY_STANDALONE:
+ clkbuflr_en = 0x1;
+ break;
+ case MSM_DSI_PHY_MASTER:
+ clkbuflr_en = 0x3;
+ pll_14nm->slave = pll_14nm_list[(pll_14nm->phy->id + 1) % DSI_MAX];
+ break;
+ case MSM_DSI_PHY_SLAVE:
+ clkbuflr_en = 0x0;
+ bandgap = 0x3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_CLKBUFLR_EN, clkbuflr_en);
+ if (bandgap)
+ dsi_phy_write(base + REG_DSI_14nm_PHY_PLL_PLL_BANDGAP, bandgap);
+
+ return 0;
+}
+
+static struct clk_hw *pll_14nm_postdiv_register(struct dsi_pll_14nm *pll_14nm,
+ const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ u8 shift)
+{
+ struct dsi_pll_14nm_postdiv *pll_postdiv;
+ struct device *dev = &pll_14nm->phy->pdev->dev;
+ struct clk_init_data postdiv_init = {
+ .parent_names = (const char *[]) { parent_name },
+ .num_parents = 1,
+ .name = name,
+ .flags = flags,
+ .ops = &clk_ops_dsi_pll_14nm_postdiv,
+ };
+ int ret;
+
+ pll_postdiv = devm_kzalloc(dev, sizeof(*pll_postdiv), GFP_KERNEL);
+ if (!pll_postdiv)
+ return ERR_PTR(-ENOMEM);
+
+ pll_postdiv->pll = pll_14nm;
+ pll_postdiv->shift = shift;
+ /* both N1 and N2 postdividers are 4 bits wide */
+ pll_postdiv->width = 4;
+ /* range of each divider is from 1 to 15 */
+ pll_postdiv->flags = CLK_DIVIDER_ONE_BASED;
+ pll_postdiv->hw.init = &postdiv_init;
+
+ ret = devm_clk_hw_register(dev, &pll_postdiv->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &pll_postdiv->hw;
+}
+
+static int pll_14nm_register(struct dsi_pll_14nm *pll_14nm, struct clk_hw **provided_clocks)
+{
+ char clk_name[32], parent[32], vco_name[32];
+ struct clk_init_data vco_init = {
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .name = vco_name,
+ .flags = CLK_IGNORE_UNUSED,
+ .ops = &clk_ops_dsi_pll_14nm_vco,
+ };
+ struct device *dev = &pll_14nm->phy->pdev->dev;
+ struct clk_hw *hw;
+ int ret;
+
+ DBG("DSI%d", pll_14nm->phy->id);
+
+ snprintf(vco_name, 32, "dsi%dvco_clk", pll_14nm->phy->id);
+ pll_14nm->clk_hw.init = &vco_init;
+
+ ret = devm_clk_hw_register(dev, &pll_14nm->clk_hw);
+ if (ret)
+ return ret;
+
+ snprintf(clk_name, 32, "dsi%dn1_postdiv_clk", pll_14nm->phy->id);
+ snprintf(parent, 32, "dsi%dvco_clk", pll_14nm->phy->id);
+
+ /* N1 postdiv, bits 0-3 in REG_DSI_14nm_PHY_CMN_CLK_CFG0 */
+ hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent,
+ CLK_SET_RATE_PARENT, 0);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ snprintf(clk_name, 32, "dsi%dpllbyte", pll_14nm->phy->id);
+ snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->phy->id);
+
+ /* DSI Byte clock = VCO_CLK / N1 / 8 */
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent,
+ CLK_SET_RATE_PARENT, 1, 8);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ provided_clocks[DSI_BYTE_PLL_CLK] = hw;
+
+ snprintf(clk_name, 32, "dsi%dn1_postdivby2_clk", pll_14nm->phy->id);
+ snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->phy->id);
+
+ /*
+ * Skip the mux for now, force DSICLK_SEL to 1, Add a /2 divider
+ * on the way. Don't let it set parent.
+ */
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 2);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ snprintf(clk_name, 32, "dsi%dpll", pll_14nm->phy->id);
+ snprintf(parent, 32, "dsi%dn1_postdivby2_clk", pll_14nm->phy->id);
+
+ /* DSI pixel clock = VCO_CLK / N1 / 2 / N2
+ * This is the output of N2 post-divider, bits 4-7 in
+ * REG_DSI_14nm_PHY_CMN_CLK_CFG0. Don't let it set parent.
+ */
+ hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, 0, 4);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ provided_clocks[DSI_PIXEL_PLL_CLK] = hw;
+
+ return 0;
+}
+
+static int dsi_pll_14nm_init(struct msm_dsi_phy *phy)
+{
+ struct platform_device *pdev = phy->pdev;
+ struct dsi_pll_14nm *pll_14nm;
+ int ret;
+
+ if (!pdev)
+ return -ENODEV;
+
+ pll_14nm = devm_kzalloc(&pdev->dev, sizeof(*pll_14nm), GFP_KERNEL);
+ if (!pll_14nm)
+ return -ENOMEM;
+
+ DBG("PLL%d", phy->id);
+
+ pll_14nm_list[phy->id] = pll_14nm;
+
+ spin_lock_init(&pll_14nm->postdiv_lock);
+
+ pll_14nm->phy = phy;
+
+ ret = pll_14nm_register(pll_14nm, phy->provided_clocks->hws);
+ if (ret) {
+ DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
+ return ret;
+ }
+
+ phy->vco_hw = &pll_14nm->clk_hw;
+
+ return 0;
+}
+
static void dsi_14nm_dphy_set_timing(struct msm_dsi_phy *phy,
struct msm_dsi_dphy_timing *timing,
int lane_idx)
@@ -47,7 +938,7 @@ static void dsi_14nm_dphy_set_timing(struct msm_dsi_phy *phy,
DSI_14nm_PHY_LN_TIMING_CTRL_11_TRIG3_CMD(0xa0));
}
-static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req)
{
struct msm_dsi_dphy_timing *timing = &phy->timing;
@@ -56,6 +947,7 @@ static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
int ret;
void __iomem *base = phy->base;
void __iomem *lane_base = phy->lane_base;
+ u32 glbl_test_ctrl;
if (msm_dsi_dphy_timing_calc_v2(timing, clk_req)) {
DRM_DEV_ERROR(&phy->pdev->dev,
@@ -103,11 +995,13 @@ static int dsi_14nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
udelay(100);
dsi_phy_write(base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0x00);
- msm_dsi_phy_set_src_pll(phy, src_pll_id,
- REG_DSI_14nm_PHY_CMN_GLBL_TEST_CTRL,
- DSI_14nm_PHY_CMN_GLBL_TEST_CTRL_BITCLK_HS_SEL);
-
- ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase);
+ glbl_test_ctrl = dsi_phy_read(base + REG_DSI_14nm_PHY_CMN_GLBL_TEST_CTRL);
+ if (phy->id == DSI_1 && phy->usecase == MSM_DSI_PHY_SLAVE)
+ glbl_test_ctrl |= DSI_14nm_PHY_CMN_GLBL_TEST_CTRL_BITCLK_HS_SEL;
+ else
+ glbl_test_ctrl &= ~DSI_14nm_PHY_CMN_GLBL_TEST_CTRL_BITCLK_HS_SEL;
+ dsi_phy_write(base + REG_DSI_14nm_PHY_CMN_GLBL_TEST_CTRL, glbl_test_ctrl);
+ ret = dsi_14nm_set_usecase(phy);
if (ret) {
DRM_DEV_ERROR(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
__func__, ret);
@@ -129,24 +1023,8 @@ static void dsi_14nm_phy_disable(struct msm_dsi_phy *phy)
wmb();
}
-static int dsi_14nm_phy_init(struct msm_dsi_phy *phy)
-{
- struct platform_device *pdev = phy->pdev;
-
- phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane",
- "DSI_PHY_LANE");
- if (IS_ERR(phy->lane_base)) {
- DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n",
- __func__);
- return -ENOMEM;
- }
-
- return 0;
-}
-
const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs = {
- .type = MSM_DSI_PHY_14NM,
- .src_pll_truthtable = { {false, false}, {true, false} },
+ .has_phy_lane = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -156,15 +1034,18 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_cfgs = {
.ops = {
.enable = dsi_14nm_phy_enable,
.disable = dsi_14nm_phy_disable,
- .init = dsi_14nm_phy_init,
+ .pll_init = dsi_pll_14nm_init,
+ .save_pll_state = dsi_14nm_pll_save_state,
+ .restore_pll_state = dsi_14nm_pll_restore_state,
},
+ .min_pll_rate = VCO_MIN_RATE,
+ .max_pll_rate = VCO_MAX_RATE,
.io_start = { 0x994400, 0x996400 },
.num_dsi_phy = 2,
};
const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs = {
- .type = MSM_DSI_PHY_14NM,
- .src_pll_truthtable = { {false, false}, {true, false} },
+ .has_phy_lane = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -174,8 +1055,12 @@ const struct msm_dsi_phy_cfg dsi_phy_14nm_660_cfgs = {
.ops = {
.enable = dsi_14nm_phy_enable,
.disable = dsi_14nm_phy_disable,
- .init = dsi_14nm_phy_init,
+ .pll_init = dsi_pll_14nm_init,
+ .save_pll_state = dsi_14nm_pll_save_state,
+ .restore_pll_state = dsi_14nm_pll_restore_state,
},
+ .min_pll_rate = VCO_MIN_RATE,
+ .max_pll_rate = VCO_MAX_RATE,
.io_start = { 0xc994400, 0xc996000 },
.num_dsi_phy = 2,
};
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c
index eca86bf448f7..e96d789aea18 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c
@@ -63,13 +63,14 @@ static void dsi_20nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_0, 0x03);
}
-static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req)
{
struct msm_dsi_dphy_timing *timing = &phy->timing;
int i;
void __iomem *base = phy->base;
u32 cfg_4[4] = {0x20, 0x40, 0x20, 0x00};
+ u32 val;
DBG("");
@@ -83,9 +84,12 @@ static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_0, 0xff);
- msm_dsi_phy_set_src_pll(phy, src_pll_id,
- REG_DSI_20nm_PHY_GLBL_TEST_CTRL,
- DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
+ val = dsi_phy_read(base + REG_DSI_20nm_PHY_GLBL_TEST_CTRL);
+ if (phy->id == DSI_1 && phy->usecase == MSM_DSI_PHY_STANDALONE)
+ val |= DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL;
+ else
+ val &= ~DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL;
+ dsi_phy_write(base + REG_DSI_20nm_PHY_GLBL_TEST_CTRL, val);
for (i = 0; i < 4; i++) {
dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_3(i),
@@ -125,8 +129,7 @@ static void dsi_20nm_phy_disable(struct msm_dsi_phy *phy)
}
const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs = {
- .type = MSM_DSI_PHY_20NM,
- .src_pll_truthtable = { {false, true}, {false, true} },
+ .has_phy_regulator = true,
.reg_cfg = {
.num = 2,
.regs = {
@@ -137,7 +140,6 @@ const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs = {
.ops = {
.enable = dsi_20nm_phy_enable,
.disable = dsi_20nm_phy_disable,
- .init = msm_dsi_phy_init_common,
},
.io_start = { 0xfd998500, 0xfd9a0500 },
.num_dsi_phy = 2,
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c
index c3c580cfd8b1..3304acda2165 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c
@@ -3,9 +3,621 @@
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*/
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
#include "dsi_phy.h"
#include "dsi.xml.h"
+/*
+ * DSI PLL 28nm - clock diagram (eg: DSI0):
+ *
+ * dsi0analog_postdiv_clk
+ * | dsi0indirect_path_div2_clk
+ * | |
+ * +------+ | +----+ | |\ dsi0byte_mux
+ * dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \ |
+ * | +------+ +----+ | m| | +----+
+ * | | u|--o--| /4 |-- dsi0pllbyte
+ * | | x| +----+
+ * o--------------------------| /
+ * | |/
+ * | +------+
+ * o----------| DIV3 |------------------------- dsi0pll
+ * +------+
+ */
+
+#define POLL_MAX_READS 10
+#define POLL_TIMEOUT_US 50
+
+#define VCO_REF_CLK_RATE 19200000
+#define VCO_MIN_RATE 350000000
+#define VCO_MAX_RATE 750000000
+
+/* v2.0.0 28nm LP implementation */
+#define DSI_PHY_28NM_QUIRK_PHY_LP BIT(0)
+
+#define LPFR_LUT_SIZE 10
+struct lpfr_cfg {
+ unsigned long vco_rate;
+ u32 resistance;
+};
+
+/* Loop filter resistance: */
+static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = {
+ { 479500000, 8 },
+ { 480000000, 11 },
+ { 575500000, 8 },
+ { 576000000, 12 },
+ { 610500000, 8 },
+ { 659500000, 9 },
+ { 671500000, 10 },
+ { 672000000, 14 },
+ { 708500000, 10 },
+ { 750000000, 11 },
+};
+
+struct pll_28nm_cached_state {
+ unsigned long vco_rate;
+ u8 postdiv3;
+ u8 postdiv1;
+ u8 byte_mux;
+};
+
+struct dsi_pll_28nm {
+ struct clk_hw clk_hw;
+
+ struct msm_dsi_phy *phy;
+
+ struct pll_28nm_cached_state cached_state;
+};
+
+#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, clk_hw)
+
+static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
+ u32 nb_tries, u32 timeout_us)
+{
+ bool pll_locked = false;
+ u32 val;
+
+ while (nb_tries--) {
+ val = dsi_phy_read(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_STATUS);
+ pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY);
+
+ if (pll_locked)
+ break;
+
+ udelay(timeout_us);
+ }
+ DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
+
+ return pll_locked;
+}
+
+static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm)
+{
+ void __iomem *base = pll_28nm->phy->pll_base;
+
+ /*
+ * Add HW recommended delays after toggling the software
+ * reset bit off and back on.
+ */
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG,
+ DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1);
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1);
+}
+
+/*
+ * Clock Callbacks
+ */
+static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+ struct device *dev = &pll_28nm->phy->pdev->dev;
+ void __iomem *base = pll_28nm->phy->pll_base;
+ unsigned long div_fbx1000, gen_vco_clk;
+ u32 refclk_cfg, frac_n_mode, frac_n_value;
+ u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
+ u32 cal_cfg10, cal_cfg11;
+ u32 rem;
+ int i;
+
+ VERB("rate=%lu, parent's=%lu", rate, parent_rate);
+
+ /* Force postdiv2 to be div-4 */
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3);
+
+ /* Configure the Loop filter resistance */
+ for (i = 0; i < LPFR_LUT_SIZE; i++)
+ if (rate <= lpfr_lut[i].vco_rate)
+ break;
+ if (i == LPFR_LUT_SIZE) {
+ DRM_DEV_ERROR(dev, "unable to get loop filter resistance. vco=%lu\n",
+ rate);
+ return -EINVAL;
+ }
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, lpfr_lut[i].resistance);
+
+ /* Loop filter capacitance values : c1 and c2 */
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15);
+
+ rem = rate % VCO_REF_CLK_RATE;
+ if (rem) {
+ refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
+ frac_n_mode = 1;
+ div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500);
+ gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500);
+ } else {
+ refclk_cfg = 0x0;
+ frac_n_mode = 0;
+ div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000);
+ gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000);
+ }
+
+ DBG("refclk_cfg = %d", refclk_cfg);
+
+ rem = div_fbx1000 % 1000;
+ frac_n_value = (rem << 16) / 1000;
+
+ DBG("div_fb = %lu", div_fbx1000);
+ DBG("frac_n_value = %d", frac_n_value);
+
+ DBG("Generated VCO Clock: %lu", gen_vco_clk);
+ rem = 0;
+ sdm_cfg1 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1);
+ sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK;
+ if (frac_n_mode) {
+ sdm_cfg0 = 0x0;
+ sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0);
+ sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(
+ (u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
+ sdm_cfg3 = frac_n_value >> 8;
+ sdm_cfg2 = frac_n_value & 0xff;
+ } else {
+ sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP;
+ sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(
+ (u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
+ sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0);
+ sdm_cfg2 = 0;
+ sdm_cfg3 = 0;
+ }
+
+ DBG("sdm_cfg0=%d", sdm_cfg0);
+ DBG("sdm_cfg1=%d", sdm_cfg1);
+ DBG("sdm_cfg2=%d", sdm_cfg2);
+ DBG("sdm_cfg3=%d", sdm_cfg3);
+
+ cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000));
+ cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000);
+ DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11);
+
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3, 0x2b);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4, 0x06);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
+
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2,
+ DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2));
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3,
+ DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3));
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00);
+
+ /* Add hardware recommended delay for correct PLL configuration */
+ if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
+ udelay(1000);
+ else
+ udelay(1);
+
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0, sdm_cfg0);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0, 0x12);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6, 0x30);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7, 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8, 0x60);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9, 0x00);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10, cal_cfg10 & 0xff);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11, cal_cfg11 & 0xff);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG, 0x20);
+
+ return 0;
+}
+
+static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+
+ return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
+ POLL_TIMEOUT_US);
+}
+
+static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+ void __iomem *base = pll_28nm->phy->pll_base;
+ u32 sdm0, doubler, sdm_byp_div;
+ u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
+ u32 ref_clk = VCO_REF_CLK_RATE;
+ unsigned long vco_rate;
+
+ VERB("parent_rate=%lu", parent_rate);
+
+ /* Check to see if the ref clk doubler is enabled */
+ doubler = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) &
+ DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
+ ref_clk += (doubler * VCO_REF_CLK_RATE);
+
+ /* see if it is integer mode or sdm mode */
+ sdm0 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0);
+ if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) {
+ /* integer mode */
+ sdm_byp_div = FIELD(
+ dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0),
+ DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1;
+ vco_rate = ref_clk * sdm_byp_div;
+ } else {
+ /* sdm mode */
+ sdm_dc_off = FIELD(
+ dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1),
+ DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET);
+ DBG("sdm_dc_off = %d", sdm_dc_off);
+ sdm2 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2),
+ DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0);
+ sdm3 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3),
+ DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8);
+ sdm_freq_seed = (sdm3 << 8) | sdm2;
+ DBG("sdm_freq_seed = %d", sdm_freq_seed);
+
+ vco_rate = (ref_clk * (sdm_dc_off + 1)) +
+ mult_frac(ref_clk, sdm_freq_seed, BIT(16));
+ DBG("vco rate = %lu", vco_rate);
+ }
+
+ DBG("returning vco rate = %lu", vco_rate);
+
+ return vco_rate;
+}
+
+static int _dsi_pll_28nm_vco_prepare_hpm(struct dsi_pll_28nm *pll_28nm)
+{
+ struct device *dev = &pll_28nm->phy->pdev->dev;
+ void __iomem *base = pll_28nm->phy->pll_base;
+ u32 max_reads = 5, timeout_us = 100;
+ bool locked;
+ u32 val;
+ int i;
+
+ DBG("id=%d", pll_28nm->phy->id);
+
+ pll_28nm_software_reset(pll_28nm);
+
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommended by hardware.
+ */
+ val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
+
+ for (i = 0; i < 2; i++) {
+ /* DSI Uniphy lock detect setting */
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,
+ 0x0c, 100);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
+
+ /* poll for PLL ready status */
+ locked = pll_28nm_poll_for_ready(pll_28nm,
+ max_reads, timeout_us);
+ if (locked)
+ break;
+
+ pll_28nm_software_reset(pll_28nm);
+
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommended by hardware.
+ */
+ val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250);
+
+ val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
+ }
+
+ if (unlikely(!locked))
+ DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
+ else
+ DBG("DSI PLL Lock success");
+
+ return locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_28nm_vco_prepare_hpm(struct clk_hw *hw)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+ int i, ret;
+
+ if (unlikely(pll_28nm->phy->pll_on))
+ return 0;
+
+ for (i = 0; i < 3; i++) {
+ ret = _dsi_pll_28nm_vco_prepare_hpm(pll_28nm);
+ if (!ret) {
+ pll_28nm->phy->pll_on = true;
+ return 0;
+ }
+ }
+
+ return ret;
+}
+
+static int dsi_pll_28nm_vco_prepare_lp(struct clk_hw *hw)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+ struct device *dev = &pll_28nm->phy->pdev->dev;
+ void __iomem *base = pll_28nm->phy->pll_base;
+ bool locked;
+ u32 max_reads = 10, timeout_us = 50;
+ u32 val;
+
+ DBG("id=%d", pll_28nm->phy->id);
+
+ if (unlikely(pll_28nm->phy->pll_on))
+ return 0;
+
+ pll_28nm_software_reset(pll_28nm);
+
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommended by hardware.
+ */
+ dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500);
+
+ val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
+ dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
+ dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
+
+ val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B |
+ DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
+ dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
+
+ /* DSI PLL toggle lock detect setting */
+ dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500);
+ dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512);
+
+ locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
+
+ if (unlikely(!locked)) {
+ DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
+ return -EINVAL;
+ }
+
+ DBG("DSI PLL lock success");
+ pll_28nm->phy->pll_on = true;
+
+ return 0;
+}
+
+static void dsi_pll_28nm_vco_unprepare(struct clk_hw *hw)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+
+ DBG("id=%d", pll_28nm->phy->id);
+
+ if (unlikely(!pll_28nm->phy->pll_on))
+ return;
+
+ dsi_phy_write(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00);
+
+ pll_28nm->phy->pll_on = false;
+}
+
+static long dsi_pll_28nm_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *parent_rate)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+
+ if (rate < pll_28nm->phy->cfg->min_pll_rate)
+ return pll_28nm->phy->cfg->min_pll_rate;
+ else if (rate > pll_28nm->phy->cfg->max_pll_rate)
+ return pll_28nm->phy->cfg->max_pll_rate;
+ else
+ return rate;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_28nm_vco_hpm = {
+ .round_rate = dsi_pll_28nm_clk_round_rate,
+ .set_rate = dsi_pll_28nm_clk_set_rate,
+ .recalc_rate = dsi_pll_28nm_clk_recalc_rate,
+ .prepare = dsi_pll_28nm_vco_prepare_hpm,
+ .unprepare = dsi_pll_28nm_vco_unprepare,
+ .is_enabled = dsi_pll_28nm_clk_is_enabled,
+};
+
+static const struct clk_ops clk_ops_dsi_pll_28nm_vco_lp = {
+ .round_rate = dsi_pll_28nm_clk_round_rate,
+ .set_rate = dsi_pll_28nm_clk_set_rate,
+ .recalc_rate = dsi_pll_28nm_clk_recalc_rate,
+ .prepare = dsi_pll_28nm_vco_prepare_lp,
+ .unprepare = dsi_pll_28nm_vco_unprepare,
+ .is_enabled = dsi_pll_28nm_clk_is_enabled,
+};
+
+/*
+ * PLL Callbacks
+ */
+
+static void dsi_28nm_pll_save_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
+ struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
+ void __iomem *base = pll_28nm->phy->pll_base;
+
+ cached_state->postdiv3 =
+ dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG);
+ cached_state->postdiv1 =
+ dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG);
+ cached_state->byte_mux = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_VREG_CFG);
+ if (dsi_pll_28nm_clk_is_enabled(phy->vco_hw))
+ cached_state->vco_rate = clk_hw_get_rate(phy->vco_hw);
+ else
+ cached_state->vco_rate = 0;
+}
+
+static int dsi_28nm_pll_restore_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
+ struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
+ void __iomem *base = pll_28nm->phy->pll_base;
+ int ret;
+
+ ret = dsi_pll_28nm_clk_set_rate(phy->vco_hw,
+ cached_state->vco_rate, 0);
+ if (ret) {
+ DRM_DEV_ERROR(&pll_28nm->phy->pdev->dev,
+ "restore vco rate failed. ret=%d\n", ret);
+ return ret;
+ }
+
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
+ cached_state->postdiv3);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
+ cached_state->postdiv1);
+ dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
+ cached_state->byte_mux);
+
+ return 0;
+}
+
+static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **provided_clocks)
+{
+ char clk_name[32], parent1[32], parent2[32], vco_name[32];
+ struct clk_init_data vco_init = {
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .name = vco_name,
+ .flags = CLK_IGNORE_UNUSED,
+ };
+ struct device *dev = &pll_28nm->phy->pdev->dev;
+ struct clk_hw *hw;
+ int ret;
+
+ DBG("%d", pll_28nm->phy->id);
+
+ if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
+ vco_init.ops = &clk_ops_dsi_pll_28nm_vco_lp;
+ else
+ vco_init.ops = &clk_ops_dsi_pll_28nm_vco_hpm;
+
+ snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->phy->id);
+ pll_28nm->clk_hw.init = &vco_init;
+ ret = devm_clk_hw_register(dev, &pll_28nm->clk_hw);
+ if (ret)
+ return ret;
+
+ snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->phy->id);
+ snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->phy->id);
+ hw = devm_clk_hw_register_divider(dev, clk_name,
+ parent1, CLK_SET_RATE_PARENT,
+ pll_28nm->phy->pll_base +
+ REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
+ 0, 4, 0, NULL);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->phy->id);
+ snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->phy->id);
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name,
+ parent1, CLK_SET_RATE_PARENT,
+ 1, 2);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ snprintf(clk_name, 32, "dsi%dpll", pll_28nm->phy->id);
+ snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->phy->id);
+ hw = devm_clk_hw_register_divider(dev, clk_name,
+ parent1, 0, pll_28nm->phy->pll_base +
+ REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
+ 0, 8, 0, NULL);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ provided_clocks[DSI_PIXEL_PLL_CLK] = hw;
+
+ snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->phy->id);
+ snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->phy->id);
+ snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->phy->id);
+ hw = devm_clk_hw_register_mux(dev, clk_name,
+ ((const char *[]){
+ parent1, parent2
+ }), 2, CLK_SET_RATE_PARENT, pll_28nm->phy->pll_base +
+ REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->phy->id);
+ snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->phy->id);
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name,
+ parent1, CLK_SET_RATE_PARENT, 1, 4);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ provided_clocks[DSI_BYTE_PLL_CLK] = hw;
+
+ return 0;
+}
+
+static int dsi_pll_28nm_init(struct msm_dsi_phy *phy)
+{
+ struct platform_device *pdev = phy->pdev;
+ struct dsi_pll_28nm *pll_28nm;
+ int ret;
+
+ if (!pdev)
+ return -ENODEV;
+
+ pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
+ if (!pll_28nm)
+ return -ENOMEM;
+
+ pll_28nm->phy = phy;
+
+ ret = pll_28nm_register(pll_28nm, phy->provided_clocks->hws);
+ if (ret) {
+ DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
+ return ret;
+ }
+
+ phy->vco_hw = &pll_28nm->clk_hw;
+
+ return 0;
+}
+
static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
struct msm_dsi_dphy_timing *timing)
{
@@ -66,7 +678,7 @@ static void dsi_28nm_phy_regulator_enable_ldo(struct msm_dsi_phy *phy)
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x1);
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
- if (phy->cfg->type == MSM_DSI_PHY_28NM_LP)
+ if (phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x05);
else
dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x0d);
@@ -86,12 +698,13 @@ static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
dsi_28nm_phy_regulator_enable_dcdc(phy);
}
-static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req)
{
struct msm_dsi_dphy_timing *timing = &phy->timing;
int i;
void __iomem *base = phy->base;
+ u32 val;
DBG("");
@@ -131,9 +744,12 @@ static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
- msm_dsi_phy_set_src_pll(phy, src_pll_id,
- REG_DSI_28nm_PHY_GLBL_TEST_CTRL,
- DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
+ val = dsi_phy_read(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL);
+ if (phy->id == DSI_1 && phy->usecase == MSM_DSI_PHY_SLAVE)
+ val &= ~DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL;
+ else
+ val |= DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL;
+ dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, val);
return 0;
}
@@ -151,8 +767,7 @@ static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
}
const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = {
- .type = MSM_DSI_PHY_28NM_HPM,
- .src_pll_truthtable = { {true, true}, {false, true} },
+ .has_phy_regulator = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -162,15 +777,18 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = {
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
- .init = msm_dsi_phy_init_common,
+ .pll_init = dsi_pll_28nm_init,
+ .save_pll_state = dsi_28nm_pll_save_state,
+ .restore_pll_state = dsi_28nm_pll_restore_state,
},
+ .min_pll_rate = VCO_MIN_RATE,
+ .max_pll_rate = VCO_MAX_RATE,
.io_start = { 0xfd922b00, 0xfd923100 },
.num_dsi_phy = 2,
};
const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = {
- .type = MSM_DSI_PHY_28NM_HPM,
- .src_pll_truthtable = { {true, true}, {false, true} },
+ .has_phy_regulator = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -180,15 +798,18 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = {
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
- .init = msm_dsi_phy_init_common,
+ .pll_init = dsi_pll_28nm_init,
+ .save_pll_state = dsi_28nm_pll_save_state,
+ .restore_pll_state = dsi_28nm_pll_restore_state,
},
+ .min_pll_rate = VCO_MIN_RATE,
+ .max_pll_rate = VCO_MAX_RATE,
.io_start = { 0x1a94400, 0x1a96400 },
.num_dsi_phy = 2,
};
const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = {
- .type = MSM_DSI_PHY_28NM_LP,
- .src_pll_truthtable = { {true, true}, {true, true} },
+ .has_phy_regulator = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -198,9 +819,14 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = {
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
- .init = msm_dsi_phy_init_common,
+ .pll_init = dsi_pll_28nm_init,
+ .save_pll_state = dsi_28nm_pll_save_state,
+ .restore_pll_state = dsi_28nm_pll_restore_state,
},
+ .min_pll_rate = VCO_MIN_RATE,
+ .max_pll_rate = VCO_MAX_RATE,
.io_start = { 0x1a98500 },
.num_dsi_phy = 1,
+ .quirks = DSI_PHY_28NM_QUIRK_PHY_LP,
};
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
index f22583353957..582b1428f971 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
@@ -3,11 +3,479 @@
* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
*/
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include "dsi_phy.h"
#include "dsi.xml.h"
+/*
+ * DSI PLL 28nm (8960/A family) - clock diagram (eg: DSI1):
+ *
+ *
+ * +------+
+ * dsi1vco_clk ----o-----| DIV1 |---dsi1pllbit (not exposed as clock)
+ * F * byte_clk | +------+
+ * | bit clock divider (F / 8)
+ * |
+ * | +------+
+ * o-----| DIV2 |---dsi0pllbyte---o---> To byte RCG
+ * | +------+ | (sets parent rate)
+ * | byte clock divider (F) |
+ * | |
+ * | o---> To esc RCG
+ * | (doesn't set parent rate)
+ * |
+ * | +------+
+ * o-----| DIV3 |----dsi0pll------o---> To dsi RCG
+ * +------+ | (sets parent rate)
+ * dsi clock divider (F * magic) |
+ * |
+ * o---> To pixel rcg
+ * (doesn't set parent rate)
+ */
+
+#define POLL_MAX_READS 8000
+#define POLL_TIMEOUT_US 1
+
+#define VCO_REF_CLK_RATE 27000000
+#define VCO_MIN_RATE 600000000
+#define VCO_MAX_RATE 1200000000
+
+#define VCO_PREF_DIV_RATIO 27
+
+struct pll_28nm_cached_state {
+ unsigned long vco_rate;
+ u8 postdiv3;
+ u8 postdiv2;
+ u8 postdiv1;
+};
+
+struct clk_bytediv {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+struct dsi_pll_28nm {
+ struct clk_hw clk_hw;
+
+ struct msm_dsi_phy *phy;
+
+ struct pll_28nm_cached_state cached_state;
+};
+
+#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, clk_hw)
+
+static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
+ int nb_tries, int timeout_us)
+{
+ bool pll_locked = false;
+ u32 val;
+
+ while (nb_tries--) {
+ val = dsi_phy_read(pll_28nm->phy->pll_base + REG_DSI_28nm_8960_PHY_PLL_RDY);
+ pll_locked = !!(val & DSI_28nm_8960_PHY_PLL_RDY_PLL_RDY);
+
+ if (pll_locked)
+ break;
+
+ udelay(timeout_us);
+ }
+ DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
+
+ return pll_locked;
+}
+
+/*
+ * Clock Callbacks
+ */
+static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+ void __iomem *base = pll_28nm->phy->pll_base;
+ u32 val, temp, fb_divider;
+
+ DBG("rate=%lu, parent's=%lu", rate, parent_rate);
+
+ temp = rate / 10;
+ val = VCO_REF_CLK_RATE / 10;
+ fb_divider = (temp * VCO_PREF_DIV_RATIO) / val;
+ fb_divider = fb_divider / 2 - 1;
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1,
+ fb_divider & 0xff);
+
+ val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2);
+
+ val |= (fb_divider >> 8) & 0x07;
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2,
+ val);
+
+ val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3);
+
+ val |= (VCO_PREF_DIV_RATIO - 1) & 0x3f;
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3,
+ val);
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_6,
+ 0xf);
+
+ val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
+ val |= 0x7 << 4;
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8,
+ val);
+
+ return 0;
+}
+
+static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+
+ return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
+ POLL_TIMEOUT_US);
+}
+
+static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+ void __iomem *base = pll_28nm->phy->pll_base;
+ unsigned long vco_rate;
+ u32 status, fb_divider, temp, ref_divider;
+
+ VERB("parent_rate=%lu", parent_rate);
+
+ status = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0);
+
+ if (status & DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE) {
+ fb_divider = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1);
+ fb_divider &= 0xff;
+ temp = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2) & 0x07;
+ fb_divider = (temp << 8) | fb_divider;
+ fb_divider += 1;
+
+ ref_divider = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3);
+ ref_divider &= 0x3f;
+ ref_divider += 1;
+
+ /* multiply by 2 */
+ vco_rate = (parent_rate / ref_divider) * fb_divider * 2;
+ } else {
+ vco_rate = 0;
+ }
+
+ DBG("returning vco rate = %lu", vco_rate);
+
+ return vco_rate;
+}
+
+static int dsi_pll_28nm_vco_prepare(struct clk_hw *hw)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+ struct device *dev = &pll_28nm->phy->pdev->dev;
+ void __iomem *base = pll_28nm->phy->pll_base;
+ bool locked;
+ unsigned int bit_div, byte_div;
+ int max_reads = 1000, timeout_us = 100;
+ u32 val;
+
+ DBG("id=%d", pll_28nm->phy->id);
+
+ if (unlikely(pll_28nm->phy->pll_on))
+ return 0;
+
+ /*
+ * before enabling the PLL, configure the bit clock divider since we
+ * don't expose it as a clock to the outside world
+ * 1: read back the byte clock divider that should already be set
+ * 2: divide by 8 to get bit clock divider
+ * 3: write it to POSTDIV1
+ */
+ val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9);
+ byte_div = val + 1;
+ bit_div = byte_div / 8;
+
+ val = dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
+ val &= ~0xf;
+ val |= (bit_div - 1);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, val);
+
+ /* enable the PLL */
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0,
+ DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE);
+
+ locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
+
+ if (unlikely(!locked)) {
+ DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
+ return -EINVAL;
+ }
+
+ DBG("DSI PLL lock success");
+ pll_28nm->phy->pll_on = true;
+
+ return 0;
+}
+
+static void dsi_pll_28nm_vco_unprepare(struct clk_hw *hw)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+
+ DBG("id=%d", pll_28nm->phy->id);
+
+ if (unlikely(!pll_28nm->phy->pll_on))
+ return;
+
+ dsi_phy_write(pll_28nm->phy->pll_base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, 0x00);
+
+ pll_28nm->phy->pll_on = false;
+}
+
+static long dsi_pll_28nm_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *parent_rate)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
+
+ if (rate < pll_28nm->phy->cfg->min_pll_rate)
+ return pll_28nm->phy->cfg->min_pll_rate;
+ else if (rate > pll_28nm->phy->cfg->max_pll_rate)
+ return pll_28nm->phy->cfg->max_pll_rate;
+ else
+ return rate;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_28nm_vco = {
+ .round_rate = dsi_pll_28nm_clk_round_rate,
+ .set_rate = dsi_pll_28nm_clk_set_rate,
+ .recalc_rate = dsi_pll_28nm_clk_recalc_rate,
+ .prepare = dsi_pll_28nm_vco_prepare,
+ .unprepare = dsi_pll_28nm_vco_unprepare,
+ .is_enabled = dsi_pll_28nm_clk_is_enabled,
+};
+
+/*
+ * Custom byte clock divier clk_ops
+ *
+ * This clock is the entry point to configuring the PLL. The user (dsi host)
+ * will set this clock's rate to the desired byte clock rate. The VCO lock
+ * frequency is a multiple of the byte clock rate. The multiplication factor
+ * (shown as F in the diagram above) is a function of the byte clock rate.
+ *
+ * This custom divider clock ensures that its parent (VCO) is set to the
+ * desired rate, and that the byte clock postdivider (POSTDIV2) is configured
+ * accordingly
+ */
+#define to_clk_bytediv(_hw) container_of(_hw, struct clk_bytediv, hw)
+
+static unsigned long clk_bytediv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_bytediv *bytediv = to_clk_bytediv(hw);
+ unsigned int div;
+
+ div = dsi_phy_read(bytediv->reg) & 0xff;
+
+ return parent_rate / (div + 1);
+}
+
+/* find multiplication factor(wrt byte clock) at which the VCO should be set */
+static unsigned int get_vco_mul_factor(unsigned long byte_clk_rate)
+{
+ unsigned long bit_mhz;
+
+ /* convert to bit clock in Mhz */
+ bit_mhz = (byte_clk_rate * 8) / 1000000;
+
+ if (bit_mhz < 125)
+ return 64;
+ else if (bit_mhz < 250)
+ return 32;
+ else if (bit_mhz < 600)
+ return 16;
+ else
+ return 8;
+}
+
+static long clk_bytediv_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long best_parent;
+ unsigned int factor;
+
+ factor = get_vco_mul_factor(rate);
+
+ best_parent = rate * factor;
+ *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
+
+ return *prate / factor;
+}
+
+static int clk_bytediv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_bytediv *bytediv = to_clk_bytediv(hw);
+ u32 val;
+ unsigned int factor;
+
+ factor = get_vco_mul_factor(rate);
+
+ val = dsi_phy_read(bytediv->reg);
+ val |= (factor - 1) & 0xff;
+ dsi_phy_write(bytediv->reg, val);
+
+ return 0;
+}
+
+/* Our special byte clock divider ops */
+static const struct clk_ops clk_bytediv_ops = {
+ .round_rate = clk_bytediv_round_rate,
+ .set_rate = clk_bytediv_set_rate,
+ .recalc_rate = clk_bytediv_recalc_rate,
+};
+
+/*
+ * PLL Callbacks
+ */
+static void dsi_28nm_pll_save_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
+ struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
+ void __iomem *base = pll_28nm->phy->pll_base;
+
+ cached_state->postdiv3 =
+ dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10);
+ cached_state->postdiv2 =
+ dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9);
+ cached_state->postdiv1 =
+ dsi_phy_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
+
+ cached_state->vco_rate = clk_hw_get_rate(phy->vco_hw);
+}
+
+static int dsi_28nm_pll_restore_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
+ struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
+ void __iomem *base = pll_28nm->phy->pll_base;
+ int ret;
+
+ ret = dsi_pll_28nm_clk_set_rate(phy->vco_hw,
+ cached_state->vco_rate, 0);
+ if (ret) {
+ DRM_DEV_ERROR(&pll_28nm->phy->pdev->dev,
+ "restore vco rate failed. ret=%d\n", ret);
+ return ret;
+ }
+
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10,
+ cached_state->postdiv3);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9,
+ cached_state->postdiv2);
+ dsi_phy_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8,
+ cached_state->postdiv1);
+
+ return 0;
+}
+
+static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **provided_clocks)
+{
+ char *clk_name, *parent_name, *vco_name;
+ struct clk_init_data vco_init = {
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .flags = CLK_IGNORE_UNUSED,
+ .ops = &clk_ops_dsi_pll_28nm_vco,
+ };
+ struct device *dev = &pll_28nm->phy->pdev->dev;
+ struct clk_hw *hw;
+ struct clk_bytediv *bytediv;
+ struct clk_init_data bytediv_init = { };
+ int ret;
+
+ DBG("%d", pll_28nm->phy->id);
+
+ bytediv = devm_kzalloc(dev, sizeof(*bytediv), GFP_KERNEL);
+ if (!bytediv)
+ return -ENOMEM;
+
+ vco_name = devm_kzalloc(dev, 32, GFP_KERNEL);
+ if (!vco_name)
+ return -ENOMEM;
+
+ clk_name = devm_kzalloc(dev, 32, GFP_KERNEL);
+ if (!clk_name)
+ return -ENOMEM;
+
+ snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->phy->id);
+ vco_init.name = vco_name;
+
+ pll_28nm->clk_hw.init = &vco_init;
+
+ ret = devm_clk_hw_register(dev, &pll_28nm->clk_hw);
+ if (ret)
+ return ret;
+
+ /* prepare and register bytediv */
+ bytediv->hw.init = &bytediv_init;
+ bytediv->reg = pll_28nm->phy->pll_base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9;
+
+ snprintf(parent_name, 32, "dsi%dvco_clk", pll_28nm->phy->id);
+ snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->phy->id);
+
+ bytediv_init.name = clk_name;
+ bytediv_init.ops = &clk_bytediv_ops;
+ bytediv_init.flags = CLK_SET_RATE_PARENT;
+ bytediv_init.parent_names = (const char * const *) &parent_name;
+ bytediv_init.num_parents = 1;
+
+ /* DIV2 */
+ ret = devm_clk_hw_register(dev, &bytediv->hw);
+ if (ret)
+ return ret;
+ provided_clocks[DSI_BYTE_PLL_CLK] = &bytediv->hw;
+
+ snprintf(clk_name, 32, "dsi%dpll", pll_28nm->phy->id);
+ /* DIV3 */
+ hw = devm_clk_hw_register_divider(dev, clk_name,
+ parent_name, 0, pll_28nm->phy->pll_base +
+ REG_DSI_28nm_8960_PHY_PLL_CTRL_10,
+ 0, 8, 0, NULL);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ provided_clocks[DSI_PIXEL_PLL_CLK] = hw;
+
+ return 0;
+}
+
+static int dsi_pll_28nm_8960_init(struct msm_dsi_phy *phy)
+{
+ struct platform_device *pdev = phy->pdev;
+ struct dsi_pll_28nm *pll_28nm;
+ int ret;
+
+ if (!pdev)
+ return -ENODEV;
+
+ pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
+ if (!pll_28nm)
+ return -ENOMEM;
+
+ pll_28nm->phy = phy;
+
+ ret = pll_28nm_register(pll_28nm, phy->provided_clocks->hws);
+ if (ret) {
+ DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
+ return ret;
+ }
+
+ phy->vco_hw = &pll_28nm->clk_hw;
+
+ return 0;
+}
+
static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
struct msm_dsi_dphy_timing *timing)
{
@@ -117,7 +585,7 @@ static void dsi_28nm_phy_lane_config(struct msm_dsi_phy *phy)
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR1, 0x88);
}
-static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req)
{
struct msm_dsi_dphy_timing *timing = &phy->timing;
@@ -174,8 +642,7 @@ static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
}
const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = {
- .type = MSM_DSI_PHY_28NM_8960,
- .src_pll_truthtable = { {true, true}, {false, true} },
+ .has_phy_regulator = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -185,8 +652,12 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = {
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
- .init = msm_dsi_phy_init_common,
+ .pll_init = dsi_pll_28nm_8960_init,
+ .save_pll_state = dsi_28nm_pll_save_state,
+ .restore_pll_state = dsi_28nm_pll_restore_state,
},
+ .min_pll_rate = VCO_MIN_RATE,
+ .max_pll_rate = VCO_MAX_RATE,
.io_start = { 0x4700300, 0x5800300 },
.num_dsi_phy = 2,
};
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
index 79c034ae075d..e76ce40a12ab 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
@@ -3,11 +3,743 @@
* Copyright (c) 2018, The Linux Foundation
*/
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/iopoll.h>
#include "dsi_phy.h"
#include "dsi.xml.h"
+/*
+ * DSI PLL 7nm - clock diagram (eg: DSI0): TODO: updated CPHY diagram
+ *
+ * dsi0_pll_out_div_clk dsi0_pll_bit_clk
+ * | |
+ * | |
+ * +---------+ | +----------+ | +----+
+ * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0_phy_pll_out_byteclk
+ * +---------+ | +----------+ | +----+
+ * | |
+ * | | dsi0_pll_by_2_bit_clk
+ * | | |
+ * | | +----+ | |\ dsi0_pclk_mux
+ * | |--| /2 |--o--| \ |
+ * | | +----+ | \ | +---------+
+ * | --------------| |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk
+ * |------------------------------| / +---------+
+ * | +-----+ | /
+ * -----------| /4? |--o----------|/
+ * +-----+ | |
+ * | |dsiclk_sel
+ * |
+ * dsi0_pll_post_out_div_clk
+ */
+
+#define VCO_REF_CLK_RATE 19200000
+#define FRAC_BITS 18
+
+/* Hardware is V4.1 */
+#define DSI_PHY_7NM_QUIRK_V4_1 BIT(0)
+
+struct dsi_pll_config {
+ bool enable_ssc;
+ bool ssc_center;
+ u32 ssc_freq;
+ u32 ssc_offset;
+ u32 ssc_adj_per;
+
+ /* out */
+ u32 decimal_div_start;
+ u32 frac_div_start;
+ u32 pll_clock_inverters;
+ u32 ssc_stepsize;
+ u32 ssc_div_per;
+};
+
+struct pll_7nm_cached_state {
+ unsigned long vco_rate;
+ u8 bit_clk_div;
+ u8 pix_clk_div;
+ u8 pll_out_div;
+ u8 pll_mux;
+};
+
+struct dsi_pll_7nm {
+ struct clk_hw clk_hw;
+
+ struct msm_dsi_phy *phy;
+
+ u64 vco_current_rate;
+
+ /* protects REG_DSI_7nm_PHY_CMN_CLK_CFG0 register */
+ spinlock_t postdiv_lock;
+
+ struct pll_7nm_cached_state cached_state;
+
+ struct dsi_pll_7nm *slave;
+};
+
+#define to_pll_7nm(x) container_of(x, struct dsi_pll_7nm, clk_hw)
+
+/*
+ * Global list of private DSI PLL struct pointers. We need this for Dual DSI
+ * mode, where the master PLL's clk_ops needs access the slave's private data
+ */
+static struct dsi_pll_7nm *pll_7nm_list[DSI_MAX];
+
+static void dsi_pll_setup_config(struct dsi_pll_config *config)
+{
+ config->ssc_freq = 31500;
+ config->ssc_offset = 4800;
+ config->ssc_adj_per = 2;
+
+ /* TODO: ssc enable */
+ config->enable_ssc = false;
+ config->ssc_center = 0;
+}
+
+static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config *config)
+{
+ u64 fref = VCO_REF_CLK_RATE;
+ u64 pll_freq;
+ u64 divider;
+ u64 dec, dec_multiple;
+ u32 frac;
+ u64 multiplier;
+
+ pll_freq = pll->vco_current_rate;
+
+ divider = fref * 2;
+
+ multiplier = 1 << FRAC_BITS;
+ dec_multiple = div_u64(pll_freq * multiplier, divider);
+ div_u64_rem(dec_multiple, multiplier, &frac);
+
+ dec = div_u64(dec_multiple, multiplier);
+
+ if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1))
+ config->pll_clock_inverters = 0x28;
+ else if (pll_freq <= 1000000000ULL)
+ config->pll_clock_inverters = 0xa0;
+ else if (pll_freq <= 2500000000ULL)
+ config->pll_clock_inverters = 0x20;
+ else if (pll_freq <= 3020000000ULL)
+ config->pll_clock_inverters = 0x00;
+ else
+ config->pll_clock_inverters = 0x40;
+
+ config->decimal_div_start = dec;
+ config->frac_div_start = frac;
+}
+
+#define SSC_CENTER BIT(0)
+#define SSC_EN BIT(1)
+
+static void dsi_pll_calc_ssc(struct dsi_pll_7nm *pll, struct dsi_pll_config *config)
+{
+ u32 ssc_per;
+ u32 ssc_mod;
+ u64 ssc_step_size;
+ u64 frac;
+
+ if (!config->enable_ssc) {
+ DBG("SSC not enabled\n");
+ return;
+ }
+
+ ssc_per = DIV_ROUND_CLOSEST(VCO_REF_CLK_RATE, config->ssc_freq) / 2 - 1;
+ ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
+ ssc_per -= ssc_mod;
+
+ frac = config->frac_div_start;
+ ssc_step_size = config->decimal_div_start;
+ ssc_step_size *= (1 << FRAC_BITS);
+ ssc_step_size += frac;
+ ssc_step_size *= config->ssc_offset;
+ ssc_step_size *= (config->ssc_adj_per + 1);
+ ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
+ ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
+
+ config->ssc_div_per = ssc_per;
+ config->ssc_stepsize = ssc_step_size;
+
+ pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n",
+ config->decimal_div_start, frac, FRAC_BITS);
+ pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n",
+ ssc_per, (u32)ssc_step_size, config->ssc_adj_per);
+}
+
+static void dsi_pll_ssc_commit(struct dsi_pll_7nm *pll, struct dsi_pll_config *config)
+{
+ void __iomem *base = pll->phy->pll_base;
+
+ if (config->enable_ssc) {
+ pr_debug("SSC is enabled\n");
+
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_LOW_1,
+ config->ssc_stepsize & 0xff);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_HIGH_1,
+ config->ssc_stepsize >> 8);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_LOW_1,
+ config->ssc_div_per & 0xff);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_HIGH_1,
+ config->ssc_div_per >> 8);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_LOW_1,
+ config->ssc_adj_per & 0xff);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_HIGH_1,
+ config->ssc_adj_per >> 8);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_SSC_CONTROL,
+ SSC_EN | (config->ssc_center ? SSC_CENTER : 0));
+ }
+}
+
+static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll)
+{
+ void __iomem *base = pll->phy->pll_base;
+ u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00;
+
+ if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
+ if (pll->vco_current_rate >= 3100000000ULL)
+ analog_controls_five_1 = 0x03;
+
+ if (pll->vco_current_rate < 1520000000ULL)
+ vco_config_1 = 0x08;
+ else if (pll->vco_current_rate < 2990000000ULL)
+ vco_config_1 = 0x01;
+ }
+
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE_1,
+ analog_controls_five_1);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_VCO_CONFIG_1, vco_config_1);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE, 0x01);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_DSM_DIVIDER, 0x00);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_OUTDIV, 0x00);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CORE_OVERRIDE, 0x00);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x0a);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_BAND_SEL_RATE_1, 0xc0);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x84);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x82);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x29);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x2f);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_IFILT, 0x2a);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_IFILT,
+ pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1 ? 0x3f : 0x22);
+
+ if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22);
+ if (pll->slave)
+ dsi_phy_write(pll->slave->phy->pll_base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22);
+ }
+}
+
+static void dsi_pll_commit(struct dsi_pll_7nm *pll, struct dsi_pll_config *config)
+{
+ void __iomem *base = pll->phy->pll_base;
+
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1, config->decimal_div_start);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1,
+ config->frac_div_start & 0xff);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1,
+ (config->frac_div_start & 0xff00) >> 8);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1,
+ (config->frac_div_start & 0x30000) >> 16);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_DELAY, 0x06);
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CMODE_1, 0x10); /* TODO: 0x00 for CPHY */
+ dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS, config->pll_clock_inverters);
+}
+
+static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
+ struct dsi_pll_config config;
+
+ DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_7nm->phy->id, rate,
+ parent_rate);
+
+ pll_7nm->vco_current_rate = rate;
+
+ dsi_pll_setup_config(&config);
+
+ dsi_pll_calc_dec_frac(pll_7nm, &config);
+
+ dsi_pll_calc_ssc(pll_7nm, &config);
+
+ dsi_pll_commit(pll_7nm, &config);
+
+ dsi_pll_config_hzindep_reg(pll_7nm);
+
+ dsi_pll_ssc_commit(pll_7nm, &config);
+
+ /* flush, ensure all register writes are done*/
+ wmb();
+
+ return 0;
+}
+
+static int dsi_pll_7nm_lock_status(struct dsi_pll_7nm *pll)
+{
+ int rc;
+ u32 status = 0;
+ u32 const delay_us = 100;
+ u32 const timeout_us = 5000;
+
+ rc = readl_poll_timeout_atomic(pll->phy->pll_base +
+ REG_DSI_7nm_PHY_PLL_COMMON_STATUS_ONE,
+ status,
+ ((status & BIT(0)) > 0),
+ delay_us,
+ timeout_us);
+ if (rc)
+ pr_err("DSI PLL(%d) lock failed, status=0x%08x\n",
+ pll->phy->id, status);
+
+ return rc;
+}
+
+static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll)
+{
+ u32 data = dsi_phy_read(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
+
+ dsi_phy_write(pll->phy->pll_base + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0);
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0, data & ~BIT(5));
+ ndelay(250);
+}
+
+static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll)
+{
+ u32 data = dsi_phy_read(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0);
+
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_0, data | BIT(5));
+ dsi_phy_write(pll->phy->pll_base + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0xc0);
+ ndelay(250);
+}
+
+static void dsi_pll_disable_global_clk(struct dsi_pll_7nm *pll)
+{
+ u32 data;
+
+ data = dsi_phy_read(pll->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, data & ~BIT(5));
+}
+
+static void dsi_pll_enable_global_clk(struct dsi_pll_7nm *pll)
+{
+ u32 data;
+
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_CTRL_3, 0x04);
+
+ data = dsi_phy_read(pll->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_CLK_CFG1,
+ data | BIT(5) | BIT(4));
+}
+
+static void dsi_pll_phy_dig_reset(struct dsi_pll_7nm *pll)
+{
+ /*
+ * Reset the PHY digital domain. This would be needed when
+ * coming out of a CX or analog rail power collapse while
+ * ensuring that the pads maintain LP00 or LP11 state
+ */
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, BIT(0));
+ wmb(); /* Ensure that the reset is deasserted */
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, 0x0);
+ wmb(); /* Ensure that the reset is deasserted */
+}
+
+static int dsi_pll_7nm_vco_prepare(struct clk_hw *hw)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
+ int rc;
+
+ dsi_pll_enable_pll_bias(pll_7nm);
+ if (pll_7nm->slave)
+ dsi_pll_enable_pll_bias(pll_7nm->slave);
+
+ /* Start PLL */
+ dsi_phy_write(pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, 0x01);
+
+ /*
+ * ensure all PLL configurations are written prior to checking
+ * for PLL lock.
+ */
+ wmb();
+
+ /* Check for PLL lock */
+ rc = dsi_pll_7nm_lock_status(pll_7nm);
+ if (rc) {
+ pr_err("PLL(%d) lock failed\n", pll_7nm->phy->id);
+ goto error;
+ }
+
+ pll_7nm->phy->pll_on = true;
+
+ /*
+ * assert power on reset for PHY digital in case the PLL is
+ * enabled after CX of analog domain power collapse. This needs
+ * to be done before enabling the global clk.
+ */
+ dsi_pll_phy_dig_reset(pll_7nm);
+ if (pll_7nm->slave)
+ dsi_pll_phy_dig_reset(pll_7nm->slave);
+
+ dsi_pll_enable_global_clk(pll_7nm);
+ if (pll_7nm->slave)
+ dsi_pll_enable_global_clk(pll_7nm->slave);
+
+error:
+ return rc;
+}
+
+static void dsi_pll_disable_sub(struct dsi_pll_7nm *pll)
+{
+ dsi_phy_write(pll->phy->base + REG_DSI_7nm_PHY_CMN_RBUF_CTRL, 0);
+ dsi_pll_disable_pll_bias(pll);
+}
+
+static void dsi_pll_7nm_vco_unprepare(struct clk_hw *hw)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
+
+ /*
+ * To avoid any stray glitches while abruptly powering down the PLL
+ * make sure to gate the clock using the clock enable bit before
+ * powering down the PLL
+ */
+ dsi_pll_disable_global_clk(pll_7nm);
+ dsi_phy_write(pll_7nm->phy->base + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, 0);
+ dsi_pll_disable_sub(pll_7nm);
+ if (pll_7nm->slave) {
+ dsi_pll_disable_global_clk(pll_7nm->slave);
+ dsi_pll_disable_sub(pll_7nm->slave);
+ }
+ /* flush, ensure all register writes are done */
+ wmb();
+ pll_7nm->phy->pll_on = false;
+}
+
+static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
+ void __iomem *base = pll_7nm->phy->pll_base;
+ u64 ref_clk = VCO_REF_CLK_RATE;
+ u64 vco_rate = 0x0;
+ u64 multiplier;
+ u32 frac;
+ u32 dec;
+ u64 pll_freq, tmp64;
+
+ dec = dsi_phy_read(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1);
+ dec &= 0xff;
+
+ frac = dsi_phy_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1);
+ frac |= ((dsi_phy_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1) &
+ 0xff) << 8);
+ frac |= ((dsi_phy_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1) &
+ 0x3) << 16);
+
+ /*
+ * TODO:
+ * 1. Assumes prescaler is disabled
+ */
+ multiplier = 1 << FRAC_BITS;
+ pll_freq = dec * (ref_clk * 2);
+ tmp64 = (ref_clk * 2 * frac);
+ pll_freq += div_u64(tmp64, multiplier);
+
+ vco_rate = pll_freq;
+
+ DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
+ pll_7nm->phy->id, (unsigned long)vco_rate, dec, frac);
+
+ return (unsigned long)vco_rate;
+}
+
+static long dsi_pll_7nm_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *parent_rate)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(hw);
+
+ if (rate < pll_7nm->phy->cfg->min_pll_rate)
+ return pll_7nm->phy->cfg->min_pll_rate;
+ else if (rate > pll_7nm->phy->cfg->max_pll_rate)
+ return pll_7nm->phy->cfg->max_pll_rate;
+ else
+ return rate;
+}
+
+static const struct clk_ops clk_ops_dsi_pll_7nm_vco = {
+ .round_rate = dsi_pll_7nm_clk_round_rate,
+ .set_rate = dsi_pll_7nm_vco_set_rate,
+ .recalc_rate = dsi_pll_7nm_vco_recalc_rate,
+ .prepare = dsi_pll_7nm_vco_prepare,
+ .unprepare = dsi_pll_7nm_vco_unprepare,
+};
+
+/*
+ * PLL Callbacks
+ */
+
+static void dsi_7nm_pll_save_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(phy->vco_hw);
+ struct pll_7nm_cached_state *cached = &pll_7nm->cached_state;
+ void __iomem *phy_base = pll_7nm->phy->base;
+ u32 cmn_clk_cfg0, cmn_clk_cfg1;
+
+ cached->pll_out_div = dsi_phy_read(pll_7nm->phy->pll_base +
+ REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE);
+ cached->pll_out_div &= 0x3;
+
+ cmn_clk_cfg0 = dsi_phy_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0);
+ cached->bit_clk_div = cmn_clk_cfg0 & 0xf;
+ cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4;
+
+ cmn_clk_cfg1 = dsi_phy_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
+ cached->pll_mux = cmn_clk_cfg1 & 0x3;
+
+ DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x",
+ pll_7nm->phy->id, cached->pll_out_div, cached->bit_clk_div,
+ cached->pix_clk_div, cached->pll_mux);
+}
+
+static int dsi_7nm_pll_restore_state(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(phy->vco_hw);
+ struct pll_7nm_cached_state *cached = &pll_7nm->cached_state;
+ void __iomem *phy_base = pll_7nm->phy->base;
+ u32 val;
+ int ret;
+
+ val = dsi_phy_read(pll_7nm->phy->pll_base + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE);
+ val &= ~0x3;
+ val |= cached->pll_out_div;
+ dsi_phy_write(pll_7nm->phy->pll_base + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, val);
+
+ dsi_phy_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0,
+ cached->bit_clk_div | (cached->pix_clk_div << 4));
+
+ val = dsi_phy_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
+ val &= ~0x3;
+ val |= cached->pll_mux;
+ dsi_phy_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, val);
+
+ ret = dsi_pll_7nm_vco_set_rate(phy->vco_hw,
+ pll_7nm->vco_current_rate,
+ VCO_REF_CLK_RATE);
+ if (ret) {
+ DRM_DEV_ERROR(&pll_7nm->phy->pdev->dev,
+ "restore vco rate failed. ret=%d\n", ret);
+ return ret;
+ }
+
+ DBG("DSI PLL%d", pll_7nm->phy->id);
+
+ return 0;
+}
+
+static int dsi_7nm_set_usecase(struct msm_dsi_phy *phy)
+{
+ struct dsi_pll_7nm *pll_7nm = to_pll_7nm(phy->vco_hw);
+ void __iomem *base = phy->base;
+ u32 data = 0x0; /* internal PLL */
+
+ DBG("DSI PLL%d", pll_7nm->phy->id);
+
+ switch (phy->usecase) {
+ case MSM_DSI_PHY_STANDALONE:
+ break;
+ case MSM_DSI_PHY_MASTER:
+ pll_7nm->slave = pll_7nm_list[(pll_7nm->phy->id + 1) % DSI_MAX];
+ break;
+ case MSM_DSI_PHY_SLAVE:
+ data = 0x1; /* external PLL */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set PLL src */
+ dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, (data << 2));
+
+ return 0;
+}
+
+/*
+ * The post dividers and mux clocks are created using the standard divider and
+ * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux
+ * state to follow the master PLL's divider/mux state. Therefore, we don't
+ * require special clock ops that also configure the slave PLL registers
+ */
+static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm, struct clk_hw **provided_clocks)
+{
+ char clk_name[32], parent[32], vco_name[32];
+ char parent2[32], parent3[32], parent4[32];
+ struct clk_init_data vco_init = {
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .name = vco_name,
+ .flags = CLK_IGNORE_UNUSED,
+ .ops = &clk_ops_dsi_pll_7nm_vco,
+ };
+ struct device *dev = &pll_7nm->phy->pdev->dev;
+ struct clk_hw *hw;
+ int ret;
+
+ DBG("DSI%d", pll_7nm->phy->id);
+
+ snprintf(vco_name, 32, "dsi%dvco_clk", pll_7nm->phy->id);
+ pll_7nm->clk_hw.init = &vco_init;
+
+ ret = devm_clk_hw_register(dev, &pll_7nm->clk_hw);
+ if (ret)
+ return ret;
+
+ snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_7nm->phy->id);
+ snprintf(parent, 32, "dsi%dvco_clk", pll_7nm->phy->id);
+
+ hw = devm_clk_hw_register_divider(dev, clk_name,
+ parent, CLK_SET_RATE_PARENT,
+ pll_7nm->phy->pll_base +
+ REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE,
+ 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->phy->id);
+
+ /* BIT CLK: DIV_CTRL_3_0 */
+ hw = devm_clk_hw_register_divider(dev, clk_name, parent,
+ CLK_SET_RATE_PARENT,
+ pll_7nm->phy->base +
+ REG_DSI_7nm_PHY_CMN_CLK_CFG0,
+ 0, 4, CLK_DIVIDER_ONE_BASED,
+ &pll_7nm->postdiv_lock);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_7nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id);
+
+ /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent,
+ CLK_SET_RATE_PARENT, 1, 8);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ provided_clocks[DSI_BYTE_PLL_CLK] = hw;
+
+ snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id);
+
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent,
+ 0, 1, 2);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->phy->id);
+
+ hw = devm_clk_hw_register_fixed_factor(dev, clk_name, parent,
+ 0, 1, 4);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_7nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->phy->id);
+ snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->phy->id);
+ snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_7nm->phy->id);
+ snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->phy->id);
+
+ hw = devm_clk_hw_register_mux(dev, clk_name,
+ ((const char *[]){
+ parent, parent2, parent3, parent4
+ }), 4, 0, pll_7nm->phy->base +
+ REG_DSI_7nm_PHY_CMN_CLK_CFG1,
+ 0, 2, 0, NULL);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_7nm->phy->id);
+ snprintf(parent, 32, "dsi%d_pclk_mux", pll_7nm->phy->id);
+
+ /* PIX CLK DIV : DIV_CTRL_7_4*/
+ hw = devm_clk_hw_register_divider(dev, clk_name, parent,
+ 0, pll_7nm->phy->base +
+ REG_DSI_7nm_PHY_CMN_CLK_CFG0,
+ 4, 4, CLK_DIVIDER_ONE_BASED,
+ &pll_7nm->postdiv_lock);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+ goto fail;
+ }
+
+ provided_clocks[DSI_PIXEL_PLL_CLK] = hw;
+
+ return 0;
+
+fail:
+
+ return ret;
+}
+
+static int dsi_pll_7nm_init(struct msm_dsi_phy *phy)
+{
+ struct platform_device *pdev = phy->pdev;
+ struct dsi_pll_7nm *pll_7nm;
+ int ret;
+
+ pll_7nm = devm_kzalloc(&pdev->dev, sizeof(*pll_7nm), GFP_KERNEL);
+ if (!pll_7nm)
+ return -ENOMEM;
+
+ DBG("DSI PLL%d", phy->id);
+
+ pll_7nm_list[phy->id] = pll_7nm;
+
+ spin_lock_init(&pll_7nm->postdiv_lock);
+
+ pll_7nm->phy = phy;
+
+ ret = pll_7nm_register(pll_7nm, phy->provided_clocks->hws);
+ if (ret) {
+ DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
+ return ret;
+ }
+
+ phy->vco_hw = &pll_7nm->clk_hw;
+
+ /* TODO: Remove this when we have proper display handover support */
+ msm_dsi_phy_pll_save_state(phy);
+
+ return 0;
+}
+
static int dsi_phy_hw_v4_0_is_pll_on(struct msm_dsi_phy *phy)
{
void __iomem *base = phy->base;
@@ -44,7 +776,7 @@ static void dsi_phy_hw_v4_0_lane_settings(struct msm_dsi_phy *phy)
const u8 *tx_dctrl = tx_dctrl_0;
void __iomem *lane_base = phy->lane_base;
- if (phy->cfg->type == MSM_DSI_PHY_7NM_V4_1)
+ if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1)
tx_dctrl = tx_dctrl_1;
/* Strength ctrl settings */
@@ -69,7 +801,7 @@ static void dsi_phy_hw_v4_0_lane_settings(struct msm_dsi_phy *phy)
}
}
-static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
+static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
struct msm_dsi_phy_clk_request *clk_req)
{
int ret;
@@ -108,7 +840,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
/* Alter PHY configurations if data rate less than 1.5GHZ*/
less_than_1500_mhz = (clk_req->bitclk_rate <= 1500000000);
- if (phy->cfg->type == MSM_DSI_PHY_7NM_V4_1) {
+ if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
vreg_ctrl_0 = less_than_1500_mhz ? 0x53 : 0x52;
glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x00;
glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x39 : 0x3c;
@@ -165,7 +897,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
/* Select full-rate mode */
dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_CTRL_2, 0x40);
- ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase);
+ ret = dsi_7nm_set_usecase(phy);
if (ret) {
DRM_DEV_ERROR(&phy->pdev->dev, "%s: set pll usecase failed, %d\n",
__func__, ret);
@@ -224,24 +956,8 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
DBG("DSI%d PHY disabled", phy->id);
}
-static int dsi_7nm_phy_init(struct msm_dsi_phy *phy)
-{
- struct platform_device *pdev = phy->pdev;
-
- phy->lane_base = msm_ioremap(pdev, "dsi_phy_lane",
- "DSI_PHY_LANE");
- if (IS_ERR(phy->lane_base)) {
- DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n",
- __func__);
- return -ENOMEM;
- }
-
- return 0;
-}
-
const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = {
- .type = MSM_DSI_PHY_7NM_V4_1,
- .src_pll_truthtable = { {false, false}, {true, false} },
+ .has_phy_lane = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -251,15 +967,19 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = {
.ops = {
.enable = dsi_7nm_phy_enable,
.disable = dsi_7nm_phy_disable,
- .init = dsi_7nm_phy_init,
+ .pll_init = dsi_pll_7nm_init,
+ .save_pll_state = dsi_7nm_pll_save_state,
+ .restore_pll_state = dsi_7nm_pll_restore_state,
},
+ .min_pll_rate = 600000000UL,
+ .max_pll_rate = (5000000000ULL < ULONG_MAX) ? 5000000000ULL : ULONG_MAX,
.io_start = { 0xae94400, 0xae96400 },
.num_dsi_phy = 2,
+ .quirks = DSI_PHY_7NM_QUIRK_V4_1,
};
const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = {
- .type = MSM_DSI_PHY_7NM,
- .src_pll_truthtable = { {false, false}, {true, false} },
+ .has_phy_lane = true,
.reg_cfg = {
.num = 1,
.regs = {
@@ -269,8 +989,12 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = {
.ops = {
.enable = dsi_7nm_phy_enable,
.disable = dsi_7nm_phy_disable,
- .init = dsi_7nm_phy_init,
+ .pll_init = dsi_pll_7nm_init,
+ .save_pll_state = dsi_7nm_pll_save_state,
+ .restore_pll_state = dsi_7nm_pll_restore_state,
},
+ .min_pll_rate = 1000000000UL,
+ .max_pll_rate = 3500000000UL,
.io_start = { 0xae94400, 0xae96400 },
.num_dsi_phy = 2,
};
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
deleted file mode 100644
index 3dc65877fa10..000000000000
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
+++ /dev/null
@@ -1,184 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
- */
-
-#include "dsi_pll.h"
-
-static int dsi_pll_enable(struct msm_dsi_pll *pll)
-{
- int i, ret = 0;
-
- /*
- * Certain PLLs do not allow VCO rate update when it is on.
- * Keep track of their status to turn on/off after set rate success.
- */
- if (unlikely(pll->pll_on))
- return 0;
-
- /* Try all enable sequences until one succeeds */
- for (i = 0; i < pll->en_seq_cnt; i++) {
- ret = pll->enable_seqs[i](pll);
- DBG("DSI PLL %s after sequence #%d",
- ret ? "unlocked" : "locked", i + 1);
- if (!ret)
- break;
- }
-
- if (ret) {
- DRM_ERROR("DSI PLL failed to lock\n");
- return ret;
- }
-
- pll->pll_on = true;
-
- return 0;
-}
-
-static void dsi_pll_disable(struct msm_dsi_pll *pll)
-{
- if (unlikely(!pll->pll_on))
- return;
-
- pll->disable_seq(pll);
-
- pll->pll_on = false;
-}
-
-/*
- * DSI PLL Helper functions
- */
-long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
- unsigned long rate, unsigned long *parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
-
- if (rate < pll->min_rate)
- return pll->min_rate;
- else if (rate > pll->max_rate)
- return pll->max_rate;
- else
- return rate;
-}
-
-int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
-
- return dsi_pll_enable(pll);
-}
-
-void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
-
- dsi_pll_disable(pll);
-}
-
-void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
- struct clk **clks, u32 num_clks)
-{
- of_clk_del_provider(pdev->dev.of_node);
-
- if (!num_clks || !clks)
- return;
-
- do {
- clk_unregister(clks[--num_clks]);
- clks[num_clks] = NULL;
- } while (num_clks);
-}
-
-/*
- * DSI PLL API
- */
-int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
- struct clk **byte_clk_provider, struct clk **pixel_clk_provider)
-{
- if (pll->get_provider)
- return pll->get_provider(pll,
- byte_clk_provider,
- pixel_clk_provider);
-
- return -EINVAL;
-}
-
-void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
-{
- if (pll->destroy)
- pll->destroy(pll);
-}
-
-void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
-{
- if (pll->save_state) {
- pll->save_state(pll);
- pll->state_saved = true;
- }
-}
-
-int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
-{
- int ret;
-
- if (pll->restore_state && pll->state_saved) {
- ret = pll->restore_state(pll);
- if (ret)
- return ret;
-
- pll->state_saved = false;
- }
-
- return 0;
-}
-
-int msm_dsi_pll_set_usecase(struct msm_dsi_pll *pll,
- enum msm_dsi_phy_usecase uc)
-{
- if (pll->set_usecase)
- return pll->set_usecase(pll, uc);
-
- return 0;
-}
-
-struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
- enum msm_dsi_phy_type type, int id)
-{
- struct device *dev = &pdev->dev;
- struct msm_dsi_pll *pll;
-
- switch (type) {
- case MSM_DSI_PHY_28NM_HPM:
- case MSM_DSI_PHY_28NM_LP:
- pll = msm_dsi_pll_28nm_init(pdev, type, id);
- break;
- case MSM_DSI_PHY_28NM_8960:
- pll = msm_dsi_pll_28nm_8960_init(pdev, id);
- break;
- case MSM_DSI_PHY_14NM:
- pll = msm_dsi_pll_14nm_init(pdev, id);
- break;
- case MSM_DSI_PHY_10NM:
- pll = msm_dsi_pll_10nm_init(pdev, id);
- break;
- case MSM_DSI_PHY_7NM:
- case MSM_DSI_PHY_7NM_V4_1:
- pll = msm_dsi_pll_7nm_init(pdev, type, id);
- break;
- default:
- pll = ERR_PTR(-ENXIO);
- break;
- }
-
- if (IS_ERR(pll)) {
- DRM_DEV_ERROR(dev, "%s: failed to init DSI PLL\n", __func__);
- return pll;
- }
-
- pll->type = type;
-
- DBG("DSI:%d PLL registered", id);
-
- return pll;
-}
-
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
deleted file mode 100644
index bbecb1de5678..000000000000
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
- */
-
-#ifndef __DSI_PLL_H__
-#define __DSI_PLL_H__
-
-#include <linux/clk-provider.h>
-#include <linux/delay.h>
-
-#include "dsi.h"
-
-#define NUM_DSI_CLOCKS_MAX 6
-#define MAX_DSI_PLL_EN_SEQS 10
-
-struct msm_dsi_pll {
- enum msm_dsi_phy_type type;
-
- struct clk_hw clk_hw;
- bool pll_on;
- bool state_saved;
-
- unsigned long min_rate;
- unsigned long max_rate;
- u32 en_seq_cnt;
-
- int (*enable_seqs[MAX_DSI_PLL_EN_SEQS])(struct msm_dsi_pll *pll);
- void (*disable_seq)(struct msm_dsi_pll *pll);
- int (*get_provider)(struct msm_dsi_pll *pll,
- struct clk **byte_clk_provider,
- struct clk **pixel_clk_provider);
- void (*destroy)(struct msm_dsi_pll *pll);
- void (*save_state)(struct msm_dsi_pll *pll);
- int (*restore_state)(struct msm_dsi_pll *pll);
- int (*set_usecase)(struct msm_dsi_pll *pll,
- enum msm_dsi_phy_usecase uc);
-};
-
-#define hw_clk_to_pll(x) container_of(x, struct msm_dsi_pll, clk_hw)
-
-static inline void pll_write(void __iomem *reg, u32 data)
-{
- msm_writel(data, reg);
-}
-
-static inline u32 pll_read(const void __iomem *reg)
-{
- return msm_readl(reg);
-}
-
-static inline void pll_write_udelay(void __iomem *reg, u32 data, u32 delay_us)
-{
- pll_write(reg, data);
- udelay(delay_us);
-}
-
-static inline void pll_write_ndelay(void __iomem *reg, u32 data, u32 delay_ns)
-{
- pll_write((reg), data);
- ndelay(delay_ns);
-}
-
-/*
- * DSI PLL Helper functions
- */
-
-/* clock callbacks */
-long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
- unsigned long rate, unsigned long *parent_rate);
-int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw);
-void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw);
-/* misc */
-void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
- struct clk **clks, u32 num_clks);
-
-/*
- * Initialization for Each PLL Type
- */
-#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
-struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
- enum msm_dsi_phy_type type, int id);
-#else
-static inline struct msm_dsi_pll *msm_dsi_pll_28nm_init(
- struct platform_device *pdev, enum msm_dsi_phy_type type, int id)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
-#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
-struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
- int id);
-#else
-static inline struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(
- struct platform_device *pdev, int id)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
-
-#ifdef CONFIG_DRM_MSM_DSI_14NM_PHY
-struct msm_dsi_pll *msm_dsi_pll_14nm_init(struct platform_device *pdev, int id);
-#else
-static inline struct msm_dsi_pll *
-msm_dsi_pll_14nm_init(struct platform_device *pdev, int id)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
-#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY
-struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id);
-#else
-static inline struct msm_dsi_pll *
-msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
-#ifdef CONFIG_DRM_MSM_DSI_7NM_PHY
-struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev,
- enum msm_dsi_phy_type type, int id);
-#else
-static inline struct msm_dsi_pll *
-msm_dsi_pll_7nm_init(struct platform_device *pdev,
- enum msm_dsi_phy_type type, int id)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
-
-#endif /* __DSI_PLL_H__ */
-
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
deleted file mode 100644
index de3b802ccd3d..000000000000
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * SPDX-License-Identifier: GPL-2.0
- * Copyright (c) 2018, The Linux Foundation
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/iopoll.h>
-
-#include "dsi_pll.h"
-#include "dsi.xml.h"
-
-/*
- * DSI PLL 10nm - clock diagram (eg: DSI0):
- *
- * dsi0_pll_out_div_clk dsi0_pll_bit_clk
- * | |
- * | |
- * +---------+ | +----------+ | +----+
- * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0_phy_pll_out_byteclk
- * +---------+ | +----------+ | +----+
- * | |
- * | | dsi0_pll_by_2_bit_clk
- * | | |
- * | | +----+ | |\ dsi0_pclk_mux
- * | |--| /2 |--o--| \ |
- * | | +----+ | \ | +---------+
- * | --------------| |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk
- * |------------------------------| / +---------+
- * | +-----+ | /
- * -----------| /4? |--o----------|/
- * +-----+ | |
- * | |dsiclk_sel
- * |
- * dsi0_pll_post_out_div_clk
- */
-
-#define DSI_BYTE_PLL_CLK 0
-#define DSI_PIXEL_PLL_CLK 1
-#define NUM_PROVIDED_CLKS 2
-
-#define VCO_REF_CLK_RATE 19200000
-
-struct dsi_pll_regs {
- u32 pll_prop_gain_rate;
- u32 pll_lockdet_rate;
- u32 decimal_div_start;
- u32 frac_div_start_low;
- u32 frac_div_start_mid;
- u32 frac_div_start_high;
- u32 pll_clock_inverters;
- u32 ssc_stepsize_low;
- u32 ssc_stepsize_high;
- u32 ssc_div_per_low;
- u32 ssc_div_per_high;
- u32 ssc_adjper_low;
- u32 ssc_adjper_high;
- u32 ssc_control;
-};
-
-struct dsi_pll_config {
- u32 ref_freq;
- bool div_override;
- u32 output_div;
- bool ignore_frac;
- bool disable_prescaler;
- bool enable_ssc;
- bool ssc_center;
- u32 dec_bits;
- u32 frac_bits;
- u32 lock_timer;
- u32 ssc_freq;
- u32 ssc_offset;
- u32 ssc_adj_per;
- u32 thresh_cycles;
- u32 refclk_cycles;
-};
-
-struct pll_10nm_cached_state {
- unsigned long vco_rate;
- u8 bit_clk_div;
- u8 pix_clk_div;
- u8 pll_out_div;
- u8 pll_mux;
-};
-
-struct dsi_pll_10nm {
- struct msm_dsi_pll base;
-
- int id;
- struct platform_device *pdev;
-
- void __iomem *phy_cmn_mmio;
- void __iomem *mmio;
-
- u64 vco_ref_clk_rate;
- u64 vco_current_rate;
-
- /* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */
- spinlock_t postdiv_lock;
-
- int vco_delay;
- struct dsi_pll_config pll_configuration;
- struct dsi_pll_regs reg_setup;
-
- /* private clocks: */
- struct clk_hw *out_div_clk_hw;
- struct clk_hw *bit_clk_hw;
- struct clk_hw *byte_clk_hw;
- struct clk_hw *by_2_bit_clk_hw;
- struct clk_hw *post_out_div_clk_hw;
- struct clk_hw *pclk_mux_hw;
- struct clk_hw *out_dsiclk_hw;
-
- /* clock-provider: */
- struct clk_hw_onecell_data *hw_data;
-
- struct pll_10nm_cached_state cached_state;
-
- enum msm_dsi_phy_usecase uc;
- struct dsi_pll_10nm *slave;
-};
-
-#define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, base)
-
-/*
- * Global list of private DSI PLL struct pointers. We need this for Dual DSI
- * mode, where the master PLL's clk_ops needs access the slave's private data
- */
-static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX];
-
-static void dsi_pll_setup_config(struct dsi_pll_10nm *pll)
-{
- struct dsi_pll_config *config = &pll->pll_configuration;
-
- config->ref_freq = pll->vco_ref_clk_rate;
- config->output_div = 1;
- config->dec_bits = 8;
- config->frac_bits = 18;
- config->lock_timer = 64;
- config->ssc_freq = 31500;
- config->ssc_offset = 5000;
- config->ssc_adj_per = 2;
- config->thresh_cycles = 32;
- config->refclk_cycles = 256;
-
- config->div_override = false;
- config->ignore_frac = false;
- config->disable_prescaler = false;
-
- config->enable_ssc = false;
- config->ssc_center = 0;
-}
-
-static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll)
-{
- struct dsi_pll_config *config = &pll->pll_configuration;
- struct dsi_pll_regs *regs = &pll->reg_setup;
- u64 fref = pll->vco_ref_clk_rate;
- u64 pll_freq;
- u64 divider;
- u64 dec, dec_multiple;
- u32 frac;
- u64 multiplier;
-
- pll_freq = pll->vco_current_rate;
-
- if (config->disable_prescaler)
- divider = fref;
- else
- divider = fref * 2;
-
- multiplier = 1 << config->frac_bits;
- dec_multiple = div_u64(pll_freq * multiplier, divider);
- dec = div_u64_rem(dec_multiple, multiplier, &frac);
-
- if (pll_freq <= 1900000000UL)
- regs->pll_prop_gain_rate = 8;
- else if (pll_freq <= 3000000000UL)
- regs->pll_prop_gain_rate = 10;
- else
- regs->pll_prop_gain_rate = 12;
- if (pll_freq < 1100000000UL)
- regs->pll_clock_inverters = 8;
- else
- regs->pll_clock_inverters = 0;
-
- regs->pll_lockdet_rate = config->lock_timer;
- regs->decimal_div_start = dec;
- regs->frac_div_start_low = (frac & 0xff);
- regs->frac_div_start_mid = (frac & 0xff00) >> 8;
- regs->frac_div_start_high = (frac & 0x30000) >> 16;
-}
-
-#define SSC_CENTER BIT(0)
-#define SSC_EN BIT(1)
-
-static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll)
-{
- struct dsi_pll_config *config = &pll->pll_configuration;
- struct dsi_pll_regs *regs = &pll->reg_setup;
- u32 ssc_per;
- u32 ssc_mod;
- u64 ssc_step_size;
- u64 frac;
-
- if (!config->enable_ssc) {
- DBG("SSC not enabled\n");
- return;
- }
-
- ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1;
- ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
- ssc_per -= ssc_mod;
-
- frac = regs->frac_div_start_low |
- (regs->frac_div_start_mid << 8) |
- (regs->frac_div_start_high << 16);
- ssc_step_size = regs->decimal_div_start;
- ssc_step_size *= (1 << config->frac_bits);
- ssc_step_size += frac;
- ssc_step_size *= config->ssc_offset;
- ssc_step_size *= (config->ssc_adj_per + 1);
- ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
- ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
-
- regs->ssc_div_per_low = ssc_per & 0xFF;
- regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8;
- regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF);
- regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8);
- regs->ssc_adjper_low = config->ssc_adj_per & 0xFF;
- regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8;
-
- regs->ssc_control = config->ssc_center ? SSC_CENTER : 0;
-
- pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n",
- regs->decimal_div_start, frac, config->frac_bits);
- pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n",
- ssc_per, (u32)ssc_step_size, config->ssc_adj_per);
-}
-
-static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll)
-{
- void __iomem *base = pll->mmio;
- struct dsi_pll_regs *regs = &pll->reg_setup;
-
- if (pll->pll_configuration.enable_ssc) {
- pr_debug("SSC is enabled\n");
-
- pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1,
- regs->ssc_stepsize_low);
- pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1,
- regs->ssc_stepsize_high);
- pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1,
- regs->ssc_div_per_low);
- pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1,
- regs->ssc_div_per_high);
- pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1,
- regs->ssc_adjper_low);
- pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1,
- regs->ssc_adjper_high);
- pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL,
- SSC_EN | regs->ssc_control);
- }
-}
-
-static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll)
-{
- void __iomem *base = pll->mmio;
-
- pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80);
- pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03);
- pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00);
- pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00);
- pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e);
- pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40);
- pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE,
- 0xba);
- pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
- pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00);
- pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1,
- 0x4c);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29);
- pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f);
-}
-
-static void dsi_pll_commit(struct dsi_pll_10nm *pll)
-{
- void __iomem *base = pll->mmio;
- struct dsi_pll_regs *reg = &pll->reg_setup;
-
- pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12);
- pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1,
- reg->decimal_div_start);
- pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1,
- reg->frac_div_start_low);
- pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1,
- reg->frac_div_start_mid);
- pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1,
- reg->frac_div_start_high);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1,
- reg->pll_lockdet_rate);
- pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06);
- pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10);
- pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS,
- reg->pll_clock_inverters);
-}
-
-static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
-
- DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate,
- parent_rate);
-
- pll_10nm->vco_current_rate = rate;
- pll_10nm->vco_ref_clk_rate = VCO_REF_CLK_RATE;
-
- dsi_pll_setup_config(pll_10nm);
-
- dsi_pll_calc_dec_frac(pll_10nm);
-
- dsi_pll_calc_ssc(pll_10nm);
-
- dsi_pll_commit(pll_10nm);
-
- dsi_pll_config_hzindep_reg(pll_10nm);
-
- dsi_pll_ssc_commit(pll_10nm);
-
- /* flush, ensure all register writes are done*/
- wmb();
-
- return 0;
-}
-
-static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll)
-{
- struct device *dev = &pll->pdev->dev;
- int rc;
- u32 status = 0;
- u32 const delay_us = 100;
- u32 const timeout_us = 5000;
-
- rc = readl_poll_timeout_atomic(pll->mmio +
- REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE,
- status,
- ((status & BIT(0)) > 0),
- delay_us,
- timeout_us);
- if (rc)
- DRM_DEV_ERROR(dev, "DSI PLL(%d) lock failed, status=0x%08x\n",
- pll->id, status);
-
- return rc;
-}
-
-static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll)
-{
- u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0);
-
- pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0);
- pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0,
- data & ~BIT(5));
- ndelay(250);
-}
-
-static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll)
-{
- u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0);
-
- pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0,
- data | BIT(5));
- pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0);
- ndelay(250);
-}
-
-static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll)
-{
- u32 data;
-
- data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
- pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1,
- data & ~BIT(5));
-}
-
-static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll)
-{
- u32 data;
-
- data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
- pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1,
- data | BIT(5));
-}
-
-static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
- struct device *dev = &pll_10nm->pdev->dev;
- int rc;
-
- dsi_pll_enable_pll_bias(pll_10nm);
- if (pll_10nm->slave)
- dsi_pll_enable_pll_bias(pll_10nm->slave);
-
- rc = dsi_pll_10nm_vco_set_rate(hw,pll_10nm->vco_current_rate, 0);
- if (rc) {
- DRM_DEV_ERROR(dev, "vco_set_rate failed, rc=%d\n", rc);
- return rc;
- }
-
- /* Start PLL */
- pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL,
- 0x01);
-
- /*
- * ensure all PLL configurations are written prior to checking
- * for PLL lock.
- */
- wmb();
-
- /* Check for PLL lock */
- rc = dsi_pll_10nm_lock_status(pll_10nm);
- if (rc) {
- DRM_DEV_ERROR(dev, "PLL(%d) lock failed\n", pll_10nm->id);
- goto error;
- }
-
- pll->pll_on = true;
-
- dsi_pll_enable_global_clk(pll_10nm);
- if (pll_10nm->slave)
- dsi_pll_enable_global_clk(pll_10nm->slave);
-
- pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL,
- 0x01);
- if (pll_10nm->slave)
- pll_write(pll_10nm->slave->phy_cmn_mmio +
- REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01);
-
-error:
- return rc;
-}
-
-static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll)
-{
- pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0);
- dsi_pll_disable_pll_bias(pll);
-}
-
-static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
-
- /*
- * To avoid any stray glitches while abruptly powering down the PLL
- * make sure to gate the clock using the clock enable bit before
- * powering down the PLL
- */
- dsi_pll_disable_global_clk(pll_10nm);
- pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0);
- dsi_pll_disable_sub(pll_10nm);
- if (pll_10nm->slave) {
- dsi_pll_disable_global_clk(pll_10nm->slave);
- dsi_pll_disable_sub(pll_10nm->slave);
- }
- /* flush, ensure all register writes are done */
- wmb();
- pll->pll_on = false;
-}
-
-static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
- struct dsi_pll_config *config = &pll_10nm->pll_configuration;
- void __iomem *base = pll_10nm->mmio;
- u64 ref_clk = pll_10nm->vco_ref_clk_rate;
- u64 vco_rate = 0x0;
- u64 multiplier;
- u32 frac;
- u32 dec;
- u64 pll_freq, tmp64;
-
- dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1);
- dec &= 0xff;
-
- frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1);
- frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) &
- 0xff) << 8);
- frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) &
- 0x3) << 16);
-
- /*
- * TODO:
- * 1. Assumes prescaler is disabled
- */
- multiplier = 1 << config->frac_bits;
- pll_freq = dec * (ref_clk * 2);
- tmp64 = (ref_clk * 2 * frac);
- pll_freq += div_u64(tmp64, multiplier);
-
- vco_rate = pll_freq;
-
- DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
- pll_10nm->id, (unsigned long)vco_rate, dec, frac);
-
- return (unsigned long)vco_rate;
-}
-
-static const struct clk_ops clk_ops_dsi_pll_10nm_vco = {
- .round_rate = msm_dsi_pll_helper_clk_round_rate,
- .set_rate = dsi_pll_10nm_vco_set_rate,
- .recalc_rate = dsi_pll_10nm_vco_recalc_rate,
- .prepare = dsi_pll_10nm_vco_prepare,
- .unprepare = dsi_pll_10nm_vco_unprepare,
-};
-
-/*
- * PLL Callbacks
- */
-
-static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
- struct pll_10nm_cached_state *cached = &pll_10nm->cached_state;
- void __iomem *phy_base = pll_10nm->phy_cmn_mmio;
- u32 cmn_clk_cfg0, cmn_clk_cfg1;
-
- cached->pll_out_div = pll_read(pll_10nm->mmio +
- REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE);
- cached->pll_out_div &= 0x3;
-
- cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0);
- cached->bit_clk_div = cmn_clk_cfg0 & 0xf;
- cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4;
-
- cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
- cached->pll_mux = cmn_clk_cfg1 & 0x3;
-
- DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x",
- pll_10nm->id, cached->pll_out_div, cached->bit_clk_div,
- cached->pix_clk_div, cached->pll_mux);
-}
-
-static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
- struct pll_10nm_cached_state *cached = &pll_10nm->cached_state;
- void __iomem *phy_base = pll_10nm->phy_cmn_mmio;
- u32 val;
- int ret;
-
- val = pll_read(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE);
- val &= ~0x3;
- val |= cached->pll_out_div;
- pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val);
-
- pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0,
- cached->bit_clk_div | (cached->pix_clk_div << 4));
-
- val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1);
- val &= ~0x3;
- val |= cached->pll_mux;
- pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val);
-
- ret = dsi_pll_10nm_vco_set_rate(&pll->clk_hw, pll_10nm->vco_current_rate, pll_10nm->vco_ref_clk_rate);
- if (ret) {
- DRM_DEV_ERROR(&pll_10nm->pdev->dev,
- "restore vco rate failed. ret=%d\n", ret);
- return ret;
- }
-
- DBG("DSI PLL%d", pll_10nm->id);
-
- return 0;
-}
-
-static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll,
- enum msm_dsi_phy_usecase uc)
-{
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
- void __iomem *base = pll_10nm->phy_cmn_mmio;
- u32 data = 0x0; /* internal PLL */
-
- DBG("DSI PLL%d", pll_10nm->id);
-
- switch (uc) {
- case MSM_DSI_PHY_STANDALONE:
- break;
- case MSM_DSI_PHY_MASTER:
- pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX];
- break;
- case MSM_DSI_PHY_SLAVE:
- data = 0x1; /* external PLL */
- break;
- default:
- return -EINVAL;
- }
-
- /* set PLL src */
- pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2));
-
- pll_10nm->uc = uc;
-
- return 0;
-}
-
-static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll,
- struct clk **byte_clk_provider,
- struct clk **pixel_clk_provider)
-{
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
- struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data;
-
- DBG("DSI PLL%d", pll_10nm->id);
-
- if (byte_clk_provider)
- *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk;
- if (pixel_clk_provider)
- *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk;
-
- return 0;
-}
-
-static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll);
- struct device *dev = &pll_10nm->pdev->dev;
-
- DBG("DSI PLL%d", pll_10nm->id);
- of_clk_del_provider(dev->of_node);
-
- clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw);
- clk_hw_unregister_mux(pll_10nm->pclk_mux_hw);
- clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw);
- clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw);
- clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw);
- clk_hw_unregister_divider(pll_10nm->bit_clk_hw);
- clk_hw_unregister_divider(pll_10nm->out_div_clk_hw);
- clk_hw_unregister(&pll_10nm->base.clk_hw);
-}
-
-/*
- * The post dividers and mux clocks are created using the standard divider and
- * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux
- * state to follow the master PLL's divider/mux state. Therefore, we don't
- * require special clock ops that also configure the slave PLL registers
- */
-static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm)
-{
- char clk_name[32], parent[32], vco_name[32];
- char parent2[32], parent3[32], parent4[32];
- struct clk_init_data vco_init = {
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .name = vco_name,
- .flags = CLK_IGNORE_UNUSED,
- .ops = &clk_ops_dsi_pll_10nm_vco,
- };
- struct device *dev = &pll_10nm->pdev->dev;
- struct clk_hw_onecell_data *hw_data;
- struct clk_hw *hw;
- int ret;
-
- DBG("DSI%d", pll_10nm->id);
-
- hw_data = devm_kzalloc(dev, sizeof(*hw_data) +
- NUM_PROVIDED_CLKS * sizeof(struct clk_hw *),
- GFP_KERNEL);
- if (!hw_data)
- return -ENOMEM;
-
- snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id);
- pll_10nm->base.clk_hw.init = &vco_init;
-
- ret = clk_hw_register(dev, &pll_10nm->base.clk_hw);
- if (ret)
- return ret;
-
- snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
- snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id);
-
- hw = clk_hw_register_divider(dev, clk_name,
- parent, CLK_SET_RATE_PARENT,
- pll_10nm->mmio +
- REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE,
- 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_base_clk_hw;
- }
-
- pll_10nm->out_div_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
- snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
-
- /* BIT CLK: DIV_CTRL_3_0 */
- hw = clk_hw_register_divider(dev, clk_name, parent,
- CLK_SET_RATE_PARENT,
- pll_10nm->phy_cmn_mmio +
- REG_DSI_10nm_PHY_CMN_CLK_CFG0,
- 0, 4, CLK_DIVIDER_ONE_BASED,
- &pll_10nm->postdiv_lock);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_out_div_clk_hw;
- }
-
- pll_10nm->bit_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->id);
- snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
-
- /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
- CLK_SET_RATE_PARENT, 1, 8);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_bit_clk_hw;
- }
-
- pll_10nm->byte_clk_hw = hw;
- hw_data->hws[DSI_BYTE_PLL_CLK] = hw;
-
- snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id);
- snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
-
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
- 0, 1, 2);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_byte_clk_hw;
- }
-
- pll_10nm->by_2_bit_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id);
- snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
-
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
- 0, 1, 4);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_by_2_bit_clk_hw;
- }
-
- pll_10nm->post_out_div_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id);
- snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id);
- snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id);
- snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id);
- snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id);
-
- hw = clk_hw_register_mux(dev, clk_name,
- ((const char *[]){
- parent, parent2, parent3, parent4
- }), 4, 0, pll_10nm->phy_cmn_mmio +
- REG_DSI_10nm_PHY_CMN_CLK_CFG1,
- 0, 2, 0, NULL);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_post_out_div_clk_hw;
- }
-
- pll_10nm->pclk_mux_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->id);
- snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id);
-
- /* PIX CLK DIV : DIV_CTRL_7_4*/
- hw = clk_hw_register_divider(dev, clk_name, parent,
- 0, pll_10nm->phy_cmn_mmio +
- REG_DSI_10nm_PHY_CMN_CLK_CFG0,
- 4, 4, CLK_DIVIDER_ONE_BASED,
- &pll_10nm->postdiv_lock);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_pclk_mux_hw;
- }
-
- pll_10nm->out_dsiclk_hw = hw;
- hw_data->hws[DSI_PIXEL_PLL_CLK] = hw;
-
- hw_data->num = NUM_PROVIDED_CLKS;
- pll_10nm->hw_data = hw_data;
-
- ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
- pll_10nm->hw_data);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
- goto err_dsiclk_hw;
- }
-
- return 0;
-
-err_dsiclk_hw:
- clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw);
-err_pclk_mux_hw:
- clk_hw_unregister_mux(pll_10nm->pclk_mux_hw);
-err_post_out_div_clk_hw:
- clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw);
-err_by_2_bit_clk_hw:
- clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw);
-err_byte_clk_hw:
- clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw);
-err_bit_clk_hw:
- clk_hw_unregister_divider(pll_10nm->bit_clk_hw);
-err_out_div_clk_hw:
- clk_hw_unregister_divider(pll_10nm->out_div_clk_hw);
-err_base_clk_hw:
- clk_hw_unregister(&pll_10nm->base.clk_hw);
-
- return ret;
-}
-
-struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id)
-{
- struct dsi_pll_10nm *pll_10nm;
- struct msm_dsi_pll *pll;
- int ret;
-
- pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL);
- if (!pll_10nm)
- return ERR_PTR(-ENOMEM);
-
- DBG("DSI PLL%d", id);
-
- pll_10nm->pdev = pdev;
- pll_10nm->id = id;
- pll_10nm_list[id] = pll_10nm;
-
- pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
- if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n");
- return ERR_PTR(-ENOMEM);
- }
-
- pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
- if (IS_ERR_OR_NULL(pll_10nm->mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n");
- return ERR_PTR(-ENOMEM);
- }
-
- spin_lock_init(&pll_10nm->postdiv_lock);
-
- pll = &pll_10nm->base;
- pll->min_rate = 1000000000UL;
- pll->max_rate = 3500000000UL;
- pll->get_provider = dsi_pll_10nm_get_provider;
- pll->destroy = dsi_pll_10nm_destroy;
- pll->save_state = dsi_pll_10nm_save_state;
- pll->restore_state = dsi_pll_10nm_restore_state;
- pll->set_usecase = dsi_pll_10nm_set_usecase;
-
- pll_10nm->vco_delay = 1;
-
- ret = pll_10nm_register(pll_10nm);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- /* TODO: Remove this when we have proper display handover support */
- msm_dsi_pll_save_state(pll);
-
- return pll;
-}
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c
deleted file mode 100644
index f847376d501e..000000000000
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c
+++ /dev/null
@@ -1,1096 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-
-#include "dsi_pll.h"
-#include "dsi.xml.h"
-
-/*
- * DSI PLL 14nm - clock diagram (eg: DSI0):
- *
- * dsi0n1_postdiv_clk
- * |
- * |
- * +----+ | +----+
- * dsi0vco_clk ---| n1 |--o--| /8 |-- dsi0pllbyte
- * +----+ | +----+
- * | dsi0n1_postdivby2_clk
- * | +----+ |
- * o---| /2 |--o--|\
- * | +----+ | \ +----+
- * | | |--| n2 |-- dsi0pll
- * o--------------| / +----+
- * |/
- */
-
-#define POLL_MAX_READS 15
-#define POLL_TIMEOUT_US 1000
-
-#define NUM_PROVIDED_CLKS 2
-
-#define VCO_REF_CLK_RATE 19200000
-#define VCO_MIN_RATE 1300000000UL
-#define VCO_MAX_RATE 2600000000UL
-
-#define DSI_BYTE_PLL_CLK 0
-#define DSI_PIXEL_PLL_CLK 1
-
-#define DSI_PLL_DEFAULT_VCO_POSTDIV 1
-
-struct dsi_pll_input {
- u32 fref; /* reference clk */
- u32 fdata; /* bit clock rate */
- u32 dsiclk_sel; /* Mux configuration (see diagram) */
- u32 ssc_en; /* SSC enable/disable */
- u32 ldo_en;
-
- /* fixed params */
- u32 refclk_dbler_en;
- u32 vco_measure_time;
- u32 kvco_measure_time;
- u32 bandgap_timer;
- u32 pll_wakeup_timer;
- u32 plllock_cnt;
- u32 plllock_rng;
- u32 ssc_center;
- u32 ssc_adj_period;
- u32 ssc_spread;
- u32 ssc_freq;
- u32 pll_ie_trim;
- u32 pll_ip_trim;
- u32 pll_iptat_trim;
- u32 pll_cpcset_cur;
- u32 pll_cpmset_cur;
-
- u32 pll_icpmset;
- u32 pll_icpcset;
-
- u32 pll_icpmset_p;
- u32 pll_icpmset_m;
-
- u32 pll_icpcset_p;
- u32 pll_icpcset_m;
-
- u32 pll_lpf_res1;
- u32 pll_lpf_cap1;
- u32 pll_lpf_cap2;
- u32 pll_c3ctrl;
- u32 pll_r3ctrl;
-};
-
-struct dsi_pll_output {
- u32 pll_txclk_en;
- u32 dec_start;
- u32 div_frac_start;
- u32 ssc_period;
- u32 ssc_step_size;
- u32 plllock_cmp;
- u32 pll_vco_div_ref;
- u32 pll_vco_count;
- u32 pll_kvco_div_ref;
- u32 pll_kvco_count;
- u32 pll_misc1;
- u32 pll_lpf2_postdiv;
- u32 pll_resetsm_cntrl;
- u32 pll_resetsm_cntrl2;
- u32 pll_resetsm_cntrl5;
- u32 pll_kvco_code;
-
- u32 cmn_clk_cfg0;
- u32 cmn_clk_cfg1;
- u32 cmn_ldo_cntrl;
-
- u32 pll_postdiv;
- u32 fcvo;
-};
-
-struct pll_14nm_cached_state {
- unsigned long vco_rate;
- u8 n2postdiv;
- u8 n1postdiv;
-};
-
-struct dsi_pll_14nm {
- struct msm_dsi_pll base;
-
- int id;
- struct platform_device *pdev;
-
- void __iomem *phy_cmn_mmio;
- void __iomem *mmio;
-
- int vco_delay;
-
- struct dsi_pll_input in;
- struct dsi_pll_output out;
-
- /* protects REG_DSI_14nm_PHY_CMN_CLK_CFG0 register */
- spinlock_t postdiv_lock;
-
- u64 vco_current_rate;
- u64 vco_ref_clk_rate;
-
- /* private clocks: */
- struct clk_hw *hws[NUM_DSI_CLOCKS_MAX];
- u32 num_hws;
-
- /* clock-provider: */
- struct clk_hw_onecell_data *hw_data;
-
- struct pll_14nm_cached_state cached_state;
-
- enum msm_dsi_phy_usecase uc;
- struct dsi_pll_14nm *slave;
-};
-
-#define to_pll_14nm(x) container_of(x, struct dsi_pll_14nm, base)
-
-/*
- * Private struct for N1/N2 post-divider clocks. These clocks are similar to
- * the generic clk_divider class of clocks. The only difference is that it
- * also sets the slave DSI PLL's post-dividers if in Dual DSI mode
- */
-struct dsi_pll_14nm_postdiv {
- struct clk_hw hw;
-
- /* divider params */
- u8 shift;
- u8 width;
- u8 flags; /* same flags as used by clk_divider struct */
-
- struct dsi_pll_14nm *pll;
-};
-
-#define to_pll_14nm_postdiv(_hw) container_of(_hw, struct dsi_pll_14nm_postdiv, hw)
-
-/*
- * Global list of private DSI PLL struct pointers. We need this for Dual DSI
- * mode, where the master PLL's clk_ops needs access the slave's private data
- */
-static struct dsi_pll_14nm *pll_14nm_list[DSI_MAX];
-
-static bool pll_14nm_poll_for_ready(struct dsi_pll_14nm *pll_14nm,
- u32 nb_tries, u32 timeout_us)
-{
- bool pll_locked = false;
- void __iomem *base = pll_14nm->mmio;
- u32 tries, val;
-
- tries = nb_tries;
- while (tries--) {
- val = pll_read(base +
- REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS);
- pll_locked = !!(val & BIT(5));
-
- if (pll_locked)
- break;
-
- udelay(timeout_us);
- }
-
- if (!pll_locked) {
- tries = nb_tries;
- while (tries--) {
- val = pll_read(base +
- REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS);
- pll_locked = !!(val & BIT(0));
-
- if (pll_locked)
- break;
-
- udelay(timeout_us);
- }
- }
-
- DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
-
- return pll_locked;
-}
-
-static void dsi_pll_14nm_input_init(struct dsi_pll_14nm *pll)
-{
- pll->in.fref = pll->vco_ref_clk_rate;
- pll->in.fdata = 0;
- pll->in.dsiclk_sel = 1; /* Use the /2 path in Mux */
- pll->in.ldo_en = 0; /* disabled for now */
-
- /* fixed input */
- pll->in.refclk_dbler_en = 0;
- pll->in.vco_measure_time = 5;
- pll->in.kvco_measure_time = 5;
- pll->in.bandgap_timer = 4;
- pll->in.pll_wakeup_timer = 5;
- pll->in.plllock_cnt = 1;
- pll->in.plllock_rng = 0;
-
- /*
- * SSC is enabled by default. We might need DT props for configuring
- * some SSC params like PPM and center/down spread etc.
- */
- pll->in.ssc_en = 1;
- pll->in.ssc_center = 0; /* down spread by default */
- pll->in.ssc_spread = 5; /* PPM / 1000 */
- pll->in.ssc_freq = 31500; /* default recommended */
- pll->in.ssc_adj_period = 37;
-
- pll->in.pll_ie_trim = 4;
- pll->in.pll_ip_trim = 4;
- pll->in.pll_cpcset_cur = 1;
- pll->in.pll_cpmset_cur = 1;
- pll->in.pll_icpmset = 4;
- pll->in.pll_icpcset = 4;
- pll->in.pll_icpmset_p = 0;
- pll->in.pll_icpmset_m = 0;
- pll->in.pll_icpcset_p = 0;
- pll->in.pll_icpcset_m = 0;
- pll->in.pll_lpf_res1 = 3;
- pll->in.pll_lpf_cap1 = 11;
- pll->in.pll_lpf_cap2 = 1;
- pll->in.pll_iptat_trim = 7;
- pll->in.pll_c3ctrl = 2;
- pll->in.pll_r3ctrl = 1;
-}
-
-#define CEIL(x, y) (((x) + ((y) - 1)) / (y))
-
-static void pll_14nm_ssc_calc(struct dsi_pll_14nm *pll)
-{
- u32 period, ssc_period;
- u32 ref, rem;
- u64 step_size;
-
- DBG("vco=%lld ref=%lld", pll->vco_current_rate, pll->vco_ref_clk_rate);
-
- ssc_period = pll->in.ssc_freq / 500;
- period = (u32)pll->vco_ref_clk_rate / 1000;
- ssc_period = CEIL(period, ssc_period);
- ssc_period -= 1;
- pll->out.ssc_period = ssc_period;
-
- DBG("ssc freq=%d spread=%d period=%d", pll->in.ssc_freq,
- pll->in.ssc_spread, pll->out.ssc_period);
-
- step_size = (u32)pll->vco_current_rate;
- ref = pll->vco_ref_clk_rate;
- ref /= 1000;
- step_size = div_u64(step_size, ref);
- step_size <<= 20;
- step_size = div_u64(step_size, 1000);
- step_size *= pll->in.ssc_spread;
- step_size = div_u64(step_size, 1000);
- step_size *= (pll->in.ssc_adj_period + 1);
-
- rem = 0;
- step_size = div_u64_rem(step_size, ssc_period + 1, &rem);
- if (rem)
- step_size++;
-
- DBG("step_size=%lld", step_size);
-
- step_size &= 0x0ffff; /* take lower 16 bits */
-
- pll->out.ssc_step_size = step_size;
-}
-
-static void pll_14nm_dec_frac_calc(struct dsi_pll_14nm *pll)
-{
- struct dsi_pll_input *pin = &pll->in;
- struct dsi_pll_output *pout = &pll->out;
- u64 multiplier = BIT(20);
- u64 dec_start_multiple, dec_start, pll_comp_val;
- u32 duration, div_frac_start;
- u64 vco_clk_rate = pll->vco_current_rate;
- u64 fref = pll->vco_ref_clk_rate;
-
- DBG("vco_clk_rate=%lld ref_clk_rate=%lld", vco_clk_rate, fref);
-
- dec_start_multiple = div_u64(vco_clk_rate * multiplier, fref);
- div_u64_rem(dec_start_multiple, multiplier, &div_frac_start);
-
- dec_start = div_u64(dec_start_multiple, multiplier);
-
- pout->dec_start = (u32)dec_start;
- pout->div_frac_start = div_frac_start;
-
- if (pin->plllock_cnt == 0)
- duration = 1024;
- else if (pin->plllock_cnt == 1)
- duration = 256;
- else if (pin->plllock_cnt == 2)
- duration = 128;
- else
- duration = 32;
-
- pll_comp_val = duration * dec_start_multiple;
- pll_comp_val = div_u64(pll_comp_val, multiplier);
- do_div(pll_comp_val, 10);
-
- pout->plllock_cmp = (u32)pll_comp_val;
-
- pout->pll_txclk_en = 1;
- pout->cmn_ldo_cntrl = 0x3c;
-}
-
-static u32 pll_14nm_kvco_slop(u32 vrate)
-{
- u32 slop = 0;
-
- if (vrate > VCO_MIN_RATE && vrate <= 1800000000UL)
- slop = 600;
- else if (vrate > 1800000000UL && vrate < 2300000000UL)
- slop = 400;
- else if (vrate > 2300000000UL && vrate < VCO_MAX_RATE)
- slop = 280;
-
- return slop;
-}
-
-static void pll_14nm_calc_vco_count(struct dsi_pll_14nm *pll)
-{
- struct dsi_pll_input *pin = &pll->in;
- struct dsi_pll_output *pout = &pll->out;
- u64 vco_clk_rate = pll->vco_current_rate;
- u64 fref = pll->vco_ref_clk_rate;
- u64 data;
- u32 cnt;
-
- data = fref * pin->vco_measure_time;
- do_div(data, 1000000);
- data &= 0x03ff; /* 10 bits */
- data -= 2;
- pout->pll_vco_div_ref = data;
-
- data = div_u64(vco_clk_rate, 1000000); /* unit is Mhz */
- data *= pin->vco_measure_time;
- do_div(data, 10);
- pout->pll_vco_count = data;
-
- data = fref * pin->kvco_measure_time;
- do_div(data, 1000000);
- data &= 0x03ff; /* 10 bits */
- data -= 1;
- pout->pll_kvco_div_ref = data;
-
- cnt = pll_14nm_kvco_slop(vco_clk_rate);
- cnt *= 2;
- cnt /= 100;
- cnt *= pin->kvco_measure_time;
- pout->pll_kvco_count = cnt;
-
- pout->pll_misc1 = 16;
- pout->pll_resetsm_cntrl = 48;
- pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3;
- pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer;
- pout->pll_kvco_code = 0;
-}
-
-static void pll_db_commit_ssc(struct dsi_pll_14nm *pll)
-{
- void __iomem *base = pll->mmio;
- struct dsi_pll_input *pin = &pll->in;
- struct dsi_pll_output *pout = &pll->out;
- u8 data;
-
- data = pin->ssc_adj_period;
- data &= 0x0ff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER1, data);
- data = (pin->ssc_adj_period >> 8);
- data &= 0x03;
- pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER2, data);
-
- data = pout->ssc_period;
- data &= 0x0ff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER1, data);
- data = (pout->ssc_period >> 8);
- data &= 0x0ff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER2, data);
-
- data = pout->ssc_step_size;
- data &= 0x0ff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE1, data);
- data = (pout->ssc_step_size >> 8);
- data &= 0x0ff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE2, data);
-
- data = (pin->ssc_center & 0x01);
- data <<= 1;
- data |= 0x01; /* enable */
- pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_EN_CENTER, data);
-
- wmb(); /* make sure register committed */
-}
-
-static void pll_db_commit_common(struct dsi_pll_14nm *pll,
- struct dsi_pll_input *pin,
- struct dsi_pll_output *pout)
-{
- void __iomem *base = pll->mmio;
- u8 data;
-
- /* confgiure the non frequency dependent pll registers */
- data = 0;
- pll_write(base + REG_DSI_14nm_PHY_PLL_SYSCLK_EN_RESET, data);
-
- data = pout->pll_txclk_en;
- pll_write(base + REG_DSI_14nm_PHY_PLL_TXCLK_EN, data);
-
- data = pout->pll_resetsm_cntrl;
- pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL, data);
- data = pout->pll_resetsm_cntrl2;
- pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL2, data);
- data = pout->pll_resetsm_cntrl5;
- pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL5, data);
-
- data = pout->pll_vco_div_ref & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF1, data);
- data = (pout->pll_vco_div_ref >> 8) & 0x3;
- pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF2, data);
-
- data = pout->pll_kvco_div_ref & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF1, data);
- data = (pout->pll_kvco_div_ref >> 8) & 0x3;
- pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF2, data);
-
- data = pout->pll_misc1;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_MISC1, data);
-
- data = pin->pll_ie_trim;
- pll_write(base + REG_DSI_14nm_PHY_PLL_IE_TRIM, data);
-
- data = pin->pll_ip_trim;
- pll_write(base + REG_DSI_14nm_PHY_PLL_IP_TRIM, data);
-
- data = pin->pll_cpmset_cur << 3 | pin->pll_cpcset_cur;
- pll_write(base + REG_DSI_14nm_PHY_PLL_CP_SET_CUR, data);
-
- data = pin->pll_icpcset_p << 3 | pin->pll_icpcset_m;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPCSET, data);
-
- data = pin->pll_icpmset_p << 3 | pin->pll_icpcset_m;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPMSET, data);
-
- data = pin->pll_icpmset << 3 | pin->pll_icpcset;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICP_SET, data);
-
- data = pin->pll_lpf_cap2 << 4 | pin->pll_lpf_cap1;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF1, data);
-
- data = pin->pll_iptat_trim;
- pll_write(base + REG_DSI_14nm_PHY_PLL_IPTAT_TRIM, data);
-
- data = pin->pll_c3ctrl | pin->pll_r3ctrl << 4;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_CRCTRL, data);
-}
-
-static void pll_14nm_software_reset(struct dsi_pll_14nm *pll_14nm)
-{
- void __iomem *cmn_base = pll_14nm->phy_cmn_mmio;
-
- /* de assert pll start and apply pll sw reset */
-
- /* stop pll */
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0);
-
- /* pll sw reset */
- pll_write_udelay(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0x20, 10);
- wmb(); /* make sure register committed */
-
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0);
- wmb(); /* make sure register committed */
-}
-
-static void pll_db_commit_14nm(struct dsi_pll_14nm *pll,
- struct dsi_pll_input *pin,
- struct dsi_pll_output *pout)
-{
- void __iomem *base = pll->mmio;
- void __iomem *cmn_base = pll->phy_cmn_mmio;
- u8 data;
-
- DBG("DSI%d PLL", pll->id);
-
- data = pout->cmn_ldo_cntrl;
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_LDO_CNTRL, data);
-
- pll_db_commit_common(pll, pin, pout);
-
- pll_14nm_software_reset(pll);
-
- data = pin->dsiclk_sel; /* set dsiclk_sel = 1 */
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG1, data);
-
- data = 0xff; /* data, clk, pll normal operation */
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_0, data);
-
- /* configure the frequency dependent pll registers */
- data = pout->dec_start;
- pll_write(base + REG_DSI_14nm_PHY_PLL_DEC_START, data);
-
- data = pout->div_frac_start & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1, data);
- data = (pout->div_frac_start >> 8) & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2, data);
- data = (pout->div_frac_start >> 16) & 0xf;
- pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3, data);
-
- data = pout->plllock_cmp & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP1, data);
-
- data = (pout->plllock_cmp >> 8) & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP2, data);
-
- data = (pout->plllock_cmp >> 16) & 0x3;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP3, data);
-
- data = pin->plllock_cnt << 1 | pin->plllock_rng << 3;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP_EN, data);
-
- data = pout->pll_vco_count & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT1, data);
- data = (pout->pll_vco_count >> 8) & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT2, data);
-
- data = pout->pll_kvco_count & 0xff;
- pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT1, data);
- data = (pout->pll_kvco_count >> 8) & 0x3;
- pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT2, data);
-
- data = (pout->pll_postdiv - 1) << 4 | pin->pll_lpf_res1;
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF2_POSTDIV, data);
-
- if (pin->ssc_en)
- pll_db_commit_ssc(pll);
-
- wmb(); /* make sure register committed */
-}
-
-/*
- * VCO clock Callbacks
- */
-static int dsi_pll_14nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- struct dsi_pll_input *pin = &pll_14nm->in;
- struct dsi_pll_output *pout = &pll_14nm->out;
-
- DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_14nm->id, rate,
- parent_rate);
-
- pll_14nm->vco_current_rate = rate;
- pll_14nm->vco_ref_clk_rate = VCO_REF_CLK_RATE;
-
- dsi_pll_14nm_input_init(pll_14nm);
-
- /*
- * This configures the post divider internal to the VCO. It's
- * fixed to divide by 1 for now.
- *
- * tx_band = pll_postdiv.
- * 0: divided by 1
- * 1: divided by 2
- * 2: divided by 4
- * 3: divided by 8
- */
- pout->pll_postdiv = DSI_PLL_DEFAULT_VCO_POSTDIV;
-
- pll_14nm_dec_frac_calc(pll_14nm);
-
- if (pin->ssc_en)
- pll_14nm_ssc_calc(pll_14nm);
-
- pll_14nm_calc_vco_count(pll_14nm);
-
- /* commit the slave DSI PLL registers if we're master. Note that we
- * don't lock the slave PLL. We just ensure that the PLL/PHY registers
- * of the master and slave are identical
- */
- if (pll_14nm->uc == MSM_DSI_PHY_MASTER) {
- struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave;
-
- pll_db_commit_14nm(pll_14nm_slave, pin, pout);
- }
-
- pll_db_commit_14nm(pll_14nm, pin, pout);
-
- return 0;
-}
-
-static unsigned long dsi_pll_14nm_vco_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- void __iomem *base = pll_14nm->mmio;
- u64 vco_rate, multiplier = BIT(20);
- u32 div_frac_start;
- u32 dec_start;
- u64 ref_clk = parent_rate;
-
- dec_start = pll_read(base + REG_DSI_14nm_PHY_PLL_DEC_START);
- dec_start &= 0x0ff;
-
- DBG("dec_start = %x", dec_start);
-
- div_frac_start = (pll_read(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3)
- & 0xf) << 16;
- div_frac_start |= (pll_read(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2)
- & 0xff) << 8;
- div_frac_start |= pll_read(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1)
- & 0xff;
-
- DBG("div_frac_start = %x", div_frac_start);
-
- vco_rate = ref_clk * dec_start;
-
- vco_rate += ((ref_clk * div_frac_start) / multiplier);
-
- /*
- * Recalculating the rate from dec_start and frac_start doesn't end up
- * the rate we originally set. Convert the freq to KHz, round it up and
- * convert it back to MHz.
- */
- vco_rate = DIV_ROUND_UP_ULL(vco_rate, 1000) * 1000;
-
- DBG("returning vco rate = %lu", (unsigned long)vco_rate);
-
- return (unsigned long)vco_rate;
-}
-
-static const struct clk_ops clk_ops_dsi_pll_14nm_vco = {
- .round_rate = msm_dsi_pll_helper_clk_round_rate,
- .set_rate = dsi_pll_14nm_vco_set_rate,
- .recalc_rate = dsi_pll_14nm_vco_recalc_rate,
- .prepare = msm_dsi_pll_helper_clk_prepare,
- .unprepare = msm_dsi_pll_helper_clk_unprepare,
-};
-
-/*
- * N1 and N2 post-divider clock callbacks
- */
-#define div_mask(width) ((1 << (width)) - 1)
-static unsigned long dsi_pll_14nm_postdiv_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw);
- struct dsi_pll_14nm *pll_14nm = postdiv->pll;
- void __iomem *base = pll_14nm->phy_cmn_mmio;
- u8 shift = postdiv->shift;
- u8 width = postdiv->width;
- u32 val;
-
- DBG("DSI%d PLL parent rate=%lu", pll_14nm->id, parent_rate);
-
- val = pll_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0) >> shift;
- val &= div_mask(width);
-
- return divider_recalc_rate(hw, parent_rate, val, NULL,
- postdiv->flags, width);
-}
-
-static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *prate)
-{
- struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw);
- struct dsi_pll_14nm *pll_14nm = postdiv->pll;
-
- DBG("DSI%d PLL parent rate=%lu", pll_14nm->id, rate);
-
- return divider_round_rate(hw, rate, prate, NULL,
- postdiv->width,
- postdiv->flags);
-}
-
-static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw);
- struct dsi_pll_14nm *pll_14nm = postdiv->pll;
- void __iomem *base = pll_14nm->phy_cmn_mmio;
- spinlock_t *lock = &pll_14nm->postdiv_lock;
- u8 shift = postdiv->shift;
- u8 width = postdiv->width;
- unsigned int value;
- unsigned long flags = 0;
- u32 val;
-
- DBG("DSI%d PLL parent rate=%lu parent rate %lu", pll_14nm->id, rate,
- parent_rate);
-
- value = divider_get_val(rate, parent_rate, NULL, postdiv->width,
- postdiv->flags);
-
- spin_lock_irqsave(lock, flags);
-
- val = pll_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0);
- val &= ~(div_mask(width) << shift);
-
- val |= value << shift;
- pll_write(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val);
-
- /* If we're master in dual DSI mode, then the slave PLL's post-dividers
- * follow the master's post dividers
- */
- if (pll_14nm->uc == MSM_DSI_PHY_MASTER) {
- struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave;
- void __iomem *slave_base = pll_14nm_slave->phy_cmn_mmio;
-
- pll_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val);
- }
-
- spin_unlock_irqrestore(lock, flags);
-
- return 0;
-}
-
-static const struct clk_ops clk_ops_dsi_pll_14nm_postdiv = {
- .recalc_rate = dsi_pll_14nm_postdiv_recalc_rate,
- .round_rate = dsi_pll_14nm_postdiv_round_rate,
- .set_rate = dsi_pll_14nm_postdiv_set_rate,
-};
-
-/*
- * PLL Callbacks
- */
-
-static int dsi_pll_14nm_enable_seq(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- void __iomem *base = pll_14nm->mmio;
- void __iomem *cmn_base = pll_14nm->phy_cmn_mmio;
- bool locked;
-
- DBG("");
-
- pll_write(base + REG_DSI_14nm_PHY_PLL_VREF_CFG1, 0x10);
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 1);
-
- locked = pll_14nm_poll_for_ready(pll_14nm, POLL_MAX_READS,
- POLL_TIMEOUT_US);
-
- if (unlikely(!locked))
- DRM_DEV_ERROR(&pll_14nm->pdev->dev, "DSI PLL lock failed\n");
- else
- DBG("DSI PLL lock success");
-
- return locked ? 0 : -EINVAL;
-}
-
-static void dsi_pll_14nm_disable_seq(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- void __iomem *cmn_base = pll_14nm->phy_cmn_mmio;
-
- DBG("");
-
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0);
-}
-
-static void dsi_pll_14nm_save_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state;
- void __iomem *cmn_base = pll_14nm->phy_cmn_mmio;
- u32 data;
-
- data = pll_read(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0);
-
- cached_state->n1postdiv = data & 0xf;
- cached_state->n2postdiv = (data >> 4) & 0xf;
-
- DBG("DSI%d PLL save state %x %x", pll_14nm->id,
- cached_state->n1postdiv, cached_state->n2postdiv);
-
- cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw);
-}
-
-static int dsi_pll_14nm_restore_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state;
- void __iomem *cmn_base = pll_14nm->phy_cmn_mmio;
- u32 data;
- int ret;
-
- ret = dsi_pll_14nm_vco_set_rate(&pll->clk_hw,
- cached_state->vco_rate, 0);
- if (ret) {
- DRM_DEV_ERROR(&pll_14nm->pdev->dev,
- "restore vco rate failed. ret=%d\n", ret);
- return ret;
- }
-
- data = cached_state->n1postdiv | (cached_state->n2postdiv << 4);
-
- DBG("DSI%d PLL restore state %x %x", pll_14nm->id,
- cached_state->n1postdiv, cached_state->n2postdiv);
-
- pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data);
-
- /* also restore post-dividers for slave DSI PLL */
- if (pll_14nm->uc == MSM_DSI_PHY_MASTER) {
- struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave;
- void __iomem *slave_base = pll_14nm_slave->phy_cmn_mmio;
-
- pll_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data);
- }
-
- return 0;
-}
-
-static int dsi_pll_14nm_set_usecase(struct msm_dsi_pll *pll,
- enum msm_dsi_phy_usecase uc)
-{
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- void __iomem *base = pll_14nm->mmio;
- u32 clkbuflr_en, bandgap = 0;
-
- switch (uc) {
- case MSM_DSI_PHY_STANDALONE:
- clkbuflr_en = 0x1;
- break;
- case MSM_DSI_PHY_MASTER:
- clkbuflr_en = 0x3;
- pll_14nm->slave = pll_14nm_list[(pll_14nm->id + 1) % DSI_MAX];
- break;
- case MSM_DSI_PHY_SLAVE:
- clkbuflr_en = 0x0;
- bandgap = 0x3;
- break;
- default:
- return -EINVAL;
- }
-
- pll_write(base + REG_DSI_14nm_PHY_PLL_CLKBUFLR_EN, clkbuflr_en);
- if (bandgap)
- pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_BANDGAP, bandgap);
-
- pll_14nm->uc = uc;
-
- return 0;
-}
-
-static int dsi_pll_14nm_get_provider(struct msm_dsi_pll *pll,
- struct clk **byte_clk_provider,
- struct clk **pixel_clk_provider)
-{
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- struct clk_hw_onecell_data *hw_data = pll_14nm->hw_data;
-
- if (byte_clk_provider)
- *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk;
- if (pixel_clk_provider)
- *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk;
-
- return 0;
-}
-
-static void dsi_pll_14nm_destroy(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll);
- struct platform_device *pdev = pll_14nm->pdev;
- int num_hws = pll_14nm->num_hws;
-
- of_clk_del_provider(pdev->dev.of_node);
-
- while (num_hws--)
- clk_hw_unregister(pll_14nm->hws[num_hws]);
-}
-
-static struct clk_hw *pll_14nm_postdiv_register(struct dsi_pll_14nm *pll_14nm,
- const char *name,
- const char *parent_name,
- unsigned long flags,
- u8 shift)
-{
- struct dsi_pll_14nm_postdiv *pll_postdiv;
- struct device *dev = &pll_14nm->pdev->dev;
- struct clk_init_data postdiv_init = {
- .parent_names = (const char *[]) { parent_name },
- .num_parents = 1,
- .name = name,
- .flags = flags,
- .ops = &clk_ops_dsi_pll_14nm_postdiv,
- };
- int ret;
-
- pll_postdiv = devm_kzalloc(dev, sizeof(*pll_postdiv), GFP_KERNEL);
- if (!pll_postdiv)
- return ERR_PTR(-ENOMEM);
-
- pll_postdiv->pll = pll_14nm;
- pll_postdiv->shift = shift;
- /* both N1 and N2 postdividers are 4 bits wide */
- pll_postdiv->width = 4;
- /* range of each divider is from 1 to 15 */
- pll_postdiv->flags = CLK_DIVIDER_ONE_BASED;
- pll_postdiv->hw.init = &postdiv_init;
-
- ret = clk_hw_register(dev, &pll_postdiv->hw);
- if (ret)
- return ERR_PTR(ret);
-
- return &pll_postdiv->hw;
-}
-
-static int pll_14nm_register(struct dsi_pll_14nm *pll_14nm)
-{
- char clk_name[32], parent[32], vco_name[32];
- struct clk_init_data vco_init = {
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .name = vco_name,
- .flags = CLK_IGNORE_UNUSED,
- .ops = &clk_ops_dsi_pll_14nm_vco,
- };
- struct device *dev = &pll_14nm->pdev->dev;
- struct clk_hw **hws = pll_14nm->hws;
- struct clk_hw_onecell_data *hw_data;
- struct clk_hw *hw;
- int num = 0;
- int ret;
-
- DBG("DSI%d", pll_14nm->id);
-
- hw_data = devm_kzalloc(dev, sizeof(*hw_data) +
- NUM_PROVIDED_CLKS * sizeof(struct clk_hw *),
- GFP_KERNEL);
- if (!hw_data)
- return -ENOMEM;
-
- snprintf(vco_name, 32, "dsi%dvco_clk", pll_14nm->id);
- pll_14nm->base.clk_hw.init = &vco_init;
-
- ret = clk_hw_register(dev, &pll_14nm->base.clk_hw);
- if (ret)
- return ret;
-
- hws[num++] = &pll_14nm->base.clk_hw;
-
- snprintf(clk_name, 32, "dsi%dn1_postdiv_clk", pll_14nm->id);
- snprintf(parent, 32, "dsi%dvco_clk", pll_14nm->id);
-
- /* N1 postdiv, bits 0-3 in REG_DSI_14nm_PHY_CMN_CLK_CFG0 */
- hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent,
- CLK_SET_RATE_PARENT, 0);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
-
- hws[num++] = hw;
-
- snprintf(clk_name, 32, "dsi%dpllbyte", pll_14nm->id);
- snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->id);
-
- /* DSI Byte clock = VCO_CLK / N1 / 8 */
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
- CLK_SET_RATE_PARENT, 1, 8);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
-
- hws[num++] = hw;
- hw_data->hws[DSI_BYTE_PLL_CLK] = hw;
-
- snprintf(clk_name, 32, "dsi%dn1_postdivby2_clk", pll_14nm->id);
- snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->id);
-
- /*
- * Skip the mux for now, force DSICLK_SEL to 1, Add a /2 divider
- * on the way. Don't let it set parent.
- */
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 2);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
-
- hws[num++] = hw;
-
- snprintf(clk_name, 32, "dsi%dpll", pll_14nm->id);
- snprintf(parent, 32, "dsi%dn1_postdivby2_clk", pll_14nm->id);
-
- /* DSI pixel clock = VCO_CLK / N1 / 2 / N2
- * This is the output of N2 post-divider, bits 4-7 in
- * REG_DSI_14nm_PHY_CMN_CLK_CFG0. Don't let it set parent.
- */
- hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, 0, 4);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
-
- hws[num++] = hw;
- hw_data->hws[DSI_PIXEL_PLL_CLK] = hw;
-
- pll_14nm->num_hws = num;
-
- hw_data->num = NUM_PROVIDED_CLKS;
- pll_14nm->hw_data = hw_data;
-
- ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
- pll_14nm->hw_data);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-struct msm_dsi_pll *msm_dsi_pll_14nm_init(struct platform_device *pdev, int id)
-{
- struct dsi_pll_14nm *pll_14nm;
- struct msm_dsi_pll *pll;
- int ret;
-
- if (!pdev)
- return ERR_PTR(-ENODEV);
-
- pll_14nm = devm_kzalloc(&pdev->dev, sizeof(*pll_14nm), GFP_KERNEL);
- if (!pll_14nm)
- return ERR_PTR(-ENOMEM);
-
- DBG("PLL%d", id);
-
- pll_14nm->pdev = pdev;
- pll_14nm->id = id;
- pll_14nm_list[id] = pll_14nm;
-
- pll_14nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
- if (IS_ERR_OR_NULL(pll_14nm->phy_cmn_mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n");
- return ERR_PTR(-ENOMEM);
- }
-
- pll_14nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
- if (IS_ERR_OR_NULL(pll_14nm->mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n");
- return ERR_PTR(-ENOMEM);
- }
-
- spin_lock_init(&pll_14nm->postdiv_lock);
-
- pll = &pll_14nm->base;
- pll->min_rate = VCO_MIN_RATE;
- pll->max_rate = VCO_MAX_RATE;
- pll->get_provider = dsi_pll_14nm_get_provider;
- pll->destroy = dsi_pll_14nm_destroy;
- pll->disable_seq = dsi_pll_14nm_disable_seq;
- pll->save_state = dsi_pll_14nm_save_state;
- pll->restore_state = dsi_pll_14nm_restore_state;
- pll->set_usecase = dsi_pll_14nm_set_usecase;
-
- pll_14nm->vco_delay = 1;
-
- pll->en_seq_cnt = 1;
- pll->enable_seqs[0] = dsi_pll_14nm_enable_seq;
-
- ret = pll_14nm_register(pll_14nm);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- return pll;
-}
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c
deleted file mode 100644
index 37a1f996a588..000000000000
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c
+++ /dev/null
@@ -1,643 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-
-#include "dsi_pll.h"
-#include "dsi.xml.h"
-
-/*
- * DSI PLL 28nm - clock diagram (eg: DSI0):
- *
- * dsi0analog_postdiv_clk
- * | dsi0indirect_path_div2_clk
- * | |
- * +------+ | +----+ | |\ dsi0byte_mux
- * dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \ |
- * | +------+ +----+ | m| | +----+
- * | | u|--o--| /4 |-- dsi0pllbyte
- * | | x| +----+
- * o--------------------------| /
- * | |/
- * | +------+
- * o----------| DIV3 |------------------------- dsi0pll
- * +------+
- */
-
-#define POLL_MAX_READS 10
-#define POLL_TIMEOUT_US 50
-
-#define NUM_PROVIDED_CLKS 2
-
-#define VCO_REF_CLK_RATE 19200000
-#define VCO_MIN_RATE 350000000
-#define VCO_MAX_RATE 750000000
-
-#define DSI_BYTE_PLL_CLK 0
-#define DSI_PIXEL_PLL_CLK 1
-
-#define LPFR_LUT_SIZE 10
-struct lpfr_cfg {
- unsigned long vco_rate;
- u32 resistance;
-};
-
-/* Loop filter resistance: */
-static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = {
- { 479500000, 8 },
- { 480000000, 11 },
- { 575500000, 8 },
- { 576000000, 12 },
- { 610500000, 8 },
- { 659500000, 9 },
- { 671500000, 10 },
- { 672000000, 14 },
- { 708500000, 10 },
- { 750000000, 11 },
-};
-
-struct pll_28nm_cached_state {
- unsigned long vco_rate;
- u8 postdiv3;
- u8 postdiv1;
- u8 byte_mux;
-};
-
-struct dsi_pll_28nm {
- struct msm_dsi_pll base;
-
- int id;
- struct platform_device *pdev;
- void __iomem *mmio;
-
- int vco_delay;
-
- /* private clocks: */
- struct clk *clks[NUM_DSI_CLOCKS_MAX];
- u32 num_clks;
-
- /* clock-provider: */
- struct clk *provided_clks[NUM_PROVIDED_CLKS];
- struct clk_onecell_data clk_data;
-
- struct pll_28nm_cached_state cached_state;
-};
-
-#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base)
-
-static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
- u32 nb_tries, u32 timeout_us)
-{
- bool pll_locked = false;
- u32 val;
-
- while (nb_tries--) {
- val = pll_read(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_STATUS);
- pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY);
-
- if (pll_locked)
- break;
-
- udelay(timeout_us);
- }
- DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
-
- return pll_locked;
-}
-
-static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm)
-{
- void __iomem *base = pll_28nm->mmio;
-
- /*
- * Add HW recommended delays after toggling the software
- * reset bit off and back on.
- */
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG,
- DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1);
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1);
-}
-
-/*
- * Clock Callbacks
- */
-static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct device *dev = &pll_28nm->pdev->dev;
- void __iomem *base = pll_28nm->mmio;
- unsigned long div_fbx1000, gen_vco_clk;
- u32 refclk_cfg, frac_n_mode, frac_n_value;
- u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
- u32 cal_cfg10, cal_cfg11;
- u32 rem;
- int i;
-
- VERB("rate=%lu, parent's=%lu", rate, parent_rate);
-
- /* Force postdiv2 to be div-4 */
- pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3);
-
- /* Configure the Loop filter resistance */
- for (i = 0; i < LPFR_LUT_SIZE; i++)
- if (rate <= lpfr_lut[i].vco_rate)
- break;
- if (i == LPFR_LUT_SIZE) {
- DRM_DEV_ERROR(dev, "unable to get loop filter resistance. vco=%lu\n",
- rate);
- return -EINVAL;
- }
- pll_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, lpfr_lut[i].resistance);
-
- /* Loop filter capacitance values : c1 and c2 */
- pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70);
- pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15);
-
- rem = rate % VCO_REF_CLK_RATE;
- if (rem) {
- refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
- frac_n_mode = 1;
- div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500);
- gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500);
- } else {
- refclk_cfg = 0x0;
- frac_n_mode = 0;
- div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000);
- gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000);
- }
-
- DBG("refclk_cfg = %d", refclk_cfg);
-
- rem = div_fbx1000 % 1000;
- frac_n_value = (rem << 16) / 1000;
-
- DBG("div_fb = %lu", div_fbx1000);
- DBG("frac_n_value = %d", frac_n_value);
-
- DBG("Generated VCO Clock: %lu", gen_vco_clk);
- rem = 0;
- sdm_cfg1 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1);
- sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK;
- if (frac_n_mode) {
- sdm_cfg0 = 0x0;
- sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0);
- sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(
- (u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
- sdm_cfg3 = frac_n_value >> 8;
- sdm_cfg2 = frac_n_value & 0xff;
- } else {
- sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP;
- sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(
- (u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
- sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0);
- sdm_cfg2 = 0;
- sdm_cfg3 = 0;
- }
-
- DBG("sdm_cfg0=%d", sdm_cfg0);
- DBG("sdm_cfg1=%d", sdm_cfg1);
- DBG("sdm_cfg2=%d", sdm_cfg2);
- DBG("sdm_cfg3=%d", sdm_cfg3);
-
- cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000));
- cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000);
- DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11);
-
- pll_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3, 0x2b);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4, 0x06);
- pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
-
- pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1);
- pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2,
- DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2));
- pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3,
- DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3));
- pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00);
-
- /* Add hardware recommended delay for correct PLL configuration */
- if (pll_28nm->vco_delay)
- udelay(pll_28nm->vco_delay);
-
- pll_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg);
- pll_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00);
- pll_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31);
- pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0, sdm_cfg0);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0, 0x12);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6, 0x30);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7, 0x00);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8, 0x60);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9, 0x00);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10, cal_cfg10 & 0xff);
- pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11, cal_cfg11 & 0xff);
- pll_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG, 0x20);
-
- return 0;
-}
-
-static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
-
- return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
- POLL_TIMEOUT_US);
-}
-
-static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- void __iomem *base = pll_28nm->mmio;
- u32 sdm0, doubler, sdm_byp_div;
- u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
- u32 ref_clk = VCO_REF_CLK_RATE;
- unsigned long vco_rate;
-
- VERB("parent_rate=%lu", parent_rate);
-
- /* Check to see if the ref clk doubler is enabled */
- doubler = pll_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) &
- DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
- ref_clk += (doubler * VCO_REF_CLK_RATE);
-
- /* see if it is integer mode or sdm mode */
- sdm0 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0);
- if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) {
- /* integer mode */
- sdm_byp_div = FIELD(
- pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0),
- DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1;
- vco_rate = ref_clk * sdm_byp_div;
- } else {
- /* sdm mode */
- sdm_dc_off = FIELD(
- pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1),
- DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET);
- DBG("sdm_dc_off = %d", sdm_dc_off);
- sdm2 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2),
- DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0);
- sdm3 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3),
- DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8);
- sdm_freq_seed = (sdm3 << 8) | sdm2;
- DBG("sdm_freq_seed = %d", sdm_freq_seed);
-
- vco_rate = (ref_clk * (sdm_dc_off + 1)) +
- mult_frac(ref_clk, sdm_freq_seed, BIT(16));
- DBG("vco rate = %lu", vco_rate);
- }
-
- DBG("returning vco rate = %lu", vco_rate);
-
- return vco_rate;
-}
-
-static const struct clk_ops clk_ops_dsi_pll_28nm_vco = {
- .round_rate = msm_dsi_pll_helper_clk_round_rate,
- .set_rate = dsi_pll_28nm_clk_set_rate,
- .recalc_rate = dsi_pll_28nm_clk_recalc_rate,
- .prepare = msm_dsi_pll_helper_clk_prepare,
- .unprepare = msm_dsi_pll_helper_clk_unprepare,
- .is_enabled = dsi_pll_28nm_clk_is_enabled,
-};
-
-/*
- * PLL Callbacks
- */
-static int dsi_pll_28nm_enable_seq_hpm(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct device *dev = &pll_28nm->pdev->dev;
- void __iomem *base = pll_28nm->mmio;
- u32 max_reads = 5, timeout_us = 100;
- bool locked;
- u32 val;
- int i;
-
- DBG("id=%d", pll_28nm->id);
-
- pll_28nm_software_reset(pll_28nm);
-
- /*
- * PLL power up sequence.
- * Add necessary delays recommended by hardware.
- */
- val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
-
- for (i = 0; i < 2; i++) {
- /* DSI Uniphy lock detect setting */
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,
- 0x0c, 100);
- pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
-
- /* poll for PLL ready status */
- locked = pll_28nm_poll_for_ready(pll_28nm,
- max_reads, timeout_us);
- if (locked)
- break;
-
- pll_28nm_software_reset(pll_28nm);
-
- /*
- * PLL power up sequence.
- * Add necessary delays recommended by hardware.
- */
- val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250);
-
- val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
- }
-
- if (unlikely(!locked))
- DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
- else
- DBG("DSI PLL Lock success");
-
- return locked ? 0 : -EINVAL;
-}
-
-static int dsi_pll_28nm_enable_seq_lp(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct device *dev = &pll_28nm->pdev->dev;
- void __iomem *base = pll_28nm->mmio;
- bool locked;
- u32 max_reads = 10, timeout_us = 50;
- u32 val;
-
- DBG("id=%d", pll_28nm->id);
-
- pll_28nm_software_reset(pll_28nm);
-
- /*
- * PLL power up sequence.
- * Add necessary delays recommended by hardware.
- */
- pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500);
-
- val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
- pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
- pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
-
- val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B |
- DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
- pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
-
- /* DSI PLL toggle lock detect setting */
- pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500);
- pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512);
-
- locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
-
- if (unlikely(!locked))
- DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
- else
- DBG("DSI PLL lock success");
-
- return locked ? 0 : -EINVAL;
-}
-
-static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
-
- DBG("id=%d", pll_28nm->id);
- pll_write(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00);
-}
-
-static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
- void __iomem *base = pll_28nm->mmio;
-
- cached_state->postdiv3 =
- pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG);
- cached_state->postdiv1 =
- pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG);
- cached_state->byte_mux = pll_read(base + REG_DSI_28nm_PHY_PLL_VREG_CFG);
- if (dsi_pll_28nm_clk_is_enabled(&pll->clk_hw))
- cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw);
- else
- cached_state->vco_rate = 0;
-}
-
-static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
- void __iomem *base = pll_28nm->mmio;
- int ret;
-
- ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
- cached_state->vco_rate, 0);
- if (ret) {
- DRM_DEV_ERROR(&pll_28nm->pdev->dev,
- "restore vco rate failed. ret=%d\n", ret);
- return ret;
- }
-
- pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
- cached_state->postdiv3);
- pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
- cached_state->postdiv1);
- pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
- cached_state->byte_mux);
-
- return 0;
-}
-
-static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll,
- struct clk **byte_clk_provider,
- struct clk **pixel_clk_provider)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
-
- if (byte_clk_provider)
- *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK];
- if (pixel_clk_provider)
- *pixel_clk_provider =
- pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK];
-
- return 0;
-}
-
-static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- int i;
-
- msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev,
- pll_28nm->clks, pll_28nm->num_clks);
-
- for (i = 0; i < NUM_PROVIDED_CLKS; i++)
- pll_28nm->provided_clks[i] = NULL;
-
- pll_28nm->num_clks = 0;
- pll_28nm->clk_data.clks = NULL;
- pll_28nm->clk_data.clk_num = 0;
-}
-
-static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
-{
- char clk_name[32], parent1[32], parent2[32], vco_name[32];
- struct clk_init_data vco_init = {
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .name = vco_name,
- .flags = CLK_IGNORE_UNUSED,
- .ops = &clk_ops_dsi_pll_28nm_vco,
- };
- struct device *dev = &pll_28nm->pdev->dev;
- struct clk **clks = pll_28nm->clks;
- struct clk **provided_clks = pll_28nm->provided_clks;
- int num = 0;
- int ret;
-
- DBG("%d", pll_28nm->id);
-
- snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id);
- pll_28nm->base.clk_hw.init = &vco_init;
- clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw);
-
- snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->id);
- snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
- clks[num++] = clk_register_divider(dev, clk_name,
- parent1, CLK_SET_RATE_PARENT,
- pll_28nm->mmio +
- REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
- 0, 4, 0, NULL);
-
- snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id);
- snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->id);
- clks[num++] = clk_register_fixed_factor(dev, clk_name,
- parent1, CLK_SET_RATE_PARENT,
- 1, 2);
-
- snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id);
- snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
- clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] =
- clk_register_divider(dev, clk_name,
- parent1, 0, pll_28nm->mmio +
- REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
- 0, 8, 0, NULL);
-
- snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->id);
- snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
- snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id);
- clks[num++] = clk_register_mux(dev, clk_name,
- ((const char *[]){
- parent1, parent2
- }), 2, CLK_SET_RATE_PARENT, pll_28nm->mmio +
- REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL);
-
- snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id);
- snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->id);
- clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] =
- clk_register_fixed_factor(dev, clk_name,
- parent1, CLK_SET_RATE_PARENT, 1, 4);
-
- pll_28nm->num_clks = num;
-
- pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS;
- pll_28nm->clk_data.clks = provided_clks;
-
- ret = of_clk_add_provider(dev->of_node,
- of_clk_src_onecell_get, &pll_28nm->clk_data);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
- enum msm_dsi_phy_type type, int id)
-{
- struct dsi_pll_28nm *pll_28nm;
- struct msm_dsi_pll *pll;
- int ret;
-
- if (!pdev)
- return ERR_PTR(-ENODEV);
-
- pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
- if (!pll_28nm)
- return ERR_PTR(-ENOMEM);
-
- pll_28nm->pdev = pdev;
- pll_28nm->id = id;
-
- pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
- if (IS_ERR_OR_NULL(pll_28nm->mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__);
- return ERR_PTR(-ENOMEM);
- }
-
- pll = &pll_28nm->base;
- pll->min_rate = VCO_MIN_RATE;
- pll->max_rate = VCO_MAX_RATE;
- pll->get_provider = dsi_pll_28nm_get_provider;
- pll->destroy = dsi_pll_28nm_destroy;
- pll->disable_seq = dsi_pll_28nm_disable_seq;
- pll->save_state = dsi_pll_28nm_save_state;
- pll->restore_state = dsi_pll_28nm_restore_state;
-
- if (type == MSM_DSI_PHY_28NM_HPM) {
- pll_28nm->vco_delay = 1;
-
- pll->en_seq_cnt = 3;
- pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_hpm;
- pll->enable_seqs[1] = dsi_pll_28nm_enable_seq_hpm;
- pll->enable_seqs[2] = dsi_pll_28nm_enable_seq_hpm;
- } else if (type == MSM_DSI_PHY_28NM_LP) {
- pll_28nm->vco_delay = 1000;
-
- pll->en_seq_cnt = 1;
- pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_lp;
- } else {
- DRM_DEV_ERROR(&pdev->dev, "phy type (%d) is not 28nm\n", type);
- return ERR_PTR(-EINVAL);
- }
-
- ret = pll_28nm_register(pll_28nm);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- return pll;
-}
-
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c
deleted file mode 100644
index a6e7a2525fe0..000000000000
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c
+++ /dev/null
@@ -1,526 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
- */
-
-#include <linux/clk-provider.h>
-
-#include "dsi_pll.h"
-#include "dsi.xml.h"
-
-/*
- * DSI PLL 28nm (8960/A family) - clock diagram (eg: DSI1):
- *
- *
- * +------+
- * dsi1vco_clk ----o-----| DIV1 |---dsi1pllbit (not exposed as clock)
- * F * byte_clk | +------+
- * | bit clock divider (F / 8)
- * |
- * | +------+
- * o-----| DIV2 |---dsi0pllbyte---o---> To byte RCG
- * | +------+ | (sets parent rate)
- * | byte clock divider (F) |
- * | |
- * | o---> To esc RCG
- * | (doesn't set parent rate)
- * |
- * | +------+
- * o-----| DIV3 |----dsi0pll------o---> To dsi RCG
- * +------+ | (sets parent rate)
- * dsi clock divider (F * magic) |
- * |
- * o---> To pixel rcg
- * (doesn't set parent rate)
- */
-
-#define POLL_MAX_READS 8000
-#define POLL_TIMEOUT_US 1
-
-#define NUM_PROVIDED_CLKS 2
-
-#define VCO_REF_CLK_RATE 27000000
-#define VCO_MIN_RATE 600000000
-#define VCO_MAX_RATE 1200000000
-
-#define DSI_BYTE_PLL_CLK 0
-#define DSI_PIXEL_PLL_CLK 1
-
-#define VCO_PREF_DIV_RATIO 27
-
-struct pll_28nm_cached_state {
- unsigned long vco_rate;
- u8 postdiv3;
- u8 postdiv2;
- u8 postdiv1;
-};
-
-struct clk_bytediv {
- struct clk_hw hw;
- void __iomem *reg;
-};
-
-struct dsi_pll_28nm {
- struct msm_dsi_pll base;
-
- int id;
- struct platform_device *pdev;
- void __iomem *mmio;
-
- /* custom byte clock divider */
- struct clk_bytediv *bytediv;
-
- /* private clocks: */
- struct clk *clks[NUM_DSI_CLOCKS_MAX];
- u32 num_clks;
-
- /* clock-provider: */
- struct clk *provided_clks[NUM_PROVIDED_CLKS];
- struct clk_onecell_data clk_data;
-
- struct pll_28nm_cached_state cached_state;
-};
-
-#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base)
-
-static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
- int nb_tries, int timeout_us)
-{
- bool pll_locked = false;
- u32 val;
-
- while (nb_tries--) {
- val = pll_read(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_RDY);
- pll_locked = !!(val & DSI_28nm_8960_PHY_PLL_RDY_PLL_RDY);
-
- if (pll_locked)
- break;
-
- udelay(timeout_us);
- }
- DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
-
- return pll_locked;
-}
-
-/*
- * Clock Callbacks
- */
-static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- void __iomem *base = pll_28nm->mmio;
- u32 val, temp, fb_divider;
-
- DBG("rate=%lu, parent's=%lu", rate, parent_rate);
-
- temp = rate / 10;
- val = VCO_REF_CLK_RATE / 10;
- fb_divider = (temp * VCO_PREF_DIV_RATIO) / val;
- fb_divider = fb_divider / 2 - 1;
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1,
- fb_divider & 0xff);
-
- val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2);
-
- val |= (fb_divider >> 8) & 0x07;
-
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2,
- val);
-
- val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3);
-
- val |= (VCO_PREF_DIV_RATIO - 1) & 0x3f;
-
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3,
- val);
-
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_6,
- 0xf);
-
- val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
- val |= 0x7 << 4;
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8,
- val);
-
- return 0;
-}
-
-static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
-
- return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
- POLL_TIMEOUT_US);
-}
-
-static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- void __iomem *base = pll_28nm->mmio;
- unsigned long vco_rate;
- u32 status, fb_divider, temp, ref_divider;
-
- VERB("parent_rate=%lu", parent_rate);
-
- status = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0);
-
- if (status & DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE) {
- fb_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1);
- fb_divider &= 0xff;
- temp = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2) & 0x07;
- fb_divider = (temp << 8) | fb_divider;
- fb_divider += 1;
-
- ref_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3);
- ref_divider &= 0x3f;
- ref_divider += 1;
-
- /* multiply by 2 */
- vco_rate = (parent_rate / ref_divider) * fb_divider * 2;
- } else {
- vco_rate = 0;
- }
-
- DBG("returning vco rate = %lu", vco_rate);
-
- return vco_rate;
-}
-
-static const struct clk_ops clk_ops_dsi_pll_28nm_vco = {
- .round_rate = msm_dsi_pll_helper_clk_round_rate,
- .set_rate = dsi_pll_28nm_clk_set_rate,
- .recalc_rate = dsi_pll_28nm_clk_recalc_rate,
- .prepare = msm_dsi_pll_helper_clk_prepare,
- .unprepare = msm_dsi_pll_helper_clk_unprepare,
- .is_enabled = dsi_pll_28nm_clk_is_enabled,
-};
-
-/*
- * Custom byte clock divier clk_ops
- *
- * This clock is the entry point to configuring the PLL. The user (dsi host)
- * will set this clock's rate to the desired byte clock rate. The VCO lock
- * frequency is a multiple of the byte clock rate. The multiplication factor
- * (shown as F in the diagram above) is a function of the byte clock rate.
- *
- * This custom divider clock ensures that its parent (VCO) is set to the
- * desired rate, and that the byte clock postdivider (POSTDIV2) is configured
- * accordingly
- */
-#define to_clk_bytediv(_hw) container_of(_hw, struct clk_bytediv, hw)
-
-static unsigned long clk_bytediv_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct clk_bytediv *bytediv = to_clk_bytediv(hw);
- unsigned int div;
-
- div = pll_read(bytediv->reg) & 0xff;
-
- return parent_rate / (div + 1);
-}
-
-/* find multiplication factor(wrt byte clock) at which the VCO should be set */
-static unsigned int get_vco_mul_factor(unsigned long byte_clk_rate)
-{
- unsigned long bit_mhz;
-
- /* convert to bit clock in Mhz */
- bit_mhz = (byte_clk_rate * 8) / 1000000;
-
- if (bit_mhz < 125)
- return 64;
- else if (bit_mhz < 250)
- return 32;
- else if (bit_mhz < 600)
- return 16;
- else
- return 8;
-}
-
-static long clk_bytediv_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- unsigned long best_parent;
- unsigned int factor;
-
- factor = get_vco_mul_factor(rate);
-
- best_parent = rate * factor;
- *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
-
- return *prate / factor;
-}
-
-static int clk_bytediv_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_bytediv *bytediv = to_clk_bytediv(hw);
- u32 val;
- unsigned int factor;
-
- factor = get_vco_mul_factor(rate);
-
- val = pll_read(bytediv->reg);
- val |= (factor - 1) & 0xff;
- pll_write(bytediv->reg, val);
-
- return 0;
-}
-
-/* Our special byte clock divider ops */
-static const struct clk_ops clk_bytediv_ops = {
- .round_rate = clk_bytediv_round_rate,
- .set_rate = clk_bytediv_set_rate,
- .recalc_rate = clk_bytediv_recalc_rate,
-};
-
-/*
- * PLL Callbacks
- */
-static int dsi_pll_28nm_enable_seq(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct device *dev = &pll_28nm->pdev->dev;
- void __iomem *base = pll_28nm->mmio;
- bool locked;
- unsigned int bit_div, byte_div;
- int max_reads = 1000, timeout_us = 100;
- u32 val;
-
- DBG("id=%d", pll_28nm->id);
-
- /*
- * before enabling the PLL, configure the bit clock divider since we
- * don't expose it as a clock to the outside world
- * 1: read back the byte clock divider that should already be set
- * 2: divide by 8 to get bit clock divider
- * 3: write it to POSTDIV1
- */
- val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9);
- byte_div = val + 1;
- bit_div = byte_div / 8;
-
- val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
- val &= ~0xf;
- val |= (bit_div - 1);
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, val);
-
- /* enable the PLL */
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0,
- DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE);
-
- locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
-
- if (unlikely(!locked))
- DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
- else
- DBG("DSI PLL lock success");
-
- return locked ? 0 : -EINVAL;
-}
-
-static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
-
- DBG("id=%d", pll_28nm->id);
- pll_write(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, 0x00);
-}
-
-static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
- void __iomem *base = pll_28nm->mmio;
-
- cached_state->postdiv3 =
- pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10);
- cached_state->postdiv2 =
- pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9);
- cached_state->postdiv1 =
- pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8);
-
- cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw);
-}
-
-static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
- struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
- void __iomem *base = pll_28nm->mmio;
- int ret;
-
- ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
- cached_state->vco_rate, 0);
- if (ret) {
- DRM_DEV_ERROR(&pll_28nm->pdev->dev,
- "restore vco rate failed. ret=%d\n", ret);
- return ret;
- }
-
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10,
- cached_state->postdiv3);
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9,
- cached_state->postdiv2);
- pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8,
- cached_state->postdiv1);
-
- return 0;
-}
-
-static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll,
- struct clk **byte_clk_provider,
- struct clk **pixel_clk_provider)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
-
- if (byte_clk_provider)
- *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK];
- if (pixel_clk_provider)
- *pixel_clk_provider =
- pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK];
-
- return 0;
-}
-
-static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
-
- msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev,
- pll_28nm->clks, pll_28nm->num_clks);
-}
-
-static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
-{
- char *clk_name, *parent_name, *vco_name;
- struct clk_init_data vco_init = {
- .parent_names = (const char *[]){ "pxo" },
- .num_parents = 1,
- .flags = CLK_IGNORE_UNUSED,
- .ops = &clk_ops_dsi_pll_28nm_vco,
- };
- struct device *dev = &pll_28nm->pdev->dev;
- struct clk **clks = pll_28nm->clks;
- struct clk **provided_clks = pll_28nm->provided_clks;
- struct clk_bytediv *bytediv;
- struct clk_init_data bytediv_init = { };
- int ret, num = 0;
-
- DBG("%d", pll_28nm->id);
-
- bytediv = devm_kzalloc(dev, sizeof(*bytediv), GFP_KERNEL);
- if (!bytediv)
- return -ENOMEM;
-
- vco_name = devm_kzalloc(dev, 32, GFP_KERNEL);
- if (!vco_name)
- return -ENOMEM;
-
- parent_name = devm_kzalloc(dev, 32, GFP_KERNEL);
- if (!parent_name)
- return -ENOMEM;
-
- clk_name = devm_kzalloc(dev, 32, GFP_KERNEL);
- if (!clk_name)
- return -ENOMEM;
-
- pll_28nm->bytediv = bytediv;
-
- snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id);
- vco_init.name = vco_name;
-
- pll_28nm->base.clk_hw.init = &vco_init;
-
- clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw);
-
- /* prepare and register bytediv */
- bytediv->hw.init = &bytediv_init;
- bytediv->reg = pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_9;
-
- snprintf(parent_name, 32, "dsi%dvco_clk", pll_28nm->id);
- snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id);
-
- bytediv_init.name = clk_name;
- bytediv_init.ops = &clk_bytediv_ops;
- bytediv_init.flags = CLK_SET_RATE_PARENT;
- bytediv_init.parent_names = (const char * const *) &parent_name;
- bytediv_init.num_parents = 1;
-
- /* DIV2 */
- clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] =
- clk_register(dev, &bytediv->hw);
-
- snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id);
- /* DIV3 */
- clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] =
- clk_register_divider(dev, clk_name,
- parent_name, 0, pll_28nm->mmio +
- REG_DSI_28nm_8960_PHY_PLL_CTRL_10,
- 0, 8, 0, NULL);
-
- pll_28nm->num_clks = num;
-
- pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS;
- pll_28nm->clk_data.clks = provided_clks;
-
- ret = of_clk_add_provider(dev->of_node,
- of_clk_src_onecell_get, &pll_28nm->clk_data);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
- int id)
-{
- struct dsi_pll_28nm *pll_28nm;
- struct msm_dsi_pll *pll;
- int ret;
-
- if (!pdev)
- return ERR_PTR(-ENODEV);
-
- pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
- if (!pll_28nm)
- return ERR_PTR(-ENOMEM);
-
- pll_28nm->pdev = pdev;
- pll_28nm->id = id + 1;
-
- pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
- if (IS_ERR_OR_NULL(pll_28nm->mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__);
- return ERR_PTR(-ENOMEM);
- }
-
- pll = &pll_28nm->base;
- pll->min_rate = VCO_MIN_RATE;
- pll->max_rate = VCO_MAX_RATE;
- pll->get_provider = dsi_pll_28nm_get_provider;
- pll->destroy = dsi_pll_28nm_destroy;
- pll->disable_seq = dsi_pll_28nm_disable_seq;
- pll->save_state = dsi_pll_28nm_save_state;
- pll->restore_state = dsi_pll_28nm_restore_state;
-
- pll->en_seq_cnt = 1;
- pll->enable_seqs[0] = dsi_pll_28nm_enable_seq;
-
- ret = pll_28nm_register(pll_28nm);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- return pll;
-}
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c
deleted file mode 100644
index e29b3bfd63d1..000000000000
--- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c
+++ /dev/null
@@ -1,913 +0,0 @@
-/*
- * SPDX-License-Identifier: GPL-2.0
- * Copyright (c) 2018, The Linux Foundation
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/iopoll.h>
-
-#include "dsi_pll.h"
-#include "dsi.xml.h"
-
-/*
- * DSI PLL 7nm - clock diagram (eg: DSI0): TODO: updated CPHY diagram
- *
- * dsi0_pll_out_div_clk dsi0_pll_bit_clk
- * | |
- * | |
- * +---------+ | +----------+ | +----+
- * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0_phy_pll_out_byteclk
- * +---------+ | +----------+ | +----+
- * | |
- * | | dsi0_pll_by_2_bit_clk
- * | | |
- * | | +----+ | |\ dsi0_pclk_mux
- * | |--| /2 |--o--| \ |
- * | | +----+ | \ | +---------+
- * | --------------| |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk
- * |------------------------------| / +---------+
- * | +-----+ | /
- * -----------| /4? |--o----------|/
- * +-----+ | |
- * | |dsiclk_sel
- * |
- * dsi0_pll_post_out_div_clk
- */
-
-#define DSI_BYTE_PLL_CLK 0
-#define DSI_PIXEL_PLL_CLK 1
-#define NUM_PROVIDED_CLKS 2
-
-#define VCO_REF_CLK_RATE 19200000
-
-struct dsi_pll_regs {
- u32 pll_prop_gain_rate;
- u32 pll_lockdet_rate;
- u32 decimal_div_start;
- u32 frac_div_start_low;
- u32 frac_div_start_mid;
- u32 frac_div_start_high;
- u32 pll_clock_inverters;
- u32 ssc_stepsize_low;
- u32 ssc_stepsize_high;
- u32 ssc_div_per_low;
- u32 ssc_div_per_high;
- u32 ssc_adjper_low;
- u32 ssc_adjper_high;
- u32 ssc_control;
-};
-
-struct dsi_pll_config {
- u32 ref_freq;
- bool div_override;
- u32 output_div;
- bool ignore_frac;
- bool disable_prescaler;
- bool enable_ssc;
- bool ssc_center;
- u32 dec_bits;
- u32 frac_bits;
- u32 lock_timer;
- u32 ssc_freq;
- u32 ssc_offset;
- u32 ssc_adj_per;
- u32 thresh_cycles;
- u32 refclk_cycles;
-};
-
-struct pll_7nm_cached_state {
- unsigned long vco_rate;
- u8 bit_clk_div;
- u8 pix_clk_div;
- u8 pll_out_div;
- u8 pll_mux;
-};
-
-struct dsi_pll_7nm {
- struct msm_dsi_pll base;
-
- int id;
- struct platform_device *pdev;
-
- void __iomem *phy_cmn_mmio;
- void __iomem *mmio;
-
- u64 vco_ref_clk_rate;
- u64 vco_current_rate;
-
- /* protects REG_DSI_7nm_PHY_CMN_CLK_CFG0 register */
- spinlock_t postdiv_lock;
-
- int vco_delay;
- struct dsi_pll_config pll_configuration;
- struct dsi_pll_regs reg_setup;
-
- /* private clocks: */
- struct clk_hw *out_div_clk_hw;
- struct clk_hw *bit_clk_hw;
- struct clk_hw *byte_clk_hw;
- struct clk_hw *by_2_bit_clk_hw;
- struct clk_hw *post_out_div_clk_hw;
- struct clk_hw *pclk_mux_hw;
- struct clk_hw *out_dsiclk_hw;
-
- /* clock-provider: */
- struct clk_hw_onecell_data *hw_data;
-
- struct pll_7nm_cached_state cached_state;
-
- enum msm_dsi_phy_usecase uc;
- struct dsi_pll_7nm *slave;
-};
-
-#define to_pll_7nm(x) container_of(x, struct dsi_pll_7nm, base)
-
-/*
- * Global list of private DSI PLL struct pointers. We need this for Dual DSI
- * mode, where the master PLL's clk_ops needs access the slave's private data
- */
-static struct dsi_pll_7nm *pll_7nm_list[DSI_MAX];
-
-static void dsi_pll_setup_config(struct dsi_pll_7nm *pll)
-{
- struct dsi_pll_config *config = &pll->pll_configuration;
-
- config->ref_freq = pll->vco_ref_clk_rate;
- config->output_div = 1;
- config->dec_bits = 8;
- config->frac_bits = 18;
- config->lock_timer = 64;
- config->ssc_freq = 31500;
- config->ssc_offset = 4800;
- config->ssc_adj_per = 2;
- config->thresh_cycles = 32;
- config->refclk_cycles = 256;
-
- config->div_override = false;
- config->ignore_frac = false;
- config->disable_prescaler = false;
-
- /* TODO: ssc enable */
- config->enable_ssc = false;
- config->ssc_center = 0;
-}
-
-static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll)
-{
- struct dsi_pll_config *config = &pll->pll_configuration;
- struct dsi_pll_regs *regs = &pll->reg_setup;
- u64 fref = pll->vco_ref_clk_rate;
- u64 pll_freq;
- u64 divider;
- u64 dec, dec_multiple;
- u32 frac;
- u64 multiplier;
-
- pll_freq = pll->vco_current_rate;
-
- if (config->disable_prescaler)
- divider = fref;
- else
- divider = fref * 2;
-
- multiplier = 1 << config->frac_bits;
- dec_multiple = div_u64(pll_freq * multiplier, divider);
- div_u64_rem(dec_multiple, multiplier, &frac);
-
- dec = div_u64(dec_multiple, multiplier);
-
- if (pll->base.type != MSM_DSI_PHY_7NM_V4_1)
- regs->pll_clock_inverters = 0x28;
- else if (pll_freq <= 1000000000ULL)
- regs->pll_clock_inverters = 0xa0;
- else if (pll_freq <= 2500000000ULL)
- regs->pll_clock_inverters = 0x20;
- else if (pll_freq <= 3020000000ULL)
- regs->pll_clock_inverters = 0x00;
- else
- regs->pll_clock_inverters = 0x40;
-
- regs->pll_lockdet_rate = config->lock_timer;
- regs->decimal_div_start = dec;
- regs->frac_div_start_low = (frac & 0xff);
- regs->frac_div_start_mid = (frac & 0xff00) >> 8;
- regs->frac_div_start_high = (frac & 0x30000) >> 16;
-}
-
-#define SSC_CENTER BIT(0)
-#define SSC_EN BIT(1)
-
-static void dsi_pll_calc_ssc(struct dsi_pll_7nm *pll)
-{
- struct dsi_pll_config *config = &pll->pll_configuration;
- struct dsi_pll_regs *regs = &pll->reg_setup;
- u32 ssc_per;
- u32 ssc_mod;
- u64 ssc_step_size;
- u64 frac;
-
- if (!config->enable_ssc) {
- DBG("SSC not enabled\n");
- return;
- }
-
- ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1;
- ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
- ssc_per -= ssc_mod;
-
- frac = regs->frac_div_start_low |
- (regs->frac_div_start_mid << 8) |
- (regs->frac_div_start_high << 16);
- ssc_step_size = regs->decimal_div_start;
- ssc_step_size *= (1 << config->frac_bits);
- ssc_step_size += frac;
- ssc_step_size *= config->ssc_offset;
- ssc_step_size *= (config->ssc_adj_per + 1);
- ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
- ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
-
- regs->ssc_div_per_low = ssc_per & 0xFF;
- regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8;
- regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF);
- regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8);
- regs->ssc_adjper_low = config->ssc_adj_per & 0xFF;
- regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8;
-
- regs->ssc_control = config->ssc_center ? SSC_CENTER : 0;
-
- pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n",
- regs->decimal_div_start, frac, config->frac_bits);
- pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n",
- ssc_per, (u32)ssc_step_size, config->ssc_adj_per);
-}
-
-static void dsi_pll_ssc_commit(struct dsi_pll_7nm *pll)
-{
- void __iomem *base = pll->mmio;
- struct dsi_pll_regs *regs = &pll->reg_setup;
-
- if (pll->pll_configuration.enable_ssc) {
- pr_debug("SSC is enabled\n");
-
- pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_LOW_1,
- regs->ssc_stepsize_low);
- pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_HIGH_1,
- regs->ssc_stepsize_high);
- pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_LOW_1,
- regs->ssc_div_per_low);
- pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_HIGH_1,
- regs->ssc_div_per_high);
- pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_LOW_1,
- regs->ssc_adjper_low);
- pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_HIGH_1,
- regs->ssc_adjper_high);
- pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_CONTROL,
- SSC_EN | regs->ssc_control);
- }
-}
-
-static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll)
-{
- void __iomem *base = pll->mmio;
- u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00;
-
- if (pll->base.type == MSM_DSI_PHY_7NM_V4_1) {
- if (pll->vco_current_rate >= 3100000000ULL)
- analog_controls_five_1 = 0x03;
-
- if (pll->vco_current_rate < 1520000000ULL)
- vco_config_1 = 0x08;
- else if (pll->vco_current_rate < 2990000000ULL)
- vco_config_1 = 0x01;
- }
-
- pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE_1,
- analog_controls_five_1);
- pll_write(base + REG_DSI_7nm_PHY_PLL_VCO_CONFIG_1, vco_config_1);
- pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE, 0x01);
- pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03);
- pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00);
- pll_write(base + REG_DSI_7nm_PHY_PLL_DSM_DIVIDER, 0x00);
- pll_write(base + REG_DSI_7nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e);
- pll_write(base + REG_DSI_7nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40);
- pll_write(base + REG_DSI_7nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba);
- pll_write(base + REG_DSI_7nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
- pll_write(base + REG_DSI_7nm_PHY_PLL_OUTDIV, 0x00);
- pll_write(base + REG_DSI_7nm_PHY_PLL_CORE_OVERRIDE, 0x00);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x0a);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_BAND_SEL_RATE_1, 0xc0);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x84);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x82);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x29);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x2f);
- pll_write(base + REG_DSI_7nm_PHY_PLL_IFILT, 0x2a);
- pll_write(base + REG_DSI_7nm_PHY_PLL_IFILT,
- pll->base.type == MSM_DSI_PHY_7NM_V4_1 ? 0x3f : 0x22);
-
- if (pll->base.type == MSM_DSI_PHY_7NM_V4_1) {
- pll_write(base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22);
- if (pll->slave)
- pll_write(pll->slave->mmio + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22);
- }
-}
-
-static void dsi_pll_commit(struct dsi_pll_7nm *pll)
-{
- void __iomem *base = pll->mmio;
- struct dsi_pll_regs *reg = &pll->reg_setup;
-
- pll_write(base + REG_DSI_7nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12);
- pll_write(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1, reg->decimal_div_start);
- pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1, reg->frac_div_start_low);
- pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1, reg->frac_div_start_mid);
- pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1, reg->frac_div_start_high);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCKDET_RATE_1, reg->pll_lockdet_rate);
- pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_DELAY, 0x06);
- pll_write(base + REG_DSI_7nm_PHY_PLL_CMODE_1, 0x10); /* TODO: 0x00 for CPHY */
- pll_write(base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS, reg->pll_clock_inverters);
-}
-
-static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
-
- DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_7nm->id, rate,
- parent_rate);
-
- pll_7nm->vco_current_rate = rate;
- pll_7nm->vco_ref_clk_rate = VCO_REF_CLK_RATE;
-
- dsi_pll_setup_config(pll_7nm);
-
- dsi_pll_calc_dec_frac(pll_7nm);
-
- dsi_pll_calc_ssc(pll_7nm);
-
- dsi_pll_commit(pll_7nm);
-
- dsi_pll_config_hzindep_reg(pll_7nm);
-
- dsi_pll_ssc_commit(pll_7nm);
-
- /* flush, ensure all register writes are done*/
- wmb();
-
- return 0;
-}
-
-static int dsi_pll_7nm_lock_status(struct dsi_pll_7nm *pll)
-{
- int rc;
- u32 status = 0;
- u32 const delay_us = 100;
- u32 const timeout_us = 5000;
-
- rc = readl_poll_timeout_atomic(pll->mmio +
- REG_DSI_7nm_PHY_PLL_COMMON_STATUS_ONE,
- status,
- ((status & BIT(0)) > 0),
- delay_us,
- timeout_us);
- if (rc)
- pr_err("DSI PLL(%d) lock failed, status=0x%08x\n",
- pll->id, status);
-
- return rc;
-}
-
-static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll)
-{
- u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0);
-
- pll_write(pll->mmio + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0);
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0, data & ~BIT(5));
- ndelay(250);
-}
-
-static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll)
-{
- u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0);
-
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0, data | BIT(5));
- pll_write(pll->mmio + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0xc0);
- ndelay(250);
-}
-
-static void dsi_pll_disable_global_clk(struct dsi_pll_7nm *pll)
-{
- u32 data;
-
- data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1, data & ~BIT(5));
-}
-
-static void dsi_pll_enable_global_clk(struct dsi_pll_7nm *pll)
-{
- u32 data;
-
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_3, 0x04);
-
- data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1,
- data | BIT(5) | BIT(4));
-}
-
-static void dsi_pll_phy_dig_reset(struct dsi_pll_7nm *pll)
-{
- /*
- * Reset the PHY digital domain. This would be needed when
- * coming out of a CX or analog rail power collapse while
- * ensuring that the pads maintain LP00 or LP11 state
- */
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, BIT(0));
- wmb(); /* Ensure that the reset is deasserted */
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, 0x0);
- wmb(); /* Ensure that the reset is deasserted */
-}
-
-static int dsi_pll_7nm_vco_prepare(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
- int rc;
-
- dsi_pll_enable_pll_bias(pll_7nm);
- if (pll_7nm->slave)
- dsi_pll_enable_pll_bias(pll_7nm->slave);
-
- /* Start PLL */
- pll_write(pll_7nm->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, 0x01);
-
- /*
- * ensure all PLL configurations are written prior to checking
- * for PLL lock.
- */
- wmb();
-
- /* Check for PLL lock */
- rc = dsi_pll_7nm_lock_status(pll_7nm);
- if (rc) {
- pr_err("PLL(%d) lock failed\n", pll_7nm->id);
- goto error;
- }
-
- pll->pll_on = true;
-
- /*
- * assert power on reset for PHY digital in case the PLL is
- * enabled after CX of analog domain power collapse. This needs
- * to be done before enabling the global clk.
- */
- dsi_pll_phy_dig_reset(pll_7nm);
- if (pll_7nm->slave)
- dsi_pll_phy_dig_reset(pll_7nm->slave);
-
- dsi_pll_enable_global_clk(pll_7nm);
- if (pll_7nm->slave)
- dsi_pll_enable_global_clk(pll_7nm->slave);
-
-error:
- return rc;
-}
-
-static void dsi_pll_disable_sub(struct dsi_pll_7nm *pll)
-{
- pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_RBUF_CTRL, 0);
- dsi_pll_disable_pll_bias(pll);
-}
-
-static void dsi_pll_7nm_vco_unprepare(struct clk_hw *hw)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
-
- /*
- * To avoid any stray glitches while abruptly powering down the PLL
- * make sure to gate the clock using the clock enable bit before
- * powering down the PLL
- */
- dsi_pll_disable_global_clk(pll_7nm);
- pll_write(pll_7nm->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, 0);
- dsi_pll_disable_sub(pll_7nm);
- if (pll_7nm->slave) {
- dsi_pll_disable_global_clk(pll_7nm->slave);
- dsi_pll_disable_sub(pll_7nm->slave);
- }
- /* flush, ensure all register writes are done */
- wmb();
- pll->pll_on = false;
-}
-
-static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
- struct dsi_pll_config *config = &pll_7nm->pll_configuration;
- void __iomem *base = pll_7nm->mmio;
- u64 ref_clk = pll_7nm->vco_ref_clk_rate;
- u64 vco_rate = 0x0;
- u64 multiplier;
- u32 frac;
- u32 dec;
- u64 pll_freq, tmp64;
-
- dec = pll_read(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1);
- dec &= 0xff;
-
- frac = pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1);
- frac |= ((pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1) &
- 0xff) << 8);
- frac |= ((pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1) &
- 0x3) << 16);
-
- /*
- * TODO:
- * 1. Assumes prescaler is disabled
- */
- multiplier = 1 << config->frac_bits;
- pll_freq = dec * (ref_clk * 2);
- tmp64 = (ref_clk * 2 * frac);
- pll_freq += div_u64(tmp64, multiplier);
-
- vco_rate = pll_freq;
-
- DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
- pll_7nm->id, (unsigned long)vco_rate, dec, frac);
-
- return (unsigned long)vco_rate;
-}
-
-static const struct clk_ops clk_ops_dsi_pll_7nm_vco = {
- .round_rate = msm_dsi_pll_helper_clk_round_rate,
- .set_rate = dsi_pll_7nm_vco_set_rate,
- .recalc_rate = dsi_pll_7nm_vco_recalc_rate,
- .prepare = dsi_pll_7nm_vco_prepare,
- .unprepare = dsi_pll_7nm_vco_unprepare,
-};
-
-/*
- * PLL Callbacks
- */
-
-static void dsi_pll_7nm_save_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
- struct pll_7nm_cached_state *cached = &pll_7nm->cached_state;
- void __iomem *phy_base = pll_7nm->phy_cmn_mmio;
- u32 cmn_clk_cfg0, cmn_clk_cfg1;
-
- cached->pll_out_div = pll_read(pll_7nm->mmio +
- REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE);
- cached->pll_out_div &= 0x3;
-
- cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0);
- cached->bit_clk_div = cmn_clk_cfg0 & 0xf;
- cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4;
-
- cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
- cached->pll_mux = cmn_clk_cfg1 & 0x3;
-
- DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x",
- pll_7nm->id, cached->pll_out_div, cached->bit_clk_div,
- cached->pix_clk_div, cached->pll_mux);
-}
-
-static int dsi_pll_7nm_restore_state(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
- struct pll_7nm_cached_state *cached = &pll_7nm->cached_state;
- void __iomem *phy_base = pll_7nm->phy_cmn_mmio;
- u32 val;
- int ret;
-
- val = pll_read(pll_7nm->mmio + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE);
- val &= ~0x3;
- val |= cached->pll_out_div;
- pll_write(pll_7nm->mmio + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, val);
-
- pll_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0,
- cached->bit_clk_div | (cached->pix_clk_div << 4));
-
- val = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1);
- val &= ~0x3;
- val |= cached->pll_mux;
- pll_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, val);
-
- ret = dsi_pll_7nm_vco_set_rate(&pll->clk_hw, pll_7nm->vco_current_rate, pll_7nm->vco_ref_clk_rate);
- if (ret) {
- DRM_DEV_ERROR(&pll_7nm->pdev->dev,
- "restore vco rate failed. ret=%d\n", ret);
- return ret;
- }
-
- DBG("DSI PLL%d", pll_7nm->id);
-
- return 0;
-}
-
-static int dsi_pll_7nm_set_usecase(struct msm_dsi_pll *pll,
- enum msm_dsi_phy_usecase uc)
-{
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
- void __iomem *base = pll_7nm->phy_cmn_mmio;
- u32 data = 0x0; /* internal PLL */
-
- DBG("DSI PLL%d", pll_7nm->id);
-
- switch (uc) {
- case MSM_DSI_PHY_STANDALONE:
- break;
- case MSM_DSI_PHY_MASTER:
- pll_7nm->slave = pll_7nm_list[(pll_7nm->id + 1) % DSI_MAX];
- break;
- case MSM_DSI_PHY_SLAVE:
- data = 0x1; /* external PLL */
- break;
- default:
- return -EINVAL;
- }
-
- /* set PLL src */
- pll_write(base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, (data << 2));
-
- pll_7nm->uc = uc;
-
- return 0;
-}
-
-static int dsi_pll_7nm_get_provider(struct msm_dsi_pll *pll,
- struct clk **byte_clk_provider,
- struct clk **pixel_clk_provider)
-{
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
- struct clk_hw_onecell_data *hw_data = pll_7nm->hw_data;
-
- DBG("DSI PLL%d", pll_7nm->id);
-
- if (byte_clk_provider)
- *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk;
- if (pixel_clk_provider)
- *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk;
-
- return 0;
-}
-
-static void dsi_pll_7nm_destroy(struct msm_dsi_pll *pll)
-{
- struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll);
- struct device *dev = &pll_7nm->pdev->dev;
-
- DBG("DSI PLL%d", pll_7nm->id);
- of_clk_del_provider(dev->of_node);
-
- clk_hw_unregister_divider(pll_7nm->out_dsiclk_hw);
- clk_hw_unregister_mux(pll_7nm->pclk_mux_hw);
- clk_hw_unregister_fixed_factor(pll_7nm->post_out_div_clk_hw);
- clk_hw_unregister_fixed_factor(pll_7nm->by_2_bit_clk_hw);
- clk_hw_unregister_fixed_factor(pll_7nm->byte_clk_hw);
- clk_hw_unregister_divider(pll_7nm->bit_clk_hw);
- clk_hw_unregister_divider(pll_7nm->out_div_clk_hw);
- clk_hw_unregister(&pll_7nm->base.clk_hw);
-}
-
-/*
- * The post dividers and mux clocks are created using the standard divider and
- * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux
- * state to follow the master PLL's divider/mux state. Therefore, we don't
- * require special clock ops that also configure the slave PLL registers
- */
-static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm)
-{
- char clk_name[32], parent[32], vco_name[32];
- char parent2[32], parent3[32], parent4[32];
- struct clk_init_data vco_init = {
- .parent_names = (const char *[]){ "bi_tcxo" },
- .num_parents = 1,
- .name = vco_name,
- .flags = CLK_IGNORE_UNUSED,
- .ops = &clk_ops_dsi_pll_7nm_vco,
- };
- struct device *dev = &pll_7nm->pdev->dev;
- struct clk_hw_onecell_data *hw_data;
- struct clk_hw *hw;
- int ret;
-
- DBG("DSI%d", pll_7nm->id);
-
- hw_data = devm_kzalloc(dev, sizeof(*hw_data) +
- NUM_PROVIDED_CLKS * sizeof(struct clk_hw *),
- GFP_KERNEL);
- if (!hw_data)
- return -ENOMEM;
-
- snprintf(vco_name, 32, "dsi%dvco_clk", pll_7nm->id);
- pll_7nm->base.clk_hw.init = &vco_init;
-
- ret = clk_hw_register(dev, &pll_7nm->base.clk_hw);
- if (ret)
- return ret;
-
- snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_7nm->id);
- snprintf(parent, 32, "dsi%dvco_clk", pll_7nm->id);
-
- hw = clk_hw_register_divider(dev, clk_name,
- parent, CLK_SET_RATE_PARENT,
- pll_7nm->mmio +
- REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE,
- 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_base_clk_hw;
- }
-
- pll_7nm->out_div_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_7nm->id);
- snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->id);
-
- /* BIT CLK: DIV_CTRL_3_0 */
- hw = clk_hw_register_divider(dev, clk_name, parent,
- CLK_SET_RATE_PARENT,
- pll_7nm->phy_cmn_mmio +
- REG_DSI_7nm_PHY_CMN_CLK_CFG0,
- 0, 4, CLK_DIVIDER_ONE_BASED,
- &pll_7nm->postdiv_lock);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_out_div_clk_hw;
- }
-
- pll_7nm->bit_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_7nm->id);
- snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id);
-
- /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
- CLK_SET_RATE_PARENT, 1, 8);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_bit_clk_hw;
- }
-
- pll_7nm->byte_clk_hw = hw;
- hw_data->hws[DSI_BYTE_PLL_CLK] = hw;
-
- snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->id);
- snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id);
-
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
- 0, 1, 2);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_byte_clk_hw;
- }
-
- pll_7nm->by_2_bit_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->id);
- snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->id);
-
- hw = clk_hw_register_fixed_factor(dev, clk_name, parent,
- 0, 1, 4);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_by_2_bit_clk_hw;
- }
-
- pll_7nm->post_out_div_clk_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_7nm->id);
- snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id);
- snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->id);
- snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_7nm->id);
- snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->id);
-
- hw = clk_hw_register_mux(dev, clk_name,
- ((const char *[]){
- parent, parent2, parent3, parent4
- }), 4, 0, pll_7nm->phy_cmn_mmio +
- REG_DSI_7nm_PHY_CMN_CLK_CFG1,
- 0, 2, 0, NULL);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_post_out_div_clk_hw;
- }
-
- pll_7nm->pclk_mux_hw = hw;
-
- snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_7nm->id);
- snprintf(parent, 32, "dsi%d_pclk_mux", pll_7nm->id);
-
- /* PIX CLK DIV : DIV_CTRL_7_4*/
- hw = clk_hw_register_divider(dev, clk_name, parent,
- 0, pll_7nm->phy_cmn_mmio +
- REG_DSI_7nm_PHY_CMN_CLK_CFG0,
- 4, 4, CLK_DIVIDER_ONE_BASED,
- &pll_7nm->postdiv_lock);
- if (IS_ERR(hw)) {
- ret = PTR_ERR(hw);
- goto err_pclk_mux_hw;
- }
-
- pll_7nm->out_dsiclk_hw = hw;
- hw_data->hws[DSI_PIXEL_PLL_CLK] = hw;
-
- hw_data->num = NUM_PROVIDED_CLKS;
- pll_7nm->hw_data = hw_data;
-
- ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
- pll_7nm->hw_data);
- if (ret) {
- DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret);
- goto err_dsiclk_hw;
- }
-
- return 0;
-
-err_dsiclk_hw:
- clk_hw_unregister_divider(pll_7nm->out_dsiclk_hw);
-err_pclk_mux_hw:
- clk_hw_unregister_mux(pll_7nm->pclk_mux_hw);
-err_post_out_div_clk_hw:
- clk_hw_unregister_fixed_factor(pll_7nm->post_out_div_clk_hw);
-err_by_2_bit_clk_hw:
- clk_hw_unregister_fixed_factor(pll_7nm->by_2_bit_clk_hw);
-err_byte_clk_hw:
- clk_hw_unregister_fixed_factor(pll_7nm->byte_clk_hw);
-err_bit_clk_hw:
- clk_hw_unregister_divider(pll_7nm->bit_clk_hw);
-err_out_div_clk_hw:
- clk_hw_unregister_divider(pll_7nm->out_div_clk_hw);
-err_base_clk_hw:
- clk_hw_unregister(&pll_7nm->base.clk_hw);
-
- return ret;
-}
-
-struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev,
- enum msm_dsi_phy_type type, int id)
-{
- struct dsi_pll_7nm *pll_7nm;
- struct msm_dsi_pll *pll;
- int ret;
-
- pll_7nm = devm_kzalloc(&pdev->dev, sizeof(*pll_7nm), GFP_KERNEL);
- if (!pll_7nm)
- return ERR_PTR(-ENOMEM);
-
- DBG("DSI PLL%d", id);
-
- pll_7nm->pdev = pdev;
- pll_7nm->id = id;
- pll_7nm_list[id] = pll_7nm;
-
- pll_7nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
- if (IS_ERR_OR_NULL(pll_7nm->phy_cmn_mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n");
- return ERR_PTR(-ENOMEM);
- }
-
- pll_7nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
- if (IS_ERR_OR_NULL(pll_7nm->mmio)) {
- DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n");
- return ERR_PTR(-ENOMEM);
- }
-
- spin_lock_init(&pll_7nm->postdiv_lock);
-
- pll = &pll_7nm->base;
- pll->min_rate = 1000000000UL;
- pll->max_rate = 3500000000UL;
- if (type == MSM_DSI_PHY_7NM_V4_1) {
- pll->min_rate = 600000000UL;
- pll->max_rate = (unsigned long)5000000000ULL;
- /* workaround for max rate overflowing on 32-bit builds: */
- pll->max_rate = max(pll->max_rate, 0xffffffffUL);
- }
- pll->get_provider = dsi_pll_7nm_get_provider;
- pll->destroy = dsi_pll_7nm_destroy;
- pll->save_state = dsi_pll_7nm_save_state;
- pll->restore_state = dsi_pll_7nm_restore_state;
- pll->set_usecase = dsi_pll_7nm_set_usecase;
-
- pll_7nm->vco_delay = 1;
-
- ret = pll_7nm_register(pll_7nm);
- if (ret) {
- DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- /* TODO: Remove this when we have proper display handover support */
- msm_dsi_pll_save_state(pll);
-
- return pll;
-}