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