Commit | Line | Data |
---|---|---|
973e02db AT |
1 | /* |
2 | * SPDX-License-Identifier: GPL-2.0 | |
3 | * Copyright (c) 2018, The Linux Foundation | |
4 | */ | |
5 | ||
6 | #include <linux/clk.h> | |
7 | #include <linux/clk-provider.h> | |
8 | #include <linux/iopoll.h> | |
9 | ||
10 | #include "dsi_pll.h" | |
11 | #include "dsi.xml.h" | |
12 | ||
28e4309a AT |
13 | /* |
14 | * DSI PLL 10nm - clock diagram (eg: DSI0): | |
15 | * | |
16 | * dsi0_pll_out_div_clk dsi0_pll_bit_clk | |
17 | * | | | |
18 | * | | | |
19 | * +---------+ | +----------+ | +----+ | |
c1866d44 | 20 | * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- dsi0_phy_pll_out_byteclk |
28e4309a AT |
21 | * +---------+ | +----------+ | +----+ |
22 | * | | | |
23 | * | | dsi0_pll_by_2_bit_clk | |
24 | * | | | | |
25 | * | | +----+ | |\ dsi0_pclk_mux | |
26 | * | |--| /2 |--o--| \ | | |
27 | * | | +----+ | \ | +---------+ | |
c1866d44 | 28 | * | --------------| |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk |
28e4309a AT |
29 | * |------------------------------| / +---------+ |
30 | * | +-----+ | / | |
31 | * -----------| /4? |--o----------|/ | |
32 | * +-----+ | | | |
33 | * | |dsiclk_sel | |
34 | * | | |
35 | * dsi0_pll_post_out_div_clk | |
36 | */ | |
37 | ||
38 | #define DSI_BYTE_PLL_CLK 0 | |
39 | #define DSI_PIXEL_PLL_CLK 1 | |
40 | #define NUM_PROVIDED_CLKS 2 | |
41 | ||
8531f058 AK |
42 | #define VCO_REF_CLK_RATE 19200000 |
43 | ||
28e4309a AT |
44 | struct dsi_pll_regs { |
45 | u32 pll_prop_gain_rate; | |
46 | u32 pll_lockdet_rate; | |
47 | u32 decimal_div_start; | |
48 | u32 frac_div_start_low; | |
49 | u32 frac_div_start_mid; | |
50 | u32 frac_div_start_high; | |
51 | u32 pll_clock_inverters; | |
52 | u32 ssc_stepsize_low; | |
53 | u32 ssc_stepsize_high; | |
54 | u32 ssc_div_per_low; | |
55 | u32 ssc_div_per_high; | |
56 | u32 ssc_adjper_low; | |
57 | u32 ssc_adjper_high; | |
58 | u32 ssc_control; | |
59 | }; | |
60 | ||
61 | struct dsi_pll_config { | |
62 | u32 ref_freq; | |
63 | bool div_override; | |
64 | u32 output_div; | |
65 | bool ignore_frac; | |
66 | bool disable_prescaler; | |
67 | bool enable_ssc; | |
68 | bool ssc_center; | |
69 | u32 dec_bits; | |
70 | u32 frac_bits; | |
71 | u32 lock_timer; | |
72 | u32 ssc_freq; | |
73 | u32 ssc_offset; | |
74 | u32 ssc_adj_per; | |
75 | u32 thresh_cycles; | |
76 | u32 refclk_cycles; | |
77 | }; | |
78 | ||
79 | struct pll_10nm_cached_state { | |
80 | unsigned long vco_rate; | |
81 | u8 bit_clk_div; | |
82 | u8 pix_clk_div; | |
83 | u8 pll_out_div; | |
84 | u8 pll_mux; | |
85 | }; | |
86 | ||
973e02db AT |
87 | struct dsi_pll_10nm { |
88 | struct msm_dsi_pll base; | |
89 | ||
90 | int id; | |
91 | struct platform_device *pdev; | |
92 | ||
93 | void __iomem *phy_cmn_mmio; | |
94 | void __iomem *mmio; | |
95 | ||
28e4309a AT |
96 | u64 vco_ref_clk_rate; |
97 | u64 vco_current_rate; | |
98 | ||
99 | /* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */ | |
100 | spinlock_t postdiv_lock; | |
101 | ||
973e02db | 102 | int vco_delay; |
28e4309a AT |
103 | struct dsi_pll_config pll_configuration; |
104 | struct dsi_pll_regs reg_setup; | |
105 | ||
106 | /* private clocks: */ | |
83dda228 SP |
107 | struct clk_hw *out_div_clk_hw; |
108 | struct clk_hw *bit_clk_hw; | |
109 | struct clk_hw *byte_clk_hw; | |
110 | struct clk_hw *by_2_bit_clk_hw; | |
111 | struct clk_hw *post_out_div_clk_hw; | |
112 | struct clk_hw *pclk_mux_hw; | |
113 | struct clk_hw *out_dsiclk_hw; | |
28e4309a AT |
114 | |
115 | /* clock-provider: */ | |
116 | struct clk_hw_onecell_data *hw_data; | |
117 | ||
118 | struct pll_10nm_cached_state cached_state; | |
973e02db AT |
119 | |
120 | enum msm_dsi_phy_usecase uc; | |
121 | struct dsi_pll_10nm *slave; | |
122 | }; | |
123 | ||
124 | #define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, base) | |
125 | ||
126 | /* | |
127 | * Global list of private DSI PLL struct pointers. We need this for Dual DSI | |
128 | * mode, where the master PLL's clk_ops needs access the slave's private data | |
129 | */ | |
130 | static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX]; | |
131 | ||
28e4309a AT |
132 | static void dsi_pll_setup_config(struct dsi_pll_10nm *pll) |
133 | { | |
134 | struct dsi_pll_config *config = &pll->pll_configuration; | |
135 | ||
136 | config->ref_freq = pll->vco_ref_clk_rate; | |
137 | config->output_div = 1; | |
138 | config->dec_bits = 8; | |
139 | config->frac_bits = 18; | |
140 | config->lock_timer = 64; | |
141 | config->ssc_freq = 31500; | |
142 | config->ssc_offset = 5000; | |
143 | config->ssc_adj_per = 2; | |
144 | config->thresh_cycles = 32; | |
145 | config->refclk_cycles = 256; | |
146 | ||
147 | config->div_override = false; | |
148 | config->ignore_frac = false; | |
149 | config->disable_prescaler = false; | |
150 | ||
151 | config->enable_ssc = false; | |
152 | config->ssc_center = 0; | |
153 | } | |
154 | ||
155 | static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll) | |
156 | { | |
157 | struct dsi_pll_config *config = &pll->pll_configuration; | |
158 | struct dsi_pll_regs *regs = &pll->reg_setup; | |
159 | u64 fref = pll->vco_ref_clk_rate; | |
160 | u64 pll_freq; | |
161 | u64 divider; | |
162 | u64 dec, dec_multiple; | |
163 | u32 frac; | |
164 | u64 multiplier; | |
165 | ||
166 | pll_freq = pll->vco_current_rate; | |
167 | ||
168 | if (config->disable_prescaler) | |
169 | divider = fref; | |
170 | else | |
171 | divider = fref * 2; | |
172 | ||
173 | multiplier = 1 << config->frac_bits; | |
174 | dec_multiple = div_u64(pll_freq * multiplier, divider); | |
175 | div_u64_rem(dec_multiple, multiplier, &frac); | |
176 | ||
177 | dec = div_u64(dec_multiple, multiplier); | |
178 | ||
179 | if (pll_freq <= 1900000000UL) | |
180 | regs->pll_prop_gain_rate = 8; | |
181 | else if (pll_freq <= 3000000000UL) | |
182 | regs->pll_prop_gain_rate = 10; | |
183 | else | |
184 | regs->pll_prop_gain_rate = 12; | |
185 | if (pll_freq < 1100000000UL) | |
186 | regs->pll_clock_inverters = 8; | |
187 | else | |
188 | regs->pll_clock_inverters = 0; | |
189 | ||
190 | regs->pll_lockdet_rate = config->lock_timer; | |
191 | regs->decimal_div_start = dec; | |
192 | regs->frac_div_start_low = (frac & 0xff); | |
193 | regs->frac_div_start_mid = (frac & 0xff00) >> 8; | |
194 | regs->frac_div_start_high = (frac & 0x30000) >> 16; | |
195 | } | |
196 | ||
197 | #define SSC_CENTER BIT(0) | |
198 | #define SSC_EN BIT(1) | |
199 | ||
200 | static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll) | |
201 | { | |
202 | struct dsi_pll_config *config = &pll->pll_configuration; | |
203 | struct dsi_pll_regs *regs = &pll->reg_setup; | |
204 | u32 ssc_per; | |
205 | u32 ssc_mod; | |
206 | u64 ssc_step_size; | |
207 | u64 frac; | |
208 | ||
209 | if (!config->enable_ssc) { | |
210 | DBG("SSC not enabled\n"); | |
211 | return; | |
212 | } | |
213 | ||
214 | ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1; | |
215 | ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); | |
216 | ssc_per -= ssc_mod; | |
217 | ||
218 | frac = regs->frac_div_start_low | | |
219 | (regs->frac_div_start_mid << 8) | | |
220 | (regs->frac_div_start_high << 16); | |
221 | ssc_step_size = regs->decimal_div_start; | |
222 | ssc_step_size *= (1 << config->frac_bits); | |
223 | ssc_step_size += frac; | |
224 | ssc_step_size *= config->ssc_offset; | |
225 | ssc_step_size *= (config->ssc_adj_per + 1); | |
226 | ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); | |
227 | ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); | |
228 | ||
229 | regs->ssc_div_per_low = ssc_per & 0xFF; | |
230 | regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; | |
231 | regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); | |
232 | regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); | |
233 | regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; | |
234 | regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; | |
235 | ||
236 | regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; | |
237 | ||
238 | pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", | |
239 | regs->decimal_div_start, frac, config->frac_bits); | |
240 | pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", | |
241 | ssc_per, (u32)ssc_step_size, config->ssc_adj_per); | |
242 | } | |
243 | ||
244 | static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll) | |
245 | { | |
246 | void __iomem *base = pll->mmio; | |
247 | struct dsi_pll_regs *regs = &pll->reg_setup; | |
248 | ||
249 | if (pll->pll_configuration.enable_ssc) { | |
250 | pr_debug("SSC is enabled\n"); | |
251 | ||
252 | pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, | |
253 | regs->ssc_stepsize_low); | |
254 | pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, | |
255 | regs->ssc_stepsize_high); | |
256 | pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, | |
257 | regs->ssc_div_per_low); | |
258 | pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, | |
259 | regs->ssc_div_per_high); | |
260 | pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, | |
261 | regs->ssc_adjper_low); | |
262 | pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, | |
263 | regs->ssc_adjper_high); | |
264 | pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, | |
265 | SSC_EN | regs->ssc_control); | |
266 | } | |
267 | } | |
268 | ||
269 | static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) | |
270 | { | |
271 | void __iomem *base = pll->mmio; | |
272 | ||
273 | pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80); | |
274 | pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); | |
275 | pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); | |
276 | pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00); | |
277 | pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); | |
278 | pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); | |
279 | pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, | |
280 | 0xba); | |
281 | pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); | |
282 | pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); | |
283 | pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); | |
284 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); | |
285 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); | |
286 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); | |
287 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); | |
288 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, | |
289 | 0x4c); | |
290 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); | |
291 | pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); | |
292 | pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); | |
293 | } | |
294 | ||
295 | static void dsi_pll_commit(struct dsi_pll_10nm *pll) | |
296 | { | |
297 | void __iomem *base = pll->mmio; | |
298 | struct dsi_pll_regs *reg = &pll->reg_setup; | |
299 | ||
300 | pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); | |
301 | pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, | |
302 | reg->decimal_div_start); | |
303 | pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, | |
304 | reg->frac_div_start_low); | |
305 | pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, | |
306 | reg->frac_div_start_mid); | |
307 | pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, | |
308 | reg->frac_div_start_high); | |
309 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, 0x40); | |
310 | pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); | |
311 | pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); | |
312 | pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, | |
313 | reg->pll_clock_inverters); | |
314 | } | |
315 | ||
973e02db AT |
316 | static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long rate, |
317 | unsigned long parent_rate) | |
318 | { | |
319 | struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | |
320 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
321 | ||
322 | DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate, | |
323 | parent_rate); | |
324 | ||
28e4309a | 325 | pll_10nm->vco_current_rate = rate; |
8531f058 | 326 | pll_10nm->vco_ref_clk_rate = VCO_REF_CLK_RATE; |
28e4309a AT |
327 | |
328 | dsi_pll_setup_config(pll_10nm); | |
329 | ||
330 | dsi_pll_calc_dec_frac(pll_10nm); | |
331 | ||
332 | dsi_pll_calc_ssc(pll_10nm); | |
333 | ||
334 | dsi_pll_commit(pll_10nm); | |
335 | ||
336 | dsi_pll_config_hzindep_reg(pll_10nm); | |
337 | ||
338 | dsi_pll_ssc_commit(pll_10nm); | |
339 | ||
340 | /* flush, ensure all register writes are done*/ | |
341 | wmb(); | |
342 | ||
973e02db AT |
343 | return 0; |
344 | } | |
345 | ||
28e4309a AT |
346 | static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll) |
347 | { | |
348 | int rc; | |
349 | u32 status = 0; | |
350 | u32 const delay_us = 100; | |
351 | u32 const timeout_us = 5000; | |
352 | ||
353 | rc = readl_poll_timeout_atomic(pll->mmio + | |
354 | REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE, | |
355 | status, | |
356 | ((status & BIT(0)) > 0), | |
357 | delay_us, | |
358 | timeout_us); | |
359 | if (rc) | |
360 | pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", | |
361 | pll->id, status); | |
362 | ||
363 | return rc; | |
364 | } | |
365 | ||
366 | static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) | |
367 | { | |
368 | u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); | |
369 | ||
370 | pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); | |
371 | pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, | |
372 | data & ~BIT(5)); | |
373 | ndelay(250); | |
374 | } | |
375 | ||
376 | static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) | |
377 | { | |
378 | u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); | |
379 | ||
380 | pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, | |
381 | data | BIT(5)); | |
382 | pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); | |
383 | ndelay(250); | |
384 | } | |
385 | ||
386 | static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) | |
387 | { | |
388 | u32 data; | |
389 | ||
390 | data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | |
391 | pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, | |
392 | data & ~BIT(5)); | |
393 | } | |
394 | ||
395 | static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) | |
396 | { | |
397 | u32 data; | |
398 | ||
399 | data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | |
400 | pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, | |
401 | data | BIT(5)); | |
402 | } | |
403 | ||
404 | static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) | |
405 | { | |
406 | struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | |
407 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
408 | int rc; | |
409 | ||
410 | dsi_pll_enable_pll_bias(pll_10nm); | |
411 | if (pll_10nm->slave) | |
412 | dsi_pll_enable_pll_bias(pll_10nm->slave); | |
413 | ||
c6659785 H |
414 | rc = dsi_pll_10nm_vco_set_rate(hw,pll_10nm->vco_current_rate, 0); |
415 | if (rc) { | |
416 | pr_err("vco_set_rate failed, rc=%d\n", rc); | |
417 | return rc; | |
418 | } | |
419 | ||
28e4309a AT |
420 | /* Start PLL */ |
421 | pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, | |
422 | 0x01); | |
423 | ||
424 | /* | |
425 | * ensure all PLL configurations are written prior to checking | |
426 | * for PLL lock. | |
427 | */ | |
428 | wmb(); | |
429 | ||
430 | /* Check for PLL lock */ | |
431 | rc = dsi_pll_10nm_lock_status(pll_10nm); | |
432 | if (rc) { | |
433 | pr_err("PLL(%d) lock failed\n", pll_10nm->id); | |
434 | goto error; | |
435 | } | |
436 | ||
437 | pll->pll_on = true; | |
438 | ||
439 | dsi_pll_enable_global_clk(pll_10nm); | |
440 | if (pll_10nm->slave) | |
441 | dsi_pll_enable_global_clk(pll_10nm->slave); | |
442 | ||
443 | pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, | |
444 | 0x01); | |
445 | if (pll_10nm->slave) | |
446 | pll_write(pll_10nm->slave->phy_cmn_mmio + | |
447 | REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); | |
448 | ||
449 | error: | |
450 | return rc; | |
451 | } | |
452 | ||
453 | static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll) | |
454 | { | |
455 | pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0); | |
456 | dsi_pll_disable_pll_bias(pll); | |
457 | } | |
458 | ||
459 | static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw) | |
460 | { | |
461 | struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | |
462 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
463 | ||
464 | /* | |
465 | * To avoid any stray glitches while abruptly powering down the PLL | |
466 | * make sure to gate the clock using the clock enable bit before | |
467 | * powering down the PLL | |
468 | */ | |
469 | dsi_pll_disable_global_clk(pll_10nm); | |
470 | pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0); | |
471 | dsi_pll_disable_sub(pll_10nm); | |
472 | if (pll_10nm->slave) { | |
473 | dsi_pll_disable_global_clk(pll_10nm->slave); | |
474 | dsi_pll_disable_sub(pll_10nm->slave); | |
475 | } | |
476 | /* flush, ensure all register writes are done */ | |
477 | wmb(); | |
478 | pll->pll_on = false; | |
479 | } | |
480 | ||
973e02db AT |
481 | static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, |
482 | unsigned long parent_rate) | |
483 | { | |
484 | struct msm_dsi_pll *pll = hw_clk_to_pll(hw); | |
485 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
28e4309a AT |
486 | void __iomem *base = pll_10nm->mmio; |
487 | u64 ref_clk = pll_10nm->vco_ref_clk_rate; | |
973e02db | 488 | u64 vco_rate = 0x0; |
28e4309a AT |
489 | u64 multiplier; |
490 | u32 frac; | |
491 | u32 dec; | |
492 | u64 pll_freq, tmp64; | |
493 | ||
494 | dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); | |
495 | dec &= 0xff; | |
496 | ||
497 | frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); | |
498 | frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) & | |
499 | 0xff) << 8); | |
500 | frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) & | |
501 | 0x3) << 16); | |
502 | ||
503 | /* | |
504 | * TODO: | |
505 | * 1. Assumes prescaler is disabled | |
506 | * 2. Multiplier is 2^18. it should be 2^(num_of_frac_bits) | |
507 | */ | |
508 | multiplier = 1 << 18; | |
509 | pll_freq = dec * (ref_clk * 2); | |
510 | tmp64 = (ref_clk * 2 * frac); | |
511 | pll_freq += div_u64(tmp64, multiplier); | |
512 | ||
513 | vco_rate = pll_freq; | |
514 | ||
515 | DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", | |
516 | pll_10nm->id, (unsigned long)vco_rate, dec, frac); | |
973e02db AT |
517 | |
518 | return (unsigned long)vco_rate; | |
519 | } | |
520 | ||
521 | static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { | |
522 | .round_rate = msm_dsi_pll_helper_clk_round_rate, | |
523 | .set_rate = dsi_pll_10nm_vco_set_rate, | |
524 | .recalc_rate = dsi_pll_10nm_vco_recalc_rate, | |
28e4309a AT |
525 | .prepare = dsi_pll_10nm_vco_prepare, |
526 | .unprepare = dsi_pll_10nm_vco_unprepare, | |
973e02db AT |
527 | }; |
528 | ||
529 | /* | |
530 | * PLL Callbacks | |
531 | */ | |
532 | ||
533 | static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll) | |
534 | { | |
535 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
28e4309a AT |
536 | struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; |
537 | void __iomem *phy_base = pll_10nm->phy_cmn_mmio; | |
538 | u32 cmn_clk_cfg0, cmn_clk_cfg1; | |
973e02db | 539 | |
28e4309a AT |
540 | cached->pll_out_div = pll_read(pll_10nm->mmio + |
541 | REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); | |
542 | cached->pll_out_div &= 0x3; | |
543 | ||
544 | cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); | |
545 | cached->bit_clk_div = cmn_clk_cfg0 & 0xf; | |
546 | cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; | |
547 | ||
548 | cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | |
549 | cached->pll_mux = cmn_clk_cfg1 & 0x3; | |
550 | ||
551 | DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", | |
552 | pll_10nm->id, cached->pll_out_div, cached->bit_clk_div, | |
553 | cached->pix_clk_div, cached->pll_mux); | |
973e02db AT |
554 | } |
555 | ||
556 | static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll) | |
557 | { | |
558 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
28e4309a AT |
559 | struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; |
560 | void __iomem *phy_base = pll_10nm->phy_cmn_mmio; | |
561 | u32 val; | |
562 | ||
563 | val = pll_read(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); | |
564 | val &= ~0x3; | |
565 | val |= cached->pll_out_div; | |
566 | pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, val); | |
567 | ||
568 | pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, | |
569 | cached->bit_clk_div | (cached->pix_clk_div << 4)); | |
570 | ||
571 | val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); | |
572 | val &= ~0x3; | |
573 | val |= cached->pll_mux; | |
574 | pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val); | |
973e02db AT |
575 | |
576 | DBG("DSI PLL%d", pll_10nm->id); | |
577 | ||
578 | return 0; | |
579 | } | |
580 | ||
581 | static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll, | |
582 | enum msm_dsi_phy_usecase uc) | |
583 | { | |
584 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
28e4309a AT |
585 | void __iomem *base = pll_10nm->phy_cmn_mmio; |
586 | u32 data = 0x0; /* internal PLL */ | |
973e02db AT |
587 | |
588 | DBG("DSI PLL%d", pll_10nm->id); | |
589 | ||
28e4309a AT |
590 | switch (uc) { |
591 | case MSM_DSI_PHY_STANDALONE: | |
592 | break; | |
593 | case MSM_DSI_PHY_MASTER: | |
594 | pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX]; | |
595 | break; | |
596 | case MSM_DSI_PHY_SLAVE: | |
597 | data = 0x1; /* external PLL */ | |
598 | break; | |
599 | default: | |
600 | return -EINVAL; | |
601 | } | |
602 | ||
603 | /* set PLL src */ | |
604 | pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2)); | |
605 | ||
606 | pll_10nm->uc = uc; | |
607 | ||
973e02db AT |
608 | return 0; |
609 | } | |
610 | ||
611 | static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, | |
612 | struct clk **byte_clk_provider, | |
613 | struct clk **pixel_clk_provider) | |
614 | { | |
615 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
28e4309a | 616 | struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data; |
973e02db AT |
617 | |
618 | DBG("DSI PLL%d", pll_10nm->id); | |
619 | ||
620 | if (byte_clk_provider) | |
28e4309a | 621 | *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; |
973e02db | 622 | if (pixel_clk_provider) |
28e4309a | 623 | *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; |
973e02db AT |
624 | |
625 | return 0; | |
626 | } | |
627 | ||
628 | static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) | |
629 | { | |
630 | struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); | |
83dda228 | 631 | struct device *dev = &pll_10nm->pdev->dev; |
973e02db AT |
632 | |
633 | DBG("DSI PLL%d", pll_10nm->id); | |
83dda228 SP |
634 | of_clk_del_provider(dev->of_node); |
635 | ||
636 | clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); | |
637 | clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); | |
638 | clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); | |
639 | clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); | |
640 | clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); | |
641 | clk_hw_unregister_divider(pll_10nm->bit_clk_hw); | |
642 | clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); | |
643 | clk_hw_unregister(&pll_10nm->base.clk_hw); | |
973e02db AT |
644 | } |
645 | ||
28e4309a AT |
646 | /* |
647 | * The post dividers and mux clocks are created using the standard divider and | |
648 | * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its dividers/mux | |
649 | * state to follow the master PLL's divider/mux state. Therefore, we don't | |
650 | * require special clock ops that also configure the slave PLL registers | |
651 | */ | |
973e02db AT |
652 | static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) |
653 | { | |
28e4309a AT |
654 | char clk_name[32], parent[32], vco_name[32]; |
655 | char parent2[32], parent3[32], parent4[32]; | |
656 | struct clk_init_data vco_init = { | |
657 | .parent_names = (const char *[]){ "xo" }, | |
658 | .num_parents = 1, | |
659 | .name = vco_name, | |
660 | .flags = CLK_IGNORE_UNUSED, | |
661 | .ops = &clk_ops_dsi_pll_10nm_vco, | |
662 | }; | |
663 | struct device *dev = &pll_10nm->pdev->dev; | |
28e4309a AT |
664 | struct clk_hw_onecell_data *hw_data; |
665 | struct clk_hw *hw; | |
28e4309a AT |
666 | int ret; |
667 | ||
668 | DBG("DSI%d", pll_10nm->id); | |
669 | ||
670 | hw_data = devm_kzalloc(dev, sizeof(*hw_data) + | |
671 | NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), | |
672 | GFP_KERNEL); | |
673 | if (!hw_data) | |
674 | return -ENOMEM; | |
675 | ||
676 | snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id); | |
677 | pll_10nm->base.clk_hw.init = &vco_init; | |
678 | ||
679 | ret = clk_hw_register(dev, &pll_10nm->base.clk_hw); | |
680 | if (ret) | |
681 | return ret; | |
682 | ||
28e4309a AT |
683 | snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); |
684 | snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id); | |
685 | ||
686 | hw = clk_hw_register_divider(dev, clk_name, | |
687 | parent, CLK_SET_RATE_PARENT, | |
688 | pll_10nm->mmio + | |
689 | REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, | |
690 | 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); | |
83dda228 SP |
691 | if (IS_ERR(hw)) { |
692 | ret = PTR_ERR(hw); | |
693 | goto err_base_clk_hw; | |
694 | } | |
28e4309a | 695 | |
83dda228 | 696 | pll_10nm->out_div_clk_hw = hw; |
28e4309a AT |
697 | |
698 | snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id); | |
699 | snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); | |
700 | ||
701 | /* BIT CLK: DIV_CTRL_3_0 */ | |
702 | hw = clk_hw_register_divider(dev, clk_name, parent, | |
703 | CLK_SET_RATE_PARENT, | |
704 | pll_10nm->phy_cmn_mmio + | |
705 | REG_DSI_10nm_PHY_CMN_CLK_CFG0, | |
706 | 0, 4, CLK_DIVIDER_ONE_BASED, | |
707 | &pll_10nm->postdiv_lock); | |
83dda228 SP |
708 | if (IS_ERR(hw)) { |
709 | ret = PTR_ERR(hw); | |
710 | goto err_out_div_clk_hw; | |
711 | } | |
28e4309a | 712 | |
83dda228 | 713 | pll_10nm->bit_clk_hw = hw; |
28e4309a | 714 | |
c1866d44 | 715 | snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->id); |
28e4309a AT |
716 | snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); |
717 | ||
718 | /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ | |
719 | hw = clk_hw_register_fixed_factor(dev, clk_name, parent, | |
720 | CLK_SET_RATE_PARENT, 1, 8); | |
83dda228 SP |
721 | if (IS_ERR(hw)) { |
722 | ret = PTR_ERR(hw); | |
723 | goto err_bit_clk_hw; | |
724 | } | |
28e4309a | 725 | |
83dda228 | 726 | pll_10nm->byte_clk_hw = hw; |
28e4309a AT |
727 | hw_data->hws[DSI_BYTE_PLL_CLK] = hw; |
728 | ||
729 | snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); | |
730 | snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); | |
731 | ||
732 | hw = clk_hw_register_fixed_factor(dev, clk_name, parent, | |
733 | 0, 1, 2); | |
83dda228 SP |
734 | if (IS_ERR(hw)) { |
735 | ret = PTR_ERR(hw); | |
736 | goto err_byte_clk_hw; | |
737 | } | |
28e4309a | 738 | |
83dda228 | 739 | pll_10nm->by_2_bit_clk_hw = hw; |
28e4309a AT |
740 | |
741 | snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); | |
742 | snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); | |
743 | ||
744 | hw = clk_hw_register_fixed_factor(dev, clk_name, parent, | |
745 | 0, 1, 4); | |
83dda228 SP |
746 | if (IS_ERR(hw)) { |
747 | ret = PTR_ERR(hw); | |
748 | goto err_by_2_bit_clk_hw; | |
749 | } | |
28e4309a | 750 | |
83dda228 | 751 | pll_10nm->post_out_div_clk_hw = hw; |
28e4309a AT |
752 | |
753 | snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id); | |
754 | snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); | |
755 | snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); | |
756 | snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); | |
757 | snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); | |
758 | ||
759 | hw = clk_hw_register_mux(dev, clk_name, | |
9611b3aa | 760 | ((const char *[]){ |
28e4309a | 761 | parent, parent2, parent3, parent4 |
9611b3aa | 762 | }), 4, 0, pll_10nm->phy_cmn_mmio + |
28e4309a AT |
763 | REG_DSI_10nm_PHY_CMN_CLK_CFG1, |
764 | 0, 2, 0, NULL); | |
83dda228 SP |
765 | if (IS_ERR(hw)) { |
766 | ret = PTR_ERR(hw); | |
767 | goto err_post_out_div_clk_hw; | |
768 | } | |
28e4309a | 769 | |
83dda228 | 770 | pll_10nm->pclk_mux_hw = hw; |
28e4309a | 771 | |
c1866d44 | 772 | snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->id); |
28e4309a AT |
773 | snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id); |
774 | ||
775 | /* PIX CLK DIV : DIV_CTRL_7_4*/ | |
776 | hw = clk_hw_register_divider(dev, clk_name, parent, | |
777 | 0, pll_10nm->phy_cmn_mmio + | |
778 | REG_DSI_10nm_PHY_CMN_CLK_CFG0, | |
779 | 4, 4, CLK_DIVIDER_ONE_BASED, | |
780 | &pll_10nm->postdiv_lock); | |
83dda228 SP |
781 | if (IS_ERR(hw)) { |
782 | ret = PTR_ERR(hw); | |
783 | goto err_pclk_mux_hw; | |
784 | } | |
28e4309a | 785 | |
83dda228 | 786 | pll_10nm->out_dsiclk_hw = hw; |
28e4309a AT |
787 | hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; |
788 | ||
28e4309a AT |
789 | hw_data->num = NUM_PROVIDED_CLKS; |
790 | pll_10nm->hw_data = hw_data; | |
791 | ||
792 | ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, | |
793 | pll_10nm->hw_data); | |
794 | if (ret) { | |
6a41da17 | 795 | DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); |
83dda228 | 796 | goto err_dsiclk_hw; |
28e4309a AT |
797 | } |
798 | ||
973e02db | 799 | return 0; |
83dda228 SP |
800 | |
801 | err_dsiclk_hw: | |
802 | clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); | |
803 | err_pclk_mux_hw: | |
804 | clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); | |
805 | err_post_out_div_clk_hw: | |
806 | clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); | |
807 | err_by_2_bit_clk_hw: | |
808 | clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); | |
809 | err_byte_clk_hw: | |
810 | clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); | |
811 | err_bit_clk_hw: | |
812 | clk_hw_unregister_divider(pll_10nm->bit_clk_hw); | |
813 | err_out_div_clk_hw: | |
814 | clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); | |
815 | err_base_clk_hw: | |
816 | clk_hw_unregister(&pll_10nm->base.clk_hw); | |
817 | ||
818 | return ret; | |
973e02db AT |
819 | } |
820 | ||
821 | struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) | |
822 | { | |
823 | struct dsi_pll_10nm *pll_10nm; | |
824 | struct msm_dsi_pll *pll; | |
825 | int ret; | |
826 | ||
973e02db AT |
827 | pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL); |
828 | if (!pll_10nm) | |
829 | return ERR_PTR(-ENOMEM); | |
830 | ||
831 | DBG("DSI PLL%d", id); | |
832 | ||
833 | pll_10nm->pdev = pdev; | |
834 | pll_10nm->id = id; | |
835 | pll_10nm_list[id] = pll_10nm; | |
836 | ||
837 | pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); | |
838 | if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) { | |
6a41da17 | 839 | DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n"); |
973e02db AT |
840 | return ERR_PTR(-ENOMEM); |
841 | } | |
842 | ||
843 | pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); | |
844 | if (IS_ERR_OR_NULL(pll_10nm->mmio)) { | |
6a41da17 | 845 | DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n"); |
973e02db AT |
846 | return ERR_PTR(-ENOMEM); |
847 | } | |
848 | ||
7a296796 RY |
849 | spin_lock_init(&pll_10nm->postdiv_lock); |
850 | ||
973e02db AT |
851 | pll = &pll_10nm->base; |
852 | pll->min_rate = 1000000000UL; | |
853 | pll->max_rate = 3500000000UL; | |
854 | pll->get_provider = dsi_pll_10nm_get_provider; | |
855 | pll->destroy = dsi_pll_10nm_destroy; | |
856 | pll->save_state = dsi_pll_10nm_save_state; | |
857 | pll->restore_state = dsi_pll_10nm_restore_state; | |
858 | pll->set_usecase = dsi_pll_10nm_set_usecase; | |
859 | ||
860 | pll_10nm->vco_delay = 1; | |
861 | ||
862 | ret = pll_10nm_register(pll_10nm); | |
863 | if (ret) { | |
6a41da17 | 864 | DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); |
973e02db AT |
865 | return ERR_PTR(ret); |
866 | } | |
867 | ||
28e4309a AT |
868 | /* TODO: Remove this when we have proper display handover support */ |
869 | msm_dsi_pll_save_state(pll); | |
870 | ||
973e02db AT |
871 | return pll; |
872 | } |