blob: 365fefc81d0844f9626c9e52c4b7658ac3c67baa [file] [log] [blame]
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001/*
Narender Ankamde426242019-12-23 20:54:31 +05302 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07003 *
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
15#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
16
17#include <linux/types.h>
18#include <linux/completion.h>
19#include <linux/delay.h>
20
Narender Ankamde426242019-12-23 20:54:31 +053021#include "msm_kms.h"
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070022#include "dp_ctrl.h"
23
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070024#define DP_KHZ_TO_HZ 1000
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070025
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070026#define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0)
27#define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3)
28
29/* dp state ctrl */
30#define ST_TRAIN_PATTERN_1 BIT(0)
31#define ST_TRAIN_PATTERN_2 BIT(1)
32#define ST_TRAIN_PATTERN_3 BIT(2)
33#define ST_TRAIN_PATTERN_4 BIT(3)
34#define ST_SYMBOL_ERR_RATE_MEASUREMENT BIT(4)
35#define ST_PRBS7 BIT(5)
36#define ST_CUSTOM_80_BIT_PATTERN BIT(6)
37#define ST_SEND_VIDEO BIT(7)
38#define ST_PUSH_IDLE BIT(8)
39
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -070040#define MR_LINK_TRAINING1 0x8
41#define MR_LINK_SYMBOL_ERM 0x80
42#define MR_LINK_PRBS7 0x100
43#define MR_LINK_CUSTOM80 0x200
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -070044#define MR_LINK_TRAINING4 0x40
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -070045
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070046struct dp_vc_tu_mapping_table {
47 u32 vic;
48 u8 lanes;
49 u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */
50 u8 bpp;
51 u8 valid_boundary_link;
52 u16 delay_start_link;
53 bool boundary_moderation_en;
54 u8 valid_lower_boundary_link;
55 u8 upper_boundary_count;
56 u8 lower_boundary_count;
57 u8 tu_size_minus1;
58};
59
60struct dp_ctrl_private {
61 struct dp_ctrl dp_ctrl;
62
63 struct device *dev;
64 struct dp_aux *aux;
65 struct dp_panel *panel;
66 struct dp_link *link;
67 struct dp_power *power;
68 struct dp_parser *parser;
69 struct dp_catalog_ctrl *catalog;
70
71 struct completion idle_comp;
72 struct completion video_comp;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070073
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070074 bool orientation;
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -080075 bool power_on;
76
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -070077 atomic_t aborted;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070078
79 u32 pixel_rate;
80 u32 vic;
81};
82
83enum notification_status {
84 NOTIFY_UNKNOWN,
85 NOTIFY_CONNECT,
86 NOTIFY_DISCONNECT,
87 NOTIFY_CONNECT_IRQ_HPD,
88 NOTIFY_DISCONNECT_IRQ_HPD,
89};
90
91static void dp_ctrl_idle_patterns_sent(struct dp_ctrl_private *ctrl)
92{
93 pr_debug("idle_patterns_sent\n");
94 complete(&ctrl->idle_comp);
95}
96
97static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl)
98{
99 pr_debug("dp_video_ready\n");
100 complete(&ctrl->video_comp);
101}
102
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700103static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl)
104{
105 struct dp_ctrl_private *ctrl;
106
107 if (!dp_ctrl) {
108 pr_err("Invalid input data\n");
109 return;
110 }
111
112 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
113
114 atomic_set(&ctrl->aborted, 1);
115}
116
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700117static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
118{
119 ctrl->catalog->state_ctrl(ctrl->catalog, state);
120}
121
122static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
123{
124 int const idle_pattern_completion_timeout_ms = 3 * HZ / 100;
125 struct dp_ctrl_private *ctrl;
126
127 if (!dp_ctrl) {
128 pr_err("Invalid input data\n");
129 return;
130 }
131
132 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
133
Tatenda Chipeperekwa449be112018-04-03 16:15:31 -0700134 if (!ctrl->power_on) {
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800135 pr_err("CTRL off, return\n");
136 return;
137 }
138
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700139 reinit_completion(&ctrl->idle_comp);
140 dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
141
142 if (!wait_for_completion_timeout(&ctrl->idle_comp,
143 idle_pattern_completion_timeout_ms))
144 pr_warn("PUSH_IDLE pattern timedout\n");
145
146 pr_debug("mainlink off done\n");
147}
148
149static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
150{
151 u32 config = 0, tbd;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700152 u8 *dpcd = ctrl->panel->dpcd;
Narender Ankamde426242019-12-23 20:54:31 +0530153 u32 out_format = ctrl->panel->pinfo.out_format;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700154
155 config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */
Narender Ankamde426242019-12-23 20:54:31 +0530156
157 if (out_format & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)
158 config |= (1 << 11); /* YUV420 */
159 else if (out_format & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR422)
160 config |= (2 << 11); /* YUV422 */
161 else
162 config |= (0 << 11); /* RGB */
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700163
164 /* Scrambler reset enable */
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700165 if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700166 config |= (1 << 10);
167
168 tbd = ctrl->link->get_test_bits_depth(ctrl->link,
169 ctrl->panel->pinfo.bpp);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700170
171 if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN)
172 tbd = DP_TEST_BIT_DEPTH_8;
173
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700174 config |= tbd << 8;
175
176 /* Num of Lanes */
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530177 config |= ((ctrl->link->link_params.lane_count - 1) << 4);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700178
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700179 if (drm_dp_enhanced_frame_cap(dpcd))
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700180 config |= 0x40;
181
182 config |= 0x04; /* progressive video */
183
184 config |= 0x03; /* sycn clock & static Mvid */
185
186 ctrl->catalog->config_ctrl(ctrl->catalog, config);
187}
188
Narender Ankamde426242019-12-23 20:54:31 +0530189static void dp_ctrl_misc_ctrl(struct dp_ctrl_private *ctrl)
190{
191 u32 out_format = ctrl->panel->pinfo.out_format;
Ramendra Kumar89c17f52020-02-10 14:32:11 +0530192 u32 yres = ctrl->panel->pinfo.v_active;
Narender Ankamde426242019-12-23 20:54:31 +0530193 u32 cc, tb;
194
195 tb = ctrl->link->get_test_bits_depth(ctrl->link,
196 ctrl->panel->pinfo.bpp);
197 cc = ctrl->link->get_colorimetry_config(ctrl->link);
Ramendra Kumar89c17f52020-02-10 14:32:11 +0530198 if (out_format == MSM_MODE_FLAG_COLOR_FORMAT_YCBCR422) {
199 cc |= (0x01 << 1); /* Set 4:2:2 Pixel Encoding */
200 cc |= BIT(3); /* Set YCbCr Colorimetry */
201 if (yres >= 720)
202 cc |= BIT(4); /* Set BT709 */
203 }
Narender Ankamde426242019-12-23 20:54:31 +0530204
205 ctrl->catalog->config_misc(ctrl->catalog, cc, tb);
206}
207
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700208/**
209 * dp_ctrl_configure_source_params() - configures DP transmitter source params
210 * @ctrl: Display Port Driver data
211 *
212 * Configures the DP transmitter source params including details such as lane
213 * configuration, output format and sink/panel timing information.
214 */
215static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
216{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700217
218 ctrl->catalog->lane_mapping(ctrl->catalog);
219 ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
220
221 dp_ctrl_config_ctrl(ctrl);
Narender Ankamde426242019-12-23 20:54:31 +0530222 dp_ctrl_misc_ctrl(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700223
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700224 ctrl->panel->timing_cfg(ctrl->panel);
225}
226
227static void dp_ctrl_get_extra_req_bytes(u64 result_valid,
228 int valid_bdary_link,
229 u64 value1, u64 value2,
230 bool *negative, u64 *result,
231 u64 compare)
232{
233 *negative = false;
234 if (result_valid >= compare) {
235 if (valid_bdary_link
236 >= compare)
237 *result = value1 + value2;
238 else {
239 if (value1 < value2)
240 *negative = true;
241 *result = (value1 >= value2) ?
242 (value1 - value2) : (value2 - value1);
243 }
244 } else {
245 if (valid_bdary_link
246 >= compare) {
247 if (value1 >= value2)
248 *negative = true;
249 *result = (value1 >= value2) ?
250 (value1 - value2) : (value2 - value1);
251 } else {
252 *result = value1 + value2;
253 *negative = true;
254 }
255 }
256}
257
258static u64 roundup_u64(u64 x, u64 y)
259{
260 x += (y - 1);
261 return (div64_ul(x, y) * y);
262}
263
264static u64 rounddown_u64(u64 x, u64 y)
265{
266 u64 rem;
267
268 div64_u64_rem(x, y, &rem);
269 return (x - rem);
270}
271
272static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
273 struct dp_vc_tu_mapping_table *tu_table)
274{
275 u32 const multiplier = 1000000;
276 u64 pclk, lclk;
Narender Ankamde426242019-12-23 20:54:31 +0530277 u32 bpp;
278 u8 ln_cnt;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700279 int run_idx = 0;
280 u32 lwidth, h_blank;
281 u32 fifo_empty = 0;
282 u32 ratio_scale = 1001;
283 u64 temp, ratio, original_ratio;
284 u64 temp2, reminder;
285 u64 temp3, temp4, result = 0;
286
287 u64 err = multiplier;
288 u64 n_err = 0, n_n_err = 0;
289 bool n_err_neg, nn_err_neg;
290 u8 hblank_margin = 16;
291
292 u8 tu_size, tu_size_desired = 0, tu_size_minus1;
293 int valid_boundary_link;
294 u64 resulting_valid;
295 u64 total_valid;
296 u64 effective_valid;
297 u64 effective_valid_recorded;
298 int n_tus;
299 int n_tus_per_lane;
300 int paired_tus;
301 int remainder_tus;
302 int remainder_tus_upper, remainder_tus_lower;
303 int extra_bytes;
304 int filler_size;
305 int delay_start_link;
306 int boundary_moderation_en = 0;
307 int upper_bdry_cnt = 0;
308 int lower_bdry_cnt = 0;
309 int i_upper_bdry_cnt = 0;
310 int i_lower_bdry_cnt = 0;
311 int valid_lower_boundary_link = 0;
312 int even_distribution_bf = 0;
313 int even_distribution_legacy = 0;
314 int even_distribution = 0;
315 int min_hblank = 0;
316 int extra_pclk_cycles;
317 u8 extra_pclk_cycle_delay = 4;
318 int extra_pclk_cycles_in_link_clk;
319 u64 ratio_by_tu;
320 u64 average_valid2;
321 u64 extra_buffer_margin;
322 int new_valid_boundary_link;
323
324 u64 resulting_valid_tmp;
325 u64 ratio_by_tu_tmp;
326 int n_tus_tmp;
327 int extra_pclk_cycles_tmp;
328 int extra_pclk_cycles_in_lclk_tmp;
329 int extra_req_bytes_new_tmp;
330 int filler_size_tmp;
331 int lower_filler_size_tmp;
332 int delay_start_link_tmp;
333 int min_hblank_tmp = 0;
334 bool extra_req_bytes_is_neg = false;
335 struct dp_panel_info *pinfo = &ctrl->panel->pinfo;
Narender Ankamde426242019-12-23 20:54:31 +0530336 int div = 0;
337 u32 out_format = pinfo->out_format;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700338
339 u8 dp_brute_force = 1;
340 u64 brute_force_threshold = 10;
341 u64 diff_abs;
342
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530343 ln_cnt = ctrl->link->link_params.lane_count;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700344
345 bpp = pinfo->bpp;
Narender Ankamde426242019-12-23 20:54:31 +0530346 if (out_format == MSM_MODE_FLAG_COLOR_FORMAT_YCBCR422) {
347 switch (pinfo->bpp) {
348 case 24:
349 bpp = 16;
350 break;
351 case 30:
352 bpp = 20;
353 break;
354 default:
355 bpp = 16;
356 break;
357 };
358 } else if (out_format == MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) {
359 div = 1;
360 }
361
362 lwidth = pinfo->h_active >> div;
363 h_blank = (pinfo->h_back_porch + pinfo->h_front_porch +
364 pinfo->h_sync_width) >> div;
365 pclk = (pinfo->pixel_clk_khz * 1000) >> div;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700366
367 boundary_moderation_en = 0;
368 upper_bdry_cnt = 0;
369 lower_bdry_cnt = 0;
370 i_upper_bdry_cnt = 0;
371 i_lower_bdry_cnt = 0;
372 valid_lower_boundary_link = 0;
373 even_distribution_bf = 0;
374 even_distribution_legacy = 0;
375 even_distribution = 0;
376 min_hblank = 0;
377
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530378 lclk = drm_dp_bw_code_to_link_rate(
379 ctrl->link->link_params.bw_code) * DP_KHZ_TO_HZ;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700380
381 pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
382 pclk, lwidth, h_blank);
383 pr_debug("lclk = %lld, ln_cnt = %d\n", lclk, ln_cnt);
384 ratio = div64_u64_rem(pclk * bpp * multiplier,
385 8 * ln_cnt * lclk, &reminder);
386 ratio = div64_u64((pclk * bpp * multiplier), (8 * ln_cnt * lclk));
387 original_ratio = ratio;
388
389 extra_buffer_margin = roundup_u64(div64_u64(extra_pclk_cycle_delay
390 * lclk * multiplier, pclk), multiplier);
391 extra_buffer_margin = div64_u64(extra_buffer_margin, multiplier);
392
393 /* To deal with cases where lines are not distributable */
394 if (((lwidth % ln_cnt) != 0) && ratio < multiplier) {
395 ratio = ratio * ratio_scale;
396 ratio = ratio < (1000 * multiplier)
397 ? ratio : (1000 * multiplier);
398 }
399 pr_debug("ratio = %lld\n", ratio);
400
401 for (tu_size = 32; tu_size <= 64; tu_size++) {
402 temp = ratio * tu_size;
403 temp2 = ((temp / multiplier) + 1) * multiplier;
404 n_err = roundup_u64(temp, multiplier) - temp;
405
406 if (n_err < err) {
407 err = n_err;
408 tu_size_desired = tu_size;
409 }
410 }
411 pr_debug("Info: tu_size_desired = %d\n", tu_size_desired);
412
413 tu_size_minus1 = tu_size_desired - 1;
414
415 valid_boundary_link = roundup_u64(ratio * tu_size_desired, multiplier);
416 valid_boundary_link /= multiplier;
417 n_tus = rounddown((lwidth * bpp * multiplier)
418 / (8 * valid_boundary_link), multiplier) / multiplier;
419 even_distribution_legacy = n_tus % ln_cnt == 0 ? 1 : 0;
420 pr_debug("Info: n_symbol_per_tu=%d, number_of_tus=%d\n",
421 valid_boundary_link, n_tus);
422
423 extra_bytes = roundup_u64((n_tus + 1)
424 * ((valid_boundary_link * multiplier)
425 - (original_ratio * tu_size_desired)), multiplier);
426 extra_bytes /= multiplier;
427 extra_pclk_cycles = roundup(extra_bytes * 8 * multiplier / bpp,
428 multiplier);
429 extra_pclk_cycles /= multiplier;
430 extra_pclk_cycles_in_link_clk = roundup_u64(div64_u64(extra_pclk_cycles
431 * lclk * multiplier, pclk), multiplier);
432 extra_pclk_cycles_in_link_clk /= multiplier;
433 filler_size = roundup_u64((tu_size_desired - valid_boundary_link)
434 * multiplier, multiplier);
435 filler_size /= multiplier;
436 ratio_by_tu = div64_u64(ratio * tu_size_desired, multiplier);
437
438 pr_debug("extra_pclk_cycles_in_link_clk=%d, extra_bytes=%d\n",
439 extra_pclk_cycles_in_link_clk, extra_bytes);
440 pr_debug("extra_pclk_cycles_in_link_clk=%d\n",
441 extra_pclk_cycles_in_link_clk);
442 pr_debug("filler_size=%d, extra_buffer_margin=%lld\n",
443 filler_size, extra_buffer_margin);
444
445 delay_start_link = ((extra_bytes > extra_pclk_cycles_in_link_clk)
446 ? extra_bytes
447 : extra_pclk_cycles_in_link_clk)
448 + filler_size + extra_buffer_margin;
449 resulting_valid = valid_boundary_link;
450 pr_debug("Info: delay_start_link=%d, filler_size=%d\n",
451 delay_start_link, filler_size);
452 pr_debug("valid_boundary_link=%d ratio_by_tu=%lld\n",
453 valid_boundary_link, ratio_by_tu);
454
455 diff_abs = (resulting_valid >= ratio_by_tu)
456 ? (resulting_valid - ratio_by_tu)
457 : (ratio_by_tu - resulting_valid);
458
459 if (err != 0 && ((diff_abs > brute_force_threshold)
460 || (even_distribution_legacy == 0)
461 || (dp_brute_force == 1))) {
462 err = multiplier;
463 for (tu_size = 32; tu_size <= 64; tu_size++) {
464 for (i_upper_bdry_cnt = 1; i_upper_bdry_cnt <= 15;
465 i_upper_bdry_cnt++) {
466 for (i_lower_bdry_cnt = 1;
467 i_lower_bdry_cnt <= 15;
468 i_lower_bdry_cnt++) {
469 new_valid_boundary_link =
470 roundup_u64(ratio
471 * tu_size, multiplier);
472 average_valid2 = (i_upper_bdry_cnt
473 * new_valid_boundary_link
474 + i_lower_bdry_cnt
475 * (new_valid_boundary_link
476 - multiplier))
477 / (i_upper_bdry_cnt
478 + i_lower_bdry_cnt);
479 n_tus = rounddown_u64(div64_u64(lwidth
480 * multiplier * multiplier
481 * (bpp / 8), average_valid2),
482 multiplier);
483 n_tus /= multiplier;
484 n_tus_per_lane
485 = rounddown(n_tus
486 * multiplier
487 / ln_cnt, multiplier);
488 n_tus_per_lane /= multiplier;
489 paired_tus =
490 rounddown((n_tus_per_lane)
491 * multiplier
492 / (i_upper_bdry_cnt
493 + i_lower_bdry_cnt),
494 multiplier);
495 paired_tus /= multiplier;
496 remainder_tus = n_tus_per_lane
497 - paired_tus
498 * (i_upper_bdry_cnt
499 + i_lower_bdry_cnt);
500 if ((remainder_tus
501 - i_upper_bdry_cnt) > 0) {
502 remainder_tus_upper
503 = i_upper_bdry_cnt;
504 remainder_tus_lower =
505 remainder_tus
506 - i_upper_bdry_cnt;
507 } else {
508 remainder_tus_upper
509 = remainder_tus;
510 remainder_tus_lower = 0;
511 }
512 total_valid = paired_tus
513 * (i_upper_bdry_cnt
514 * new_valid_boundary_link
515 + i_lower_bdry_cnt
516 * (new_valid_boundary_link
517 - multiplier))
518 + (remainder_tus_upper
519 * new_valid_boundary_link)
520 + (remainder_tus_lower
521 * (new_valid_boundary_link
522 - multiplier));
523 n_err_neg = nn_err_neg = false;
524 effective_valid
525 = div_u64(total_valid,
526 n_tus_per_lane);
527 n_n_err = (effective_valid
528 >= (ratio * tu_size))
529 ? (effective_valid
530 - (ratio * tu_size))
531 : ((ratio * tu_size)
532 - effective_valid);
533 if (effective_valid < (ratio * tu_size))
534 nn_err_neg = true;
535 n_err = (average_valid2
536 >= (ratio * tu_size))
537 ? (average_valid2
538 - (ratio * tu_size))
539 : ((ratio * tu_size)
540 - average_valid2);
541 if (average_valid2 < (ratio * tu_size))
542 n_err_neg = true;
543 even_distribution =
544 n_tus % ln_cnt == 0 ? 1 : 0;
545 diff_abs =
546 resulting_valid >= ratio_by_tu
547 ? (resulting_valid
548 - ratio_by_tu)
549 : (ratio_by_tu
550 - resulting_valid);
551
552 resulting_valid_tmp = div64_u64(
553 (i_upper_bdry_cnt
554 * new_valid_boundary_link
555 + i_lower_bdry_cnt
556 * (new_valid_boundary_link
557 - multiplier)),
558 (i_upper_bdry_cnt
559 + i_lower_bdry_cnt));
560 ratio_by_tu_tmp =
561 original_ratio * tu_size;
562 ratio_by_tu_tmp /= multiplier;
563 n_tus_tmp = rounddown_u64(
564 div64_u64(lwidth
565 * multiplier * multiplier
566 * bpp / 8,
567 resulting_valid_tmp),
568 multiplier);
569 n_tus_tmp /= multiplier;
570
571 temp3 = (resulting_valid_tmp
572 >= (original_ratio * tu_size))
573 ? (resulting_valid_tmp
574 - original_ratio * tu_size)
575 : (original_ratio * tu_size)
576 - resulting_valid_tmp;
577 temp3 = (n_tus_tmp + 1) * temp3;
578 temp4 = (new_valid_boundary_link
579 >= (original_ratio * tu_size))
580 ? (new_valid_boundary_link
581 - original_ratio
582 * tu_size)
583 : (original_ratio * tu_size)
584 - new_valid_boundary_link;
585 temp4 = (i_upper_bdry_cnt
586 * ln_cnt * temp4);
587
588 temp3 = roundup_u64(temp3, multiplier);
589 temp4 = roundup_u64(temp4, multiplier);
590 dp_ctrl_get_extra_req_bytes
591 (resulting_valid_tmp,
592 new_valid_boundary_link,
593 temp3, temp4,
594 &extra_req_bytes_is_neg,
595 &result,
596 (original_ratio * tu_size));
597 extra_req_bytes_new_tmp
598 = div64_ul(result, multiplier);
599 if ((extra_req_bytes_is_neg)
600 && (extra_req_bytes_new_tmp
601 > 1))
602 extra_req_bytes_new_tmp
603 = extra_req_bytes_new_tmp - 1;
604 if (extra_req_bytes_new_tmp == 0)
605 extra_req_bytes_new_tmp = 1;
606 extra_pclk_cycles_tmp =
607 (u64)(extra_req_bytes_new_tmp
608 * 8 * multiplier) / bpp;
609 extra_pclk_cycles_tmp /= multiplier;
610
611 if (extra_pclk_cycles_tmp <= 0)
612 extra_pclk_cycles_tmp = 1;
613 extra_pclk_cycles_in_lclk_tmp =
614 roundup_u64(div64_u64(
615 extra_pclk_cycles_tmp
616 * lclk * multiplier,
617 pclk), multiplier);
618 extra_pclk_cycles_in_lclk_tmp
619 /= multiplier;
620 filler_size_tmp = roundup_u64(
621 (tu_size * multiplier *
622 new_valid_boundary_link),
623 multiplier);
624 filler_size_tmp /= multiplier;
625 lower_filler_size_tmp =
626 filler_size_tmp + 1;
627 if (extra_req_bytes_is_neg)
628 temp3 = (extra_req_bytes_new_tmp
629 > extra_pclk_cycles_in_lclk_tmp
630 ? extra_pclk_cycles_in_lclk_tmp
631 : extra_req_bytes_new_tmp);
632 else
633 temp3 = (extra_req_bytes_new_tmp
634 > extra_pclk_cycles_in_lclk_tmp
635 ? extra_req_bytes_new_tmp :
636 extra_pclk_cycles_in_lclk_tmp);
637
638 temp4 = lower_filler_size_tmp
639 + extra_buffer_margin;
640 if (extra_req_bytes_is_neg)
641 delay_start_link_tmp
642 = (temp3 >= temp4)
643 ? (temp3 - temp4)
644 : (temp4 - temp3);
645 else
646 delay_start_link_tmp
647 = temp3 + temp4;
648
649 min_hblank_tmp = (int)div64_u64(
650 roundup_u64(
651 div64_u64(delay_start_link_tmp
652 * pclk * multiplier, lclk),
653 multiplier), multiplier)
654 + hblank_margin;
655
656 if (((even_distribution == 1)
657 || ((even_distribution_bf == 0)
658 && (even_distribution_legacy
659 == 0)))
660 && !n_err_neg && !nn_err_neg
661 && n_n_err < err
662 && (n_n_err < diff_abs
663 || (dp_brute_force == 1))
664 && (new_valid_boundary_link
665 - 1) > 0
666 && (h_blank >=
667 (u32)min_hblank_tmp)) {
668 upper_bdry_cnt =
669 i_upper_bdry_cnt;
670 lower_bdry_cnt =
671 i_lower_bdry_cnt;
672 err = n_n_err;
673 boundary_moderation_en = 1;
674 tu_size_desired = tu_size;
675 valid_boundary_link =
676 new_valid_boundary_link;
677 effective_valid_recorded
678 = effective_valid;
679 delay_start_link
680 = delay_start_link_tmp;
681 filler_size = filler_size_tmp;
682 min_hblank = min_hblank_tmp;
683 n_tus = n_tus_tmp;
684 even_distribution_bf = 1;
685
686 pr_debug("upper_bdry_cnt=%d, lower_boundary_cnt=%d, err=%lld, tu_size_desired=%d, valid_boundary_link=%d, effective_valid=%lld\n",
687 upper_bdry_cnt,
688 lower_bdry_cnt, err,
689 tu_size_desired,
690 valid_boundary_link,
691 effective_valid);
692 }
693 }
694 }
695 }
696
697 if (boundary_moderation_en == 1) {
698 resulting_valid = (u64)(upper_bdry_cnt
699 *valid_boundary_link + lower_bdry_cnt
700 * (valid_boundary_link - 1))
701 / (upper_bdry_cnt + lower_bdry_cnt);
702 ratio_by_tu = original_ratio * tu_size_desired;
703 valid_lower_boundary_link =
704 (valid_boundary_link / multiplier) - 1;
705
706 tu_size_minus1 = tu_size_desired - 1;
707 even_distribution_bf = 1;
708 valid_boundary_link /= multiplier;
709 pr_debug("Info: Boundary_moderation enabled\n");
710 }
711 }
712
713 min_hblank = ((int) roundup_u64(div64_u64(delay_start_link * pclk
714 * multiplier, lclk), multiplier))
715 / multiplier + hblank_margin;
716 if (h_blank < (u32)min_hblank) {
717 pr_debug(" WARNING: run_idx=%d Programmed h_blank %d is smaller than the min_hblank %d supported.\n",
718 run_idx, h_blank, min_hblank);
719 }
720
721 if (fifo_empty) {
722 tu_size_minus1 = 31;
723 valid_boundary_link = 32;
724 delay_start_link = 0;
725 boundary_moderation_en = 0;
726 }
727
728 pr_debug("tu_size_minus1=%d valid_boundary_link=%d delay_start_link=%d boundary_moderation_en=%d\n upper_boundary_cnt=%d lower_boundary_cnt=%d valid_lower_boundary_link=%d min_hblank=%d\n",
729 tu_size_minus1, valid_boundary_link, delay_start_link,
730 boundary_moderation_en, upper_bdry_cnt, lower_bdry_cnt,
731 valid_lower_boundary_link, min_hblank);
732
733 tu_table->valid_boundary_link = valid_boundary_link;
734 tu_table->delay_start_link = delay_start_link;
735 tu_table->boundary_moderation_en = boundary_moderation_en;
736 tu_table->valid_lower_boundary_link = valid_lower_boundary_link;
737 tu_table->upper_boundary_count = upper_bdry_cnt;
738 tu_table->lower_boundary_count = lower_bdry_cnt;
739 tu_table->tu_size_minus1 = tu_size_minus1;
740}
741
742static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl)
743{
744 u32 dp_tu = 0x0;
745 u32 valid_boundary = 0x0;
746 u32 valid_boundary2 = 0x0;
747 struct dp_vc_tu_mapping_table tu_calc_table;
748
749 dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
750
751 dp_tu |= tu_calc_table.tu_size_minus1;
752 valid_boundary |= tu_calc_table.valid_boundary_link;
753 valid_boundary |= (tu_calc_table.delay_start_link << 16);
754
755 valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1);
756 valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16);
757 valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20);
758
759 if (tu_calc_table.boundary_moderation_en)
760 valid_boundary2 |= BIT(0);
761
762 pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n",
763 dp_tu, valid_boundary, valid_boundary2);
764
765 ctrl->catalog->dp_tu = dp_tu;
766 ctrl->catalog->valid_boundary = valid_boundary;
767 ctrl->catalog->valid_boundary2 = valid_boundary2;
768
769 ctrl->catalog->update_transfer_unit(ctrl->catalog);
770}
771
772static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
773{
774 int ret = 0;
775
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700776 ret = wait_for_completion_timeout(&ctrl->video_comp, HZ / 2);
777 if (ret <= 0) {
778 pr_err("Link Train timedout\n");
779 ret = -EINVAL;
780 }
781
782 return ret;
783}
784
785static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl,
786 u32 voltage_level, u32 pre_emphasis_level)
787{
788 int i;
789 u8 buf[4];
790 u32 max_level_reached = 0;
791
792 if (voltage_level == DP_LINK_VOLTAGE_MAX) {
793 pr_debug("max. voltage swing level reached %d\n",
794 voltage_level);
795 max_level_reached |= BIT(2);
796 }
797
798 if (pre_emphasis_level == DP_LINK_PRE_EMPHASIS_MAX) {
799 pr_debug("max. pre-emphasis level reached %d\n",
800 pre_emphasis_level);
801 max_level_reached |= BIT(5);
802 }
803
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700804 pre_emphasis_level <<= 3;
805
806 for (i = 0; i < 4; i++)
807 buf[i] = voltage_level | pre_emphasis_level | max_level_reached;
808
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700809 pr_debug("sink: p|v=0x%x\n", voltage_level | pre_emphasis_level);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700810 return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700811}
812
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530813static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700814{
815 struct dp_link *link = ctrl->link;
816
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700817 ctrl->catalog->update_vx_px(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530818 link->phy_params.v_level, link->phy_params.p_level);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700819
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530820 return dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530821 link->phy_params.p_level);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700822}
823
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530824static int dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700825 u8 pattern)
826{
827 u8 buf[4];
828
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700829 pr_debug("sink: pattern=%x\n", pattern);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700830
831 buf[0] = pattern;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530832 return drm_dp_dpcd_write(ctrl->aux->drm_aux,
833 DP_TRAINING_PATTERN_SET, buf, 1);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700834}
835
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700836static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
837 u8 *link_status)
838{
839 int ret = 0, len;
840 u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS;
841 u32 link_status_read_max_retries = 100;
842
843 while (--link_status_read_max_retries) {
844 len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
845 link_status);
846 if (len != DP_LINK_STATUS_SIZE) {
847 pr_err("DP link status read failed, err: %d\n", len);
848 ret = len;
849 break;
850 }
851
852 if (!(link_status[offset] & DP_LINK_STATUS_UPDATED))
853 break;
854 }
855
856 return ret;
857}
858
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700859static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
860{
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700861 int tries, old_v_level, ret = 0;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700862 u8 link_status[DP_LINK_STATUS_SIZE];
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700863 int const maximum_retries = 5;
864
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800865 ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED;
866 ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED;
867 ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED;
868
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700869 dp_ctrl_state_ctrl(ctrl, 0);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700870 /* Make sure to clear the current pattern before starting a new one */
871 wmb();
872
873 ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530874 ret = dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700875 DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530876 if (ret <= 0) {
877 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800878 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530879 }
880
881 ret = dp_ctrl_update_vx_px(ctrl);
882 if (ret <= 0) {
883 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800884 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530885 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700886
887 tries = 0;
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530888 old_v_level = ctrl->link->phy_params.v_level;
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800889 while (!atomic_read(&ctrl->aborted)) {
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700890 drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700891
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700892 ret = dp_ctrl_read_link_status(ctrl, link_status);
893 if (ret)
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700894 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700895
896 if (drm_dp_clock_recovery_ok(link_status,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530897 ctrl->link->link_params.lane_count)) {
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700898 break;
899 }
900
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530901 if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) {
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700902 pr_err_ratelimited("max v_level reached\n");
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700903 ret = -EAGAIN;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700904 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700905 }
906
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530907 if (old_v_level == ctrl->link->phy_params.v_level) {
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700908 tries++;
909 if (tries >= maximum_retries) {
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700910 pr_err("max tries reached\n");
Tatenda Chipeperekwaf7d82ce2017-08-22 19:13:47 -0700911 ret = -ETIMEDOUT;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700912 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700913 }
914 } else {
915 tries = 0;
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530916 old_v_level = ctrl->link->phy_params.v_level;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700917 }
918
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700919 pr_debug("clock recovery not done, adjusting vx px\n");
920
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700921 ctrl->link->adjust_levels(ctrl->link, link_status);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530922 ret = dp_ctrl_update_vx_px(ctrl);
923 if (ret <= 0) {
924 ret = -EINVAL;
925 break;
926 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700927 }
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800928end:
929 ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED;
930
931 if (ret)
932 ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED;
933 else
934 ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700935
936 return ret;
937}
938
939static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
940{
941 int ret = 0;
942
943 if (!ctrl)
944 return -EINVAL;
945
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530946 switch (ctrl->link->link_params.bw_code) {
Aravind Venkateswaranc28b7772017-08-18 17:20:18 -0700947 case DP_LINK_BW_8_1:
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +0530948 ctrl->link->link_params.bw_code = DP_LINK_BW_5_4;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700949 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700950 case DP_LINK_BW_5_4:
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +0530951 ctrl->link->link_params.bw_code = DP_LINK_BW_2_7;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700952 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700953 case DP_LINK_BW_2_7:
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700954 case DP_LINK_BW_1_62:
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700955 default:
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +0530956 ctrl->link->link_params.bw_code = DP_LINK_BW_1_62;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700957 break;
958 };
959
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530960 pr_debug("new bw code=0x%x\n", ctrl->link->link_params.bw_code);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700961
962 return ret;
963}
964
965static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
966{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700967 dp_ctrl_train_pattern_set(ctrl, 0);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700968 drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700969}
970
971static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
972{
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700973 int tries = 0, ret = 0;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700974 char pattern;
975 int const maximum_retries = 5;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700976 u8 link_status[DP_LINK_STATUS_SIZE];
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700977
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800978 ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED;
979 ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED;
980 ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED;
981
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700982 dp_ctrl_state_ctrl(ctrl, 0);
983 /* Make sure to clear the current pattern before starting a new one */
984 wmb();
985
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700986 if (drm_dp_tps3_supported(ctrl->panel->dpcd))
987 pattern = DP_TRAINING_PATTERN_3;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700988 else
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700989 pattern = DP_TRAINING_PATTERN_2;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700990
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530991 ret = dp_ctrl_update_vx_px(ctrl);
992 if (ret <= 0) {
993 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800994 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530995 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700996 ctrl->catalog->set_pattern(ctrl->catalog, pattern);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530997 ret = dp_ctrl_train_pattern_set(ctrl,
998 pattern | DP_RECOVERED_CLOCK_OUT_EN);
999 if (ret <= 0) {
1000 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001001 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301002 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001003
1004 do {
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001005 drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001006
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001007 ret = dp_ctrl_read_link_status(ctrl, link_status);
1008 if (ret)
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001009 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001010
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301011 if (drm_dp_channel_eq_ok(link_status,
1012 ctrl->link->link_params.lane_count))
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001013 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001014
1015 if (tries > maximum_retries) {
Tatenda Chipeperekwaf7d82ce2017-08-22 19:13:47 -07001016 ret = -ETIMEDOUT;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001017 break;
1018 }
1019 tries++;
1020
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001021 ctrl->link->adjust_levels(ctrl->link, link_status);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301022 ret = dp_ctrl_update_vx_px(ctrl);
1023 if (ret <= 0) {
1024 ret = -EINVAL;
1025 break;
1026 }
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001027 } while (!atomic_read(&ctrl->aborted));
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001028end:
1029 ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001030
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001031 if (ret)
1032 ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED;
1033 else
1034 ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001035 return ret;
1036}
1037
1038static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
1039{
1040 int ret = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001041 u8 encoding = 0x1;
1042 struct drm_dp_link link_info = {0};
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001043
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301044 ctrl->link->phy_params.p_level = 0;
1045 ctrl->link->phy_params.v_level = 0;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001046
1047 dp_ctrl_config_ctrl(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001048
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301049 link_info.num_lanes = ctrl->link->link_params.lane_count;
1050 link_info.rate = drm_dp_bw_code_to_link_rate(
1051 ctrl->link->link_params.bw_code);
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001052 link_info.capabilities = ctrl->panel->link_info.capabilities;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001053
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301054 ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
1055 if (ret)
1056 goto end;
1057
1058 ret = drm_dp_dpcd_write(ctrl->aux->drm_aux,
1059 DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1);
1060 if (ret <= 0) {
1061 ret = -EINVAL;
1062 goto end;
1063 }
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001064
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001065 ret = dp_ctrl_link_train_1(ctrl);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001066 if (ret) {
1067 pr_err("link training #1 failed\n");
1068 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001069 }
1070
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001071 /* print success info as this is a result of user initiated action */
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001072 pr_info("link training #1 successful\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001073
1074 ret = dp_ctrl_link_training_2(ctrl);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001075 if (ret) {
1076 pr_err("link training #2 failed\n");
1077 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001078 }
1079
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001080 /* print success info as this is a result of user initiated action */
Ajay Singh Parmarfae11672017-09-01 19:49:30 -07001081 pr_info("link training #2 successful\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001082
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001083end:
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001084 dp_ctrl_state_ctrl(ctrl, 0);
1085 /* Make sure to clear the current pattern before starting a new one */
1086 wmb();
1087
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001088 dp_ctrl_clear_training_pattern(ctrl);
1089 return ret;
1090}
1091
1092static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)
1093{
1094 bool mainlink_ready = false;
1095 int ret = 0;
1096
1097 ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
1098
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001099 if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001100 goto end;
1101
1102 if (!train)
1103 goto send_video;
1104
1105 /*
1106 * As part of previous calls, DP controller state might have
1107 * transitioned to PUSH_IDLE. In order to start transmitting a link
1108 * training pattern, we have to first to a DP software reset.
1109 */
1110 ctrl->catalog->reset(ctrl->catalog);
1111
1112 ret = dp_ctrl_link_train(ctrl);
1113 if (ret)
1114 goto end;
1115
1116send_video:
1117 /*
1118 * Set up transfer unit values and set controller state to send
1119 * video.
1120 */
1121 dp_ctrl_setup_tr_unit(ctrl);
1122 ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO);
1123
1124 dp_ctrl_wait4video_ready(ctrl);
1125 mainlink_ready = ctrl->catalog->mainlink_ready(ctrl->catalog);
1126 pr_debug("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
1127end:
1128 return ret;
1129}
1130
1131static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
1132 char *name, u32 rate)
1133{
1134 u32 num = ctrl->parser->mp[DP_CTRL_PM].num_clk;
1135 struct dss_clk *cfg = ctrl->parser->mp[DP_CTRL_PM].clk_config;
1136
1137 while (num && strcmp(cfg->clk_name, name)) {
1138 num--;
1139 cfg++;
1140 }
1141
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001142 pr_debug("setting rate=%d on clk=%s\n", rate, name);
1143
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001144 if (num)
1145 cfg->rate = rate;
1146 else
1147 pr_err("%s clock could not be set with rate %d\n", name, rate);
1148}
1149
1150static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
1151{
1152 int ret = 0;
1153
1154 ctrl->power->set_pixel_clk_parent(ctrl->power);
1155
1156 dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301157 drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code));
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001158
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001159 dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate);
1160
1161 ret = ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, true);
1162 if (ret) {
1163 pr_err("Unabled to start link clocks\n");
1164 ret = -EINVAL;
1165 }
1166
1167 return ret;
1168}
1169
1170static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl)
1171{
1172 return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false);
1173}
1174
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001175static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001176{
1177 struct dp_ctrl_private *ctrl;
1178 struct dp_catalog_ctrl *catalog;
1179
1180 if (!dp_ctrl) {
1181 pr_err("Invalid input data\n");
1182 return -EINVAL;
1183 }
1184
1185 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1186
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001187 ctrl->orientation = flip;
1188 catalog = ctrl->catalog;
1189
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001190 if (reset) {
Padmanabhan Komanduru4af597e2017-11-08 08:54:08 +05301191 catalog->usb_reset(ctrl->catalog, flip);
1192 catalog->phy_reset(ctrl->catalog);
1193 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001194 catalog->enable_irq(ctrl->catalog, true);
1195
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001196 return 0;
1197}
1198
1199/**
1200 * dp_ctrl_host_deinit() - Uninitialize DP controller
1201 * @ctrl: Display Port Driver data
1202 *
1203 * Perform required steps to uninitialize DP controller
1204 * and its resources.
1205 */
1206static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
1207{
1208 struct dp_ctrl_private *ctrl;
1209
1210 if (!dp_ctrl) {
1211 pr_err("Invalid input data\n");
1212 return;
1213 }
1214
1215 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1216
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001217 ctrl->catalog->enable_irq(ctrl->catalog, false);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001218
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001219 pr_debug("Host deinitialized successfully\n");
1220}
1221
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001222static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001223{
1224 int ret = 0;
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001225 struct dp_ctrl_private *ctrl;
1226
1227 if (!dp_ctrl) {
1228 pr_err("Invalid input data\n");
1229 return -EINVAL;
1230 }
1231
1232 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301233
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001234 if (!ctrl->power_on || atomic_read(&ctrl->aborted)) {
1235 pr_err("CTRL off, return\n");
1236 return -EINVAL;
1237 }
1238
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001239 ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
1240 ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;
1241 ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;
1242
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001243 ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
1244 ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301245
Narender Ankamde426242019-12-23 20:54:31 +05301246 ctrl->pixel_rate = ctrl->panel->get_pixel_clk(ctrl->panel);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001247
1248 do {
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +05301249 if (ret == -EAGAIN) {
1250 /* try with lower link rate */
1251 dp_ctrl_link_rate_down_shift(ctrl);
1252
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001253 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +05301254 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001255
1256 ctrl->catalog->phy_lane_cfg(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301257 ctrl->orientation, ctrl->link->link_params.lane_count);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001258
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001259 /*
1260 * Disable and re-enable the mainlink clock since the
1261 * link clock might have been adjusted as part of the
1262 * link maintenance.
1263 */
1264 dp_ctrl_disable_mainlink_clocks(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001265
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001266 ret = dp_ctrl_enable_mainlink_clocks(ctrl);
1267 if (ret)
1268 continue;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001269
1270 dp_ctrl_configure_source_params(ctrl);
1271
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001272 ctrl->catalog->config_msa(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301273 drm_dp_bw_code_to_link_rate(
Narender Ankamde426242019-12-23 20:54:31 +05301274 ctrl->link->link_params.bw_code),
1275 ctrl->pixel_rate,
1276 ctrl->panel->pinfo.out_format);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001277
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001278 reinit_completion(&ctrl->idle_comp);
1279
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301280 ret = dp_ctrl_setup_main_link(ctrl, true);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001281 } while (ret == -EAGAIN);
1282
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001283 ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED;
1284
1285 if (ret)
1286 ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED;
1287 else
1288 ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED;
1289
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001290 return ret;
1291}
1292
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001293static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl)
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001294{
1295 int ret = 0;
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001296 struct dp_ctrl_private *ctrl;
1297
1298 if (!dp_ctrl) {
1299 pr_err("Invalid input data\n");
1300 return;
1301 }
1302
1303 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001304
1305 if (!ctrl->link->phy_params.phy_test_pattern_sel) {
1306 pr_debug("no test pattern selected by sink\n");
1307 return;
1308 }
1309
1310 pr_debug("start\n");
1311
1312 ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
1313 /*
1314 * The global reset will need DP link ralated clocks to be
1315 * running. Add the global reset just before disabling the
1316 * link clocks and core clocks.
1317 */
1318 ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
1319 ctrl->dp_ctrl.off(&ctrl->dp_ctrl);
1320
1321 ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl);
1322 if (ret)
1323 pr_err("failed to enable DP controller\n");
1324
1325 pr_debug("end\n");
1326}
1327
1328static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
1329{
1330 bool success = false;
1331 u32 pattern_sent = 0x0;
1332 u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
1333
Tatenda Chipeperekwa70fc1f12018-11-15 15:49:35 -08001334 dp_ctrl_update_vx_px(ctrl);
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001335 ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested);
1336 ctrl->link->send_test_response(ctrl->link);
1337
1338 pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog);
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001339 pr_debug("pattern_request: %s. pattern_sent: 0x%x\n",
1340 dp_link_get_phy_test_pattern(pattern_requested),
1341 pattern_sent);
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001342
1343 switch (pattern_sent) {
1344 case MR_LINK_TRAINING1:
1345 if (pattern_requested ==
1346 DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING)
1347 success = true;
1348 break;
1349 case MR_LINK_SYMBOL_ERM:
1350 if ((pattern_requested ==
1351 DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT)
1352 || (pattern_requested ==
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001353 DP_TEST_PHY_PATTERN_CP2520_PATTERN_1))
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001354 success = true;
1355 break;
1356 case MR_LINK_PRBS7:
1357 if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7)
1358 success = true;
1359 break;
1360 case MR_LINK_CUSTOM80:
1361 if (pattern_requested ==
1362 DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN)
1363 success = true;
1364 break;
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001365 case MR_LINK_TRAINING4:
1366 if (pattern_requested ==
1367 DP_TEST_PHY_PATTERN_CP2520_PATTERN_3)
1368 success = true;
1369 break;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001370 default:
1371 success = false;
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001372 break;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001373 }
1374
1375 pr_debug("%s: %s\n", success ? "success" : "failed",
1376 dp_link_get_phy_test_pattern(pattern_requested));
1377}
1378
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301379static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001380{
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301381 struct dp_ctrl_private *ctrl;
1382
1383 if (!dp_ctrl) {
1384 pr_err("invalid params\n");
1385 return;
1386 }
1387
1388 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1389 ctrl->catalog->reset(ctrl->catalog);
1390}
1391
1392static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
1393{
1394 int rc = 0;
1395 struct dp_ctrl_private *ctrl;
1396 u32 rate = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001397 u32 link_train_max_retries = 100;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001398 u32 const phy_cts_pixel_clk_khz = 148500;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001399
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301400 if (!dp_ctrl) {
1401 rc = -EINVAL;
1402 goto end;
1403 }
1404
1405 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1406
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001407 atomic_set(&ctrl->aborted, 0);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301408 rate = ctrl->panel->link_info.rate;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001409
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001410 ctrl->catalog->hpd_config(ctrl->catalog, true);
1411
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001412 if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
1413 pr_debug("using phy test link parameters\n");
1414 if (!ctrl->panel->pinfo.pixel_clk_khz)
1415 ctrl->pixel_rate = phy_cts_pixel_clk_khz;
1416 } else {
1417 ctrl->link->link_params.bw_code =
1418 drm_dp_link_rate_to_bw_code(rate);
1419 ctrl->link->link_params.lane_count =
1420 ctrl->panel->link_info.num_lanes;
Narender Ankamde426242019-12-23 20:54:31 +05301421 ctrl->pixel_rate = ctrl->panel->get_pixel_clk(ctrl->panel);
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001422 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001423
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001424 pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n",
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301425 ctrl->link->link_params.bw_code,
1426 ctrl->link->link_params.lane_count, ctrl->pixel_rate);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001427
1428 ctrl->catalog->phy_lane_cfg(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301429 ctrl->orientation, ctrl->link->link_params.lane_count);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001430
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301431 rc = dp_ctrl_enable_mainlink_clocks(ctrl);
1432 if (rc)
1433 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001434
1435 reinit_completion(&ctrl->idle_comp);
1436
1437 dp_ctrl_configure_source_params(ctrl);
1438
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001439 while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
1440 ctrl->catalog->config_msa(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301441 drm_dp_bw_code_to_link_rate(
Narender Ankamde426242019-12-23 20:54:31 +05301442 ctrl->link->link_params.bw_code),
1443 ctrl->pixel_rate, ctrl->panel->pinfo.out_format);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001444
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301445 rc = dp_ctrl_setup_main_link(ctrl, true);
1446 if (!rc)
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001447 break;
1448
1449 /* try with lower link rate */
1450 dp_ctrl_link_rate_down_shift(ctrl);
1451
1452 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
1453
1454 dp_ctrl_disable_mainlink_clocks(ctrl);
1455 /* hw recommended delay before re-enabling clocks */
1456 msleep(20);
1457
1458 dp_ctrl_enable_mainlink_clocks(ctrl);
1459 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001460
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001461 if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
1462 dp_ctrl_send_phy_test_pattern(ctrl);
1463
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001464 ctrl->power_on = true;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001465 pr_debug("End-\n");
1466
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001467end:
1468 return rc;
1469}
1470
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301471static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001472{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001473 struct dp_ctrl_private *ctrl;
1474
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001475 if (!dp_ctrl)
1476 return;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001477
1478 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1479
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301480 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
Tatenda Chipeperekwa52f1d802017-08-29 18:57:48 -07001481 ctrl->catalog->reset(ctrl->catalog);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301482
Tatenda Chipeperekwa52f1d802017-08-29 18:57:48 -07001483 /* Make sure DP is disabled before clk disable */
1484 wmb();
1485
1486 dp_ctrl_disable_mainlink_clocks(ctrl);
1487
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001488 ctrl->power_on = false;
Tatenda Chipeperekwa52f1d802017-08-29 18:57:48 -07001489 pr_debug("DP off done\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001490}
1491
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001492static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001493{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001494 struct dp_ctrl_private *ctrl;
1495
1496 if (!dp_ctrl)
1497 return;
1498
1499 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1500
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001501 ctrl->catalog->get_interrupt(ctrl->catalog);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001502
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001503 if (ctrl->catalog->isr & DP_CTRL_INTR_READY_FOR_VIDEO)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001504 dp_ctrl_video_ready(ctrl);
1505
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001506 if (ctrl->catalog->isr & DP_CTRL_INTR_IDLE_PATTERN_SENT)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001507 dp_ctrl_idle_patterns_sent(ctrl);
1508}
1509
1510struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
1511{
1512 int rc = 0;
1513 struct dp_ctrl_private *ctrl;
1514 struct dp_ctrl *dp_ctrl;
1515
1516 if (!in->dev || !in->panel || !in->aux ||
1517 !in->link || !in->catalog) {
1518 pr_err("invalid input\n");
1519 rc = -EINVAL;
1520 goto error;
1521 }
1522
1523 ctrl = devm_kzalloc(in->dev, sizeof(*ctrl), GFP_KERNEL);
1524 if (!ctrl) {
1525 rc = -ENOMEM;
1526 goto error;
1527 }
1528
1529 init_completion(&ctrl->idle_comp);
1530 init_completion(&ctrl->video_comp);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001531
1532 /* in parameters */
1533 ctrl->parser = in->parser;
1534 ctrl->panel = in->panel;
1535 ctrl->power = in->power;
1536 ctrl->aux = in->aux;
1537 ctrl->link = in->link;
1538 ctrl->catalog = in->catalog;
Tatenda Chipeperekwa2bc44872017-10-18 18:26:56 -07001539 ctrl->dev = in->dev;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001540
1541 dp_ctrl = &ctrl->dp_ctrl;
1542
1543 /* out parameters */
1544 dp_ctrl->init = dp_ctrl_host_init;
1545 dp_ctrl->deinit = dp_ctrl_host_deinit;
1546 dp_ctrl->on = dp_ctrl_on;
1547 dp_ctrl->off = dp_ctrl_off;
1548 dp_ctrl->push_idle = dp_ctrl_push_idle;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001549 dp_ctrl->abort = dp_ctrl_abort;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001550 dp_ctrl->isr = dp_ctrl_isr;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301551 dp_ctrl->reset = dp_ctrl_reset;
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001552 dp_ctrl->link_maintenance = dp_ctrl_link_maintenance;
1553 dp_ctrl->process_phy_test_request = dp_ctrl_process_phy_test_request;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001554
1555 return dp_ctrl;
1556error:
1557 return ERR_PTR(rc);
1558}
1559
1560void dp_ctrl_put(struct dp_ctrl *dp_ctrl)
1561{
1562 struct dp_ctrl_private *ctrl;
1563
1564 if (!dp_ctrl)
1565 return;
1566
1567 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1568
1569 devm_kfree(ctrl->dev, ctrl);
1570}