aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHai Li <hali@codeaurora.org>2015-05-15 13:04:04 -0400
committerRob Clark <robdclark@gmail.com>2015-06-11 13:11:04 -0400
commit825637b9c06cede2a742421b0ea6f24428099af3 (patch)
treeb0195dbd6f733b19d749e31d1a0b8aba1707a1fa
parentbdc80de2a6dbaa0d08c393b4ba8912a0ad4b047f (diff)
drm/msm/dsi: Add DSI PLL clock driver support
DSI byte clock and pixel clocks are sourced from DSI PLL. This change adds the DSI PLL source clock driver under common clock framework. This change handles DSI 28nm PLL only. Signed-off-by: Hai Li <hali@codeaurora.org> Signed-off-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Stephane Viau <sviau@codeaurora.org> Signed-off-by: Wentao Xu <wentaox@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r--drivers/gpu/drm/msm/Kconfig7
-rw-r--r--drivers/gpu/drm/msm/Makefile5
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h3
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c10
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_phy.c3
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.c164
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll.h89
-rw-r--r--drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c652
8 files changed, 926 insertions, 7 deletions
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 0a6f6764a37c..08ba8d0d93f5 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -46,3 +46,10 @@ config DRM_MSM_DSI
46 Choose this option if you have a need for MIPI DSI connector 46 Choose this option if you have a need for MIPI DSI connector
47 support. 47 support.
48 48
49config DRM_MSM_DSI_PLL
50 bool "Enable DSI PLL driver in MSM DRM"
51 depends on DRM_MSM_DSI && COMMON_CLK
52 default y
53 help
54 Choose this option to enable DSI PLL driver which provides DSI
55 source clocks under common clock framework.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index ab2086783fee..16a81b94d6f0 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -1,4 +1,5 @@
1ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm 1ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm
2ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi
2 3
3msm-y := \ 4msm-y := \
4 adreno/adreno_device.o \ 5 adreno/adreno_device.o \
@@ -50,10 +51,14 @@ msm-y := \
50 51
51msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o 52msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
52msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o 53msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
54
53msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ 55msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
54 dsi/dsi_host.o \ 56 dsi/dsi_host.o \
55 dsi/dsi_manager.o \ 57 dsi/dsi_manager.o \
56 dsi/dsi_phy.o \ 58 dsi/dsi_phy.o \
57 mdp/mdp5/mdp5_cmd_encoder.o 59 mdp/mdp5/mdp5_cmd_encoder.o
58 60
61msm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \
62 dsi/pll/dsi_pll_28nm.o
63
59obj-$(CONFIG_DRM_MSM) += msm.o 64obj-$(CONFIG_DRM_MSM) += msm.o
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 10f54d4e379a..321964a6b27e 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -103,7 +103,8 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi);
103struct msm_dsi_phy; 103struct msm_dsi_phy;
104enum msm_dsi_phy_type { 104enum msm_dsi_phy_type {
105 MSM_DSI_PHY_UNKNOWN, 105 MSM_DSI_PHY_UNKNOWN,
106 MSM_DSI_PHY_28NM, 106 MSM_DSI_PHY_28NM_HPM,
107 MSM_DSI_PHY_28NM_LP,
107 MSM_DSI_PHY_MAX 108 MSM_DSI_PHY_MAX
108}; 109};
109struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev, 110struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 517e0709b77d..8a246cfa5d19 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -64,7 +64,7 @@ static const struct dsi_config dsi_cfgs[] = {
64 .major = MSM_DSI_VER_MAJOR_6G, 64 .major = MSM_DSI_VER_MAJOR_6G,
65 .minor = MSM_DSI_6G_VER_MINOR_V1_0, 65 .minor = MSM_DSI_6G_VER_MINOR_V1_0,
66 .io_offset = DSI_6G_REG_SHIFT, 66 .io_offset = DSI_6G_REG_SHIFT,
67 .phy_type = MSM_DSI_PHY_28NM, 67 .phy_type = MSM_DSI_PHY_28NM_HPM,
68 .reg_cfg = { 68 .reg_cfg = {
69 .num = 4, 69 .num = 4,
70 .regs = { 70 .regs = {
@@ -79,7 +79,7 @@ static const struct dsi_config dsi_cfgs[] = {
79 .major = MSM_DSI_VER_MAJOR_6G, 79 .major = MSM_DSI_VER_MAJOR_6G,
80 .minor = MSM_DSI_6G_VER_MINOR_V1_1, 80 .minor = MSM_DSI_6G_VER_MINOR_V1_1,
81 .io_offset = DSI_6G_REG_SHIFT, 81 .io_offset = DSI_6G_REG_SHIFT,
82 .phy_type = MSM_DSI_PHY_28NM, 82 .phy_type = MSM_DSI_PHY_28NM_HPM,
83 .reg_cfg = { 83 .reg_cfg = {
84 .num = 4, 84 .num = 4,
85 .regs = { 85 .regs = {
@@ -94,7 +94,7 @@ static const struct dsi_config dsi_cfgs[] = {
94 .major = MSM_DSI_VER_MAJOR_6G, 94 .major = MSM_DSI_VER_MAJOR_6G,
95 .minor = MSM_DSI_6G_VER_MINOR_V1_1_1, 95 .minor = MSM_DSI_6G_VER_MINOR_V1_1_1,
96 .io_offset = DSI_6G_REG_SHIFT, 96 .io_offset = DSI_6G_REG_SHIFT,
97 .phy_type = MSM_DSI_PHY_28NM, 97 .phy_type = MSM_DSI_PHY_28NM_HPM,
98 .reg_cfg = { 98 .reg_cfg = {
99 .num = 4, 99 .num = 4,
100 .regs = { 100 .regs = {
@@ -109,7 +109,7 @@ static const struct dsi_config dsi_cfgs[] = {
109 .major = MSM_DSI_VER_MAJOR_6G, 109 .major = MSM_DSI_VER_MAJOR_6G,
110 .minor = MSM_DSI_6G_VER_MINOR_V1_2, 110 .minor = MSM_DSI_6G_VER_MINOR_V1_2,
111 .io_offset = DSI_6G_REG_SHIFT, 111 .io_offset = DSI_6G_REG_SHIFT,
112 .phy_type = MSM_DSI_PHY_28NM, 112 .phy_type = MSM_DSI_PHY_28NM_HPM,
113 .reg_cfg = { 113 .reg_cfg = {
114 .num = 4, 114 .num = 4,
115 .regs = { 115 .regs = {
@@ -124,7 +124,7 @@ static const struct dsi_config dsi_cfgs[] = {
124 .major = MSM_DSI_VER_MAJOR_6G, 124 .major = MSM_DSI_VER_MAJOR_6G,
125 .minor = MSM_DSI_6G_VER_MINOR_V1_3_1, 125 .minor = MSM_DSI_6G_VER_MINOR_V1_3_1,
126 .io_offset = DSI_6G_REG_SHIFT, 126 .io_offset = DSI_6G_REG_SHIFT,
127 .phy_type = MSM_DSI_PHY_28NM, 127 .phy_type = MSM_DSI_PHY_28NM_LP,
128 .reg_cfg = { 128 .reg_cfg = {
129 .num = 4, 129 .num = 4,
130 .regs = { 130 .regs = {
diff --git a/drivers/gpu/drm/msm/dsi/dsi_phy.c b/drivers/gpu/drm/msm/dsi/dsi_phy.c
index 61af19312711..4403f38bf220 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_phy.c
@@ -311,7 +311,8 @@ struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
311 } 311 }
312 312
313 switch (type) { 313 switch (type) {
314 case MSM_DSI_PHY_28NM: 314 case MSM_DSI_PHY_28NM_HPM:
315 case MSM_DSI_PHY_28NM_LP:
315 dsi_phy_func_init(28nm); 316 dsi_phy_func_init(28nm);
316 break; 317 break;
317 default: 318 default:
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
new file mode 100644
index 000000000000..509376fdd112
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c
@@ -0,0 +1,164 @@
1/*
2 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include "dsi_pll.h"
15
16static int dsi_pll_enable(struct msm_dsi_pll *pll)
17{
18 int i, ret = 0;
19
20 /*
21 * Certain PLLs do not allow VCO rate update when it is on.
22 * Keep track of their status to turn on/off after set rate success.
23 */
24 if (unlikely(pll->pll_on))
25 return 0;
26
27 /* Try all enable sequences until one succeeds */
28 for (i = 0; i < pll->en_seq_cnt; i++) {
29 ret = pll->enable_seqs[i](pll);
30 DBG("DSI PLL %s after sequence #%d",
31 ret ? "unlocked" : "locked", i + 1);
32 if (!ret)
33 break;
34 }
35
36 if (ret) {
37 DRM_ERROR("DSI PLL failed to lock\n");
38 return ret;
39 }
40
41 pll->pll_on = true;
42
43 return 0;
44}
45
46static void dsi_pll_disable(struct msm_dsi_pll *pll)
47{
48 if (unlikely(!pll->pll_on))
49 return;
50
51 pll->disable_seq(pll);
52
53 pll->pll_on = false;
54}
55
56/*
57 * DSI PLL Helper functions
58 */
59long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
60 unsigned long rate, unsigned long *parent_rate)
61{
62 struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
63
64 if (rate < pll->min_rate)
65 return pll->min_rate;
66 else if (rate > pll->max_rate)
67 return pll->max_rate;
68 else
69 return rate;
70}
71
72int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
73{
74 struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
75 int ret;
76
77 /*
78 * Certain PLLs need to update the same VCO rate and registers
79 * after resume in suspend/resume scenario.
80 */
81 if (pll->restore_state) {
82 ret = pll->restore_state(pll);
83 if (ret)
84 goto error;
85 }
86
87 ret = dsi_pll_enable(pll);
88
89error:
90 return ret;
91}
92
93void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
94{
95 struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
96
97 if (pll->save_state)
98 pll->save_state(pll);
99
100 dsi_pll_disable(pll);
101}
102
103void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
104 struct clk **clks, u32 num_clks)
105{
106 of_clk_del_provider(pdev->dev.of_node);
107
108 if (!num_clks || !clks)
109 return;
110
111 do {
112 clk_unregister(clks[--num_clks]);
113 clks[num_clks] = NULL;
114 } while (num_clks);
115}
116
117/*
118 * DSI PLL API
119 */
120int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
121 struct clk **byte_clk_provider, struct clk **pixel_clk_provider)
122{
123 if (pll->get_provider)
124 return pll->get_provider(pll,
125 byte_clk_provider,
126 pixel_clk_provider);
127
128 return -EINVAL;
129}
130
131void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
132{
133 if (pll->destroy)
134 pll->destroy(pll);
135}
136
137struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
138 enum msm_dsi_phy_type type, int id)
139{
140 struct device *dev = &pdev->dev;
141 struct msm_dsi_pll *pll;
142
143 switch (type) {
144 case MSM_DSI_PHY_28NM_HPM:
145 case MSM_DSI_PHY_28NM_LP:
146 pll = msm_dsi_pll_28nm_init(pdev, type, id);
147 break;
148 default:
149 pll = ERR_PTR(-ENXIO);
150 break;
151 }
152
153 if (IS_ERR(pll)) {
154 dev_err(dev, "%s: failed to init DSI PLL\n", __func__);
155 return NULL;
156 }
157
158 pll->type = type;
159
160 DBG("DSI:%d PLL registered", id);
161
162 return pll;
163}
164
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
new file mode 100644
index 000000000000..5a3bb241c039
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
@@ -0,0 +1,89 @@
1/*
2 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#ifndef __DSI_PLL_H__
15#define __DSI_PLL_H__
16
17#include <linux/clk.h>
18#include <linux/clk-provider.h>
19
20#include "dsi.h"
21
22#define NUM_DSI_CLOCKS_MAX 6
23#define MAX_DSI_PLL_EN_SEQS 10
24
25struct msm_dsi_pll {
26 enum msm_dsi_phy_type type;
27
28 struct clk_hw clk_hw;
29 bool pll_on;
30
31 unsigned long min_rate;
32 unsigned long max_rate;
33 u32 en_seq_cnt;
34
35 int (*enable_seqs[MAX_DSI_PLL_EN_SEQS])(struct msm_dsi_pll *pll);
36 void (*disable_seq)(struct msm_dsi_pll *pll);
37 int (*get_provider)(struct msm_dsi_pll *pll,
38 struct clk **byte_clk_provider,
39 struct clk **pixel_clk_provider);
40 void (*destroy)(struct msm_dsi_pll *pll);
41 void (*save_state)(struct msm_dsi_pll *pll);
42 int (*restore_state)(struct msm_dsi_pll *pll);
43};
44
45#define hw_clk_to_pll(x) container_of(x, struct msm_dsi_pll, clk_hw)
46
47static inline void pll_write(void __iomem *reg, u32 data)
48{
49 msm_writel(data, reg);
50}
51
52static inline u32 pll_read(const void __iomem *reg)
53{
54 return msm_readl(reg);
55}
56
57static inline void pll_write_udelay(void __iomem *reg, u32 data, u32 delay_us)
58{
59 pll_write(reg, data);
60 udelay(delay_us);
61}
62
63static inline void pll_write_ndelay(void __iomem *reg, u32 data, u32 delay_ns)
64{
65 pll_write((reg), data);
66 ndelay(delay_ns);
67}
68
69/*
70 * DSI PLL Helper functions
71 */
72
73/* clock callbacks */
74long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
75 unsigned long rate, unsigned long *parent_rate);
76int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw);
77void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw);
78/* misc */
79void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
80 struct clk **clks, u32 num_clks);
81
82/*
83 * Initialization for Each PLL Type
84 */
85struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
86 enum msm_dsi_phy_type type, int id);
87
88#endif /* __DSI_PLL_H__ */
89
diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c
new file mode 100644
index 000000000000..eb8ac3097ff5
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c
@@ -0,0 +1,652 @@
1/*
2 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/clk.h>
15#include <linux/clk-provider.h>
16
17#include "dsi_pll.h"
18#include "dsi.xml.h"
19
20/*
21 * DSI PLL 28nm - clock diagram (eg: DSI0):
22 *
23 * dsi0analog_postdiv_clk
24 * | dsi0indirect_path_div2_clk
25 * | |
26 * +------+ | +----+ | |\ dsi0byte_mux
27 * dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \ |
28 * | +------+ +----+ | m| | +----+
29 * | | u|--o--| /4 |-- dsi0pllbyte
30 * | | x| +----+
31 * o--------------------------| /
32 * | |/
33 * | +------+
34 * o----------| DIV3 |------------------------- dsi0pll
35 * +------+
36 */
37
38#define POLL_MAX_READS 10
39#define POLL_TIMEOUT_US 50
40
41#define NUM_PROVIDED_CLKS 2
42
43#define VCO_REF_CLK_RATE 19200000
44#define VCO_MIN_RATE 350000000
45#define VCO_MAX_RATE 750000000
46
47#define DSI_BYTE_PLL_CLK 0
48#define DSI_PIXEL_PLL_CLK 1
49
50#define LPFR_LUT_SIZE 10
51struct lpfr_cfg {
52 unsigned long vco_rate;
53 u32 resistance;
54};
55
56/* Loop filter resistance: */
57static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = {
58 { 479500000, 8 },
59 { 480000000, 11 },
60 { 575500000, 8 },
61 { 576000000, 12 },
62 { 610500000, 8 },
63 { 659500000, 9 },
64 { 671500000, 10 },
65 { 672000000, 14 },
66 { 708500000, 10 },
67 { 750000000, 11 },
68};
69
70struct pll_28nm_cached_state {
71 unsigned long vco_rate;
72 u8 postdiv3;
73 u8 postdiv1;
74 u8 byte_mux;
75};
76
77struct dsi_pll_28nm {
78 struct msm_dsi_pll base;
79
80 int id;
81 struct platform_device *pdev;
82 void __iomem *mmio;
83
84 int vco_delay;
85
86 /* private clocks: */
87 struct clk *clks[NUM_DSI_CLOCKS_MAX];
88 u32 num_clks;
89
90 /* clock-provider: */
91 struct clk *provided_clks[NUM_PROVIDED_CLKS];
92 struct clk_onecell_data clk_data;
93
94 struct pll_28nm_cached_state cached_state;
95};
96
97#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base)
98
99static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
100 u32 nb_tries, u32 timeout_us)
101{
102 bool pll_locked = false;
103 u32 val;
104
105 while (nb_tries--) {
106 val = pll_read(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_STATUS);
107 pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY);
108
109 if (pll_locked)
110 break;
111
112 udelay(timeout_us);
113 }
114 DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
115
116 return pll_locked;
117}
118
119static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm)
120{
121 void __iomem *base = pll_28nm->mmio;
122
123 /*
124 * Add HW recommended delays after toggling the software
125 * reset bit off and back on.
126 */
127 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG,
128 DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1);
129 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1);
130}
131
132/*
133 * Clock Callbacks
134 */
135static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
136 unsigned long parent_rate)
137{
138 struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
139 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
140 struct device *dev = &pll_28nm->pdev->dev;
141 void __iomem *base = pll_28nm->mmio;
142 unsigned long div_fbx1000, gen_vco_clk;
143 u32 refclk_cfg, frac_n_mode, frac_n_value;
144 u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
145 u32 cal_cfg10, cal_cfg11;
146 u32 rem;
147 int i;
148
149 VERB("rate=%lu, parent's=%lu", rate, parent_rate);
150
151 /* Force postdiv2 to be div-4 */
152 pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3);
153
154 /* Configure the Loop filter resistance */
155 for (i = 0; i < LPFR_LUT_SIZE; i++)
156 if (rate <= lpfr_lut[i].vco_rate)
157 break;
158 if (i == LPFR_LUT_SIZE) {
159 dev_err(dev, "unable to get loop filter resistance. vco=%lu\n",
160 rate);
161 return -EINVAL;
162 }
163 pll_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, lpfr_lut[i].resistance);
164
165 /* Loop filter capacitance values : c1 and c2 */
166 pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70);
167 pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15);
168
169 rem = rate % VCO_REF_CLK_RATE;
170 if (rem) {
171 refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
172 frac_n_mode = 1;
173 div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500);
174 gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500);
175 } else {
176 refclk_cfg = 0x0;
177 frac_n_mode = 0;
178 div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000);
179 gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000);
180 }
181
182 DBG("refclk_cfg = %d", refclk_cfg);
183
184 rem = div_fbx1000 % 1000;
185 frac_n_value = (rem << 16) / 1000;
186
187 DBG("div_fb = %lu", div_fbx1000);
188 DBG("frac_n_value = %d", frac_n_value);
189
190 DBG("Generated VCO Clock: %lu", gen_vco_clk);
191 rem = 0;
192 sdm_cfg1 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1);
193 sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK;
194 if (frac_n_mode) {
195 sdm_cfg0 = 0x0;
196 sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0);
197 sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(
198 (u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
199 sdm_cfg3 = frac_n_value >> 8;
200 sdm_cfg2 = frac_n_value & 0xff;
201 } else {
202 sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP;
203 sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(
204 (u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
205 sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0);
206 sdm_cfg2 = 0;
207 sdm_cfg3 = 0;
208 }
209
210 DBG("sdm_cfg0=%d", sdm_cfg0);
211 DBG("sdm_cfg1=%d", sdm_cfg1);
212 DBG("sdm_cfg2=%d", sdm_cfg2);
213 DBG("sdm_cfg3=%d", sdm_cfg3);
214
215 cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000));
216 cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000);
217 DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11);
218
219 pll_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02);
220 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3, 0x2b);
221 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4, 0x06);
222 pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
223
224 pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1);
225 pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2,
226 DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2));
227 pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3,
228 DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3));
229 pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00);
230
231 /* Add hardware recommended delay for correct PLL configuration */
232 if (pll_28nm->vco_delay)
233 udelay(pll_28nm->vco_delay);
234
235 pll_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg);
236 pll_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00);
237 pll_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31);
238 pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0, sdm_cfg0);
239 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0, 0x12);
240 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6, 0x30);
241 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7, 0x00);
242 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8, 0x60);
243 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9, 0x00);
244 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10, cal_cfg10 & 0xff);
245 pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11, cal_cfg11 & 0xff);
246 pll_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG, 0x20);
247
248 return 0;
249}
250
251static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
252{
253 struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
254 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
255
256 return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
257 POLL_TIMEOUT_US);
258}
259
260static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
261 unsigned long parent_rate)
262{
263 struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
264 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
265 void __iomem *base = pll_28nm->mmio;
266 u32 sdm0, doubler, sdm_byp_div;
267 u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
268 u32 ref_clk = VCO_REF_CLK_RATE;
269 unsigned long vco_rate;
270
271 VERB("parent_rate=%lu", parent_rate);
272
273 /* Check to see if the ref clk doubler is enabled */
274 doubler = pll_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) &
275 DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
276 ref_clk += (doubler * VCO_REF_CLK_RATE);
277
278 /* see if it is integer mode or sdm mode */
279 sdm0 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0);
280 if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) {
281 /* integer mode */
282 sdm_byp_div = FIELD(
283 pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0),
284 DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1;
285 vco_rate = ref_clk * sdm_byp_div;
286 } else {
287 /* sdm mode */
288 sdm_dc_off = FIELD(
289 pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1),
290 DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET);
291 DBG("sdm_dc_off = %d", sdm_dc_off);
292 sdm2 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2),
293 DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0);
294 sdm3 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3),
295 DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8);
296 sdm_freq_seed = (sdm3 << 8) | sdm2;
297 DBG("sdm_freq_seed = %d", sdm_freq_seed);
298
299 vco_rate = (ref_clk * (sdm_dc_off + 1)) +
300 mult_frac(ref_clk, sdm_freq_seed, BIT(16));
301 DBG("vco rate = %lu", vco_rate);
302 }
303
304 DBG("returning vco rate = %lu", vco_rate);
305
306 return vco_rate;
307}
308
309static const struct clk_ops clk_ops_dsi_pll_28nm_vco = {
310 .round_rate = msm_dsi_pll_helper_clk_round_rate,
311 .set_rate = dsi_pll_28nm_clk_set_rate,
312 .recalc_rate = dsi_pll_28nm_clk_recalc_rate,
313 .prepare = msm_dsi_pll_helper_clk_prepare,
314 .unprepare = msm_dsi_pll_helper_clk_unprepare,
315 .is_enabled = dsi_pll_28nm_clk_is_enabled,
316};
317
318/*
319 * PLL Callbacks
320 */
321static int dsi_pll_28nm_enable_seq_hpm(struct msm_dsi_pll *pll)
322{
323 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
324 struct device *dev = &pll_28nm->pdev->dev;
325 void __iomem *base = pll_28nm->mmio;
326 u32 max_reads = 5, timeout_us = 100;
327 bool locked;
328 u32 val;
329 int i;
330
331 DBG("id=%d", pll_28nm->id);
332
333 pll_28nm_software_reset(pll_28nm);
334
335 /*
336 * PLL power up sequence.
337 * Add necessary delays recommended by hardware.
338 */
339 val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
340 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
341
342 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
343 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
344
345 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
346 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
347
348 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
349 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
350
351 for (i = 0; i < 2; i++) {
352 /* DSI Uniphy lock detect setting */
353 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,
354 0x0c, 100);
355 pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
356
357 /* poll for PLL ready status */
358 locked = pll_28nm_poll_for_ready(pll_28nm,
359 max_reads, timeout_us);
360 if (locked)
361 break;
362
363 pll_28nm_software_reset(pll_28nm);
364
365 /*
366 * PLL power up sequence.
367 * Add necessary delays recommended by hardware.
368 */
369 val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
370 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
371
372 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
373 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
374
375 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
376 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250);
377
378 val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
379 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
380
381 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
382 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
383
384 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
385 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
386 }
387
388 if (unlikely(!locked))
389 dev_err(dev, "DSI PLL lock failed\n");
390 else
391 DBG("DSI PLL Lock success");
392
393 return locked ? 0 : -EINVAL;
394}
395
396static int dsi_pll_28nm_enable_seq_lp(struct msm_dsi_pll *pll)
397{
398 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
399 struct device *dev = &pll_28nm->pdev->dev;
400 void __iomem *base = pll_28nm->mmio;
401 bool locked;
402 u32 max_reads = 10, timeout_us = 50;
403 u32 val;
404
405 DBG("id=%d", pll_28nm->id);
406
407 pll_28nm_software_reset(pll_28nm);
408
409 /*
410 * PLL power up sequence.
411 * Add necessary delays recommended by hardware.
412 */
413 pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500);
414
415 val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
416 pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
417
418 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
419 pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
420
421 val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B |
422 DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
423 pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
424
425 /* DSI PLL toggle lock detect setting */
426 pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500);
427 pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512);
428
429 locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
430
431 if (unlikely(!locked))
432 dev_err(dev, "DSI PLL lock failed\n");
433 else
434 DBG("DSI PLL lock success");
435
436 return locked ? 0 : -EINVAL;
437}
438
439static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll)
440{
441 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
442
443 DBG("id=%d", pll_28nm->id);
444 pll_write(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00);
445}
446
447static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll)
448{
449 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
450 struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
451 void __iomem *base = pll_28nm->mmio;
452
453 cached_state->postdiv3 =
454 pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG);
455 cached_state->postdiv1 =
456 pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG);
457 cached_state->byte_mux = pll_read(base + REG_DSI_28nm_PHY_PLL_VREG_CFG);
458 cached_state->vco_rate = __clk_get_rate(pll->clk_hw.clk);
459}
460
461static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll)
462{
463 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
464 struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
465 void __iomem *base = pll_28nm->mmio;
466 int ret;
467
468 if ((cached_state->vco_rate != 0) &&
469 (cached_state->vco_rate == __clk_get_rate(pll->clk_hw.clk))) {
470 ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw,
471 cached_state->vco_rate, 0);
472 if (ret) {
473 dev_err(&pll_28nm->pdev->dev,
474 "restore vco rate failed. ret=%d\n", ret);
475 return ret;
476 }
477
478 pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
479 cached_state->postdiv3);
480 pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
481 cached_state->postdiv1);
482 pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
483 cached_state->byte_mux);
484
485 cached_state->vco_rate = 0;
486 }
487
488 return 0;
489}
490
491static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll,
492 struct clk **byte_clk_provider,
493 struct clk **pixel_clk_provider)
494{
495 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
496
497 if (byte_clk_provider)
498 *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK];
499 if (pixel_clk_provider)
500 *pixel_clk_provider =
501 pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK];
502
503 return 0;
504}
505
506static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll)
507{
508 struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll);
509 int i;
510
511 msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev,
512 pll_28nm->clks, pll_28nm->num_clks);
513
514 for (i = 0; i < NUM_PROVIDED_CLKS; i++)
515 pll_28nm->provided_clks[i] = NULL;
516
517 pll_28nm->num_clks = 0;
518 pll_28nm->clk_data.clks = NULL;
519 pll_28nm->clk_data.clk_num = 0;
520}
521
522static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm)
523{
524 char clk_name[32], parent1[32], parent2[32], vco_name[32];
525 struct clk_init_data vco_init = {
526 .parent_names = (const char *[]){ "xo" },
527 .num_parents = 1,
528 .name = vco_name,
529 .ops = &clk_ops_dsi_pll_28nm_vco,
530 };
531 struct device *dev = &pll_28nm->pdev->dev;
532 struct clk **clks = pll_28nm->clks;
533 struct clk **provided_clks = pll_28nm->provided_clks;
534 int num = 0;
535 int ret;
536
537 DBG("%d", pll_28nm->id);
538
539 snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id);
540 pll_28nm->base.clk_hw.init = &vco_init;
541 clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw);
542
543 snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->id);
544 snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
545 clks[num++] = clk_register_divider(dev, clk_name,
546 parent1, CLK_SET_RATE_PARENT,
547 pll_28nm->mmio +
548 REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
549 0, 4, 0, NULL);
550
551 snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id);
552 snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->id);
553 clks[num++] = clk_register_fixed_factor(dev, clk_name,
554 parent1, CLK_SET_RATE_PARENT,
555 1, 2);
556
557 snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id);
558 snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
559 clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] =
560 clk_register_divider(dev, clk_name,
561 parent1, 0, pll_28nm->mmio +
562 REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
563 0, 8, 0, NULL);
564
565 snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->id);
566 snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
567 snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id);
568 clks[num++] = clk_register_mux(dev, clk_name,
569 (const char *[]){
570 parent1, parent2
571 }, 2, CLK_SET_RATE_PARENT, pll_28nm->mmio +
572 REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL);
573
574 snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id);
575 snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->id);
576 clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] =
577 clk_register_fixed_factor(dev, clk_name,
578 parent1, CLK_SET_RATE_PARENT, 1, 4);
579
580 pll_28nm->num_clks = num;
581
582 pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS;
583 pll_28nm->clk_data.clks = provided_clks;
584
585 ret = of_clk_add_provider(dev->of_node,
586 of_clk_src_onecell_get, &pll_28nm->clk_data);
587 if (ret) {
588 dev_err(dev, "failed to register clk provider: %d\n", ret);
589 return ret;
590 }
591
592 return 0;
593}
594
595struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev,
596 enum msm_dsi_phy_type type, int id)
597{
598 struct dsi_pll_28nm *pll_28nm;
599 struct msm_dsi_pll *pll;
600 int ret;
601
602 if (!pdev)
603 return ERR_PTR(-ENODEV);
604
605 pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
606 if (!pll_28nm)
607 return ERR_PTR(-ENOMEM);
608
609 pll_28nm->pdev = pdev;
610 pll_28nm->id = id;
611
612 pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL");
613 if (IS_ERR_OR_NULL(pll_28nm->mmio)) {
614 dev_err(&pdev->dev, "%s: failed to map pll base\n", __func__);
615 return ERR_PTR(-ENOMEM);
616 }
617
618 pll = &pll_28nm->base;
619 pll->min_rate = VCO_MIN_RATE;
620 pll->max_rate = VCO_MAX_RATE;
621 pll->get_provider = dsi_pll_28nm_get_provider;
622 pll->destroy = dsi_pll_28nm_destroy;
623 pll->disable_seq = dsi_pll_28nm_disable_seq;
624 pll->save_state = dsi_pll_28nm_save_state;
625 pll->restore_state = dsi_pll_28nm_restore_state;
626
627 if (type == MSM_DSI_PHY_28NM_HPM) {
628 pll_28nm->vco_delay = 1;
629
630 pll->en_seq_cnt = 3;
631 pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_hpm;
632 pll->enable_seqs[1] = dsi_pll_28nm_enable_seq_hpm;
633 pll->enable_seqs[2] = dsi_pll_28nm_enable_seq_hpm;
634 } else if (type == MSM_DSI_PHY_28NM_LP) {
635 pll_28nm->vco_delay = 1000;
636
637 pll->en_seq_cnt = 1;
638 pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_lp;
639 } else {
640 dev_err(&pdev->dev, "phy type (%d) is not 28nm\n", type);
641 return ERR_PTR(-EINVAL);
642 }
643
644 ret = pll_28nm_register(pll_28nm);
645 if (ret) {
646 dev_err(&pdev->dev, "failed to register PLL: %d\n", ret);
647 return ERR_PTR(ret);
648 }
649
650 return pll;
651}
652