blob: 6ce0d76861a2b34ce1ea19e0d99efa359e9e9c00 [file] [log] [blame]
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001/*
2 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/err.h>
18#include <linux/iopoll.h>
19#include <linux/delay.h>
Aravind Venkateswaran5773d732016-03-08 16:55:01 -080020#include "mdss-dsi-pll.h"
21#include "mdss-pll.h"
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -080022#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
Aravind Venkateswaran5773d732016-03-08 16:55:01 -080023
24#define VCO_DELAY_USEC 1
25
26#define MHZ_375 375000000UL
27#define MHZ_750 750000000UL
28#define MHZ_1500 1500000000UL
29#define MHZ_1900 1900000000UL
30#define MHZ_3000 3000000000UL
31
32/* Register Offsets from PLL base address */
33#define PLL_ANALOG_CONTROLS_ONE 0x000
34#define PLL_ANALOG_CONTROLS_TWO 0x004
35#define PLL_ANALOG_CONTROLS_THREE 0x010
36#define PLL_DSM_DIVIDER 0x01c
37#define PLL_FEEDBACK_DIVIDER 0x020
38#define PLL_SYSTEM_MUXES 0x024
39#define PLL_CMODE 0x02c
40#define PLL_CALIBRATION_SETTINGS 0x030
41#define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054
42#define PLL_FREQ_DETECT_SETTINGS_ONE 0x064
43#define PLL_OUTDIV 0x094
44#define PLL_CORE_OVERRIDE 0x0a4
45#define PLL_CORE_INPUT_OVERRIDE 0x0a8
46#define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4
47#define PLL_DECIMAL_DIV_START_1 0x0cc
48#define PLL_FRAC_DIV_START_LOW_1 0x0d0
49#define PLL_FRAC_DIV_START_MID_1 0x0d4
50#define PLL_FRAC_DIV_START_HIGH_1 0x0d8
Benjamin Chan50580372016-05-30 14:58:12 -040051#define PLL_SSC_STEPSIZE_LOW_1 0x10c
52#define PLL_SSC_STEPSIZE_HIGH_1 0x110
53#define PLL_SSC_DIV_PER_LOW_1 0x114
54#define PLL_SSC_DIV_PER_HIGH_1 0x118
55#define PLL_SSC_DIV_ADJPER_LOW_1 0x11c
56#define PLL_SSC_DIV_ADJPER_HIGH_1 0x120
57#define PLL_SSC_CONTROL 0x13c
Aravind Venkateswaran5773d732016-03-08 16:55:01 -080058#define PLL_PLL_OUTDIV_RATE 0x140
59#define PLL_PLL_LOCKDET_RATE_1 0x144
60#define PLL_PLL_PROP_GAIN_RATE_1 0x14c
61#define PLL_PLL_BAND_SET_RATE_1 0x154
62#define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c
63#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164
64#define PLL_PLL_LOCK_OVERRIDE 0x180
65#define PLL_PLL_LOCK_DELAY 0x184
66#define PLL_COMMON_STATUS_ONE 0x1a0
67
68/* Register Offsets from PHY base address */
69#define PHY_CMN_CLK_CFG0 0x010
70#define PHY_CMN_CLK_CFG1 0x014
71#define PHY_CMN_RBUF_CTRL 0x01c
72#define PHY_CMN_PLL_CNTRL 0x038
73#define PHY_CMN_CTRL_0 0x024
74
Benjamin Chan50580372016-05-30 14:58:12 -040075/* Bit definition of SSC control registers */
76#define SSC_CENTER BIT(0)
77#define SSC_EN BIT(1)
78#define SSC_FREQ_UPDATE BIT(2)
79#define SSC_FREQ_UPDATE_MUX BIT(3)
80#define SSC_UPDATE_SSC BIT(4)
81#define SSC_UPDATE_SSC_MUX BIT(5)
82#define SSC_START BIT(6)
83#define SSC_START_MUX BIT(7)
84
Aravind Venkateswaran5773d732016-03-08 16:55:01 -080085enum {
86 DSI_PLL_0,
87 DSI_PLL_1,
88 DSI_PLL_MAX
89};
90
91struct dsi_pll_regs {
92 u32 pll_prop_gain_rate;
93 u32 pll_outdiv_rate;
94 u32 pll_lockdet_rate;
95 u32 decimal_div_start;
96 u32 frac_div_start_low;
97 u32 frac_div_start_mid;
98 u32 frac_div_start_high;
Benjamin Chan50580372016-05-30 14:58:12 -040099 u32 ssc_stepsize_low;
100 u32 ssc_stepsize_high;
101 u32 ssc_div_per_low;
102 u32 ssc_div_per_high;
103 u32 ssc_adjper_low;
104 u32 ssc_adjper_high;
105 u32 ssc_control;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800106};
107
108struct dsi_pll_config {
109 u32 ref_freq;
110 bool div_override;
111 u32 output_div;
112 bool ignore_frac;
113 bool disable_prescaler;
Benjamin Chan50580372016-05-30 14:58:12 -0400114 bool enable_ssc;
115 bool ssc_center;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800116 u32 dec_bits;
117 u32 frac_bits;
118 u32 lock_timer;
119 u32 ssc_freq;
120 u32 ssc_offset;
121 u32 ssc_adj_per;
122 u32 thresh_cycles;
123 u32 refclk_cycles;
124};
125
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800126struct dsi_pll_10nm {
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800127 struct mdss_pll_resources *rsc;
128 struct dsi_pll_config pll_configuration;
129 struct dsi_pll_regs reg_setup;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800130};
131
132static struct mdss_pll_resources *pll_rsc_db[DSI_PLL_MAX];
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800133static struct dsi_pll_10nm plls[DSI_PLL_MAX];
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800134
135static void dsi_pll_config_slave(struct mdss_pll_resources *rsc)
136{
137 u32 reg;
138 struct mdss_pll_resources *orsc = pll_rsc_db[DSI_PLL_1];
139
140 if (!rsc)
141 return;
142
143 /* Only DSI PLL0 can act as a master */
144 if (rsc->index != DSI_PLL_0)
145 return;
146
147 /* default configuration: source is either internal or ref clock */
148 rsc->slave = NULL;
149
150 if (!orsc) {
151 pr_warn("slave PLL unavilable, assuming standalone config\n");
152 return;
153 }
154
155 /* check to see if the source of DSI1 PLL bitclk is set to external */
156 reg = MDSS_PLL_REG_R(orsc->phy_base, PHY_CMN_CLK_CFG1);
157 reg &= (BIT(2) | BIT(3));
158 if (reg == 0x04)
159 rsc->slave = pll_rsc_db[DSI_PLL_1]; /* external source */
160
161 pr_debug("Slave PLL %s\n", rsc->slave ? "configured" : "absent");
162}
163
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800164static void dsi_pll_setup_config(struct dsi_pll_10nm *pll,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800165 struct mdss_pll_resources *rsc)
166{
167 struct dsi_pll_config *config = &pll->pll_configuration;
168
169 config->ref_freq = 19200000;
170 config->output_div = 1;
171 config->dec_bits = 8;
172 config->frac_bits = 18;
173 config->lock_timer = 64;
174 config->ssc_freq = 31500;
Benjamin Chan50580372016-05-30 14:58:12 -0400175 config->ssc_offset = 5000;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800176 config->ssc_adj_per = 2;
177 config->thresh_cycles = 32;
178 config->refclk_cycles = 256;
179
180 config->div_override = false;
181 config->ignore_frac = false;
182 config->disable_prescaler = false;
Benjamin Chan50580372016-05-30 14:58:12 -0400183 config->enable_ssc = rsc->ssc_en;
184 config->ssc_center = rsc->ssc_center;
185
186 if (config->enable_ssc) {
187 if (rsc->ssc_freq)
188 config->ssc_freq = rsc->ssc_freq;
189 if (rsc->ssc_ppm)
190 config->ssc_offset = rsc->ssc_ppm;
191 }
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800192
193 dsi_pll_config_slave(rsc);
194}
195
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800196static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800197 struct mdss_pll_resources *rsc)
198{
199 struct dsi_pll_config *config = &pll->pll_configuration;
200 struct dsi_pll_regs *regs = &pll->reg_setup;
201 u64 target_freq;
202 u64 fref = rsc->vco_ref_clk_rate;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800203 u32 computed_output_div, div_log = 0;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800204 u64 pll_freq;
205 u64 divider;
206 u64 dec, dec_multiple;
207 u32 frac;
208 u64 multiplier;
209
Aravind Venkateswaran071ecc82016-05-18 15:18:34 -0700210 target_freq = rsc->vco_current_rate;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800211 pr_debug("target_freq = %llu\n", target_freq);
212
213 if (config->div_override) {
214 computed_output_div = config->output_div;
215 } else {
216 if (target_freq < MHZ_375) {
217 computed_output_div = 8;
218 div_log = 3;
219 } else if (target_freq < MHZ_750) {
220 computed_output_div = 4;
221 div_log = 2;
222 } else if (target_freq < MHZ_1500) {
223 computed_output_div = 2;
224 div_log = 1;
225 } else {
226 computed_output_div = 1;
227 div_log = 0;
228 }
229 }
230 pr_debug("computed_output_div = %d\n", computed_output_div);
231
232 pll_freq = target_freq * computed_output_div;
233
234 if (config->disable_prescaler)
235 divider = fref;
236 else
237 divider = fref * 2;
238
239 multiplier = 1 << config->frac_bits;
240 dec_multiple = div_u64(pll_freq * multiplier, divider);
241 div_u64_rem(dec_multiple, multiplier, &frac);
242
243 dec = div_u64(dec_multiple, multiplier);
244
245 if (pll_freq <= MHZ_1900)
246 regs->pll_prop_gain_rate = 8;
247 else if (pll_freq <= MHZ_3000)
248 regs->pll_prop_gain_rate = 10;
249 else
250 regs->pll_prop_gain_rate = 12;
251
252 regs->pll_outdiv_rate = div_log;
253 regs->pll_lockdet_rate = config->lock_timer;
254 regs->decimal_div_start = dec;
255 regs->frac_div_start_low = (frac & 0xff);
256 regs->frac_div_start_mid = (frac & 0xff00) >> 8;
257 regs->frac_div_start_high = (frac & 0x30000) >> 16;
258}
259
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800260static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll,
Benjamin Chan50580372016-05-30 14:58:12 -0400261 struct mdss_pll_resources *rsc)
262{
263 struct dsi_pll_config *config = &pll->pll_configuration;
264 struct dsi_pll_regs *regs = &pll->reg_setup;
265 u32 ssc_per;
266 u32 ssc_mod;
267 u64 ssc_step_size;
268 u64 frac;
269
270 if (!config->enable_ssc) {
271 pr_debug("SSC not enabled\n");
272 return;
273 }
274
275 ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1;
276 ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1);
277 ssc_per -= ssc_mod;
278
279 frac = regs->frac_div_start_low |
280 (regs->frac_div_start_mid << 8) |
281 (regs->frac_div_start_high << 16);
282 ssc_step_size = regs->decimal_div_start;
283 ssc_step_size *= (1 << config->frac_bits);
284 ssc_step_size += frac;
285 ssc_step_size *= config->ssc_offset;
286 ssc_step_size *= (config->ssc_adj_per + 1);
287 ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1));
288 ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000);
289
290 regs->ssc_div_per_low = ssc_per & 0xFF;
291 regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8;
292 regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF);
293 regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8);
294 regs->ssc_adjper_low = config->ssc_adj_per & 0xFF;
295 regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8;
296
297 regs->ssc_control = config->ssc_center ? SSC_CENTER : 0;
298
299 pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n",
300 regs->decimal_div_start, frac, config->frac_bits);
301 pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n",
302 ssc_per, (u32)ssc_step_size, config->ssc_adj_per);
303}
304
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800305static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll,
Benjamin Chan50580372016-05-30 14:58:12 -0400306 struct mdss_pll_resources *rsc)
307{
308 void __iomem *pll_base = rsc->pll_base;
309 struct dsi_pll_regs *regs = &pll->reg_setup;
310
311 if (pll->pll_configuration.enable_ssc) {
312 pr_debug("SSC is enabled\n");
313
314 MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1,
315 regs->ssc_stepsize_low);
316 MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_1,
317 regs->ssc_stepsize_high);
318 MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_1,
319 regs->ssc_div_per_low);
320 MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_1,
321 regs->ssc_div_per_high);
322 MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_ADJPER_LOW_1,
323 regs->ssc_adjper_low);
324 MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_ADJPER_HIGH_1,
325 regs->ssc_adjper_high);
326 MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL,
327 SSC_EN | regs->ssc_control);
328 }
329}
330
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800331static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800332 struct mdss_pll_resources *rsc)
333{
334 void __iomem *pll_base = rsc->pll_base;
335
336 MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_ONE, 0x80);
337 MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_TWO, 0x03);
338 MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_THREE, 0x00);
339 MDSS_PLL_REG_W(pll_base, PLL_DSM_DIVIDER, 0x00);
340 MDSS_PLL_REG_W(pll_base, PLL_FEEDBACK_DIVIDER, 0x4e);
341 MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x00);
342 MDSS_PLL_REG_W(pll_base, PLL_CALIBRATION_SETTINGS, 0x40);
343 MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba);
344 MDSS_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
345 MDSS_PLL_REG_W(pll_base, PLL_OUTDIV, 0x00);
346 MDSS_PLL_REG_W(pll_base, PLL_CORE_OVERRIDE, 0x00);
347 MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
348 MDSS_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x08);
349 MDSS_PLL_REG_W(pll_base, PLL_PLL_BAND_SET_RATE_1, 0xc0);
350 MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x82);
351 MDSS_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c);
352 MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x80);
353}
354
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800355static void dsi_pll_commit(struct dsi_pll_10nm *pll,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800356 struct mdss_pll_resources *rsc)
357{
358 void __iomem *pll_base = rsc->pll_base;
359 struct dsi_pll_regs *reg = &pll->reg_setup;
360
361 MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x12);
362 MDSS_PLL_REG_W(pll_base, PLL_DECIMAL_DIV_START_1,
363 reg->decimal_div_start);
364 MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_LOW_1,
365 reg->frac_div_start_low);
366 MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_MID_1,
367 reg->frac_div_start_mid);
368 MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1,
369 reg->frac_div_start_high);
370 MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0xc8);
371 MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
372 MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x0a);
373
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800374}
375
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800376static int vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate,
377 unsigned long parent_rate)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800378{
379 int rc;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800380 struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw);
Aravind Venkateswaran071ecc82016-05-18 15:18:34 -0700381 struct mdss_pll_resources *rsc = vco->priv;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800382 struct dsi_pll_10nm *pll;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800383
384 if (!rsc) {
385 pr_err("pll resource not found\n");
386 return -EINVAL;
387 }
388
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800389 if (rsc->pll_on)
390 return 0;
391
392 pll = rsc->priv;
393 if (!pll) {
394 pr_err("pll configuration not found\n");
395 return -EINVAL;
396 }
397
Aravind Venkateswaran071ecc82016-05-18 15:18:34 -0700398 pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate);
399
400 rsc->vco_current_rate = rate;
401 rsc->vco_ref_clk_rate = vco->ref_clk_rate;
402
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800403 rc = mdss_pll_resource_enable(rsc, true);
404 if (rc) {
405 pr_err("failed to enable mdss dsi pll(%d), rc=%d\n",
406 rsc->index, rc);
407 return rc;
408 }
409
410 dsi_pll_setup_config(pll, rsc);
411
412 dsi_pll_calc_dec_frac(pll, rsc);
413
Benjamin Chan50580372016-05-30 14:58:12 -0400414 dsi_pll_calc_ssc(pll, rsc);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800415
416 dsi_pll_commit(pll, rsc);
417
Benjamin Chan50580372016-05-30 14:58:12 -0400418 dsi_pll_config_hzindep_reg(pll, rsc);
419
420 dsi_pll_ssc_commit(pll, rsc);
421
422 /* flush, ensure all register writes are done*/
423 wmb();
424
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800425 mdss_pll_resource_enable(rsc, false);
426
Aravind Venkateswaran071ecc82016-05-18 15:18:34 -0700427 return 0;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800428}
429
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800430static int dsi_pll_10nm_lock_status(struct mdss_pll_resources *pll)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800431{
432 int rc;
433 u32 status;
434 u32 const delay_us = 100;
435 u32 const timeout_us = 5000;
436
437 rc = readl_poll_timeout_atomic(pll->pll_base + PLL_COMMON_STATUS_ONE,
438 status,
439 ((status & BIT(0)) > 0),
440 delay_us,
441 timeout_us);
442 if (rc)
443 pr_err("DSI PLL(%d) lock failed, status=0x%08x\n",
444 pll->index, status);
445
446 return rc;
447}
448
449static void dsi_pll_disable_pll_bias(struct mdss_pll_resources *rsc)
450{
451 u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0);
452
453 MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5));
454 MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0);
455 ndelay(250);
456}
457
458static void dsi_pll_enable_pll_bias(struct mdss_pll_resources *rsc)
459{
460 u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0);
461
462 MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5));
463 MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0xc0);
464 ndelay(250);
465}
466
467static int dsi_pll_enable(struct dsi_pll_vco_clk *vco)
468{
469 int rc;
470 struct mdss_pll_resources *rsc = vco->priv;
471
472 dsi_pll_enable_pll_bias(rsc);
473 if (rsc->slave)
474 dsi_pll_enable_pll_bias(rsc->slave);
475
476 /* Start PLL */
477 MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01);
478
479 /*
480 * ensure all PLL configurations are written prior to checking
481 * for PLL lock.
482 */
483 wmb();
484
485 /* Check for PLL lock */
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800486 rc = dsi_pll_10nm_lock_status(rsc);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800487 if (rc) {
488 pr_err("PLL(%d) lock failed\n", rsc->index);
489 goto error;
490 }
491
492 rsc->pll_on = true;
493 MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0x01);
494 if (rsc->slave)
495 MDSS_PLL_REG_W(rsc->slave->phy_base, PHY_CMN_RBUF_CTRL, 0x01);
496
497error:
498 return rc;
499}
500
501static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc)
502{
503 dsi_pll_disable_pll_bias(rsc);
504 MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0);
505}
506
507static void dsi_pll_disable(struct dsi_pll_vco_clk *vco)
508{
509 struct mdss_pll_resources *rsc = vco->priv;
510
511 if (!rsc->pll_on &&
512 mdss_pll_resource_enable(rsc, true)) {
513 pr_err("failed to enable pll (%d) resources\n", rsc->index);
514 return;
515 }
516
517 rsc->handoff_resources = false;
518
519 pr_debug("stop PLL (%d)\n", rsc->index);
520
521 MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0);
522 dsi_pll_disable_sub(rsc);
523 if (rsc->slave)
524 dsi_pll_disable_sub(rsc->slave);
525
526 /* flush, ensure all register writes are done*/
527 wmb();
528 rsc->pll_on = false;
529}
530
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800531long vco_10nm_round_rate(struct clk_hw *hw, unsigned long rate,
532 unsigned long *parent_rate)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800533{
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800534 unsigned long rrate = rate;
535 struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw);
536
537 if (rate < vco->min_rate)
538 rrate = vco->min_rate;
539 if (rate > vco->max_rate)
540 rrate = vco->max_rate;
541
542 *parent_rate = rrate;
543
544 return rrate;
545}
546
547static void vco_10nm_unprepare(struct clk_hw *hw)
548{
549 struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800550 struct mdss_pll_resources *pll = vco->priv;
551
552 if (!pll) {
553 pr_err("dsi pll resources not available\n");
554 return;
555 }
556
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800557 pll->vco_cached_rate = clk_hw_get_rate(hw);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800558 dsi_pll_disable(vco);
559 mdss_pll_resource_enable(pll, false);
560}
561
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800562static int vco_10nm_prepare(struct clk_hw *hw)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800563{
564 int rc = 0;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800565 struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800566 struct mdss_pll_resources *pll = vco->priv;
567
568 if (!pll) {
569 pr_err("dsi pll resources are not available\n");
570 return -EINVAL;
571 }
572
573 rc = mdss_pll_resource_enable(pll, true);
574 if (rc) {
575 pr_err("failed to enable pll (%d) resource, rc=%d\n",
576 pll->index, rc);
577 return rc;
578 }
579
580 if ((pll->vco_cached_rate != 0) &&
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800581 (pll->vco_cached_rate == clk_hw_get_rate(hw))) {
582 rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate,
583 pll->vco_cached_rate);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800584 if (rc) {
585 pr_err("pll(%d) set_rate failed, rc=%d\n",
586 pll->index, rc);
587 mdss_pll_resource_enable(pll, false);
588 return rc;
589 }
590 }
591
592 rc = dsi_pll_enable(vco);
593 if (rc) {
594 mdss_pll_resource_enable(pll, false);
595 pr_err("pll(%d) enable failed, rc=%d\n", pll->index, rc);
596 return rc;
597 }
598
599 return rc;
600}
601
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800602static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw,
603 unsigned long parent_rate)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800604{
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800605 struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800606 struct mdss_pll_resources *pll = vco->priv;
607 int rc;
608 u64 ref_clk = vco->ref_clk_rate;
609 u64 vco_rate;
610 u64 multiplier;
611 u32 frac;
612 u32 dec;
613 u32 outdiv;
614 u64 pll_freq, tmp64;
615
616 rc = mdss_pll_resource_enable(pll, true);
617 if (rc) {
618 pr_err("failed to enable pll(%d) resource, rc=%d\n",
619 pll->index, rc);
620 return 0;
621 }
622
623 dec = MDSS_PLL_REG_R(pll->pll_base, PLL_DECIMAL_DIV_START_1);
624 dec &= 0xFF;
625
626 frac = MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_LOW_1);
627 frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_MID_1) &
628 0xFF) <<
629 8);
630 frac |= ((MDSS_PLL_REG_R(pll->pll_base, PLL_FRAC_DIV_START_HIGH_1) &
631 0x3) <<
632 16);
633
634 /* OUTDIV_1:0 field is (log(outdiv, 2)) */
Aravind Venkateswaran55d0e222016-06-28 12:00:11 -0700635 outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800636 outdiv &= 0x3;
637 outdiv = 1 << outdiv;
638
639 /*
640 * TODO:
641 * 1. Assumes prescaler is disabled
642 * 2. Multiplier is 2^18. it should be 2^(num_of_frac_bits)
643 **/
644 multiplier = 1 << 18;
645 pll_freq = dec * (ref_clk * 2);
646 tmp64 = (ref_clk * 2 * frac);
Aravind Venkateswaran55d0e222016-06-28 12:00:11 -0700647 pll_freq += div_u64(tmp64, multiplier);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800648
Aravind Venkateswaran55d0e222016-06-28 12:00:11 -0700649 vco_rate = div_u64(pll_freq, outdiv);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800650
Aravind Venkateswaran55d0e222016-06-28 12:00:11 -0700651 pr_debug("dec=0x%x, frac=0x%x, outdiv=%d, vco=%llu\n",
652 dec, frac, outdiv, vco_rate);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800653
654 (void)mdss_pll_resource_enable(pll, false);
655
656 return (unsigned long)vco_rate;
657}
658
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800659static int pixel_clk_get_div(void *context, unsigned int reg, unsigned int *div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800660{
661 int rc;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800662 struct mdss_pll_resources *pll = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800663 u32 reg_val;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800664
665 rc = mdss_pll_resource_enable(pll, true);
666 if (rc) {
667 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
668 return rc;
669 }
670
671 reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800672 *div = (reg_val & 0xF0) >> 4;
673
674 if (*div == 0)
675 *div = 1;
676 else
677 *div -= 1;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800678
679 (void)mdss_pll_resource_enable(pll, false);
680
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800681 return rc;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800682}
683
684static void pixel_clk_set_div_sub(struct mdss_pll_resources *pll, int div)
685{
686 u32 reg_val;
687
688 reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
689 reg_val &= ~0xF0;
690 reg_val |= (div << 4);
691 MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val);
692}
693
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800694static int pixel_clk_set_div(void *context, unsigned int reg, unsigned int div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800695{
696 int rc;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800697 struct mdss_pll_resources *pll = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800698
699 rc = mdss_pll_resource_enable(pll, true);
700 if (rc) {
701 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
702 return rc;
703 }
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800704 /* In common clock framework the divider value provided is one less */
705 div++;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800706
707 pixel_clk_set_div_sub(pll, div);
708 if (pll->slave)
709 pixel_clk_set_div_sub(pll->slave, div);
710
711 (void)mdss_pll_resource_enable(pll, false);
712
713 return 0;
714}
715
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800716static int bit_clk_get_div(void *context, unsigned int reg, unsigned int *div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800717{
718 int rc;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800719 struct mdss_pll_resources *pll = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800720 u32 reg_val;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800721
722 rc = mdss_pll_resource_enable(pll, true);
723 if (rc) {
724 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
725 return rc;
726 }
727
728 reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800729 *div = (reg_val & 0x0F);
730
731 /* Common clock framework will add one to divider value sent */
732 if (*div == 0)
733 *div = 1;
734 else
735 *div -= 1;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800736
737 (void)mdss_pll_resource_enable(pll, false);
738
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800739 return rc;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800740}
741
742static void bit_clk_set_div_sub(struct mdss_pll_resources *rsc, int div)
743{
744 u32 reg_val;
745
746 reg_val = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0);
747 reg_val &= ~0x0F;
Aravind Venkateswaran071ecc82016-05-18 15:18:34 -0700748 reg_val |= div;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800749 MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG0, reg_val);
750}
751
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800752static int bit_clk_set_div(void *context, unsigned int reg, unsigned int div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800753{
754 int rc;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800755 struct mdss_pll_resources *rsc = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800756 struct dsi_pll_8998 *pll;
757
758 if (!rsc) {
759 pr_err("pll resource not found\n");
760 return -EINVAL;
761 }
762
763 pll = rsc->priv;
764 if (!pll) {
765 pr_err("pll configuration not found\n");
766 return -EINVAL;
767 }
768
769 rc = mdss_pll_resource_enable(rsc, true);
770 if (rc) {
771 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
772 return rc;
773 }
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800774 div++;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800775
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800776 bit_clk_set_div_sub(rsc, div);
Aravind Venkateswaran071ecc82016-05-18 15:18:34 -0700777 /* For slave PLL, this divider always should be set to 1 */
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800778 if (rsc->slave)
Aravind Venkateswaran071ecc82016-05-18 15:18:34 -0700779 bit_clk_set_div_sub(rsc->slave, 1);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800780
781 (void)mdss_pll_resource_enable(rsc, false);
782
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800783 return rc;
784}
785
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800786static int post_vco_clk_get_div(void *context, unsigned int reg,
787 unsigned int *div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800788{
789 int rc;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800790 struct mdss_pll_resources *pll = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800791 u32 reg_val;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800792
793 rc = mdss_pll_resource_enable(pll, true);
794 if (rc) {
795 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
796 return rc;
797 }
798
799 reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
800 reg_val &= 0x3;
801
802 if (reg_val == 2)
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800803 *div = 1;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800804 else if (reg_val == 3)
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800805 *div = 4;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800806 else
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800807 *div = 1;
808
809 if (*div == 0)
810 *div = 1;
811 else
812 *div -= 1;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800813
814 (void)mdss_pll_resource_enable(pll, false);
815
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800816 return rc;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800817}
818
819static int post_vco_clk_set_div_sub(struct mdss_pll_resources *pll, int div)
820{
821 u32 reg_val;
822 int rc = 0;
823
824 reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
825 reg_val &= ~0x03;
826 if (div == 1) {
827 reg_val |= 0x2;
828 } else if (div == 4) {
829 reg_val |= 0x3;
830 } else {
831 rc = -EINVAL;
832 pr_err("unsupported divider %d\n", div);
833 goto error;
834 }
835
836 MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val);
837
838error:
839 return rc;
840}
841
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800842static int post_vco_clk_set_div(void *context, unsigned int reg,
843 unsigned int div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800844{
845 int rc = 0;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800846 struct mdss_pll_resources *pll = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800847
848 rc = mdss_pll_resource_enable(pll, true);
849 if (rc) {
850 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
851 return rc;
852 }
853
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800854 div++;
855
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800856 rc = post_vco_clk_set_div_sub(pll, div);
857 if (!rc && pll->slave)
858 rc = post_vco_clk_set_div_sub(pll->slave, div);
859
860 (void)mdss_pll_resource_enable(pll, false);
861
862 return rc;
863}
864
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800865static int post_bit_clk_get_div(void *context, unsigned int reg,
866 unsigned int *div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800867{
868 int rc;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800869 struct mdss_pll_resources *pll = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800870 u32 reg_val;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800871
872 rc = mdss_pll_resource_enable(pll, true);
873 if (rc) {
874 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
875 return rc;
876 }
877
878 reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
879 reg_val &= 0x3;
880
881 if (reg_val == 0)
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800882 *div = 1;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800883 else if (reg_val == 1)
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800884 *div = 2;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800885 else
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800886 *div = 1;
887
888 if (*div == 0)
889 *div = 1;
890 else
891 *div -= 1;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800892
893 (void)mdss_pll_resource_enable(pll, false);
894
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800895 return rc;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800896}
897
898static int post_bit_clk_set_div_sub(struct mdss_pll_resources *pll, int div)
899{
900 int rc = 0;
901 u32 reg_val;
902
903 reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG1);
904 reg_val &= ~0x03;
905 if (div == 1) {
906 reg_val |= 0x0;
907 } else if (div == 2) {
908 reg_val |= 0x1;
909 } else {
910 rc = -EINVAL;
911 pr_err("unsupported divider %d\n", div);
912 goto error;
913 }
914
915 MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG1, reg_val);
916
917error:
918 return rc;
919}
920
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800921static int post_bit_clk_set_div(void *context, unsigned int reg,
922 unsigned int div)
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800923{
924 int rc = 0;
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800925 struct mdss_pll_resources *pll = context;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800926
927 rc = mdss_pll_resource_enable(pll, true);
928 if (rc) {
929 pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
930 return rc;
931 }
932
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800933 div++;
934
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800935 rc = post_bit_clk_set_div_sub(pll, div);
936 if (!rc && pll->slave)
937 rc = post_bit_clk_set_div_sub(pll->slave, div);
938
939 (void)mdss_pll_resource_enable(pll, false);
940
941 return rc;
942}
943
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800944static struct regmap_config dsi_pll_10nm_config = {
945 .reg_bits = 32,
946 .reg_stride = 4,
947 .val_bits = 32,
948 .max_register = 0x7c0,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800949};
950
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800951static struct regmap_bus post_vco_regmap_bus = {
952 .reg_write = post_vco_clk_set_div,
953 .reg_read = post_vco_clk_get_div,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800954};
955
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800956static struct regmap_bus post_bit_regmap_bus = {
957 .reg_write = post_bit_clk_set_div,
958 .reg_read = post_bit_clk_get_div,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800959};
960
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800961static struct regmap_bus pclk_src_regmap_bus = {
962 .reg_write = pixel_clk_set_div,
963 .reg_read = pixel_clk_get_div,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800964};
965
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800966static struct regmap_bus bitclk_src_regmap_bus = {
967 .reg_write = bit_clk_set_div,
968 .reg_read = bit_clk_get_div,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800969};
970
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -0800971static const struct clk_ops clk_ops_vco_10nm = {
972 .recalc_rate = vco_10nm_recalc_rate,
973 .set_rate = vco_10nm_set_rate,
974 .round_rate = vco_10nm_round_rate,
975 .prepare = vco_10nm_prepare,
976 .unprepare = vco_10nm_unprepare,
977};
978
979static struct regmap_bus mdss_mux_regmap_bus = {
980 .reg_write = mdss_set_mux_sel,
981 .reg_read = mdss_get_mux_sel,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -0800982};
983
984/*
985 * Clock tree for generating DSI byte and pixel clocks.
986 *
987 *
988 * +---------------+
989 * | vco_clk |
990 * +-------+-------+
991 * |
992 * +--------------------------------------+
993 * | |
994 * +-------v-------+ |
995 * | bitclk_src | |
996 * | DIV(1..15) | |
997 * +-------+-------+ |
998 * | |
999 * +--------------------+ |
1000 * Shadow Path | | |
1001 * + +-------v-------+ +------v------+ +------v-------+
1002 * | | byteclk_src | |post_bit_div | |post_vco_div |
1003 * | | DIV(8) | |DIV(1,2) | |DIV(1,4) |
1004 * | +-------+-------+ +------+------+ +------+-------+
1005 * | | | |
1006 * | | +------+ +----+
1007 * | +--------+ | |
1008 * | | +----v-----v------+
1009 * +-v---------v----+ \ pclk_src_mux /
1010 * \ byteclk_mux / \ /
1011 * \ / +-----+-----+
1012 * +----+-----+ | Shadow Path
1013 * | | +
1014 * v +-----v------+ |
1015 * dsi_byte_clk | pclk_src | |
1016 * | DIV(1..15) | |
1017 * +-----+------+ |
1018 * | |
1019 * | |
1020 * +--------+ |
1021 * | |
1022 * +---v----v----+
1023 * \ pclk_mux /
1024 * \ /
1025 * +---+---+
1026 * |
1027 * |
1028 * v
1029 * dsi_pclk
1030 *
1031 */
1032
1033static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
1034 .ref_clk_rate = 19200000UL,
1035 .min_rate = 1500000000UL,
1036 .max_rate = 3500000000UL,
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001037 .hw.init = &(struct clk_init_data){
1038 .name = "dsi0pll_vco_clk",
1039 .parent_names = (const char *[]){"xo_board"},
1040 .num_parents = 1,
1041 .ops = &clk_ops_vco_10nm,
1042 .flags = CLK_GET_RATE_NOCACHE,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001043 },
1044};
1045
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001046static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
1047 .ref_clk_rate = 19200000UL,
1048 .min_rate = 1500000000UL,
1049 .max_rate = 3500000000UL,
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001050 .hw.init = &(struct clk_init_data){
1051 .name = "dsi1pll_vco_clk",
1052 .parent_names = (const char *[]){"xo_board"},
1053 .num_parents = 1,
1054 .ops = &clk_ops_vco_10nm,
1055 .flags = CLK_GET_RATE_NOCACHE,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001056 },
1057};
1058
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001059static struct clk_regmap_div dsi0pll_bitclk_src = {
1060 .reg = 0x48,
1061 .shift = 0,
1062 .width = 4,
1063 .clkr = {
1064 .hw.init = &(struct clk_init_data){
1065 .name = "dsi0pll_bitclk_src",
1066 .parent_names = (const char *[]){"dsi0pll_vco_clk"},
1067 .num_parents = 1,
1068 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1069 .ops = &clk_regmap_div_ops,
1070 },
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001071 },
1072};
1073
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001074static struct clk_regmap_div dsi1pll_bitclk_src = {
1075 .reg = 0x48,
1076 .shift = 0,
1077 .width = 4,
1078 .clkr = {
1079 .hw.init = &(struct clk_init_data){
1080 .name = "dsi1pll_bitclk_src",
1081 .parent_names = (const char *[]){"dsi1pll_vco_clk"},
1082 .num_parents = 1,
1083 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1084 .ops = &clk_regmap_div_ops,
1085 },
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001086 },
1087};
1088
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001089static struct clk_regmap_div dsi0pll_post_vco_div = {
1090 .reg = 0x48,
1091 .shift = 0,
1092 .width = 4,
1093 .clkr = {
1094 .hw.init = &(struct clk_init_data){
1095 .name = "dsi0pll_post_vco_div",
1096 .parent_names = (const char *[]){"dsi0pll_vco_clk"},
1097 .num_parents = 1,
1098 .flags = CLK_GET_RATE_NOCACHE,
1099 .ops = &clk_regmap_div_ops,
1100 },
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001101 },
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001102};
1103
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001104static struct clk_regmap_div dsi1pll_post_vco_div = {
1105 .reg = 0x48,
1106 .shift = 0,
1107 .width = 4,
1108 .clkr = {
1109 .hw.init = &(struct clk_init_data){
1110 .name = "dsi1pll_post_vco_div",
1111 .parent_names = (const char *[]){"dsi1pll_vco_clk"},
1112 .num_parents = 1,
1113 .flags = CLK_GET_RATE_NOCACHE,
1114 .ops = &clk_regmap_div_ops,
1115 },
1116 },
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001117};
1118
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001119static struct clk_fixed_factor dsi0pll_byteclk_src = {
1120 .div = 8,
1121 .mult = 1,
1122 .hw.init = &(struct clk_init_data){
1123 .name = "dsi0pll_byteclk_src",
1124 .parent_names = (const char *[]){"dsi0pll_bitclk_src"},
1125 .num_parents = 1,
1126 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1127 .ops = &clk_fixed_factor_ops,
1128 },
1129};
1130
1131static struct clk_fixed_factor dsi1pll_byteclk_src = {
1132 .div = 8,
1133 .mult = 1,
1134 .hw.init = &(struct clk_init_data){
1135 .name = "dsi1pll_byteclk_src",
1136 .parent_names = (const char *[]){"dsi1pll_bitclk_src"},
1137 .num_parents = 1,
1138 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1139 .ops = &clk_fixed_factor_ops,
1140 },
1141};
1142
1143static struct clk_regmap_div dsi0pll_post_bit_div = {
1144 .reg = 0x48,
1145 .shift = 0,
1146 .width = 4,
1147 .clkr = {
1148 .hw.init = &(struct clk_init_data){
1149 .name = "dsi0pll_post_bit_div",
1150 .parent_names = (const char *[]){"dsi0pll_bitclk_src"},
1151 .num_parents = 1,
1152 .flags = CLK_GET_RATE_NOCACHE,
1153 .ops = &clk_regmap_div_ops,
1154 },
1155 },
1156};
1157
1158static struct clk_regmap_div dsi1pll_post_bit_div = {
1159 .reg = 0x48,
1160 .shift = 0,
1161 .width = 4,
1162 .clkr = {
1163 .hw.init = &(struct clk_init_data){
1164 .name = "dsi1pll_post_bit_div",
1165 .parent_names = (const char *[]){"dsi1pll_bitclk_src"},
1166 .num_parents = 1,
1167 .flags = CLK_GET_RATE_NOCACHE,
1168 .ops = &clk_regmap_div_ops,
1169 },
1170 },
1171};
1172
1173static struct clk_regmap_mux dsi0pll_byteclk_mux = {
1174 .reg = 0x48,
1175 .shift = 0,
1176 .width = 4,
1177 .clkr = {
1178 .hw.init = &(struct clk_init_data){
1179 .name = "dsi0pll_byteclk_mux",
1180 .parent_names = (const char *[]){"dsi0pll_byteclk_src"},
1181 .num_parents = 1,
1182 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1183 .ops = &clk_regmap_mux_closest_ops,
1184 },
1185 },
1186};
1187
1188static struct clk_regmap_mux dsi1pll_byteclk_mux = {
1189 .reg = 0x48,
1190 .shift = 0,
1191 .width = 4,
1192 .clkr = {
1193 .hw.init = &(struct clk_init_data){
1194 .name = "dsi1pll_byteclk_mux",
1195 .parent_names = (const char *[]){"dsi1pll_byteclk_src"},
1196 .num_parents = 1,
1197 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1198 .ops = &clk_regmap_mux_closest_ops,
1199 },
1200 },
1201};
1202
1203static struct clk_regmap_mux dsi0pll_pclk_src_mux = {
1204 .reg = 0x48,
1205 .shift = 0,
1206 .width = 4,
1207 .clkr = {
1208 .hw.init = &(struct clk_init_data){
1209 .name = "dsi0pll_pclk_src_mux",
1210 .parent_names = (const char *[]){"dsi0pll_post_bit_div",
1211 "dsi0pll_post_bit_div"},
1212 .num_parents = 1,
1213 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1214 .ops = &clk_regmap_mux_closest_ops,
1215 },
1216 },
1217};
1218
1219static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
1220 .reg = 0x48,
1221 .shift = 0,
1222 .width = 4,
1223 .clkr = {
1224 .hw.init = &(struct clk_init_data){
1225 .name = "dsi1pll_pclk_src_mux",
1226 .parent_names = (const char *[]){"dsi1pll_post_bit_div",
1227 "dsi1pll_post_bit_div"},
1228 .num_parents = 1,
1229 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1230 .ops = &clk_regmap_mux_closest_ops,
1231 },
1232 },
1233};
1234
1235static struct clk_regmap_div dsi0pll_pclk_src = {
1236 .reg = 0x48,
1237 .shift = 0,
1238 .width = 4,
1239 .clkr = {
1240 .hw.init = &(struct clk_init_data){
1241 .name = "dsi0pll_pclk_src",
1242 .parent_names = (const char *[]){
1243 "dsi0pll_pclk_src_mux"},
1244 .num_parents = 1,
1245 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1246 .ops = &clk_regmap_div_ops,
1247 },
1248 },
1249};
1250
1251static struct clk_regmap_div dsi1pll_pclk_src = {
1252 .reg = 0x48,
1253 .shift = 0,
1254 .width = 4,
1255 .clkr = {
1256 .hw.init = &(struct clk_init_data){
1257 .name = "dsi1pll_pclk_src",
1258 .parent_names = (const char *[]){
1259 "dsi1pll_pclk_src_mux"},
1260 .num_parents = 1,
1261 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1262 .ops = &clk_regmap_div_ops,
1263 },
1264 },
1265};
1266
1267static struct clk_regmap_mux dsi0pll_pclk_mux = {
1268 .reg = 0x48,
1269 .shift = 0,
1270 .width = 4,
1271 .clkr = {
1272 .hw.init = &(struct clk_init_data){
1273 .name = "dsi0pll_pclk_mux",
1274 .parent_names = (const char *[]){"dsi0pll_pclk_src"},
1275 .num_parents = 1,
1276 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1277 .ops = &clk_regmap_mux_closest_ops,
1278 },
1279 },
1280};
1281
1282static struct clk_regmap_mux dsi1pll_pclk_mux = {
1283 .reg = 0x48,
1284 .shift = 0,
1285 .width = 4,
1286 .clkr = {
1287 .hw.init = &(struct clk_init_data){
1288 .name = "dsi1pll_pclk_mux",
1289 .parent_names = (const char *[]){"dsi1pll_pclk_src"},
1290 .num_parents = 1,
1291 .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
1292 .ops = &clk_regmap_mux_closest_ops,
1293 },
1294 },
1295};
1296
1297static struct clk_hw *mdss_dsi_pllcc_10nm[] = {
1298 [VCO_CLK_0] = &dsi0pll_vco_clk.hw,
1299 [BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw,
1300 [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw,
1301 [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.clkr.hw,
1302 [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.clkr.hw,
1303 [BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw,
1304 [PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw,
1305 [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw,
1306 [PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw,
1307 [VCO_CLK_1] = &dsi1pll_vco_clk.hw,
1308 [BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw,
1309 [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw,
1310 [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.clkr.hw,
1311 [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.clkr.hw,
1312 [BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw,
1313 [PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw,
1314 [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw,
1315 [PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw,
1316
1317};
1318
1319int dsi_pll_clock_register_10nm(struct platform_device *pdev,
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001320 struct mdss_pll_resources *pll_res)
1321{
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001322 int rc = 0, ndx, i;
1323 struct clk *clk;
1324 struct clk_onecell_data *clk_data;
1325 int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_10nm);
1326 struct regmap *rmap;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001327
1328 if (!pdev || !pdev->dev.of_node ||
1329 !pll_res || !pll_res->pll_base || !pll_res->phy_base) {
1330 pr_err("Invalid params\n");
1331 return -EINVAL;
1332 }
1333
1334 ndx = pll_res->index;
1335
1336 if (ndx >= DSI_PLL_MAX) {
1337 pr_err("pll index(%d) NOT supported\n", ndx);
1338 return -EINVAL;
1339 }
1340
1341 pll_rsc_db[ndx] = pll_res;
1342 pll_res->priv = &plls[ndx];
1343 plls[ndx].rsc = pll_res;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001344 pll_res->vco_delay = VCO_DELAY_USEC;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001345
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001346 clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
1347 GFP_KERNEL);
1348 if (!clk_data)
1349 return -ENOMEM;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001350
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001351 clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks *
1352 sizeof(struct clk *)), GFP_KERNEL);
1353 if (!clk_data->clks) {
1354 devm_kfree(&pdev->dev, clk_data);
1355 return -ENOMEM;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001356 }
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001357 clk_data->clk_num = num_clks;
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001358
Shashank Babu Chinta Venkata704b93b2017-02-06 15:23:11 -08001359 /* Establish client data */
1360 if (ndx == 0) {
1361 rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus,
1362 pll_res, &dsi_pll_10nm_config);
1363 dsi0pll_post_vco_div.clkr.regmap = rmap;
1364
1365 rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus,
1366 pll_res, &dsi_pll_10nm_config);
1367 dsi0pll_post_bit_div.clkr.regmap = rmap;
1368
1369 rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
1370 pll_res, &dsi_pll_10nm_config);
1371 dsi0pll_bitclk_src.clkr.regmap = rmap;
1372
1373 rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus,
1374 pll_res, &dsi_pll_10nm_config);
1375 dsi0pll_pclk_src.clkr.regmap = rmap;
1376
1377 rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
1378 pll_res, &dsi_pll_10nm_config);
1379 dsi0pll_pclk_mux.clkr.regmap = rmap;
1380
1381 rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
1382 pll_res, &dsi_pll_10nm_config);
1383 dsi0pll_pclk_src_mux.clkr.regmap = rmap;
1384
1385 rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
1386 pll_res, &dsi_pll_10nm_config);
1387 dsi0pll_byteclk_mux.clkr.regmap = rmap;
1388
1389 for (i = VCO_CLK_0; i <= PCLK_MUX_0_CLK; i++) {
1390 clk = devm_clk_register(&pdev->dev,
1391 mdss_dsi_pllcc_10nm[i]);
1392 if (IS_ERR(clk)) {
1393 pr_err("clk registration failed for DSI clock:%d\n",
1394 pll_res->index);
1395 rc = -EINVAL;
1396 goto clk_register_fail;
1397 }
1398 clk_data->clks[i] = clk;
1399
1400 }
1401
1402 rc = of_clk_add_provider(pdev->dev.of_node,
1403 of_clk_src_onecell_get, clk_data);
1404
1405
1406 } else {
1407 rmap = devm_regmap_init(&pdev->dev, &post_vco_regmap_bus,
1408 pll_res, &dsi_pll_10nm_config);
1409 dsi1pll_post_vco_div.clkr.regmap = rmap;
1410
1411 rmap = devm_regmap_init(&pdev->dev, &post_bit_regmap_bus,
1412 pll_res, &dsi_pll_10nm_config);
1413 dsi1pll_post_bit_div.clkr.regmap = rmap;
1414
1415 rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus,
1416 pll_res, &dsi_pll_10nm_config);
1417 dsi1pll_bitclk_src.clkr.regmap = rmap;
1418
1419 rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus,
1420 pll_res, &dsi_pll_10nm_config);
1421 dsi1pll_pclk_src.clkr.regmap = rmap;
1422
1423 rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
1424 pll_res, &dsi_pll_10nm_config);
1425 dsi1pll_pclk_mux.clkr.regmap = rmap;
1426
1427 rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
1428 pll_res, &dsi_pll_10nm_config);
1429 dsi1pll_pclk_src_mux.clkr.regmap = rmap;
1430
1431 rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
1432 pll_res, &dsi_pll_10nm_config);
1433 dsi1pll_byteclk_mux.clkr.regmap = rmap;
1434
1435 for (i = VCO_CLK_1; i <= PCLK_MUX_1_CLK; i++) {
1436 clk = devm_clk_register(&pdev->dev,
1437 mdss_dsi_pllcc_10nm[i]);
1438 if (IS_ERR(clk)) {
1439 pr_err("clk registration failed for DSI clock:%d\n",
1440 pll_res->index);
1441 rc = -EINVAL;
1442 goto clk_register_fail;
1443 }
1444 clk_data->clks[i] = clk;
1445
1446 }
1447
1448 rc = of_clk_add_provider(pdev->dev.of_node,
1449 of_clk_src_onecell_get, clk_data);
1450 }
1451 if (!rc) {
1452 pr_info("Registered DSI PLL ndx=%d, clocks successfully", ndx);
1453
1454 return rc;
1455 }
1456clk_register_fail:
1457 devm_kfree(&pdev->dev, clk_data->clks);
1458 devm_kfree(&pdev->dev, clk_data);
Aravind Venkateswaran5773d732016-03-08 16:55:01 -08001459 return rc;
1460}