197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25c829028SHai Li /*
35c829028SHai Li  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
45c829028SHai Li  */
55c829028SHai Li 
6d6d1439eSDmitry Baryshkov #include <linux/clk.h>
7d6d1439eSDmitry Baryshkov #include <linux/clk-provider.h>
8d6d1439eSDmitry Baryshkov 
95c829028SHai Li #include "dsi_phy.h"
105c829028SHai Li #include "dsi.xml.h"
115c829028SHai Li 
12d6d1439eSDmitry Baryshkov /*
13d6d1439eSDmitry Baryshkov  * DSI PLL 28nm - clock diagram (eg: DSI0):
14d6d1439eSDmitry Baryshkov  *
15d6d1439eSDmitry Baryshkov  *         dsi0analog_postdiv_clk
16d6d1439eSDmitry Baryshkov  *                             |         dsi0indirect_path_div2_clk
17d6d1439eSDmitry Baryshkov  *                             |          |
18d6d1439eSDmitry Baryshkov  *                   +------+  |  +----+  |  |\   dsi0byte_mux
19d6d1439eSDmitry Baryshkov  *  dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \   |
20d6d1439eSDmitry Baryshkov  *                |  +------+     +----+     | m|  |  +----+
21d6d1439eSDmitry Baryshkov  *                |                          | u|--o--| /4 |-- dsi0pllbyte
22d6d1439eSDmitry Baryshkov  *                |                          | x|     +----+
23d6d1439eSDmitry Baryshkov  *                o--------------------------| /
24d6d1439eSDmitry Baryshkov  *                |                          |/
25d6d1439eSDmitry Baryshkov  *                |          +------+
26d6d1439eSDmitry Baryshkov  *                o----------| DIV3 |------------------------- dsi0pll
27d6d1439eSDmitry Baryshkov  *                           +------+
28d6d1439eSDmitry Baryshkov  */
29d6d1439eSDmitry Baryshkov 
30d6d1439eSDmitry Baryshkov #define POLL_MAX_READS			10
31d6d1439eSDmitry Baryshkov #define POLL_TIMEOUT_US		50
32d6d1439eSDmitry Baryshkov 
33d6d1439eSDmitry Baryshkov #define VCO_REF_CLK_RATE		19200000
34d6d1439eSDmitry Baryshkov #define VCO_MIN_RATE			350000000
35d6d1439eSDmitry Baryshkov #define VCO_MAX_RATE			750000000
36d6d1439eSDmitry Baryshkov 
3780d2229bSDmitry Baryshkov /* v2.0.0 28nm LP implementation */
3880d2229bSDmitry Baryshkov #define DSI_PHY_28NM_QUIRK_PHY_LP	BIT(0)
3980d2229bSDmitry Baryshkov 
40d6d1439eSDmitry Baryshkov #define LPFR_LUT_SIZE			10
41d6d1439eSDmitry Baryshkov struct lpfr_cfg {
42d6d1439eSDmitry Baryshkov 	unsigned long vco_rate;
43d6d1439eSDmitry Baryshkov 	u32 resistance;
44d6d1439eSDmitry Baryshkov };
45d6d1439eSDmitry Baryshkov 
46d6d1439eSDmitry Baryshkov /* Loop filter resistance: */
47d6d1439eSDmitry Baryshkov static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = {
48d6d1439eSDmitry Baryshkov 	{ 479500000,  8 },
49d6d1439eSDmitry Baryshkov 	{ 480000000, 11 },
50d6d1439eSDmitry Baryshkov 	{ 575500000,  8 },
51d6d1439eSDmitry Baryshkov 	{ 576000000, 12 },
52d6d1439eSDmitry Baryshkov 	{ 610500000,  8 },
53d6d1439eSDmitry Baryshkov 	{ 659500000,  9 },
54d6d1439eSDmitry Baryshkov 	{ 671500000, 10 },
55d6d1439eSDmitry Baryshkov 	{ 672000000, 14 },
56d6d1439eSDmitry Baryshkov 	{ 708500000, 10 },
57d6d1439eSDmitry Baryshkov 	{ 750000000, 11 },
58d6d1439eSDmitry Baryshkov };
59d6d1439eSDmitry Baryshkov 
60d6d1439eSDmitry Baryshkov struct pll_28nm_cached_state {
61d6d1439eSDmitry Baryshkov 	unsigned long vco_rate;
62d6d1439eSDmitry Baryshkov 	u8 postdiv3;
63d6d1439eSDmitry Baryshkov 	u8 postdiv1;
64d6d1439eSDmitry Baryshkov 	u8 byte_mux;
65d6d1439eSDmitry Baryshkov };
66d6d1439eSDmitry Baryshkov 
67d6d1439eSDmitry Baryshkov struct dsi_pll_28nm {
68007687c3SDmitry Baryshkov 	struct clk_hw clk_hw;
69d6d1439eSDmitry Baryshkov 
70d6d1439eSDmitry Baryshkov 	int id;
71d6d1439eSDmitry Baryshkov 	struct platform_device *pdev;
72007687c3SDmitry Baryshkov 
73007687c3SDmitry Baryshkov 	struct msm_dsi_phy *phy;
74007687c3SDmitry Baryshkov 
75d6d1439eSDmitry Baryshkov 	struct pll_28nm_cached_state cached_state;
76d6d1439eSDmitry Baryshkov };
77d6d1439eSDmitry Baryshkov 
78007687c3SDmitry Baryshkov #define to_pll_28nm(x)	container_of(x, struct dsi_pll_28nm, clk_hw)
79d6d1439eSDmitry Baryshkov 
80d6d1439eSDmitry Baryshkov static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
81d6d1439eSDmitry Baryshkov 				u32 nb_tries, u32 timeout_us)
82d6d1439eSDmitry Baryshkov {
83d6d1439eSDmitry Baryshkov 	bool pll_locked = false;
84d6d1439eSDmitry Baryshkov 	u32 val;
85d6d1439eSDmitry Baryshkov 
86d6d1439eSDmitry Baryshkov 	while (nb_tries--) {
87*b7cf8a54SDmitry Baryshkov 		val = dsi_phy_read(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_STATUS);
88d6d1439eSDmitry Baryshkov 		pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY);
89d6d1439eSDmitry Baryshkov 
90d6d1439eSDmitry Baryshkov 		if (pll_locked)
91d6d1439eSDmitry Baryshkov 			break;
92d6d1439eSDmitry Baryshkov 
93d6d1439eSDmitry Baryshkov 		udelay(timeout_us);
94d6d1439eSDmitry Baryshkov 	}
95d6d1439eSDmitry Baryshkov 	DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
96d6d1439eSDmitry Baryshkov 
97d6d1439eSDmitry Baryshkov 	return pll_locked;
98d6d1439eSDmitry Baryshkov }
99d6d1439eSDmitry Baryshkov 
100d6d1439eSDmitry Baryshkov static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm)
101d6d1439eSDmitry Baryshkov {
102*b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
103d6d1439eSDmitry Baryshkov 
104d6d1439eSDmitry Baryshkov 	/*
105d6d1439eSDmitry Baryshkov 	 * Add HW recommended delays after toggling the software
106d6d1439eSDmitry Baryshkov 	 * reset bit off and back on.
107d6d1439eSDmitry Baryshkov 	 */
108e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG,
109d6d1439eSDmitry Baryshkov 			DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1);
110e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1);
111d6d1439eSDmitry Baryshkov }
112d6d1439eSDmitry Baryshkov 
113d6d1439eSDmitry Baryshkov /*
114d6d1439eSDmitry Baryshkov  * Clock Callbacks
115d6d1439eSDmitry Baryshkov  */
116d6d1439eSDmitry Baryshkov static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
117d6d1439eSDmitry Baryshkov 		unsigned long parent_rate)
118d6d1439eSDmitry Baryshkov {
119007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
120d6d1439eSDmitry Baryshkov 	struct device *dev = &pll_28nm->pdev->dev;
121*b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
122d6d1439eSDmitry Baryshkov 	unsigned long div_fbx1000, gen_vco_clk;
123d6d1439eSDmitry Baryshkov 	u32 refclk_cfg, frac_n_mode, frac_n_value;
124d6d1439eSDmitry Baryshkov 	u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
125d6d1439eSDmitry Baryshkov 	u32 cal_cfg10, cal_cfg11;
126d6d1439eSDmitry Baryshkov 	u32 rem;
127d6d1439eSDmitry Baryshkov 	int i;
128d6d1439eSDmitry Baryshkov 
129d6d1439eSDmitry Baryshkov 	VERB("rate=%lu, parent's=%lu", rate, parent_rate);
130d6d1439eSDmitry Baryshkov 
131d6d1439eSDmitry Baryshkov 	/* Force postdiv2 to be div-4 */
132e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3);
133d6d1439eSDmitry Baryshkov 
134d6d1439eSDmitry Baryshkov 	/* Configure the Loop filter resistance */
135d6d1439eSDmitry Baryshkov 	for (i = 0; i < LPFR_LUT_SIZE; i++)
136d6d1439eSDmitry Baryshkov 		if (rate <= lpfr_lut[i].vco_rate)
137d6d1439eSDmitry Baryshkov 			break;
138d6d1439eSDmitry Baryshkov 	if (i == LPFR_LUT_SIZE) {
139d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(dev, "unable to get loop filter resistance. vco=%lu\n",
140d6d1439eSDmitry Baryshkov 				rate);
141d6d1439eSDmitry Baryshkov 		return -EINVAL;
142d6d1439eSDmitry Baryshkov 	}
143e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, lpfr_lut[i].resistance);
144d6d1439eSDmitry Baryshkov 
145d6d1439eSDmitry Baryshkov 	/* Loop filter capacitance values : c1 and c2 */
146e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70);
147e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15);
148d6d1439eSDmitry Baryshkov 
149d6d1439eSDmitry Baryshkov 	rem = rate % VCO_REF_CLK_RATE;
150d6d1439eSDmitry Baryshkov 	if (rem) {
151d6d1439eSDmitry Baryshkov 		refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
152d6d1439eSDmitry Baryshkov 		frac_n_mode = 1;
153d6d1439eSDmitry Baryshkov 		div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500);
154d6d1439eSDmitry Baryshkov 		gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500);
155d6d1439eSDmitry Baryshkov 	} else {
156d6d1439eSDmitry Baryshkov 		refclk_cfg = 0x0;
157d6d1439eSDmitry Baryshkov 		frac_n_mode = 0;
158d6d1439eSDmitry Baryshkov 		div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000);
159d6d1439eSDmitry Baryshkov 		gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000);
160d6d1439eSDmitry Baryshkov 	}
161d6d1439eSDmitry Baryshkov 
162d6d1439eSDmitry Baryshkov 	DBG("refclk_cfg = %d", refclk_cfg);
163d6d1439eSDmitry Baryshkov 
164d6d1439eSDmitry Baryshkov 	rem = div_fbx1000 % 1000;
165d6d1439eSDmitry Baryshkov 	frac_n_value = (rem << 16) / 1000;
166d6d1439eSDmitry Baryshkov 
167d6d1439eSDmitry Baryshkov 	DBG("div_fb = %lu", div_fbx1000);
168d6d1439eSDmitry Baryshkov 	DBG("frac_n_value = %d", frac_n_value);
169d6d1439eSDmitry Baryshkov 
170d6d1439eSDmitry Baryshkov 	DBG("Generated VCO Clock: %lu", gen_vco_clk);
171d6d1439eSDmitry Baryshkov 	rem = 0;
172e55b3fbbSDmitry Baryshkov 	sdm_cfg1 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1);
173d6d1439eSDmitry Baryshkov 	sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK;
174d6d1439eSDmitry Baryshkov 	if (frac_n_mode) {
175d6d1439eSDmitry Baryshkov 		sdm_cfg0 = 0x0;
176d6d1439eSDmitry Baryshkov 		sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0);
177d6d1439eSDmitry Baryshkov 		sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(
178d6d1439eSDmitry Baryshkov 				(u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
179d6d1439eSDmitry Baryshkov 		sdm_cfg3 = frac_n_value >> 8;
180d6d1439eSDmitry Baryshkov 		sdm_cfg2 = frac_n_value & 0xff;
181d6d1439eSDmitry Baryshkov 	} else {
182d6d1439eSDmitry Baryshkov 		sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP;
183d6d1439eSDmitry Baryshkov 		sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(
184d6d1439eSDmitry Baryshkov 				(u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
185d6d1439eSDmitry Baryshkov 		sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0);
186d6d1439eSDmitry Baryshkov 		sdm_cfg2 = 0;
187d6d1439eSDmitry Baryshkov 		sdm_cfg3 = 0;
188d6d1439eSDmitry Baryshkov 	}
189d6d1439eSDmitry Baryshkov 
190d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg0=%d", sdm_cfg0);
191d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg1=%d", sdm_cfg1);
192d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg2=%d", sdm_cfg2);
193d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg3=%d", sdm_cfg3);
194d6d1439eSDmitry Baryshkov 
195d6d1439eSDmitry Baryshkov 	cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000));
196d6d1439eSDmitry Baryshkov 	cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000);
197d6d1439eSDmitry Baryshkov 	DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11);
198d6d1439eSDmitry Baryshkov 
199e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02);
200e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3,    0x2b);
201e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4,    0x06);
202e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,  0x0d);
203d6d1439eSDmitry Baryshkov 
204e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1);
205e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2,
206d6d1439eSDmitry Baryshkov 		DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2));
207e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3,
208d6d1439eSDmitry Baryshkov 		DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3));
209e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00);
210d6d1439eSDmitry Baryshkov 
211d6d1439eSDmitry Baryshkov 	/* Add hardware recommended delay for correct PLL configuration */
212007687c3SDmitry Baryshkov 	if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
21389da8153SDmitry Baryshkov 		udelay(1000);
21489da8153SDmitry Baryshkov 	else
21589da8153SDmitry Baryshkov 		udelay(1);
216d6d1439eSDmitry Baryshkov 
217e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg);
218e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00);
219e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31);
220e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0,   sdm_cfg0);
221e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0,   0x12);
222e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6,   0x30);
223e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7,   0x00);
224e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8,   0x60);
225e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9,   0x00);
226e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10,  cal_cfg10 & 0xff);
227e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11,  cal_cfg11 & 0xff);
228e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG,  0x20);
229d6d1439eSDmitry Baryshkov 
230d6d1439eSDmitry Baryshkov 	return 0;
231d6d1439eSDmitry Baryshkov }
232d6d1439eSDmitry Baryshkov 
233d6d1439eSDmitry Baryshkov static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
234d6d1439eSDmitry Baryshkov {
235007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
236d6d1439eSDmitry Baryshkov 
237d6d1439eSDmitry Baryshkov 	return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
238d6d1439eSDmitry Baryshkov 					POLL_TIMEOUT_US);
239d6d1439eSDmitry Baryshkov }
240d6d1439eSDmitry Baryshkov 
241d6d1439eSDmitry Baryshkov static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
242d6d1439eSDmitry Baryshkov 		unsigned long parent_rate)
243d6d1439eSDmitry Baryshkov {
244007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
245*b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
246d6d1439eSDmitry Baryshkov 	u32 sdm0, doubler, sdm_byp_div;
247d6d1439eSDmitry Baryshkov 	u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
248d6d1439eSDmitry Baryshkov 	u32 ref_clk = VCO_REF_CLK_RATE;
249d6d1439eSDmitry Baryshkov 	unsigned long vco_rate;
250d6d1439eSDmitry Baryshkov 
251d6d1439eSDmitry Baryshkov 	VERB("parent_rate=%lu", parent_rate);
252d6d1439eSDmitry Baryshkov 
253d6d1439eSDmitry Baryshkov 	/* Check to see if the ref clk doubler is enabled */
254e55b3fbbSDmitry Baryshkov 	doubler = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) &
255d6d1439eSDmitry Baryshkov 			DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
256d6d1439eSDmitry Baryshkov 	ref_clk += (doubler * VCO_REF_CLK_RATE);
257d6d1439eSDmitry Baryshkov 
258d6d1439eSDmitry Baryshkov 	/* see if it is integer mode or sdm mode */
259e55b3fbbSDmitry Baryshkov 	sdm0 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0);
260d6d1439eSDmitry Baryshkov 	if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) {
261d6d1439eSDmitry Baryshkov 		/* integer mode */
262d6d1439eSDmitry Baryshkov 		sdm_byp_div = FIELD(
263e55b3fbbSDmitry Baryshkov 				dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0),
264d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1;
265d6d1439eSDmitry Baryshkov 		vco_rate = ref_clk * sdm_byp_div;
266d6d1439eSDmitry Baryshkov 	} else {
267d6d1439eSDmitry Baryshkov 		/* sdm mode */
268d6d1439eSDmitry Baryshkov 		sdm_dc_off = FIELD(
269e55b3fbbSDmitry Baryshkov 				dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1),
270d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET);
271d6d1439eSDmitry Baryshkov 		DBG("sdm_dc_off = %d", sdm_dc_off);
272e55b3fbbSDmitry Baryshkov 		sdm2 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2),
273d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0);
274e55b3fbbSDmitry Baryshkov 		sdm3 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3),
275d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8);
276d6d1439eSDmitry Baryshkov 		sdm_freq_seed = (sdm3 << 8) | sdm2;
277d6d1439eSDmitry Baryshkov 		DBG("sdm_freq_seed = %d", sdm_freq_seed);
278d6d1439eSDmitry Baryshkov 
279d6d1439eSDmitry Baryshkov 		vco_rate = (ref_clk * (sdm_dc_off + 1)) +
280d6d1439eSDmitry Baryshkov 			mult_frac(ref_clk, sdm_freq_seed, BIT(16));
281d6d1439eSDmitry Baryshkov 		DBG("vco rate = %lu", vco_rate);
282d6d1439eSDmitry Baryshkov 	}
283d6d1439eSDmitry Baryshkov 
284d6d1439eSDmitry Baryshkov 	DBG("returning vco rate = %lu", vco_rate);
285d6d1439eSDmitry Baryshkov 
286d6d1439eSDmitry Baryshkov 	return vco_rate;
287d6d1439eSDmitry Baryshkov }
288d6d1439eSDmitry Baryshkov 
289007687c3SDmitry Baryshkov static int _dsi_pll_28nm_vco_prepare_hpm(struct dsi_pll_28nm *pll_28nm)
290d6d1439eSDmitry Baryshkov {
291d6d1439eSDmitry Baryshkov 	struct device *dev = &pll_28nm->pdev->dev;
292*b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
293d6d1439eSDmitry Baryshkov 	u32 max_reads = 5, timeout_us = 100;
294d6d1439eSDmitry Baryshkov 	bool locked;
295d6d1439eSDmitry Baryshkov 	u32 val;
296d6d1439eSDmitry Baryshkov 	int i;
297d6d1439eSDmitry Baryshkov 
298d6d1439eSDmitry Baryshkov 	DBG("id=%d", pll_28nm->id);
299d6d1439eSDmitry Baryshkov 
300d6d1439eSDmitry Baryshkov 	pll_28nm_software_reset(pll_28nm);
301d6d1439eSDmitry Baryshkov 
302d6d1439eSDmitry Baryshkov 	/*
303d6d1439eSDmitry Baryshkov 	 * PLL power up sequence.
304d6d1439eSDmitry Baryshkov 	 * Add necessary delays recommended by hardware.
305d6d1439eSDmitry Baryshkov 	 */
306d6d1439eSDmitry Baryshkov 	val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
307e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
308d6d1439eSDmitry Baryshkov 
309d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
310e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
311d6d1439eSDmitry Baryshkov 
312d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
313e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
314d6d1439eSDmitry Baryshkov 
315d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
316e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
317d6d1439eSDmitry Baryshkov 
318d6d1439eSDmitry Baryshkov 	for (i = 0; i < 2; i++) {
319d6d1439eSDmitry Baryshkov 		/* DSI Uniphy lock detect setting */
320e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,
321d6d1439eSDmitry Baryshkov 				0x0c, 100);
322e55b3fbbSDmitry Baryshkov 		dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
323d6d1439eSDmitry Baryshkov 
324d6d1439eSDmitry Baryshkov 		/* poll for PLL ready status */
325d6d1439eSDmitry Baryshkov 		locked = pll_28nm_poll_for_ready(pll_28nm,
326d6d1439eSDmitry Baryshkov 						max_reads, timeout_us);
327d6d1439eSDmitry Baryshkov 		if (locked)
328d6d1439eSDmitry Baryshkov 			break;
329d6d1439eSDmitry Baryshkov 
330d6d1439eSDmitry Baryshkov 		pll_28nm_software_reset(pll_28nm);
331d6d1439eSDmitry Baryshkov 
332d6d1439eSDmitry Baryshkov 		/*
333d6d1439eSDmitry Baryshkov 		 * PLL power up sequence.
334d6d1439eSDmitry Baryshkov 		 * Add necessary delays recommended by hardware.
335d6d1439eSDmitry Baryshkov 		 */
336d6d1439eSDmitry Baryshkov 		val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
337e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
338d6d1439eSDmitry Baryshkov 
339d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
340e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
341d6d1439eSDmitry Baryshkov 
342d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
343e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250);
344d6d1439eSDmitry Baryshkov 
345d6d1439eSDmitry Baryshkov 		val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
346e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
347d6d1439eSDmitry Baryshkov 
348d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
349e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
350d6d1439eSDmitry Baryshkov 
351d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
352e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
353d6d1439eSDmitry Baryshkov 	}
354d6d1439eSDmitry Baryshkov 
355d6d1439eSDmitry Baryshkov 	if (unlikely(!locked))
356d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
357d6d1439eSDmitry Baryshkov 	else
358d6d1439eSDmitry Baryshkov 		DBG("DSI PLL Lock success");
359d6d1439eSDmitry Baryshkov 
360d6d1439eSDmitry Baryshkov 	return locked ? 0 : -EINVAL;
361d6d1439eSDmitry Baryshkov }
362d6d1439eSDmitry Baryshkov 
36362d5325dSDmitry Baryshkov static int dsi_pll_28nm_vco_prepare_hpm(struct clk_hw *hw)
3646a58cfecSDmitry Baryshkov {
365007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
3666a58cfecSDmitry Baryshkov 	int i, ret;
3676a58cfecSDmitry Baryshkov 
368007687c3SDmitry Baryshkov 	if (unlikely(pll_28nm->phy->pll_on))
3696a58cfecSDmitry Baryshkov 		return 0;
37062d5325dSDmitry Baryshkov 
37162d5325dSDmitry Baryshkov 	for (i = 0; i < 3; i++) {
372007687c3SDmitry Baryshkov 		ret = _dsi_pll_28nm_vco_prepare_hpm(pll_28nm);
37362d5325dSDmitry Baryshkov 		if (!ret) {
374007687c3SDmitry Baryshkov 			pll_28nm->phy->pll_on = true;
37562d5325dSDmitry Baryshkov 			return 0;
37662d5325dSDmitry Baryshkov 		}
3776a58cfecSDmitry Baryshkov 	}
3786a58cfecSDmitry Baryshkov 
3796a58cfecSDmitry Baryshkov 	return ret;
3806a58cfecSDmitry Baryshkov }
3816a58cfecSDmitry Baryshkov 
38262d5325dSDmitry Baryshkov static int dsi_pll_28nm_vco_prepare_lp(struct clk_hw *hw)
383d6d1439eSDmitry Baryshkov {
384007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
385d6d1439eSDmitry Baryshkov 	struct device *dev = &pll_28nm->pdev->dev;
386*b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
387d6d1439eSDmitry Baryshkov 	bool locked;
388d6d1439eSDmitry Baryshkov 	u32 max_reads = 10, timeout_us = 50;
389d6d1439eSDmitry Baryshkov 	u32 val;
390d6d1439eSDmitry Baryshkov 
391d6d1439eSDmitry Baryshkov 	DBG("id=%d", pll_28nm->id);
392d6d1439eSDmitry Baryshkov 
393007687c3SDmitry Baryshkov 	if (unlikely(pll_28nm->phy->pll_on))
39462d5325dSDmitry Baryshkov 		return 0;
39562d5325dSDmitry Baryshkov 
396d6d1439eSDmitry Baryshkov 	pll_28nm_software_reset(pll_28nm);
397d6d1439eSDmitry Baryshkov 
398d6d1439eSDmitry Baryshkov 	/*
399d6d1439eSDmitry Baryshkov 	 * PLL power up sequence.
400d6d1439eSDmitry Baryshkov 	 * Add necessary delays recommended by hardware.
401d6d1439eSDmitry Baryshkov 	 */
402e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500);
403d6d1439eSDmitry Baryshkov 
404d6d1439eSDmitry Baryshkov 	val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
405e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
406d6d1439eSDmitry Baryshkov 
407d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
408e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
409d6d1439eSDmitry Baryshkov 
410d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B |
411d6d1439eSDmitry Baryshkov 		DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
412e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
413d6d1439eSDmitry Baryshkov 
414d6d1439eSDmitry Baryshkov 	/* DSI PLL toggle lock detect setting */
415e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500);
416e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512);
417d6d1439eSDmitry Baryshkov 
418d6d1439eSDmitry Baryshkov 	locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
419d6d1439eSDmitry Baryshkov 
42062d5325dSDmitry Baryshkov 	if (unlikely(!locked)) {
421d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
42262d5325dSDmitry Baryshkov 		return -EINVAL;
423d6d1439eSDmitry Baryshkov 	}
424d6d1439eSDmitry Baryshkov 
42562d5325dSDmitry Baryshkov 	DBG("DSI PLL lock success");
426007687c3SDmitry Baryshkov 	pll_28nm->phy->pll_on = true;
42762d5325dSDmitry Baryshkov 
42862d5325dSDmitry Baryshkov 	return 0;
42962d5325dSDmitry Baryshkov }
43062d5325dSDmitry Baryshkov 
43162d5325dSDmitry Baryshkov static void dsi_pll_28nm_vco_unprepare(struct clk_hw *hw)
432d6d1439eSDmitry Baryshkov {
433007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
434d6d1439eSDmitry Baryshkov 
435d6d1439eSDmitry Baryshkov 	DBG("id=%d", pll_28nm->id);
43662d5325dSDmitry Baryshkov 
437007687c3SDmitry Baryshkov 	if (unlikely(!pll_28nm->phy->pll_on))
43862d5325dSDmitry Baryshkov 		return;
43962d5325dSDmitry Baryshkov 
440*b7cf8a54SDmitry Baryshkov 	dsi_phy_write(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00);
44162d5325dSDmitry Baryshkov 
442007687c3SDmitry Baryshkov 	pll_28nm->phy->pll_on = false;
443007687c3SDmitry Baryshkov }
444007687c3SDmitry Baryshkov 
445007687c3SDmitry Baryshkov static long dsi_pll_28nm_clk_round_rate(struct clk_hw *hw,
446007687c3SDmitry Baryshkov 		unsigned long rate, unsigned long *parent_rate)
447007687c3SDmitry Baryshkov {
448007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
449007687c3SDmitry Baryshkov 
450007687c3SDmitry Baryshkov 	if      (rate < pll_28nm->phy->cfg->min_pll_rate)
451007687c3SDmitry Baryshkov 		return  pll_28nm->phy->cfg->min_pll_rate;
452007687c3SDmitry Baryshkov 	else if (rate > pll_28nm->phy->cfg->max_pll_rate)
453007687c3SDmitry Baryshkov 		return  pll_28nm->phy->cfg->max_pll_rate;
454007687c3SDmitry Baryshkov 	else
455007687c3SDmitry Baryshkov 		return rate;
456d6d1439eSDmitry Baryshkov }
457d6d1439eSDmitry Baryshkov 
45862d5325dSDmitry Baryshkov static const struct clk_ops clk_ops_dsi_pll_28nm_vco_hpm = {
459007687c3SDmitry Baryshkov 	.round_rate = dsi_pll_28nm_clk_round_rate,
46062d5325dSDmitry Baryshkov 	.set_rate = dsi_pll_28nm_clk_set_rate,
46162d5325dSDmitry Baryshkov 	.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
46262d5325dSDmitry Baryshkov 	.prepare = dsi_pll_28nm_vco_prepare_hpm,
46362d5325dSDmitry Baryshkov 	.unprepare = dsi_pll_28nm_vco_unprepare,
46462d5325dSDmitry Baryshkov 	.is_enabled = dsi_pll_28nm_clk_is_enabled,
46562d5325dSDmitry Baryshkov };
46662d5325dSDmitry Baryshkov 
46762d5325dSDmitry Baryshkov static const struct clk_ops clk_ops_dsi_pll_28nm_vco_lp = {
468007687c3SDmitry Baryshkov 	.round_rate = dsi_pll_28nm_clk_round_rate,
46962d5325dSDmitry Baryshkov 	.set_rate = dsi_pll_28nm_clk_set_rate,
47062d5325dSDmitry Baryshkov 	.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
47162d5325dSDmitry Baryshkov 	.prepare = dsi_pll_28nm_vco_prepare_lp,
47262d5325dSDmitry Baryshkov 	.unprepare = dsi_pll_28nm_vco_unprepare,
47362d5325dSDmitry Baryshkov 	.is_enabled = dsi_pll_28nm_clk_is_enabled,
47462d5325dSDmitry Baryshkov };
47562d5325dSDmitry Baryshkov 
47662d5325dSDmitry Baryshkov /*
47762d5325dSDmitry Baryshkov  * PLL Callbacks
47862d5325dSDmitry Baryshkov  */
47962d5325dSDmitry Baryshkov 
4802a831d9eSDmitry Baryshkov static void dsi_28nm_pll_save_state(struct msm_dsi_phy *phy)
481d6d1439eSDmitry Baryshkov {
482007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
483d6d1439eSDmitry Baryshkov 	struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
484*b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
485d6d1439eSDmitry Baryshkov 
486d6d1439eSDmitry Baryshkov 	cached_state->postdiv3 =
487e55b3fbbSDmitry Baryshkov 			dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG);
488d6d1439eSDmitry Baryshkov 	cached_state->postdiv1 =
489e55b3fbbSDmitry Baryshkov 			dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG);
490e55b3fbbSDmitry Baryshkov 	cached_state->byte_mux = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_VREG_CFG);
491007687c3SDmitry Baryshkov 	if (dsi_pll_28nm_clk_is_enabled(phy->vco_hw))
492007687c3SDmitry Baryshkov 		cached_state->vco_rate = clk_hw_get_rate(phy->vco_hw);
493d6d1439eSDmitry Baryshkov 	else
494d6d1439eSDmitry Baryshkov 		cached_state->vco_rate = 0;
495d6d1439eSDmitry Baryshkov }
496d6d1439eSDmitry Baryshkov 
4972a831d9eSDmitry Baryshkov static int dsi_28nm_pll_restore_state(struct msm_dsi_phy *phy)
498d6d1439eSDmitry Baryshkov {
499007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
500d6d1439eSDmitry Baryshkov 	struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
501*b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
502d6d1439eSDmitry Baryshkov 	int ret;
503d6d1439eSDmitry Baryshkov 
504007687c3SDmitry Baryshkov 	ret = dsi_pll_28nm_clk_set_rate(phy->vco_hw,
505d6d1439eSDmitry Baryshkov 					cached_state->vco_rate, 0);
506d6d1439eSDmitry Baryshkov 	if (ret) {
507d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(&pll_28nm->pdev->dev,
508d6d1439eSDmitry Baryshkov 			"restore vco rate failed. ret=%d\n", ret);
509d6d1439eSDmitry Baryshkov 		return ret;
510d6d1439eSDmitry Baryshkov 	}
511d6d1439eSDmitry Baryshkov 
512e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
513d6d1439eSDmitry Baryshkov 			cached_state->postdiv3);
514e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
515d6d1439eSDmitry Baryshkov 			cached_state->postdiv1);
516e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
517d6d1439eSDmitry Baryshkov 			cached_state->byte_mux);
518d6d1439eSDmitry Baryshkov 
519d6d1439eSDmitry Baryshkov 	return 0;
520d6d1439eSDmitry Baryshkov }
521d6d1439eSDmitry Baryshkov 
5225d134596SDmitry Baryshkov static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **provided_clocks)
523d6d1439eSDmitry Baryshkov {
524d6d1439eSDmitry Baryshkov 	char clk_name[32], parent1[32], parent2[32], vco_name[32];
525d6d1439eSDmitry Baryshkov 	struct clk_init_data vco_init = {
526d6d1439eSDmitry Baryshkov 		.parent_names = (const char *[]){ "xo" },
527d6d1439eSDmitry Baryshkov 		.num_parents = 1,
528d6d1439eSDmitry Baryshkov 		.name = vco_name,
529d6d1439eSDmitry Baryshkov 		.flags = CLK_IGNORE_UNUSED,
530d6d1439eSDmitry Baryshkov 	};
531d6d1439eSDmitry Baryshkov 	struct device *dev = &pll_28nm->pdev->dev;
532613cbd1dSDmitry Baryshkov 	struct clk_hw *hw;
533613cbd1dSDmitry Baryshkov 	int ret;
534d6d1439eSDmitry Baryshkov 
535d6d1439eSDmitry Baryshkov 	DBG("%d", pll_28nm->id);
536d6d1439eSDmitry Baryshkov 
537007687c3SDmitry Baryshkov 	if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
53862d5325dSDmitry Baryshkov 		vco_init.ops = &clk_ops_dsi_pll_28nm_vco_lp;
53962d5325dSDmitry Baryshkov 	else
54062d5325dSDmitry Baryshkov 		vco_init.ops = &clk_ops_dsi_pll_28nm_vco_hpm;
54162d5325dSDmitry Baryshkov 
542d6d1439eSDmitry Baryshkov 	snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id);
543007687c3SDmitry Baryshkov 	pll_28nm->clk_hw.init = &vco_init;
544007687c3SDmitry Baryshkov 	ret = devm_clk_hw_register(dev, &pll_28nm->clk_hw);
545613cbd1dSDmitry Baryshkov 	if (ret)
546613cbd1dSDmitry Baryshkov 		return ret;
547d6d1439eSDmitry Baryshkov 
548d6d1439eSDmitry Baryshkov 	snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->id);
549d6d1439eSDmitry Baryshkov 	snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
550613cbd1dSDmitry Baryshkov 	hw = devm_clk_hw_register_divider(dev, clk_name,
551d6d1439eSDmitry Baryshkov 			parent1, CLK_SET_RATE_PARENT,
552*b7cf8a54SDmitry Baryshkov 			pll_28nm->phy->pll_base +
553d6d1439eSDmitry Baryshkov 			REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
554d6d1439eSDmitry Baryshkov 			0, 4, 0, NULL);
555613cbd1dSDmitry Baryshkov 	if (IS_ERR(hw))
556613cbd1dSDmitry Baryshkov 		return PTR_ERR(hw);
557d6d1439eSDmitry Baryshkov 
558d6d1439eSDmitry Baryshkov 	snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id);
559d6d1439eSDmitry Baryshkov 	snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->id);
560613cbd1dSDmitry Baryshkov 	hw = devm_clk_hw_register_fixed_factor(dev, clk_name,
561d6d1439eSDmitry Baryshkov 			parent1, CLK_SET_RATE_PARENT,
562d6d1439eSDmitry Baryshkov 			1, 2);
563613cbd1dSDmitry Baryshkov 	if (IS_ERR(hw))
564613cbd1dSDmitry Baryshkov 		return PTR_ERR(hw);
565d6d1439eSDmitry Baryshkov 
566d6d1439eSDmitry Baryshkov 	snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id);
567d6d1439eSDmitry Baryshkov 	snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
568613cbd1dSDmitry Baryshkov 	hw = devm_clk_hw_register_divider(dev, clk_name,
569*b7cf8a54SDmitry Baryshkov 				parent1, 0, pll_28nm->phy->pll_base +
570d6d1439eSDmitry Baryshkov 				REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
571d6d1439eSDmitry Baryshkov 				0, 8, 0, NULL);
572613cbd1dSDmitry Baryshkov 	if (IS_ERR(hw))
573613cbd1dSDmitry Baryshkov 		return PTR_ERR(hw);
574613cbd1dSDmitry Baryshkov 	provided_clocks[DSI_PIXEL_PLL_CLK] = hw;
575d6d1439eSDmitry Baryshkov 
576d6d1439eSDmitry Baryshkov 	snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->id);
577d6d1439eSDmitry Baryshkov 	snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id);
578d6d1439eSDmitry Baryshkov 	snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id);
579613cbd1dSDmitry Baryshkov 	hw = devm_clk_hw_register_mux(dev, clk_name,
580d6d1439eSDmitry Baryshkov 			((const char *[]){
581d6d1439eSDmitry Baryshkov 				parent1, parent2
582*b7cf8a54SDmitry Baryshkov 			}), 2, CLK_SET_RATE_PARENT, pll_28nm->phy->pll_base +
583d6d1439eSDmitry Baryshkov 			REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL);
584613cbd1dSDmitry Baryshkov 	if (IS_ERR(hw))
585613cbd1dSDmitry Baryshkov 		return PTR_ERR(hw);
586d6d1439eSDmitry Baryshkov 
587d6d1439eSDmitry Baryshkov 	snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id);
588d6d1439eSDmitry Baryshkov 	snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->id);
589613cbd1dSDmitry Baryshkov 	hw = devm_clk_hw_register_fixed_factor(dev, clk_name,
590d6d1439eSDmitry Baryshkov 				parent1, CLK_SET_RATE_PARENT, 1, 4);
591613cbd1dSDmitry Baryshkov 	if (IS_ERR(hw))
592613cbd1dSDmitry Baryshkov 		return PTR_ERR(hw);
593613cbd1dSDmitry Baryshkov 	provided_clocks[DSI_BYTE_PLL_CLK] = hw;
594d6d1439eSDmitry Baryshkov 
595d6d1439eSDmitry Baryshkov 	return 0;
596d6d1439eSDmitry Baryshkov }
597d6d1439eSDmitry Baryshkov 
59893cf7d62SDmitry Baryshkov static int dsi_pll_28nm_init(struct msm_dsi_phy *phy)
599d6d1439eSDmitry Baryshkov {
60093cf7d62SDmitry Baryshkov 	struct platform_device *pdev = phy->pdev;
60193cf7d62SDmitry Baryshkov 	int id = phy->id;
602d6d1439eSDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm;
603d6d1439eSDmitry Baryshkov 	int ret;
604d6d1439eSDmitry Baryshkov 
605d6d1439eSDmitry Baryshkov 	if (!pdev)
60693cf7d62SDmitry Baryshkov 		return -ENODEV;
607d6d1439eSDmitry Baryshkov 
608d6d1439eSDmitry Baryshkov 	pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
609d6d1439eSDmitry Baryshkov 	if (!pll_28nm)
61093cf7d62SDmitry Baryshkov 		return -ENOMEM;
611d6d1439eSDmitry Baryshkov 
612d6d1439eSDmitry Baryshkov 	pll_28nm->pdev = pdev;
613d6d1439eSDmitry Baryshkov 	pll_28nm->id = id;
614007687c3SDmitry Baryshkov 	pll_28nm->phy = phy;
615d6d1439eSDmitry Baryshkov 
6165d134596SDmitry Baryshkov 	ret = pll_28nm_register(pll_28nm, phy->provided_clocks->hws);
617d6d1439eSDmitry Baryshkov 	if (ret) {
618d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
61993cf7d62SDmitry Baryshkov 		return ret;
620d6d1439eSDmitry Baryshkov 	}
621d6d1439eSDmitry Baryshkov 
622007687c3SDmitry Baryshkov 	phy->vco_hw = &pll_28nm->clk_hw;
623d6d1439eSDmitry Baryshkov 
62493cf7d62SDmitry Baryshkov 	return 0;
62593cf7d62SDmitry Baryshkov }
626d6d1439eSDmitry Baryshkov 
6275c829028SHai Li static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
6285c829028SHai Li 		struct msm_dsi_dphy_timing *timing)
6295c829028SHai Li {
6305c829028SHai Li 	void __iomem *base = phy->base;
6315c829028SHai Li 
6325c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
6335c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
6345c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
6355c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
6365c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
6375c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
6385c829028SHai Li 	if (timing->clk_zero & BIT(8))
6395c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
6405c829028SHai Li 			DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
6415c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
6425c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
6435c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
6445c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
6455c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
6465c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
6475c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
6485c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
6495c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
6505c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
6515c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
6525c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
6535c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
6545c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
6555c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
6565c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
6575c829028SHai Li 		DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
6585c829028SHai Li }
6595c829028SHai Li 
66049c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_enable_dcdc(struct msm_dsi_phy *phy)
6615c829028SHai Li {
6625c829028SHai Li 	void __iomem *base = phy->reg_base;
6635c829028SHai Li 
6645c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
6655c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
6665c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
6675c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
6685c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
6695c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
6705c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
6715c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
67249c4868aSStephan Gerhold 	dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
67349c4868aSStephan Gerhold }
67449c4868aSStephan Gerhold 
67549c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_enable_ldo(struct msm_dsi_phy *phy)
67649c4868aSStephan Gerhold {
67749c4868aSStephan Gerhold 	void __iomem *base = phy->reg_base;
67849c4868aSStephan Gerhold 
67949c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
68049c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
68149c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0x7);
68249c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
68349c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x1);
68449c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x1);
68549c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
68649c4868aSStephan Gerhold 
68780d2229bSDmitry Baryshkov 	if (phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
68849c4868aSStephan Gerhold 		dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x05);
68949c4868aSStephan Gerhold 	else
69049c4868aSStephan Gerhold 		dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x0d);
69149c4868aSStephan Gerhold }
69249c4868aSStephan Gerhold 
69349c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
69449c4868aSStephan Gerhold {
69549c4868aSStephan Gerhold 	if (!enable) {
69649c4868aSStephan Gerhold 		dsi_phy_write(phy->reg_base +
69749c4868aSStephan Gerhold 			      REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
69849c4868aSStephan Gerhold 		return;
69949c4868aSStephan Gerhold 	}
70049c4868aSStephan Gerhold 
70149c4868aSStephan Gerhold 	if (phy->regulator_ldo_mode)
70249c4868aSStephan Gerhold 		dsi_28nm_phy_regulator_enable_ldo(phy);
70349c4868aSStephan Gerhold 	else
70449c4868aSStephan Gerhold 		dsi_28nm_phy_regulator_enable_dcdc(phy);
7055c829028SHai Li }
7065c829028SHai Li 
7075c829028SHai Li static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
708b62aa70aSHai Li 				struct msm_dsi_phy_clk_request *clk_req)
7095c829028SHai Li {
7105c829028SHai Li 	struct msm_dsi_dphy_timing *timing = &phy->timing;
7115c829028SHai Li 	int i;
7125c829028SHai Li 	void __iomem *base = phy->base;
7135c829028SHai Li 
7145c829028SHai Li 	DBG("");
7155c829028SHai Li 
716b62aa70aSHai Li 	if (msm_dsi_dphy_timing_calc(timing, clk_req)) {
7176a41da17SMamta Shukla 		DRM_DEV_ERROR(&phy->pdev->dev,
7185c829028SHai Li 			"%s: D-PHY timing calculation failed\n", __func__);
7195c829028SHai Li 		return -EINVAL;
7205c829028SHai Li 	}
7215c829028SHai Li 
7225c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
7235c829028SHai Li 
7245c829028SHai Li 	dsi_28nm_phy_regulator_ctrl(phy, true);
7255c829028SHai Li 
7265c829028SHai Li 	dsi_28nm_dphy_set_timing(phy, timing);
7275c829028SHai Li 
7285c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
7295c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
7305c829028SHai Li 
7315c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
7325c829028SHai Li 
7335c829028SHai Li 	for (i = 0; i < 4; i++) {
7345c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
7355c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
7365c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
7375c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
738e01b1bfdSHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(i), 0);
7395c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
7405c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
7415c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
7425c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
7435c829028SHai Li 	}
7445c829028SHai Li 
745e01b1bfdSHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_4, 0);
7465c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
7475c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
7485c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
7495c829028SHai Li 
7505c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
7515c829028SHai Li 
7525c829028SHai Li 	msm_dsi_phy_set_src_pll(phy, src_pll_id,
7535c829028SHai Li 				REG_DSI_28nm_PHY_GLBL_TEST_CTRL,
7545c829028SHai Li 				DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
7555c829028SHai Li 
7565c829028SHai Li 	return 0;
7575c829028SHai Li }
7585c829028SHai Li 
7595c829028SHai Li static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
7605c829028SHai Li {
7615c829028SHai Li 	dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
7625c829028SHai Li 	dsi_28nm_phy_regulator_ctrl(phy, false);
7635c829028SHai Li 
7645c829028SHai Li 	/*
7655c829028SHai Li 	 * Wait for the registers writes to complete in order to
7665c829028SHai Li 	 * ensure that the phy is completely disabled
7675c829028SHai Li 	 */
7685c829028SHai Li 	wmb();
7695c829028SHai Li }
7705c829028SHai Li 
7715c829028SHai Li const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = {
7725c829028SHai Li 	.src_pll_truthtable = { {true, true}, {false, true} },
773266a4e58SDmitry Baryshkov 	.has_phy_regulator = true,
7745c829028SHai Li 	.reg_cfg = {
7755c829028SHai Li 		.num = 1,
7765c829028SHai Li 		.regs = {
777f377d597SArchit Taneja 			{"vddio", 100000, 100},
7785c829028SHai Li 		},
7795c829028SHai Li 	},
7805c829028SHai Li 	.ops = {
7815c829028SHai Li 		.enable = dsi_28nm_phy_enable,
7825c829028SHai Li 		.disable = dsi_28nm_phy_disable,
78393cf7d62SDmitry Baryshkov 		.pll_init = dsi_pll_28nm_init,
7842a831d9eSDmitry Baryshkov 		.save_pll_state = dsi_28nm_pll_save_state,
7852a831d9eSDmitry Baryshkov 		.restore_pll_state = dsi_28nm_pll_restore_state,
7865c829028SHai Li 	},
787076437c9SDmitry Baryshkov 	.min_pll_rate = VCO_MIN_RATE,
788076437c9SDmitry Baryshkov 	.max_pll_rate = VCO_MAX_RATE,
78932280d66SArchit Taneja 	.io_start = { 0xfd922b00, 0xfd923100 },
79032280d66SArchit Taneja 	.num_dsi_phy = 2,
7915c829028SHai Li };
7925c829028SHai Li 
793332d6084SAngeloGioacchino Del Regno const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = {
794332d6084SAngeloGioacchino Del Regno 	.src_pll_truthtable = { {true, true}, {false, true} },
795266a4e58SDmitry Baryshkov 	.has_phy_regulator = true,
796332d6084SAngeloGioacchino Del Regno 	.reg_cfg = {
797332d6084SAngeloGioacchino Del Regno 		.num = 1,
798332d6084SAngeloGioacchino Del Regno 		.regs = {
799332d6084SAngeloGioacchino Del Regno 			{"vddio", 100000, 100},
800332d6084SAngeloGioacchino Del Regno 		},
801332d6084SAngeloGioacchino Del Regno 	},
802332d6084SAngeloGioacchino Del Regno 	.ops = {
803332d6084SAngeloGioacchino Del Regno 		.enable = dsi_28nm_phy_enable,
804332d6084SAngeloGioacchino Del Regno 		.disable = dsi_28nm_phy_disable,
80593cf7d62SDmitry Baryshkov 		.pll_init = dsi_pll_28nm_init,
8062a831d9eSDmitry Baryshkov 		.save_pll_state = dsi_28nm_pll_save_state,
8072a831d9eSDmitry Baryshkov 		.restore_pll_state = dsi_28nm_pll_restore_state,
808332d6084SAngeloGioacchino Del Regno 	},
809076437c9SDmitry Baryshkov 	.min_pll_rate = VCO_MIN_RATE,
810076437c9SDmitry Baryshkov 	.max_pll_rate = VCO_MAX_RATE,
811332d6084SAngeloGioacchino Del Regno 	.io_start = { 0x1a94400, 0x1a96400 },
812332d6084SAngeloGioacchino Del Regno 	.num_dsi_phy = 2,
813332d6084SAngeloGioacchino Del Regno };
814332d6084SAngeloGioacchino Del Regno 
8155c829028SHai Li const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = {
8165c829028SHai Li 	.src_pll_truthtable = { {true, true}, {true, true} },
817266a4e58SDmitry Baryshkov 	.has_phy_regulator = true,
8185c829028SHai Li 	.reg_cfg = {
8195c829028SHai Li 		.num = 1,
8205c829028SHai Li 		.regs = {
821f377d597SArchit Taneja 			{"vddio", 100000, 100},	/* 1.8 V */
8225c829028SHai Li 		},
8235c829028SHai Li 	},
8245c829028SHai Li 	.ops = {
8255c829028SHai Li 		.enable = dsi_28nm_phy_enable,
8265c829028SHai Li 		.disable = dsi_28nm_phy_disable,
82793cf7d62SDmitry Baryshkov 		.pll_init = dsi_pll_28nm_init,
8282a831d9eSDmitry Baryshkov 		.save_pll_state = dsi_28nm_pll_save_state,
8292a831d9eSDmitry Baryshkov 		.restore_pll_state = dsi_28nm_pll_restore_state,
8305c829028SHai Li 	},
831076437c9SDmitry Baryshkov 	.min_pll_rate = VCO_MIN_RATE,
832076437c9SDmitry Baryshkov 	.max_pll_rate = VCO_MAX_RATE,
83332280d66SArchit Taneja 	.io_start = { 0x1a98500 },
83432280d66SArchit Taneja 	.num_dsi_phy = 1,
83580d2229bSDmitry Baryshkov 	.quirks = DSI_PHY_28NM_QUIRK_PHY_LP,
8365c829028SHai Li };
8375c829028SHai Li 
838