aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dsi/phy/dsi_phy.c')
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.c239
1 files changed, 209 insertions, 30 deletions
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index f39386ed75e4..0c2eb9c9a1fc 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -54,8 +54,10 @@ static void dsi_dphy_timing_calc_clk_zero(struct msm_dsi_dphy_timing *timing,
54} 54}
55 55
56int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing, 56int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
57 const unsigned long bit_rate, const unsigned long esc_rate) 57 struct msm_dsi_phy_clk_request *clk_req)
58{ 58{
59 const unsigned long bit_rate = clk_req->bitclk_rate;
60 const unsigned long esc_rate = clk_req->escclk_rate;
59 s32 ui, lpx; 61 s32 ui, lpx;
60 s32 tmax, tmin; 62 s32 tmax, tmin;
61 s32 pcnt0 = 10; 63 s32 pcnt0 = 10;
@@ -115,8 +117,8 @@ int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
115 temp = ((timing->hs_exit >> 1) + 1) * 2 * ui; 117 temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
116 temp = 60 * coeff + 52 * ui - 24 * ui - temp; 118 temp = 60 * coeff + 52 * ui - 24 * ui - temp;
117 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1; 119 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
118 timing->clk_post = linear_inter(tmax, tmin, pcnt2, 0, false); 120 timing->shared_timings.clk_post = linear_inter(tmax, tmin, pcnt2, 0,
119 121 false);
120 tmax = 63; 122 tmax = 63;
121 temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui; 123 temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
122 temp += ((timing->clk_zero >> 1) + 1) * 2 * ui; 124 temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
@@ -124,17 +126,21 @@ int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
124 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1; 126 tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
125 if (tmin > tmax) { 127 if (tmin > tmax) {
126 temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false); 128 temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false);
127 timing->clk_pre = temp >> 1; 129 timing->shared_timings.clk_pre = temp >> 1;
130 timing->shared_timings.clk_pre_inc_by_2 = true;
128 } else { 131 } else {
129 timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false); 132 timing->shared_timings.clk_pre =
133 linear_inter(tmax, tmin, pcnt2, 0, false);
134 timing->shared_timings.clk_pre_inc_by_2 = false;
130 } 135 }
131 136
132 timing->ta_go = 3; 137 timing->ta_go = 3;
133 timing->ta_sure = 0; 138 timing->ta_sure = 0;
134 timing->ta_get = 4; 139 timing->ta_get = 4;
135 140
136 DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", 141 DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
137 timing->clk_pre, timing->clk_post, timing->clk_zero, 142 timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
143 timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
138 timing->clk_trail, timing->clk_prepare, timing->hs_exit, 144 timing->clk_trail, timing->clk_prepare, timing->hs_exit,
139 timing->hs_zero, timing->hs_prepare, timing->hs_trail, 145 timing->hs_zero, timing->hs_prepare, timing->hs_trail,
140 timing->hs_rqst); 146 timing->hs_rqst);
@@ -142,6 +148,123 @@ int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
142 return 0; 148 return 0;
143} 149}
144 150
151int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing,
152 struct msm_dsi_phy_clk_request *clk_req)
153{
154 const unsigned long bit_rate = clk_req->bitclk_rate;
155 const unsigned long esc_rate = clk_req->escclk_rate;
156 s32 ui, ui_x8, lpx;
157 s32 tmax, tmin;
158 s32 pcnt0 = 50;
159 s32 pcnt1 = 50;
160 s32 pcnt2 = 10;
161 s32 pcnt3 = 30;
162 s32 pcnt4 = 10;
163 s32 pcnt5 = 2;
164 s32 coeff = 1000; /* Precision, should avoid overflow */
165 s32 hb_en, hb_en_ckln, pd_ckln, pd;
166 s32 val, val_ckln;
167 s32 temp;
168
169 if (!bit_rate || !esc_rate)
170 return -EINVAL;
171
172 timing->hs_halfbyte_en = 0;
173 hb_en = 0;
174 timing->hs_halfbyte_en_ckln = 0;
175 hb_en_ckln = 0;
176 timing->hs_prep_dly_ckln = (bit_rate > 100000000) ? 0 : 3;
177 pd_ckln = timing->hs_prep_dly_ckln;
178 timing->hs_prep_dly = (bit_rate > 120000000) ? 0 : 1;
179 pd = timing->hs_prep_dly;
180
181 val = (hb_en << 2) + (pd << 1);
182 val_ckln = (hb_en_ckln << 2) + (pd_ckln << 1);
183
184 ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
185 ui_x8 = ui << 3;
186 lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
187
188 temp = S_DIV_ROUND_UP(38 * coeff - val_ckln * ui, ui_x8);
189 tmin = max_t(s32, temp, 0);
190 temp = (95 * coeff - val_ckln * ui) / ui_x8;
191 tmax = max_t(s32, temp, 0);
192 timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
193
194 temp = 300 * coeff - ((timing->clk_prepare << 3) + val_ckln) * ui;
195 tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
196 tmax = (tmin > 255) ? 511 : 255;
197 timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
198
199 tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
200 temp = 105 * coeff + 12 * ui - 20 * coeff;
201 tmax = (temp + 3 * ui) / ui_x8;
202 timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
203
204 temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui - val * ui, ui_x8);
205 tmin = max_t(s32, temp, 0);
206 temp = (85 * coeff + 6 * ui - val * ui) / ui_x8;
207 tmax = max_t(s32, temp, 0);
208 timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
209
210 temp = 145 * coeff + 10 * ui - ((timing->hs_prepare << 3) + val) * ui;
211 tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
212 tmax = 255;
213 timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
214
215 tmin = DIV_ROUND_UP(60 * coeff + 4 * ui + 3 * ui, ui_x8);
216 temp = 105 * coeff + 12 * ui - 20 * coeff;
217 tmax = (temp + 3 * ui) / ui_x8;
218 timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
219
220 temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
221 timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
222
223 tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
224 tmax = 255;
225 timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
226
227 temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
228 timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
229
230 temp = 60 * coeff + 52 * ui - 43 * ui;
231 tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
232 tmax = 63;
233 timing->shared_timings.clk_post =
234 linear_inter(tmax, tmin, pcnt2, 0, false);
235
236 temp = 8 * ui + ((timing->clk_prepare << 3) + val_ckln) * ui;
237 temp += (((timing->clk_zero + 3) << 3) + 11 - (pd_ckln << 1)) * ui;
238 temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
239 (((timing->hs_rqst_ckln << 3) + 8) * ui);
240 tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
241 tmax = 63;
242 if (tmin > tmax) {
243 temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
244 timing->shared_timings.clk_pre = temp >> 1;
245 timing->shared_timings.clk_pre_inc_by_2 = 1;
246 } else {
247 timing->shared_timings.clk_pre =
248 linear_inter(tmax, tmin, pcnt2, 0, false);
249 timing->shared_timings.clk_pre_inc_by_2 = 0;
250 }
251
252 timing->ta_go = 3;
253 timing->ta_sure = 0;
254 timing->ta_get = 4;
255
256 DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
257 timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
258 timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
259 timing->clk_trail, timing->clk_prepare, timing->hs_exit,
260 timing->hs_zero, timing->hs_prepare, timing->hs_trail,
261 timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
262 timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
263 timing->hs_prep_dly_ckln);
264
265 return 0;
266}
267
145void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg, 268void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
146 u32 bit_mask) 269 u32 bit_mask)
147{ 270{
@@ -268,6 +391,10 @@ static const struct of_device_id dsi_phy_dt_match[] = {
268 { .compatible = "qcom,dsi-phy-28nm-8960", 391 { .compatible = "qcom,dsi-phy-28nm-8960",
269 .data = &dsi_phy_28nm_8960_cfgs }, 392 .data = &dsi_phy_28nm_8960_cfgs },
270#endif 393#endif
394#ifdef CONFIG_DRM_MSM_DSI_14NM_PHY
395 { .compatible = "qcom,dsi-phy-14nm",
396 .data = &dsi_phy_14nm_cfgs },
397#endif
271 {} 398 {}
272}; 399};
273 400
@@ -295,6 +422,24 @@ static int dsi_phy_get_id(struct msm_dsi_phy *phy)
295 return -EINVAL; 422 return -EINVAL;
296} 423}
297 424
425int msm_dsi_phy_init_common(struct msm_dsi_phy *phy)
426{
427 struct platform_device *pdev = phy->pdev;
428 int ret = 0;
429
430 phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
431 "DSI_PHY_REG");
432 if (IS_ERR(phy->reg_base)) {
433 dev_err(&pdev->dev, "%s: failed to map phy regulator base\n",
434 __func__);
435 ret = -ENOMEM;
436 goto fail;
437 }
438
439fail:
440 return ret;
441}
442
298static int dsi_phy_driver_probe(struct platform_device *pdev) 443static int dsi_phy_driver_probe(struct platform_device *pdev)
299{ 444{
300 struct msm_dsi_phy *phy; 445 struct msm_dsi_phy *phy;
@@ -331,15 +476,6 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
331 goto fail; 476 goto fail;
332 } 477 }
333 478
334 phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
335 "DSI_PHY_REG");
336 if (IS_ERR(phy->reg_base)) {
337 dev_err(dev, "%s: failed to map phy regulator base\n",
338 __func__);
339 ret = -ENOMEM;
340 goto fail;
341 }
342
343 ret = dsi_phy_regulator_init(phy); 479 ret = dsi_phy_regulator_init(phy);
344 if (ret) { 480 if (ret) {
345 dev_err(dev, "%s: failed to init regulator\n", __func__); 481 dev_err(dev, "%s: failed to init regulator\n", __func__);
@@ -353,6 +489,12 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
353 goto fail; 489 goto fail;
354 } 490 }
355 491
492 if (phy->cfg->ops.init) {
493 ret = phy->cfg->ops.init(phy);
494 if (ret)
495 goto fail;
496 }
497
356 /* PLL init will call into clk_register which requires 498 /* PLL init will call into clk_register which requires
357 * register access, so we need to enable power and ahb clock. 499 * register access, so we need to enable power and ahb clock.
358 */ 500 */
@@ -410,7 +552,7 @@ void __exit msm_dsi_phy_driver_unregister(void)
410} 552}
411 553
412int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, 554int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
413 const unsigned long bit_rate, const unsigned long esc_rate) 555 struct msm_dsi_phy_clk_request *clk_req)
414{ 556{
415 struct device *dev = &phy->pdev->dev; 557 struct device *dev = &phy->pdev->dev;
416 int ret; 558 int ret;
@@ -418,21 +560,52 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
418 if (!phy || !phy->cfg->ops.enable) 560 if (!phy || !phy->cfg->ops.enable)
419 return -EINVAL; 561 return -EINVAL;
420 562
563 ret = dsi_phy_enable_resource(phy);
564 if (ret) {
565 dev_err(dev, "%s: resource enable failed, %d\n",
566 __func__, ret);
567 goto res_en_fail;
568 }
569
421 ret = dsi_phy_regulator_enable(phy); 570 ret = dsi_phy_regulator_enable(phy);
422 if (ret) { 571 if (ret) {
423 dev_err(dev, "%s: regulator enable failed, %d\n", 572 dev_err(dev, "%s: regulator enable failed, %d\n",
424 __func__, ret); 573 __func__, ret);
425 return ret; 574 goto reg_en_fail;
426 } 575 }
427 576
428 ret = phy->cfg->ops.enable(phy, src_pll_id, bit_rate, esc_rate); 577 ret = phy->cfg->ops.enable(phy, src_pll_id, clk_req);
429 if (ret) { 578 if (ret) {
430 dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret); 579 dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret);
431 dsi_phy_regulator_disable(phy); 580 goto phy_en_fail;
432 return ret; 581 }
582
583 /*
584 * Resetting DSI PHY silently changes its PLL registers to reset status,
585 * which will confuse clock driver and result in wrong output rate of
586 * link clocks. Restore PLL status if its PLL is being used as clock
587 * source.
588 */
589 if (phy->usecase != MSM_DSI_PHY_SLAVE) {
590 ret = msm_dsi_pll_restore_state(phy->pll);
591 if (ret) {
592 dev_err(dev, "%s: failed to restore pll state, %d\n",
593 __func__, ret);
594 goto pll_restor_fail;
595 }
433 } 596 }
434 597
435 return 0; 598 return 0;
599
600pll_restor_fail:
601 if (phy->cfg->ops.disable)
602 phy->cfg->ops.disable(phy);
603phy_en_fail:
604 dsi_phy_regulator_disable(phy);
605reg_en_fail:
606 dsi_phy_disable_resource(phy);
607res_en_fail:
608 return ret;
436} 609}
437 610
438void msm_dsi_phy_disable(struct msm_dsi_phy *phy) 611void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
@@ -440,21 +613,21 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
440 if (!phy || !phy->cfg->ops.disable) 613 if (!phy || !phy->cfg->ops.disable)
441 return; 614 return;
442 615
616 /* Save PLL status if it is a clock source */
617 if (phy->usecase != MSM_DSI_PHY_SLAVE)
618 msm_dsi_pll_save_state(phy->pll);
619
443 phy->cfg->ops.disable(phy); 620 phy->cfg->ops.disable(phy);
444 621
445 dsi_phy_regulator_disable(phy); 622 dsi_phy_regulator_disable(phy);
623 dsi_phy_disable_resource(phy);
446} 624}
447 625
448void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy, 626void msm_dsi_phy_get_shared_timings(struct msm_dsi_phy *phy,
449 u32 *clk_pre, u32 *clk_post) 627 struct msm_dsi_phy_shared_timings *shared_timings)
450{ 628{
451 if (!phy) 629 memcpy(shared_timings, &phy->timing.shared_timings,
452 return; 630 sizeof(*shared_timings));
453
454 if (clk_pre)
455 *clk_pre = phy->timing.clk_pre;
456 if (clk_post)
457 *clk_post = phy->timing.clk_post;
458} 631}
459 632
460struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy) 633struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
@@ -465,3 +638,9 @@ struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy)
465 return phy->pll; 638 return phy->pll;
466} 639}
467 640
641void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy,
642 enum msm_dsi_phy_usecase uc)
643{
644 if (phy)
645 phy->usecase = uc;
646}