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"
11cc4c26d4SRob Clark #include "dsi_phy_28nm.xml.h"
125c829028SHai Li 
13d6d1439eSDmitry Baryshkov /*
14d6d1439eSDmitry Baryshkov  * DSI PLL 28nm - clock diagram (eg: DSI0):
15d6d1439eSDmitry Baryshkov  *
16d6d1439eSDmitry Baryshkov  *         dsi0analog_postdiv_clk
17d6d1439eSDmitry Baryshkov  *                             |         dsi0indirect_path_div2_clk
18d6d1439eSDmitry Baryshkov  *                             |          |
19d6d1439eSDmitry Baryshkov  *                   +------+  |  +----+  |  |\   dsi0byte_mux
20d6d1439eSDmitry Baryshkov  *  dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \   |
21d6d1439eSDmitry Baryshkov  *                |  +------+     +----+     | m|  |  +----+
22d6d1439eSDmitry Baryshkov  *                |                          | u|--o--| /4 |-- dsi0pllbyte
23d6d1439eSDmitry Baryshkov  *                |                          | x|     +----+
24d6d1439eSDmitry Baryshkov  *                o--------------------------| /
25d6d1439eSDmitry Baryshkov  *                |                          |/
26d6d1439eSDmitry Baryshkov  *                |          +------+
27d6d1439eSDmitry Baryshkov  *                o----------| DIV3 |------------------------- dsi0pll
28d6d1439eSDmitry Baryshkov  *                           +------+
29d6d1439eSDmitry Baryshkov  */
30d6d1439eSDmitry Baryshkov 
31d6d1439eSDmitry Baryshkov #define POLL_MAX_READS			10
32d6d1439eSDmitry Baryshkov #define POLL_TIMEOUT_US		50
33d6d1439eSDmitry Baryshkov 
34d6d1439eSDmitry Baryshkov #define VCO_REF_CLK_RATE		19200000
35d6d1439eSDmitry Baryshkov #define VCO_MIN_RATE			350000000
36d6d1439eSDmitry Baryshkov #define VCO_MAX_RATE			750000000
37d6d1439eSDmitry Baryshkov 
3880d2229bSDmitry Baryshkov /* v2.0.0 28nm LP implementation */
3980d2229bSDmitry Baryshkov #define DSI_PHY_28NM_QUIRK_PHY_LP	BIT(0)
40*1531d0b9SLuca Weiss #define DSI_PHY_28NM_QUIRK_PHY_8226	BIT(1)
4180d2229bSDmitry Baryshkov 
42d6d1439eSDmitry Baryshkov #define LPFR_LUT_SIZE			10
43d6d1439eSDmitry Baryshkov struct lpfr_cfg {
44d6d1439eSDmitry Baryshkov 	unsigned long vco_rate;
45d6d1439eSDmitry Baryshkov 	u32 resistance;
46d6d1439eSDmitry Baryshkov };
47d6d1439eSDmitry Baryshkov 
48d6d1439eSDmitry Baryshkov /* Loop filter resistance: */
49d6d1439eSDmitry Baryshkov static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = {
50d6d1439eSDmitry Baryshkov 	{ 479500000,  8 },
51d6d1439eSDmitry Baryshkov 	{ 480000000, 11 },
52d6d1439eSDmitry Baryshkov 	{ 575500000,  8 },
53d6d1439eSDmitry Baryshkov 	{ 576000000, 12 },
54d6d1439eSDmitry Baryshkov 	{ 610500000,  8 },
55d6d1439eSDmitry Baryshkov 	{ 659500000,  9 },
56d6d1439eSDmitry Baryshkov 	{ 671500000, 10 },
57d6d1439eSDmitry Baryshkov 	{ 672000000, 14 },
58d6d1439eSDmitry Baryshkov 	{ 708500000, 10 },
59d6d1439eSDmitry Baryshkov 	{ 750000000, 11 },
60d6d1439eSDmitry Baryshkov };
61d6d1439eSDmitry Baryshkov 
62d6d1439eSDmitry Baryshkov struct pll_28nm_cached_state {
63d6d1439eSDmitry Baryshkov 	unsigned long vco_rate;
64d6d1439eSDmitry Baryshkov 	u8 postdiv3;
65d6d1439eSDmitry Baryshkov 	u8 postdiv1;
66d6d1439eSDmitry Baryshkov 	u8 byte_mux;
67d6d1439eSDmitry Baryshkov };
68d6d1439eSDmitry Baryshkov 
69d6d1439eSDmitry Baryshkov struct dsi_pll_28nm {
70007687c3SDmitry Baryshkov 	struct clk_hw clk_hw;
71d6d1439eSDmitry Baryshkov 
72007687c3SDmitry Baryshkov 	struct msm_dsi_phy *phy;
73007687c3SDmitry Baryshkov 
74d6d1439eSDmitry Baryshkov 	struct pll_28nm_cached_state cached_state;
75d6d1439eSDmitry Baryshkov };
76d6d1439eSDmitry Baryshkov 
77007687c3SDmitry Baryshkov #define to_pll_28nm(x)	container_of(x, struct dsi_pll_28nm, clk_hw)
78d6d1439eSDmitry Baryshkov 
pll_28nm_poll_for_ready(struct dsi_pll_28nm * pll_28nm,u32 nb_tries,u32 timeout_us)79d6d1439eSDmitry Baryshkov static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm,
80d6d1439eSDmitry Baryshkov 				u32 nb_tries, u32 timeout_us)
81d6d1439eSDmitry Baryshkov {
82d6d1439eSDmitry Baryshkov 	bool pll_locked = false;
83d6d1439eSDmitry Baryshkov 	u32 val;
84d6d1439eSDmitry Baryshkov 
85d6d1439eSDmitry Baryshkov 	while (nb_tries--) {
86b7cf8a54SDmitry Baryshkov 		val = dsi_phy_read(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_STATUS);
87d6d1439eSDmitry Baryshkov 		pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY);
88d6d1439eSDmitry Baryshkov 
89d6d1439eSDmitry Baryshkov 		if (pll_locked)
90d6d1439eSDmitry Baryshkov 			break;
91d6d1439eSDmitry Baryshkov 
92d6d1439eSDmitry Baryshkov 		udelay(timeout_us);
93d6d1439eSDmitry Baryshkov 	}
94d6d1439eSDmitry Baryshkov 	DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* ");
95d6d1439eSDmitry Baryshkov 
96d6d1439eSDmitry Baryshkov 	return pll_locked;
97d6d1439eSDmitry Baryshkov }
98d6d1439eSDmitry Baryshkov 
pll_28nm_software_reset(struct dsi_pll_28nm * pll_28nm)99d6d1439eSDmitry Baryshkov static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm)
100d6d1439eSDmitry Baryshkov {
101b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
102d6d1439eSDmitry Baryshkov 
103d6d1439eSDmitry Baryshkov 	/*
104d6d1439eSDmitry Baryshkov 	 * Add HW recommended delays after toggling the software
105d6d1439eSDmitry Baryshkov 	 * reset bit off and back on.
106d6d1439eSDmitry Baryshkov 	 */
107e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG,
108d6d1439eSDmitry Baryshkov 			     DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1);
109e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1);
110d6d1439eSDmitry Baryshkov }
111d6d1439eSDmitry Baryshkov 
112d6d1439eSDmitry Baryshkov /*
113d6d1439eSDmitry Baryshkov  * Clock Callbacks
114d6d1439eSDmitry Baryshkov  */
dsi_pll_28nm_clk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)115d6d1439eSDmitry Baryshkov static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
116d6d1439eSDmitry Baryshkov 		unsigned long parent_rate)
117d6d1439eSDmitry Baryshkov {
118007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
1199f91f22aSDmitry Baryshkov 	struct device *dev = &pll_28nm->phy->pdev->dev;
120b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
121d6d1439eSDmitry Baryshkov 	unsigned long div_fbx1000, gen_vco_clk;
122d6d1439eSDmitry Baryshkov 	u32 refclk_cfg, frac_n_mode, frac_n_value;
123d6d1439eSDmitry Baryshkov 	u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
124d6d1439eSDmitry Baryshkov 	u32 cal_cfg10, cal_cfg11;
125d6d1439eSDmitry Baryshkov 	u32 rem;
126d6d1439eSDmitry Baryshkov 	int i;
127d6d1439eSDmitry Baryshkov 
128d6d1439eSDmitry Baryshkov 	VERB("rate=%lu, parent's=%lu", rate, parent_rate);
129d6d1439eSDmitry Baryshkov 
130d6d1439eSDmitry Baryshkov 	/* Force postdiv2 to be div-4 */
131e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3);
132d6d1439eSDmitry Baryshkov 
133d6d1439eSDmitry Baryshkov 	/* Configure the Loop filter resistance */
134d6d1439eSDmitry Baryshkov 	for (i = 0; i < LPFR_LUT_SIZE; i++)
135d6d1439eSDmitry Baryshkov 		if (rate <= lpfr_lut[i].vco_rate)
136d6d1439eSDmitry Baryshkov 			break;
137d6d1439eSDmitry Baryshkov 	if (i == LPFR_LUT_SIZE) {
138d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(dev, "unable to get loop filter resistance. vco=%lu\n",
139d6d1439eSDmitry Baryshkov 				rate);
140d6d1439eSDmitry Baryshkov 		return -EINVAL;
141d6d1439eSDmitry Baryshkov 	}
142e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, lpfr_lut[i].resistance);
143d6d1439eSDmitry Baryshkov 
144d6d1439eSDmitry Baryshkov 	/* Loop filter capacitance values : c1 and c2 */
145e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70);
146e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15);
147d6d1439eSDmitry Baryshkov 
148d6d1439eSDmitry Baryshkov 	rem = rate % VCO_REF_CLK_RATE;
149d6d1439eSDmitry Baryshkov 	if (rem) {
150d6d1439eSDmitry Baryshkov 		refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
151d6d1439eSDmitry Baryshkov 		frac_n_mode = 1;
152d6d1439eSDmitry Baryshkov 		div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500);
153d6d1439eSDmitry Baryshkov 		gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500);
154d6d1439eSDmitry Baryshkov 	} else {
155d6d1439eSDmitry Baryshkov 		refclk_cfg = 0x0;
156d6d1439eSDmitry Baryshkov 		frac_n_mode = 0;
157d6d1439eSDmitry Baryshkov 		div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000);
158d6d1439eSDmitry Baryshkov 		gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000);
159d6d1439eSDmitry Baryshkov 	}
160d6d1439eSDmitry Baryshkov 
161d6d1439eSDmitry Baryshkov 	DBG("refclk_cfg = %d", refclk_cfg);
162d6d1439eSDmitry Baryshkov 
163d6d1439eSDmitry Baryshkov 	rem = div_fbx1000 % 1000;
164d6d1439eSDmitry Baryshkov 	frac_n_value = (rem << 16) / 1000;
165d6d1439eSDmitry Baryshkov 
166d6d1439eSDmitry Baryshkov 	DBG("div_fb = %lu", div_fbx1000);
167d6d1439eSDmitry Baryshkov 	DBG("frac_n_value = %d", frac_n_value);
168d6d1439eSDmitry Baryshkov 
169d6d1439eSDmitry Baryshkov 	DBG("Generated VCO Clock: %lu", gen_vco_clk);
170d6d1439eSDmitry Baryshkov 	rem = 0;
171e55b3fbbSDmitry Baryshkov 	sdm_cfg1 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1);
172d6d1439eSDmitry Baryshkov 	sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK;
173d6d1439eSDmitry Baryshkov 	if (frac_n_mode) {
174d6d1439eSDmitry Baryshkov 		sdm_cfg0 = 0x0;
175d6d1439eSDmitry Baryshkov 		sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0);
176d6d1439eSDmitry Baryshkov 		sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(
177d6d1439eSDmitry Baryshkov 				(u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
178d6d1439eSDmitry Baryshkov 		sdm_cfg3 = frac_n_value >> 8;
179d6d1439eSDmitry Baryshkov 		sdm_cfg2 = frac_n_value & 0xff;
180d6d1439eSDmitry Baryshkov 	} else {
181d6d1439eSDmitry Baryshkov 		sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP;
182d6d1439eSDmitry Baryshkov 		sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(
183d6d1439eSDmitry Baryshkov 				(u32)(((div_fbx1000 / 1000) & 0x3f) - 1));
184d6d1439eSDmitry Baryshkov 		sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0);
185d6d1439eSDmitry Baryshkov 		sdm_cfg2 = 0;
186d6d1439eSDmitry Baryshkov 		sdm_cfg3 = 0;
187d6d1439eSDmitry Baryshkov 	}
188d6d1439eSDmitry Baryshkov 
189d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg0=%d", sdm_cfg0);
190d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg1=%d", sdm_cfg1);
191d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg2=%d", sdm_cfg2);
192d6d1439eSDmitry Baryshkov 	DBG("sdm_cfg3=%d", sdm_cfg3);
193d6d1439eSDmitry Baryshkov 
194d6d1439eSDmitry Baryshkov 	cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000));
195d6d1439eSDmitry Baryshkov 	cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000);
196d6d1439eSDmitry Baryshkov 	DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11);
197d6d1439eSDmitry Baryshkov 
198e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02);
199e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3,    0x2b);
200e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4,    0x06);
201e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,  0x0d);
202d6d1439eSDmitry Baryshkov 
203e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1);
204e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2,
205d6d1439eSDmitry Baryshkov 		      DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2));
206e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3,
207d6d1439eSDmitry Baryshkov 		      DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3));
208e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00);
209d6d1439eSDmitry Baryshkov 
210d6d1439eSDmitry Baryshkov 	/* Add hardware recommended delay for correct PLL configuration */
211007687c3SDmitry Baryshkov 	if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
21289da8153SDmitry Baryshkov 		udelay(1000);
21389da8153SDmitry Baryshkov 	else
21489da8153SDmitry Baryshkov 		udelay(1);
215d6d1439eSDmitry Baryshkov 
216e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg);
217e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00);
218e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31);
219e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0,   sdm_cfg0);
220e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0,   0x12);
221e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6,   0x30);
222e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7,   0x00);
223e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8,   0x60);
224e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9,   0x00);
225e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10,  cal_cfg10 & 0xff);
226e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11,  cal_cfg11 & 0xff);
227e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG,  0x20);
228d6d1439eSDmitry Baryshkov 
229d6d1439eSDmitry Baryshkov 	return 0;
230d6d1439eSDmitry Baryshkov }
231d6d1439eSDmitry Baryshkov 
dsi_pll_28nm_clk_is_enabled(struct clk_hw * hw)232d6d1439eSDmitry Baryshkov static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw)
233d6d1439eSDmitry Baryshkov {
234007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
235d6d1439eSDmitry Baryshkov 
236d6d1439eSDmitry Baryshkov 	return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS,
237d6d1439eSDmitry Baryshkov 					POLL_TIMEOUT_US);
238d6d1439eSDmitry Baryshkov }
239d6d1439eSDmitry Baryshkov 
dsi_pll_28nm_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)240d6d1439eSDmitry Baryshkov static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw,
241d6d1439eSDmitry Baryshkov 		unsigned long parent_rate)
242d6d1439eSDmitry Baryshkov {
243007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
244b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
245d6d1439eSDmitry Baryshkov 	u32 sdm0, doubler, sdm_byp_div;
246d6d1439eSDmitry Baryshkov 	u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
247d6d1439eSDmitry Baryshkov 	u32 ref_clk = VCO_REF_CLK_RATE;
248d6d1439eSDmitry Baryshkov 	unsigned long vco_rate;
249d6d1439eSDmitry Baryshkov 
250d6d1439eSDmitry Baryshkov 	VERB("parent_rate=%lu", parent_rate);
251d6d1439eSDmitry Baryshkov 
252d6d1439eSDmitry Baryshkov 	/* Check to see if the ref clk doubler is enabled */
253e55b3fbbSDmitry Baryshkov 	doubler = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) &
254d6d1439eSDmitry Baryshkov 			DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR;
255d6d1439eSDmitry Baryshkov 	ref_clk += (doubler * VCO_REF_CLK_RATE);
256d6d1439eSDmitry Baryshkov 
257d6d1439eSDmitry Baryshkov 	/* see if it is integer mode or sdm mode */
258e55b3fbbSDmitry Baryshkov 	sdm0 = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0);
259d6d1439eSDmitry Baryshkov 	if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) {
260d6d1439eSDmitry Baryshkov 		/* integer mode */
261d6d1439eSDmitry Baryshkov 		sdm_byp_div = FIELD(
262e55b3fbbSDmitry Baryshkov 				dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0),
263d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1;
264d6d1439eSDmitry Baryshkov 		vco_rate = ref_clk * sdm_byp_div;
265d6d1439eSDmitry Baryshkov 	} else {
266d6d1439eSDmitry Baryshkov 		/* sdm mode */
267d6d1439eSDmitry Baryshkov 		sdm_dc_off = FIELD(
268e55b3fbbSDmitry Baryshkov 				dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1),
269d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET);
270d6d1439eSDmitry Baryshkov 		DBG("sdm_dc_off = %d", sdm_dc_off);
271e55b3fbbSDmitry Baryshkov 		sdm2 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2),
272d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0);
273e55b3fbbSDmitry Baryshkov 		sdm3 = FIELD(dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3),
274d6d1439eSDmitry Baryshkov 				DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8);
275d6d1439eSDmitry Baryshkov 		sdm_freq_seed = (sdm3 << 8) | sdm2;
276d6d1439eSDmitry Baryshkov 		DBG("sdm_freq_seed = %d", sdm_freq_seed);
277d6d1439eSDmitry Baryshkov 
278d6d1439eSDmitry Baryshkov 		vco_rate = (ref_clk * (sdm_dc_off + 1)) +
279d6d1439eSDmitry Baryshkov 			mult_frac(ref_clk, sdm_freq_seed, BIT(16));
280d6d1439eSDmitry Baryshkov 		DBG("vco rate = %lu", vco_rate);
281d6d1439eSDmitry Baryshkov 	}
282d6d1439eSDmitry Baryshkov 
283d6d1439eSDmitry Baryshkov 	DBG("returning vco rate = %lu", vco_rate);
284d6d1439eSDmitry Baryshkov 
285d6d1439eSDmitry Baryshkov 	return vco_rate;
286d6d1439eSDmitry Baryshkov }
287d6d1439eSDmitry Baryshkov 
_dsi_pll_28nm_vco_prepare_hpm(struct dsi_pll_28nm * pll_28nm)288007687c3SDmitry Baryshkov static int _dsi_pll_28nm_vco_prepare_hpm(struct dsi_pll_28nm *pll_28nm)
289d6d1439eSDmitry Baryshkov {
2909f91f22aSDmitry Baryshkov 	struct device *dev = &pll_28nm->phy->pdev->dev;
291b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
292d6d1439eSDmitry Baryshkov 	u32 max_reads = 5, timeout_us = 100;
293d6d1439eSDmitry Baryshkov 	bool locked;
294d6d1439eSDmitry Baryshkov 	u32 val;
295d6d1439eSDmitry Baryshkov 	int i;
296d6d1439eSDmitry Baryshkov 
2979f91f22aSDmitry Baryshkov 	DBG("id=%d", pll_28nm->phy->id);
298d6d1439eSDmitry Baryshkov 
299d6d1439eSDmitry Baryshkov 	pll_28nm_software_reset(pll_28nm);
300d6d1439eSDmitry Baryshkov 
301d6d1439eSDmitry Baryshkov 	/*
302d6d1439eSDmitry Baryshkov 	 * PLL power up sequence.
303d6d1439eSDmitry Baryshkov 	 * Add necessary delays recommended by hardware.
304d6d1439eSDmitry Baryshkov 	 */
305d6d1439eSDmitry Baryshkov 	val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
306e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
307d6d1439eSDmitry Baryshkov 
308d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
309e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
310d6d1439eSDmitry Baryshkov 
311d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
312e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
313d6d1439eSDmitry Baryshkov 
314d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
315e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
316d6d1439eSDmitry Baryshkov 
317d6d1439eSDmitry Baryshkov 	for (i = 0; i < 2; i++) {
318d6d1439eSDmitry Baryshkov 		/* DSI Uniphy lock detect setting */
319e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,
320d6d1439eSDmitry Baryshkov 				     0x0c, 100);
321e55b3fbbSDmitry Baryshkov 		dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
322d6d1439eSDmitry Baryshkov 
323d6d1439eSDmitry Baryshkov 		/* poll for PLL ready status */
324dcfde8f6SMarijn Suijten 		locked = pll_28nm_poll_for_ready(pll_28nm, max_reads,
325dcfde8f6SMarijn Suijten 						 timeout_us);
326d6d1439eSDmitry Baryshkov 		if (locked)
327d6d1439eSDmitry Baryshkov 			break;
328d6d1439eSDmitry Baryshkov 
329d6d1439eSDmitry Baryshkov 		pll_28nm_software_reset(pll_28nm);
330d6d1439eSDmitry Baryshkov 
331d6d1439eSDmitry Baryshkov 		/*
332d6d1439eSDmitry Baryshkov 		 * PLL power up sequence.
333d6d1439eSDmitry Baryshkov 		 * Add necessary delays recommended by hardware.
334d6d1439eSDmitry Baryshkov 		 */
335d6d1439eSDmitry Baryshkov 		val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
336e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1);
337d6d1439eSDmitry Baryshkov 
338d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
339e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
340d6d1439eSDmitry Baryshkov 
341d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
342e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250);
343d6d1439eSDmitry Baryshkov 
344d6d1439eSDmitry Baryshkov 		val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
345e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
346d6d1439eSDmitry Baryshkov 
347d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
348e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
349d6d1439eSDmitry Baryshkov 
350d6d1439eSDmitry Baryshkov 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
351e55b3fbbSDmitry Baryshkov 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
352d6d1439eSDmitry Baryshkov 	}
353d6d1439eSDmitry Baryshkov 
354d6d1439eSDmitry Baryshkov 	if (unlikely(!locked))
355d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
356d6d1439eSDmitry Baryshkov 	else
357d6d1439eSDmitry Baryshkov 		DBG("DSI PLL Lock success");
358d6d1439eSDmitry Baryshkov 
359d6d1439eSDmitry Baryshkov 	return locked ? 0 : -EINVAL;
360d6d1439eSDmitry Baryshkov }
361d6d1439eSDmitry Baryshkov 
dsi_pll_28nm_vco_prepare_hpm(struct clk_hw * hw)36262d5325dSDmitry Baryshkov static int dsi_pll_28nm_vco_prepare_hpm(struct clk_hw *hw)
3636a58cfecSDmitry Baryshkov {
364007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
3656a58cfecSDmitry Baryshkov 	int i, ret;
3666a58cfecSDmitry Baryshkov 
367007687c3SDmitry Baryshkov 	if (unlikely(pll_28nm->phy->pll_on))
3686a58cfecSDmitry Baryshkov 		return 0;
36962d5325dSDmitry Baryshkov 
37062d5325dSDmitry Baryshkov 	for (i = 0; i < 3; i++) {
371007687c3SDmitry Baryshkov 		ret = _dsi_pll_28nm_vco_prepare_hpm(pll_28nm);
37262d5325dSDmitry Baryshkov 		if (!ret) {
373007687c3SDmitry Baryshkov 			pll_28nm->phy->pll_on = true;
37462d5325dSDmitry Baryshkov 			return 0;
37562d5325dSDmitry Baryshkov 		}
3766a58cfecSDmitry Baryshkov 	}
3776a58cfecSDmitry Baryshkov 
3786a58cfecSDmitry Baryshkov 	return ret;
3796a58cfecSDmitry Baryshkov }
3806a58cfecSDmitry Baryshkov 
dsi_pll_28nm_vco_prepare_8226(struct clk_hw * hw)381*1531d0b9SLuca Weiss static int dsi_pll_28nm_vco_prepare_8226(struct clk_hw *hw)
382*1531d0b9SLuca Weiss {
383*1531d0b9SLuca Weiss 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
384*1531d0b9SLuca Weiss 	struct device *dev = &pll_28nm->phy->pdev->dev;
385*1531d0b9SLuca Weiss 	void __iomem *base = pll_28nm->phy->pll_base;
386*1531d0b9SLuca Weiss 	u32 max_reads = 5, timeout_us = 100;
387*1531d0b9SLuca Weiss 	bool locked;
388*1531d0b9SLuca Weiss 	u32 val;
389*1531d0b9SLuca Weiss 	int i;
390*1531d0b9SLuca Weiss 
391*1531d0b9SLuca Weiss 	DBG("id=%d", pll_28nm->phy->id);
392*1531d0b9SLuca Weiss 
393*1531d0b9SLuca Weiss 	pll_28nm_software_reset(pll_28nm);
394*1531d0b9SLuca Weiss 
395*1531d0b9SLuca Weiss 	/*
396*1531d0b9SLuca Weiss 	 * PLL power up sequence.
397*1531d0b9SLuca Weiss 	 * Add necessary delays recommended by hardware.
398*1531d0b9SLuca Weiss 	 */
399*1531d0b9SLuca Weiss 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34);
400*1531d0b9SLuca Weiss 
401*1531d0b9SLuca Weiss 	val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
402*1531d0b9SLuca Weiss 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
403*1531d0b9SLuca Weiss 
404*1531d0b9SLuca Weiss 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
405*1531d0b9SLuca Weiss 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200);
406*1531d0b9SLuca Weiss 
407*1531d0b9SLuca Weiss 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
408*1531d0b9SLuca Weiss 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
409*1531d0b9SLuca Weiss 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
410*1531d0b9SLuca Weiss 
411*1531d0b9SLuca Weiss 	for (i = 0; i < 7; i++) {
412*1531d0b9SLuca Weiss 		/* DSI Uniphy lock detect setting */
413*1531d0b9SLuca Weiss 		dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
414*1531d0b9SLuca Weiss 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2,
415*1531d0b9SLuca Weiss 				0x0c, 100);
416*1531d0b9SLuca Weiss 		dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d);
417*1531d0b9SLuca Weiss 
418*1531d0b9SLuca Weiss 		/* poll for PLL ready status */
419*1531d0b9SLuca Weiss 		locked = pll_28nm_poll_for_ready(pll_28nm,
420*1531d0b9SLuca Weiss 						max_reads, timeout_us);
421*1531d0b9SLuca Weiss 		if (locked)
422*1531d0b9SLuca Weiss 			break;
423*1531d0b9SLuca Weiss 
424*1531d0b9SLuca Weiss 		pll_28nm_software_reset(pll_28nm);
425*1531d0b9SLuca Weiss 
426*1531d0b9SLuca Weiss 		/*
427*1531d0b9SLuca Weiss 		 * PLL power up sequence.
428*1531d0b9SLuca Weiss 		 * Add necessary delays recommended by hardware.
429*1531d0b9SLuca Weiss 		 */
430*1531d0b9SLuca Weiss 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00, 50);
431*1531d0b9SLuca Weiss 
432*1531d0b9SLuca Weiss 		val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
433*1531d0b9SLuca Weiss 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
434*1531d0b9SLuca Weiss 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 100);
435*1531d0b9SLuca Weiss 
436*1531d0b9SLuca Weiss 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B;
437*1531d0b9SLuca Weiss 		val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
438*1531d0b9SLuca Weiss 		dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600);
439*1531d0b9SLuca Weiss 	}
440*1531d0b9SLuca Weiss 
441*1531d0b9SLuca Weiss 	if (unlikely(!locked))
442*1531d0b9SLuca Weiss 		DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
443*1531d0b9SLuca Weiss 	else
444*1531d0b9SLuca Weiss 		DBG("DSI PLL Lock success");
445*1531d0b9SLuca Weiss 
446*1531d0b9SLuca Weiss 	return locked ? 0 : -EINVAL;
447*1531d0b9SLuca Weiss }
448*1531d0b9SLuca Weiss 
dsi_pll_28nm_vco_prepare_lp(struct clk_hw * hw)44962d5325dSDmitry Baryshkov static int dsi_pll_28nm_vco_prepare_lp(struct clk_hw *hw)
450d6d1439eSDmitry Baryshkov {
451007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
4529f91f22aSDmitry Baryshkov 	struct device *dev = &pll_28nm->phy->pdev->dev;
453b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
454d6d1439eSDmitry Baryshkov 	bool locked;
455d6d1439eSDmitry Baryshkov 	u32 max_reads = 10, timeout_us = 50;
456d6d1439eSDmitry Baryshkov 	u32 val;
457d6d1439eSDmitry Baryshkov 
4589f91f22aSDmitry Baryshkov 	DBG("id=%d", pll_28nm->phy->id);
459d6d1439eSDmitry Baryshkov 
460007687c3SDmitry Baryshkov 	if (unlikely(pll_28nm->phy->pll_on))
46162d5325dSDmitry Baryshkov 		return 0;
46262d5325dSDmitry Baryshkov 
463d6d1439eSDmitry Baryshkov 	pll_28nm_software_reset(pll_28nm);
464d6d1439eSDmitry Baryshkov 
465d6d1439eSDmitry Baryshkov 	/*
466d6d1439eSDmitry Baryshkov 	 * PLL power up sequence.
467d6d1439eSDmitry Baryshkov 	 * Add necessary delays recommended by hardware.
468d6d1439eSDmitry Baryshkov 	 */
469e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500);
470d6d1439eSDmitry Baryshkov 
471d6d1439eSDmitry Baryshkov 	val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B;
472e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
473d6d1439eSDmitry Baryshkov 
474d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B;
475e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
476d6d1439eSDmitry Baryshkov 
477d6d1439eSDmitry Baryshkov 	val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B |
478d6d1439eSDmitry Baryshkov 		DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE;
479e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500);
480d6d1439eSDmitry Baryshkov 
481d6d1439eSDmitry Baryshkov 	/* DSI PLL toggle lock detect setting */
482e55b3fbbSDmitry Baryshkov 	dsi_phy_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500);
483e55b3fbbSDmitry Baryshkov 	dsi_phy_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512);
484d6d1439eSDmitry Baryshkov 
485d6d1439eSDmitry Baryshkov 	locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us);
486d6d1439eSDmitry Baryshkov 
48762d5325dSDmitry Baryshkov 	if (unlikely(!locked)) {
488d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(dev, "DSI PLL lock failed\n");
48962d5325dSDmitry Baryshkov 		return -EINVAL;
490d6d1439eSDmitry Baryshkov 	}
491d6d1439eSDmitry Baryshkov 
49262d5325dSDmitry Baryshkov 	DBG("DSI PLL lock success");
493007687c3SDmitry Baryshkov 	pll_28nm->phy->pll_on = true;
49462d5325dSDmitry Baryshkov 
49562d5325dSDmitry Baryshkov 	return 0;
49662d5325dSDmitry Baryshkov }
49762d5325dSDmitry Baryshkov 
dsi_pll_28nm_vco_unprepare(struct clk_hw * hw)49862d5325dSDmitry Baryshkov static void dsi_pll_28nm_vco_unprepare(struct clk_hw *hw)
499d6d1439eSDmitry Baryshkov {
500007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
501d6d1439eSDmitry Baryshkov 
5029f91f22aSDmitry Baryshkov 	DBG("id=%d", pll_28nm->phy->id);
50362d5325dSDmitry Baryshkov 
504007687c3SDmitry Baryshkov 	if (unlikely(!pll_28nm->phy->pll_on))
50562d5325dSDmitry Baryshkov 		return;
50662d5325dSDmitry Baryshkov 
507b7cf8a54SDmitry Baryshkov 	dsi_phy_write(pll_28nm->phy->pll_base + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00);
50862d5325dSDmitry Baryshkov 
509007687c3SDmitry Baryshkov 	pll_28nm->phy->pll_on = false;
510007687c3SDmitry Baryshkov }
511007687c3SDmitry Baryshkov 
dsi_pll_28nm_clk_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)512007687c3SDmitry Baryshkov static long dsi_pll_28nm_clk_round_rate(struct clk_hw *hw,
513007687c3SDmitry Baryshkov 		unsigned long rate, unsigned long *parent_rate)
514007687c3SDmitry Baryshkov {
515007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(hw);
516007687c3SDmitry Baryshkov 
517007687c3SDmitry Baryshkov 	if      (rate < pll_28nm->phy->cfg->min_pll_rate)
518007687c3SDmitry Baryshkov 		return  pll_28nm->phy->cfg->min_pll_rate;
519007687c3SDmitry Baryshkov 	else if (rate > pll_28nm->phy->cfg->max_pll_rate)
520007687c3SDmitry Baryshkov 		return  pll_28nm->phy->cfg->max_pll_rate;
521007687c3SDmitry Baryshkov 	else
522007687c3SDmitry Baryshkov 		return rate;
523d6d1439eSDmitry Baryshkov }
524d6d1439eSDmitry Baryshkov 
52562d5325dSDmitry Baryshkov static const struct clk_ops clk_ops_dsi_pll_28nm_vco_hpm = {
526007687c3SDmitry Baryshkov 	.round_rate = dsi_pll_28nm_clk_round_rate,
52762d5325dSDmitry Baryshkov 	.set_rate = dsi_pll_28nm_clk_set_rate,
52862d5325dSDmitry Baryshkov 	.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
52962d5325dSDmitry Baryshkov 	.prepare = dsi_pll_28nm_vco_prepare_hpm,
53062d5325dSDmitry Baryshkov 	.unprepare = dsi_pll_28nm_vco_unprepare,
53162d5325dSDmitry Baryshkov 	.is_enabled = dsi_pll_28nm_clk_is_enabled,
53262d5325dSDmitry Baryshkov };
53362d5325dSDmitry Baryshkov 
53462d5325dSDmitry Baryshkov static const struct clk_ops clk_ops_dsi_pll_28nm_vco_lp = {
535007687c3SDmitry Baryshkov 	.round_rate = dsi_pll_28nm_clk_round_rate,
53662d5325dSDmitry Baryshkov 	.set_rate = dsi_pll_28nm_clk_set_rate,
53762d5325dSDmitry Baryshkov 	.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
53862d5325dSDmitry Baryshkov 	.prepare = dsi_pll_28nm_vco_prepare_lp,
53962d5325dSDmitry Baryshkov 	.unprepare = dsi_pll_28nm_vco_unprepare,
54062d5325dSDmitry Baryshkov 	.is_enabled = dsi_pll_28nm_clk_is_enabled,
54162d5325dSDmitry Baryshkov };
54262d5325dSDmitry Baryshkov 
543*1531d0b9SLuca Weiss static const struct clk_ops clk_ops_dsi_pll_28nm_vco_8226 = {
544*1531d0b9SLuca Weiss 	.round_rate = dsi_pll_28nm_clk_round_rate,
545*1531d0b9SLuca Weiss 	.set_rate = dsi_pll_28nm_clk_set_rate,
546*1531d0b9SLuca Weiss 	.recalc_rate = dsi_pll_28nm_clk_recalc_rate,
547*1531d0b9SLuca Weiss 	.prepare = dsi_pll_28nm_vco_prepare_8226,
548*1531d0b9SLuca Weiss 	.unprepare = dsi_pll_28nm_vco_unprepare,
549*1531d0b9SLuca Weiss 	.is_enabled = dsi_pll_28nm_clk_is_enabled,
550*1531d0b9SLuca Weiss };
551*1531d0b9SLuca Weiss 
55262d5325dSDmitry Baryshkov /*
55362d5325dSDmitry Baryshkov  * PLL Callbacks
55462d5325dSDmitry Baryshkov  */
55562d5325dSDmitry Baryshkov 
dsi_28nm_pll_save_state(struct msm_dsi_phy * phy)5562a831d9eSDmitry Baryshkov static void dsi_28nm_pll_save_state(struct msm_dsi_phy *phy)
557d6d1439eSDmitry Baryshkov {
558007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
559d6d1439eSDmitry Baryshkov 	struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
560b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
561d6d1439eSDmitry Baryshkov 
562d6d1439eSDmitry Baryshkov 	cached_state->postdiv3 =
563e55b3fbbSDmitry Baryshkov 			dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG);
564d6d1439eSDmitry Baryshkov 	cached_state->postdiv1 =
565e55b3fbbSDmitry Baryshkov 			dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG);
566e55b3fbbSDmitry Baryshkov 	cached_state->byte_mux = dsi_phy_read(base + REG_DSI_28nm_PHY_PLL_VREG_CFG);
567007687c3SDmitry Baryshkov 	if (dsi_pll_28nm_clk_is_enabled(phy->vco_hw))
568007687c3SDmitry Baryshkov 		cached_state->vco_rate = clk_hw_get_rate(phy->vco_hw);
569d6d1439eSDmitry Baryshkov 	else
570d6d1439eSDmitry Baryshkov 		cached_state->vco_rate = 0;
571d6d1439eSDmitry Baryshkov }
572d6d1439eSDmitry Baryshkov 
dsi_28nm_pll_restore_state(struct msm_dsi_phy * phy)5732a831d9eSDmitry Baryshkov static int dsi_28nm_pll_restore_state(struct msm_dsi_phy *phy)
574d6d1439eSDmitry Baryshkov {
575007687c3SDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm = to_pll_28nm(phy->vco_hw);
576d6d1439eSDmitry Baryshkov 	struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state;
577b7cf8a54SDmitry Baryshkov 	void __iomem *base = pll_28nm->phy->pll_base;
578d6d1439eSDmitry Baryshkov 	int ret;
579d6d1439eSDmitry Baryshkov 
580007687c3SDmitry Baryshkov 	ret = dsi_pll_28nm_clk_set_rate(phy->vco_hw,
581d6d1439eSDmitry Baryshkov 					cached_state->vco_rate, 0);
582d6d1439eSDmitry Baryshkov 	if (ret) {
5839f91f22aSDmitry Baryshkov 		DRM_DEV_ERROR(&pll_28nm->phy->pdev->dev,
584d6d1439eSDmitry Baryshkov 			"restore vco rate failed. ret=%d\n", ret);
585d6d1439eSDmitry Baryshkov 		return ret;
586d6d1439eSDmitry Baryshkov 	}
587d6d1439eSDmitry Baryshkov 
588e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
589d6d1439eSDmitry Baryshkov 		      cached_state->postdiv3);
590e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
591d6d1439eSDmitry Baryshkov 		      cached_state->postdiv1);
592e55b3fbbSDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG,
593d6d1439eSDmitry Baryshkov 		      cached_state->byte_mux);
594d6d1439eSDmitry Baryshkov 
595d6d1439eSDmitry Baryshkov 	return 0;
596d6d1439eSDmitry Baryshkov }
597d6d1439eSDmitry Baryshkov 
pll_28nm_register(struct dsi_pll_28nm * pll_28nm,struct clk_hw ** provided_clocks)5985d134596SDmitry Baryshkov static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm, struct clk_hw **provided_clocks)
599d6d1439eSDmitry Baryshkov {
60009186dd9SMarijn Suijten 	char clk_name[32];
601d6d1439eSDmitry Baryshkov 	struct clk_init_data vco_init = {
6023a3ee71bSMarijn Suijten 		.parent_data = &(const struct clk_parent_data) {
6033a3ee71bSMarijn Suijten 			.fw_name = "ref", .name = "xo",
6043a3ee71bSMarijn Suijten 		},
605d6d1439eSDmitry Baryshkov 		.num_parents = 1,
60609186dd9SMarijn Suijten 		.name = clk_name,
607d6d1439eSDmitry Baryshkov 		.flags = CLK_IGNORE_UNUSED,
608d6d1439eSDmitry Baryshkov 	};
6099f91f22aSDmitry Baryshkov 	struct device *dev = &pll_28nm->phy->pdev->dev;
61009186dd9SMarijn Suijten 	struct clk_hw *hw, *analog_postdiv, *indirect_path_div2, *byte_mux;
611613cbd1dSDmitry Baryshkov 	int ret;
612d6d1439eSDmitry Baryshkov 
6139f91f22aSDmitry Baryshkov 	DBG("%d", pll_28nm->phy->id);
614d6d1439eSDmitry Baryshkov 
615007687c3SDmitry Baryshkov 	if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
61662d5325dSDmitry Baryshkov 		vco_init.ops = &clk_ops_dsi_pll_28nm_vco_lp;
617*1531d0b9SLuca Weiss 	else if (pll_28nm->phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_8226)
618*1531d0b9SLuca Weiss 		vco_init.ops = &clk_ops_dsi_pll_28nm_vco_8226;
61962d5325dSDmitry Baryshkov 	else
62062d5325dSDmitry Baryshkov 		vco_init.ops = &clk_ops_dsi_pll_28nm_vco_hpm;
62162d5325dSDmitry Baryshkov 
62209186dd9SMarijn Suijten 	snprintf(clk_name, sizeof(clk_name), "dsi%dvco_clk", pll_28nm->phy->id);
623007687c3SDmitry Baryshkov 	pll_28nm->clk_hw.init = &vco_init;
624007687c3SDmitry Baryshkov 	ret = devm_clk_hw_register(dev, &pll_28nm->clk_hw);
625613cbd1dSDmitry Baryshkov 	if (ret)
626613cbd1dSDmitry Baryshkov 		return ret;
627d6d1439eSDmitry Baryshkov 
628e139dfa0SMarijn Suijten 	snprintf(clk_name, sizeof(clk_name), "dsi%danalog_postdiv_clk", pll_28nm->phy->id);
62909186dd9SMarijn Suijten 	analog_postdiv = devm_clk_hw_register_divider_parent_hw(dev, clk_name,
63009186dd9SMarijn Suijten 			&pll_28nm->clk_hw, CLK_SET_RATE_PARENT,
63109186dd9SMarijn Suijten 			pll_28nm->phy->pll_base +
632d6d1439eSDmitry Baryshkov 				REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG,
633d6d1439eSDmitry Baryshkov 			0, 4, 0, NULL);
63409186dd9SMarijn Suijten 	if (IS_ERR(analog_postdiv))
63509186dd9SMarijn Suijten 		return PTR_ERR(analog_postdiv);
636d6d1439eSDmitry Baryshkov 
637e139dfa0SMarijn Suijten 	snprintf(clk_name, sizeof(clk_name), "dsi%dindirect_path_div2_clk", pll_28nm->phy->id);
63809186dd9SMarijn Suijten 	indirect_path_div2 = devm_clk_hw_register_fixed_factor_parent_hw(dev,
63909186dd9SMarijn Suijten 			clk_name, analog_postdiv, CLK_SET_RATE_PARENT, 1, 2);
64009186dd9SMarijn Suijten 	if (IS_ERR(indirect_path_div2))
64109186dd9SMarijn Suijten 		return PTR_ERR(indirect_path_div2);
642d6d1439eSDmitry Baryshkov 
643e139dfa0SMarijn Suijten 	snprintf(clk_name, sizeof(clk_name), "dsi%dpll", pll_28nm->phy->id);
64409186dd9SMarijn Suijten 	hw = devm_clk_hw_register_divider_parent_hw(dev, clk_name,
64509186dd9SMarijn Suijten 			&pll_28nm->clk_hw, 0, pll_28nm->phy->pll_base +
646d6d1439eSDmitry Baryshkov 				REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG,
647d6d1439eSDmitry Baryshkov 			0, 8, 0, NULL);
648613cbd1dSDmitry Baryshkov 	if (IS_ERR(hw))
649613cbd1dSDmitry Baryshkov 		return PTR_ERR(hw);
650613cbd1dSDmitry Baryshkov 	provided_clocks[DSI_PIXEL_PLL_CLK] = hw;
651d6d1439eSDmitry Baryshkov 
652e139dfa0SMarijn Suijten 	snprintf(clk_name, sizeof(clk_name), "dsi%dbyte_mux", pll_28nm->phy->id);
65309186dd9SMarijn Suijten 	byte_mux = devm_clk_hw_register_mux_parent_hws(dev, clk_name,
65409186dd9SMarijn Suijten 			((const struct clk_hw *[]){
65509186dd9SMarijn Suijten 				&pll_28nm->clk_hw,
65609186dd9SMarijn Suijten 				indirect_path_div2,
657b7cf8a54SDmitry Baryshkov 			}), 2, CLK_SET_RATE_PARENT, pll_28nm->phy->pll_base +
658d6d1439eSDmitry Baryshkov 				REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL);
65909186dd9SMarijn Suijten 	if (IS_ERR(byte_mux))
66009186dd9SMarijn Suijten 		return PTR_ERR(byte_mux);
661d6d1439eSDmitry Baryshkov 
662e139dfa0SMarijn Suijten 	snprintf(clk_name, sizeof(clk_name), "dsi%dpllbyte", pll_28nm->phy->id);
66309186dd9SMarijn Suijten 	hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, clk_name,
66409186dd9SMarijn Suijten 			byte_mux, CLK_SET_RATE_PARENT, 1, 4);
665613cbd1dSDmitry Baryshkov 	if (IS_ERR(hw))
666613cbd1dSDmitry Baryshkov 		return PTR_ERR(hw);
667613cbd1dSDmitry Baryshkov 	provided_clocks[DSI_BYTE_PLL_CLK] = hw;
668d6d1439eSDmitry Baryshkov 
669d6d1439eSDmitry Baryshkov 	return 0;
670d6d1439eSDmitry Baryshkov }
671d6d1439eSDmitry Baryshkov 
dsi_pll_28nm_init(struct msm_dsi_phy * phy)67293cf7d62SDmitry Baryshkov static int dsi_pll_28nm_init(struct msm_dsi_phy *phy)
673d6d1439eSDmitry Baryshkov {
67493cf7d62SDmitry Baryshkov 	struct platform_device *pdev = phy->pdev;
675d6d1439eSDmitry Baryshkov 	struct dsi_pll_28nm *pll_28nm;
676d6d1439eSDmitry Baryshkov 	int ret;
677d6d1439eSDmitry Baryshkov 
678d6d1439eSDmitry Baryshkov 	if (!pdev)
67993cf7d62SDmitry Baryshkov 		return -ENODEV;
680d6d1439eSDmitry Baryshkov 
681d6d1439eSDmitry Baryshkov 	pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL);
682d6d1439eSDmitry Baryshkov 	if (!pll_28nm)
68393cf7d62SDmitry Baryshkov 		return -ENOMEM;
684d6d1439eSDmitry Baryshkov 
685007687c3SDmitry Baryshkov 	pll_28nm->phy = phy;
686d6d1439eSDmitry Baryshkov 
6875d134596SDmitry Baryshkov 	ret = pll_28nm_register(pll_28nm, phy->provided_clocks->hws);
688d6d1439eSDmitry Baryshkov 	if (ret) {
689d6d1439eSDmitry Baryshkov 		DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret);
69093cf7d62SDmitry Baryshkov 		return ret;
691d6d1439eSDmitry Baryshkov 	}
692d6d1439eSDmitry Baryshkov 
693007687c3SDmitry Baryshkov 	phy->vco_hw = &pll_28nm->clk_hw;
694d6d1439eSDmitry Baryshkov 
69593cf7d62SDmitry Baryshkov 	return 0;
69693cf7d62SDmitry Baryshkov }
697d6d1439eSDmitry Baryshkov 
dsi_28nm_dphy_set_timing(struct msm_dsi_phy * phy,struct msm_dsi_dphy_timing * timing)6985c829028SHai Li static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
6995c829028SHai Li 		struct msm_dsi_dphy_timing *timing)
7005c829028SHai Li {
7015c829028SHai Li 	void __iomem *base = phy->base;
7025c829028SHai Li 
7035c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
7045c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
7055c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
7065c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
7075c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
7085c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
7095c829028SHai Li 	if (timing->clk_zero & BIT(8))
7105c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
7115c829028SHai Li 			      DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
7125c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
7135c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
7145c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
7155c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
7165c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
7175c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
7185c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
7195c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
7205c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
7215c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
7225c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
7235c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
7245c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
7255c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
7265c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
7275c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
7285c829028SHai Li 		      DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
7295c829028SHai Li }
7305c829028SHai Li 
dsi_28nm_phy_regulator_enable_dcdc(struct msm_dsi_phy * phy)73149c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_enable_dcdc(struct msm_dsi_phy *phy)
7325c829028SHai Li {
7335c829028SHai Li 	void __iomem *base = phy->reg_base;
7345c829028SHai Li 
7355c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
7365c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
7375c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
7385c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
7395c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
7405c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
7415c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
7425c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
74349c4868aSStephan Gerhold 	dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
74449c4868aSStephan Gerhold }
74549c4868aSStephan Gerhold 
dsi_28nm_phy_regulator_enable_ldo(struct msm_dsi_phy * phy)74649c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_enable_ldo(struct msm_dsi_phy *phy)
74749c4868aSStephan Gerhold {
74849c4868aSStephan Gerhold 	void __iomem *base = phy->reg_base;
74949c4868aSStephan Gerhold 
75049c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
75149c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
75249c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0x7);
75349c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
75449c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x1);
75549c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x1);
75649c4868aSStephan Gerhold 	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
75749c4868aSStephan Gerhold 
75880d2229bSDmitry Baryshkov 	if (phy->cfg->quirks & DSI_PHY_28NM_QUIRK_PHY_LP)
75949c4868aSStephan Gerhold 		dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x05);
76049c4868aSStephan Gerhold 	else
76149c4868aSStephan Gerhold 		dsi_phy_write(phy->base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x0d);
76249c4868aSStephan Gerhold }
76349c4868aSStephan Gerhold 
dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy * phy,bool enable)76449c4868aSStephan Gerhold static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
76549c4868aSStephan Gerhold {
76649c4868aSStephan Gerhold 	if (!enable) {
76749c4868aSStephan Gerhold 		dsi_phy_write(phy->reg_base +
76849c4868aSStephan Gerhold 			      REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
76949c4868aSStephan Gerhold 		return;
77049c4868aSStephan Gerhold 	}
77149c4868aSStephan Gerhold 
77249c4868aSStephan Gerhold 	if (phy->regulator_ldo_mode)
77349c4868aSStephan Gerhold 		dsi_28nm_phy_regulator_enable_ldo(phy);
77449c4868aSStephan Gerhold 	else
77549c4868aSStephan Gerhold 		dsi_28nm_phy_regulator_enable_dcdc(phy);
7765c829028SHai Li }
7775c829028SHai Li 
dsi_28nm_phy_enable(struct msm_dsi_phy * phy,struct msm_dsi_phy_clk_request * clk_req)77836c5dde5SDmitry Baryshkov static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy,
779b62aa70aSHai Li 				struct msm_dsi_phy_clk_request *clk_req)
7805c829028SHai Li {
7815c829028SHai Li 	struct msm_dsi_dphy_timing *timing = &phy->timing;
7825c829028SHai Li 	int i;
7835c829028SHai Li 	void __iomem *base = phy->base;
7846e2ad9c3SDmitry Baryshkov 	u32 val;
7855c829028SHai Li 
7865c829028SHai Li 	DBG("");
7875c829028SHai Li 
788b62aa70aSHai Li 	if (msm_dsi_dphy_timing_calc(timing, clk_req)) {
7896a41da17SMamta Shukla 		DRM_DEV_ERROR(&phy->pdev->dev,
790dcfde8f6SMarijn Suijten 			      "%s: D-PHY timing calculation failed\n",
791dcfde8f6SMarijn Suijten 			      __func__);
7925c829028SHai Li 		return -EINVAL;
7935c829028SHai Li 	}
7945c829028SHai Li 
7955c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
7965c829028SHai Li 
7975c829028SHai Li 	dsi_28nm_phy_regulator_ctrl(phy, true);
7985c829028SHai Li 
7995c829028SHai Li 	dsi_28nm_dphy_set_timing(phy, timing);
8005c829028SHai Li 
8015c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
8025c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
8035c829028SHai Li 
8045c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
8055c829028SHai Li 
8065c829028SHai Li 	for (i = 0; i < 4; i++) {
8075c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
8085c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
8095c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
8105c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
811e01b1bfdSHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(i), 0);
8125c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
8135c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
8145c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
8155c829028SHai Li 		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
8165c829028SHai Li 	}
8175c829028SHai Li 
818e01b1bfdSHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_4, 0);
8195c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
8205c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
8215c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
8225c829028SHai Li 
8235c829028SHai Li 	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
8245c829028SHai Li 
8256e2ad9c3SDmitry Baryshkov 	val = dsi_phy_read(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL);
82636c5dde5SDmitry Baryshkov 	if (phy->id == DSI_1 && phy->usecase == MSM_DSI_PHY_SLAVE)
8276e2ad9c3SDmitry Baryshkov 		val &= ~DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL;
8286e2ad9c3SDmitry Baryshkov 	else
8296e2ad9c3SDmitry Baryshkov 		val |= DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL;
8306e2ad9c3SDmitry Baryshkov 	dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, val);
8315c829028SHai Li 
8325c829028SHai Li 	return 0;
8335c829028SHai Li }
8345c829028SHai Li 
dsi_28nm_phy_disable(struct msm_dsi_phy * phy)8355c829028SHai Li static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
8365c829028SHai Li {
8375c829028SHai Li 	dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
8385c829028SHai Li 	dsi_28nm_phy_regulator_ctrl(phy, false);
8395c829028SHai Li 
8405c829028SHai Li 	/*
8415c829028SHai Li 	 * Wait for the registers writes to complete in order to
8425c829028SHai Li 	 * ensure that the phy is completely disabled
8435c829028SHai Li 	 */
8445c829028SHai Li 	wmb();
8455c829028SHai Li }
8465c829028SHai Li 
847d8810a66SDouglas Anderson static const struct regulator_bulk_data dsi_phy_28nm_regulators[] = {
848d8810a66SDouglas Anderson 	{ .supply = "vddio", .init_load_uA = 100000 },
849d8810a66SDouglas Anderson };
850d8810a66SDouglas Anderson 
8515c829028SHai Li const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = {
852266a4e58SDmitry Baryshkov 	.has_phy_regulator = true,
853d8810a66SDouglas Anderson 	.regulator_data = dsi_phy_28nm_regulators,
854d8810a66SDouglas Anderson 	.num_regulators = ARRAY_SIZE(dsi_phy_28nm_regulators),
8555c829028SHai Li 	.ops = {
8565c829028SHai Li 		.enable = dsi_28nm_phy_enable,
8575c829028SHai Li 		.disable = dsi_28nm_phy_disable,
85893cf7d62SDmitry Baryshkov 		.pll_init = dsi_pll_28nm_init,
8592a831d9eSDmitry Baryshkov 		.save_pll_state = dsi_28nm_pll_save_state,
8602a831d9eSDmitry Baryshkov 		.restore_pll_state = dsi_28nm_pll_restore_state,
8615c829028SHai Li 	},
862076437c9SDmitry Baryshkov 	.min_pll_rate = VCO_MIN_RATE,
863076437c9SDmitry Baryshkov 	.max_pll_rate = VCO_MAX_RATE,
86432280d66SArchit Taneja 	.io_start = { 0xfd922b00, 0xfd923100 },
86532280d66SArchit Taneja 	.num_dsi_phy = 2,
8665c829028SHai Li };
8675c829028SHai Li 
868332d6084SAngeloGioacchino Del Regno const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_famb_cfgs = {
869266a4e58SDmitry Baryshkov 	.has_phy_regulator = true,
870d8810a66SDouglas Anderson 	.regulator_data = dsi_phy_28nm_regulators,
871d8810a66SDouglas Anderson 	.num_regulators = ARRAY_SIZE(dsi_phy_28nm_regulators),
872332d6084SAngeloGioacchino Del Regno 	.ops = {
873332d6084SAngeloGioacchino Del Regno 		.enable = dsi_28nm_phy_enable,
874332d6084SAngeloGioacchino Del Regno 		.disable = dsi_28nm_phy_disable,
87593cf7d62SDmitry Baryshkov 		.pll_init = dsi_pll_28nm_init,
8762a831d9eSDmitry Baryshkov 		.save_pll_state = dsi_28nm_pll_save_state,
8772a831d9eSDmitry Baryshkov 		.restore_pll_state = dsi_28nm_pll_restore_state,
878332d6084SAngeloGioacchino Del Regno 	},
879076437c9SDmitry Baryshkov 	.min_pll_rate = VCO_MIN_RATE,
880076437c9SDmitry Baryshkov 	.max_pll_rate = VCO_MAX_RATE,
881332d6084SAngeloGioacchino Del Regno 	.io_start = { 0x1a94400, 0x1a96400 },
882332d6084SAngeloGioacchino Del Regno 	.num_dsi_phy = 2,
883332d6084SAngeloGioacchino Del Regno };
884332d6084SAngeloGioacchino Del Regno 
8855c829028SHai Li const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = {
886266a4e58SDmitry Baryshkov 	.has_phy_regulator = true,
887d8810a66SDouglas Anderson 	.regulator_data = dsi_phy_28nm_regulators,
888d8810a66SDouglas Anderson 	.num_regulators = ARRAY_SIZE(dsi_phy_28nm_regulators),
8895c829028SHai Li 	.ops = {
8905c829028SHai Li 		.enable = dsi_28nm_phy_enable,
8915c829028SHai Li 		.disable = dsi_28nm_phy_disable,
89293cf7d62SDmitry Baryshkov 		.pll_init = dsi_pll_28nm_init,
8932a831d9eSDmitry Baryshkov 		.save_pll_state = dsi_28nm_pll_save_state,
8942a831d9eSDmitry Baryshkov 		.restore_pll_state = dsi_28nm_pll_restore_state,
8955c829028SHai Li 	},
896076437c9SDmitry Baryshkov 	.min_pll_rate = VCO_MIN_RATE,
897076437c9SDmitry Baryshkov 	.max_pll_rate = VCO_MAX_RATE,
89832280d66SArchit Taneja 	.io_start = { 0x1a98500 },
89932280d66SArchit Taneja 	.num_dsi_phy = 1,
90080d2229bSDmitry Baryshkov 	.quirks = DSI_PHY_28NM_QUIRK_PHY_LP,
9015c829028SHai Li };
9025c829028SHai Li 
903*1531d0b9SLuca Weiss const struct msm_dsi_phy_cfg dsi_phy_28nm_8226_cfgs = {
904*1531d0b9SLuca Weiss 	.has_phy_regulator = true,
905*1531d0b9SLuca Weiss 	.regulator_data = dsi_phy_28nm_regulators,
906*1531d0b9SLuca Weiss 	.num_regulators = ARRAY_SIZE(dsi_phy_28nm_regulators),
907*1531d0b9SLuca Weiss 	.ops = {
908*1531d0b9SLuca Weiss 		.enable = dsi_28nm_phy_enable,
909*1531d0b9SLuca Weiss 		.disable = dsi_28nm_phy_disable,
910*1531d0b9SLuca Weiss 		.pll_init = dsi_pll_28nm_init,
911*1531d0b9SLuca Weiss 		.save_pll_state = dsi_28nm_pll_save_state,
912*1531d0b9SLuca Weiss 		.restore_pll_state = dsi_28nm_pll_restore_state,
913*1531d0b9SLuca Weiss 	},
914*1531d0b9SLuca Weiss 	.min_pll_rate = VCO_MIN_RATE,
915*1531d0b9SLuca Weiss 	.max_pll_rate = VCO_MAX_RATE,
916*1531d0b9SLuca Weiss 	.io_start = { 0xfd922b00 },
917*1531d0b9SLuca Weiss 	.num_dsi_phy = 1,
918*1531d0b9SLuca Weiss 	.quirks = DSI_PHY_28NM_QUIRK_PHY_8226,
919*1531d0b9SLuca Weiss };
920