blob: 51abcf550689957918f759dbd891358a976e142f [file] [log] [blame]
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001/*
2 * Copyright (c) 2012-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
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
21#include "dp_ctrl.h"
22
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070023#define DP_KHZ_TO_HZ 1000
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070024
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070025#define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0)
26#define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3)
27
28/* dp state ctrl */
29#define ST_TRAIN_PATTERN_1 BIT(0)
30#define ST_TRAIN_PATTERN_2 BIT(1)
31#define ST_TRAIN_PATTERN_3 BIT(2)
32#define ST_TRAIN_PATTERN_4 BIT(3)
33#define ST_SYMBOL_ERR_RATE_MEASUREMENT BIT(4)
34#define ST_PRBS7 BIT(5)
35#define ST_CUSTOM_80_BIT_PATTERN BIT(6)
36#define ST_SEND_VIDEO BIT(7)
37#define ST_PUSH_IDLE BIT(8)
38
39struct dp_vc_tu_mapping_table {
40 u32 vic;
41 u8 lanes;
42 u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */
43 u8 bpp;
44 u8 valid_boundary_link;
45 u16 delay_start_link;
46 bool boundary_moderation_en;
47 u8 valid_lower_boundary_link;
48 u8 upper_boundary_count;
49 u8 lower_boundary_count;
50 u8 tu_size_minus1;
51};
52
53struct dp_ctrl_private {
54 struct dp_ctrl dp_ctrl;
55
56 struct device *dev;
57 struct dp_aux *aux;
58 struct dp_panel *panel;
59 struct dp_link *link;
60 struct dp_power *power;
61 struct dp_parser *parser;
62 struct dp_catalog_ctrl *catalog;
63
64 struct completion idle_comp;
65 struct completion video_comp;
66 struct completion irq_comp;
67
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070068 bool psm_enabled;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070069 bool orientation;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -070070 atomic_t aborted;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070071
72 u32 pixel_rate;
73 u32 vic;
74};
75
76enum notification_status {
77 NOTIFY_UNKNOWN,
78 NOTIFY_CONNECT,
79 NOTIFY_DISCONNECT,
80 NOTIFY_CONNECT_IRQ_HPD,
81 NOTIFY_DISCONNECT_IRQ_HPD,
82};
83
84static void dp_ctrl_idle_patterns_sent(struct dp_ctrl_private *ctrl)
85{
86 pr_debug("idle_patterns_sent\n");
87 complete(&ctrl->idle_comp);
88}
89
90static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl)
91{
92 pr_debug("dp_video_ready\n");
93 complete(&ctrl->video_comp);
94}
95
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -070096static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl)
97{
98 struct dp_ctrl_private *ctrl;
99
100 if (!dp_ctrl) {
101 pr_err("Invalid input data\n");
102 return;
103 }
104
105 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
106
107 atomic_set(&ctrl->aborted, 1);
108}
109
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700110static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
111{
112 ctrl->catalog->state_ctrl(ctrl->catalog, state);
113}
114
115static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
116{
117 int const idle_pattern_completion_timeout_ms = 3 * HZ / 100;
118 struct dp_ctrl_private *ctrl;
119
120 if (!dp_ctrl) {
121 pr_err("Invalid input data\n");
122 return;
123 }
124
125 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
126
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700127 reinit_completion(&ctrl->idle_comp);
128 dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
129
130 if (!wait_for_completion_timeout(&ctrl->idle_comp,
131 idle_pattern_completion_timeout_ms))
132 pr_warn("PUSH_IDLE pattern timedout\n");
133
134 pr_debug("mainlink off done\n");
135}
136
137static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
138{
139 u32 config = 0, tbd;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700140 u8 *dpcd = ctrl->panel->dpcd;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700141
142 config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */
143 config |= (0 << 11); /* RGB */
144
145 /* Scrambler reset enable */
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700146 if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700147 config |= (1 << 10);
148
149 tbd = ctrl->link->get_test_bits_depth(ctrl->link,
150 ctrl->panel->pinfo.bpp);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700151
152 if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN)
153 tbd = DP_TEST_BIT_DEPTH_8;
154
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700155 config |= tbd << 8;
156
157 /* Num of Lanes */
158 config |= ((ctrl->link->lane_count - 1) << 4);
159
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700160 if (drm_dp_enhanced_frame_cap(dpcd))
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700161 config |= 0x40;
162
163 config |= 0x04; /* progressive video */
164
165 config |= 0x03; /* sycn clock & static Mvid */
166
167 ctrl->catalog->config_ctrl(ctrl->catalog, config);
168}
169
170/**
171 * dp_ctrl_configure_source_params() - configures DP transmitter source params
172 * @ctrl: Display Port Driver data
173 *
174 * Configures the DP transmitter source params including details such as lane
175 * configuration, output format and sink/panel timing information.
176 */
177static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
178{
179 u32 cc, tb;
180
181 ctrl->catalog->lane_mapping(ctrl->catalog);
182 ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
183
184 dp_ctrl_config_ctrl(ctrl);
185
186 tb = ctrl->link->get_test_bits_depth(ctrl->link,
187 ctrl->panel->pinfo.bpp);
188 cc = ctrl->link->get_colorimetry_config(ctrl->link);
189 ctrl->catalog->config_misc(ctrl->catalog, cc, tb);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700190 ctrl->panel->timing_cfg(ctrl->panel);
191}
192
193static void dp_ctrl_get_extra_req_bytes(u64 result_valid,
194 int valid_bdary_link,
195 u64 value1, u64 value2,
196 bool *negative, u64 *result,
197 u64 compare)
198{
199 *negative = false;
200 if (result_valid >= compare) {
201 if (valid_bdary_link
202 >= compare)
203 *result = value1 + value2;
204 else {
205 if (value1 < value2)
206 *negative = true;
207 *result = (value1 >= value2) ?
208 (value1 - value2) : (value2 - value1);
209 }
210 } else {
211 if (valid_bdary_link
212 >= compare) {
213 if (value1 >= value2)
214 *negative = true;
215 *result = (value1 >= value2) ?
216 (value1 - value2) : (value2 - value1);
217 } else {
218 *result = value1 + value2;
219 *negative = true;
220 }
221 }
222}
223
224static u64 roundup_u64(u64 x, u64 y)
225{
226 x += (y - 1);
227 return (div64_ul(x, y) * y);
228}
229
230static u64 rounddown_u64(u64 x, u64 y)
231{
232 u64 rem;
233
234 div64_u64_rem(x, y, &rem);
235 return (x - rem);
236}
237
238static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
239 struct dp_vc_tu_mapping_table *tu_table)
240{
241 u32 const multiplier = 1000000;
242 u64 pclk, lclk;
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700243 u8 bpp, ln_cnt;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700244 int run_idx = 0;
245 u32 lwidth, h_blank;
246 u32 fifo_empty = 0;
247 u32 ratio_scale = 1001;
248 u64 temp, ratio, original_ratio;
249 u64 temp2, reminder;
250 u64 temp3, temp4, result = 0;
251
252 u64 err = multiplier;
253 u64 n_err = 0, n_n_err = 0;
254 bool n_err_neg, nn_err_neg;
255 u8 hblank_margin = 16;
256
257 u8 tu_size, tu_size_desired = 0, tu_size_minus1;
258 int valid_boundary_link;
259 u64 resulting_valid;
260 u64 total_valid;
261 u64 effective_valid;
262 u64 effective_valid_recorded;
263 int n_tus;
264 int n_tus_per_lane;
265 int paired_tus;
266 int remainder_tus;
267 int remainder_tus_upper, remainder_tus_lower;
268 int extra_bytes;
269 int filler_size;
270 int delay_start_link;
271 int boundary_moderation_en = 0;
272 int upper_bdry_cnt = 0;
273 int lower_bdry_cnt = 0;
274 int i_upper_bdry_cnt = 0;
275 int i_lower_bdry_cnt = 0;
276 int valid_lower_boundary_link = 0;
277 int even_distribution_bf = 0;
278 int even_distribution_legacy = 0;
279 int even_distribution = 0;
280 int min_hblank = 0;
281 int extra_pclk_cycles;
282 u8 extra_pclk_cycle_delay = 4;
283 int extra_pclk_cycles_in_link_clk;
284 u64 ratio_by_tu;
285 u64 average_valid2;
286 u64 extra_buffer_margin;
287 int new_valid_boundary_link;
288
289 u64 resulting_valid_tmp;
290 u64 ratio_by_tu_tmp;
291 int n_tus_tmp;
292 int extra_pclk_cycles_tmp;
293 int extra_pclk_cycles_in_lclk_tmp;
294 int extra_req_bytes_new_tmp;
295 int filler_size_tmp;
296 int lower_filler_size_tmp;
297 int delay_start_link_tmp;
298 int min_hblank_tmp = 0;
299 bool extra_req_bytes_is_neg = false;
300 struct dp_panel_info *pinfo = &ctrl->panel->pinfo;
301
302 u8 dp_brute_force = 1;
303 u64 brute_force_threshold = 10;
304 u64 diff_abs;
305
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700306 ln_cnt = ctrl->link->lane_count;
307
308 bpp = pinfo->bpp;
309 lwidth = pinfo->h_active;
310 h_blank = pinfo->h_back_porch + pinfo->h_front_porch +
311 pinfo->h_sync_width;
312 pclk = pinfo->pixel_clk_khz * 1000;
313
314 boundary_moderation_en = 0;
315 upper_bdry_cnt = 0;
316 lower_bdry_cnt = 0;
317 i_upper_bdry_cnt = 0;
318 i_lower_bdry_cnt = 0;
319 valid_lower_boundary_link = 0;
320 even_distribution_bf = 0;
321 even_distribution_legacy = 0;
322 even_distribution = 0;
323 min_hblank = 0;
324
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700325 lclk = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code) * DP_KHZ_TO_HZ;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700326
327 pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
328 pclk, lwidth, h_blank);
329 pr_debug("lclk = %lld, ln_cnt = %d\n", lclk, ln_cnt);
330 ratio = div64_u64_rem(pclk * bpp * multiplier,
331 8 * ln_cnt * lclk, &reminder);
332 ratio = div64_u64((pclk * bpp * multiplier), (8 * ln_cnt * lclk));
333 original_ratio = ratio;
334
335 extra_buffer_margin = roundup_u64(div64_u64(extra_pclk_cycle_delay
336 * lclk * multiplier, pclk), multiplier);
337 extra_buffer_margin = div64_u64(extra_buffer_margin, multiplier);
338
339 /* To deal with cases where lines are not distributable */
340 if (((lwidth % ln_cnt) != 0) && ratio < multiplier) {
341 ratio = ratio * ratio_scale;
342 ratio = ratio < (1000 * multiplier)
343 ? ratio : (1000 * multiplier);
344 }
345 pr_debug("ratio = %lld\n", ratio);
346
347 for (tu_size = 32; tu_size <= 64; tu_size++) {
348 temp = ratio * tu_size;
349 temp2 = ((temp / multiplier) + 1) * multiplier;
350 n_err = roundup_u64(temp, multiplier) - temp;
351
352 if (n_err < err) {
353 err = n_err;
354 tu_size_desired = tu_size;
355 }
356 }
357 pr_debug("Info: tu_size_desired = %d\n", tu_size_desired);
358
359 tu_size_minus1 = tu_size_desired - 1;
360
361 valid_boundary_link = roundup_u64(ratio * tu_size_desired, multiplier);
362 valid_boundary_link /= multiplier;
363 n_tus = rounddown((lwidth * bpp * multiplier)
364 / (8 * valid_boundary_link), multiplier) / multiplier;
365 even_distribution_legacy = n_tus % ln_cnt == 0 ? 1 : 0;
366 pr_debug("Info: n_symbol_per_tu=%d, number_of_tus=%d\n",
367 valid_boundary_link, n_tus);
368
369 extra_bytes = roundup_u64((n_tus + 1)
370 * ((valid_boundary_link * multiplier)
371 - (original_ratio * tu_size_desired)), multiplier);
372 extra_bytes /= multiplier;
373 extra_pclk_cycles = roundup(extra_bytes * 8 * multiplier / bpp,
374 multiplier);
375 extra_pclk_cycles /= multiplier;
376 extra_pclk_cycles_in_link_clk = roundup_u64(div64_u64(extra_pclk_cycles
377 * lclk * multiplier, pclk), multiplier);
378 extra_pclk_cycles_in_link_clk /= multiplier;
379 filler_size = roundup_u64((tu_size_desired - valid_boundary_link)
380 * multiplier, multiplier);
381 filler_size /= multiplier;
382 ratio_by_tu = div64_u64(ratio * tu_size_desired, multiplier);
383
384 pr_debug("extra_pclk_cycles_in_link_clk=%d, extra_bytes=%d\n",
385 extra_pclk_cycles_in_link_clk, extra_bytes);
386 pr_debug("extra_pclk_cycles_in_link_clk=%d\n",
387 extra_pclk_cycles_in_link_clk);
388 pr_debug("filler_size=%d, extra_buffer_margin=%lld\n",
389 filler_size, extra_buffer_margin);
390
391 delay_start_link = ((extra_bytes > extra_pclk_cycles_in_link_clk)
392 ? extra_bytes
393 : extra_pclk_cycles_in_link_clk)
394 + filler_size + extra_buffer_margin;
395 resulting_valid = valid_boundary_link;
396 pr_debug("Info: delay_start_link=%d, filler_size=%d\n",
397 delay_start_link, filler_size);
398 pr_debug("valid_boundary_link=%d ratio_by_tu=%lld\n",
399 valid_boundary_link, ratio_by_tu);
400
401 diff_abs = (resulting_valid >= ratio_by_tu)
402 ? (resulting_valid - ratio_by_tu)
403 : (ratio_by_tu - resulting_valid);
404
405 if (err != 0 && ((diff_abs > brute_force_threshold)
406 || (even_distribution_legacy == 0)
407 || (dp_brute_force == 1))) {
408 err = multiplier;
409 for (tu_size = 32; tu_size <= 64; tu_size++) {
410 for (i_upper_bdry_cnt = 1; i_upper_bdry_cnt <= 15;
411 i_upper_bdry_cnt++) {
412 for (i_lower_bdry_cnt = 1;
413 i_lower_bdry_cnt <= 15;
414 i_lower_bdry_cnt++) {
415 new_valid_boundary_link =
416 roundup_u64(ratio
417 * tu_size, multiplier);
418 average_valid2 = (i_upper_bdry_cnt
419 * new_valid_boundary_link
420 + i_lower_bdry_cnt
421 * (new_valid_boundary_link
422 - multiplier))
423 / (i_upper_bdry_cnt
424 + i_lower_bdry_cnt);
425 n_tus = rounddown_u64(div64_u64(lwidth
426 * multiplier * multiplier
427 * (bpp / 8), average_valid2),
428 multiplier);
429 n_tus /= multiplier;
430 n_tus_per_lane
431 = rounddown(n_tus
432 * multiplier
433 / ln_cnt, multiplier);
434 n_tus_per_lane /= multiplier;
435 paired_tus =
436 rounddown((n_tus_per_lane)
437 * multiplier
438 / (i_upper_bdry_cnt
439 + i_lower_bdry_cnt),
440 multiplier);
441 paired_tus /= multiplier;
442 remainder_tus = n_tus_per_lane
443 - paired_tus
444 * (i_upper_bdry_cnt
445 + i_lower_bdry_cnt);
446 if ((remainder_tus
447 - i_upper_bdry_cnt) > 0) {
448 remainder_tus_upper
449 = i_upper_bdry_cnt;
450 remainder_tus_lower =
451 remainder_tus
452 - i_upper_bdry_cnt;
453 } else {
454 remainder_tus_upper
455 = remainder_tus;
456 remainder_tus_lower = 0;
457 }
458 total_valid = paired_tus
459 * (i_upper_bdry_cnt
460 * new_valid_boundary_link
461 + i_lower_bdry_cnt
462 * (new_valid_boundary_link
463 - multiplier))
464 + (remainder_tus_upper
465 * new_valid_boundary_link)
466 + (remainder_tus_lower
467 * (new_valid_boundary_link
468 - multiplier));
469 n_err_neg = nn_err_neg = false;
470 effective_valid
471 = div_u64(total_valid,
472 n_tus_per_lane);
473 n_n_err = (effective_valid
474 >= (ratio * tu_size))
475 ? (effective_valid
476 - (ratio * tu_size))
477 : ((ratio * tu_size)
478 - effective_valid);
479 if (effective_valid < (ratio * tu_size))
480 nn_err_neg = true;
481 n_err = (average_valid2
482 >= (ratio * tu_size))
483 ? (average_valid2
484 - (ratio * tu_size))
485 : ((ratio * tu_size)
486 - average_valid2);
487 if (average_valid2 < (ratio * tu_size))
488 n_err_neg = true;
489 even_distribution =
490 n_tus % ln_cnt == 0 ? 1 : 0;
491 diff_abs =
492 resulting_valid >= ratio_by_tu
493 ? (resulting_valid
494 - ratio_by_tu)
495 : (ratio_by_tu
496 - resulting_valid);
497
498 resulting_valid_tmp = div64_u64(
499 (i_upper_bdry_cnt
500 * new_valid_boundary_link
501 + i_lower_bdry_cnt
502 * (new_valid_boundary_link
503 - multiplier)),
504 (i_upper_bdry_cnt
505 + i_lower_bdry_cnt));
506 ratio_by_tu_tmp =
507 original_ratio * tu_size;
508 ratio_by_tu_tmp /= multiplier;
509 n_tus_tmp = rounddown_u64(
510 div64_u64(lwidth
511 * multiplier * multiplier
512 * bpp / 8,
513 resulting_valid_tmp),
514 multiplier);
515 n_tus_tmp /= multiplier;
516
517 temp3 = (resulting_valid_tmp
518 >= (original_ratio * tu_size))
519 ? (resulting_valid_tmp
520 - original_ratio * tu_size)
521 : (original_ratio * tu_size)
522 - resulting_valid_tmp;
523 temp3 = (n_tus_tmp + 1) * temp3;
524 temp4 = (new_valid_boundary_link
525 >= (original_ratio * tu_size))
526 ? (new_valid_boundary_link
527 - original_ratio
528 * tu_size)
529 : (original_ratio * tu_size)
530 - new_valid_boundary_link;
531 temp4 = (i_upper_bdry_cnt
532 * ln_cnt * temp4);
533
534 temp3 = roundup_u64(temp3, multiplier);
535 temp4 = roundup_u64(temp4, multiplier);
536 dp_ctrl_get_extra_req_bytes
537 (resulting_valid_tmp,
538 new_valid_boundary_link,
539 temp3, temp4,
540 &extra_req_bytes_is_neg,
541 &result,
542 (original_ratio * tu_size));
543 extra_req_bytes_new_tmp
544 = div64_ul(result, multiplier);
545 if ((extra_req_bytes_is_neg)
546 && (extra_req_bytes_new_tmp
547 > 1))
548 extra_req_bytes_new_tmp
549 = extra_req_bytes_new_tmp - 1;
550 if (extra_req_bytes_new_tmp == 0)
551 extra_req_bytes_new_tmp = 1;
552 extra_pclk_cycles_tmp =
553 (u64)(extra_req_bytes_new_tmp
554 * 8 * multiplier) / bpp;
555 extra_pclk_cycles_tmp /= multiplier;
556
557 if (extra_pclk_cycles_tmp <= 0)
558 extra_pclk_cycles_tmp = 1;
559 extra_pclk_cycles_in_lclk_tmp =
560 roundup_u64(div64_u64(
561 extra_pclk_cycles_tmp
562 * lclk * multiplier,
563 pclk), multiplier);
564 extra_pclk_cycles_in_lclk_tmp
565 /= multiplier;
566 filler_size_tmp = roundup_u64(
567 (tu_size * multiplier *
568 new_valid_boundary_link),
569 multiplier);
570 filler_size_tmp /= multiplier;
571 lower_filler_size_tmp =
572 filler_size_tmp + 1;
573 if (extra_req_bytes_is_neg)
574 temp3 = (extra_req_bytes_new_tmp
575 > extra_pclk_cycles_in_lclk_tmp
576 ? extra_pclk_cycles_in_lclk_tmp
577 : extra_req_bytes_new_tmp);
578 else
579 temp3 = (extra_req_bytes_new_tmp
580 > extra_pclk_cycles_in_lclk_tmp
581 ? extra_req_bytes_new_tmp :
582 extra_pclk_cycles_in_lclk_tmp);
583
584 temp4 = lower_filler_size_tmp
585 + extra_buffer_margin;
586 if (extra_req_bytes_is_neg)
587 delay_start_link_tmp
588 = (temp3 >= temp4)
589 ? (temp3 - temp4)
590 : (temp4 - temp3);
591 else
592 delay_start_link_tmp
593 = temp3 + temp4;
594
595 min_hblank_tmp = (int)div64_u64(
596 roundup_u64(
597 div64_u64(delay_start_link_tmp
598 * pclk * multiplier, lclk),
599 multiplier), multiplier)
600 + hblank_margin;
601
602 if (((even_distribution == 1)
603 || ((even_distribution_bf == 0)
604 && (even_distribution_legacy
605 == 0)))
606 && !n_err_neg && !nn_err_neg
607 && n_n_err < err
608 && (n_n_err < diff_abs
609 || (dp_brute_force == 1))
610 && (new_valid_boundary_link
611 - 1) > 0
612 && (h_blank >=
613 (u32)min_hblank_tmp)) {
614 upper_bdry_cnt =
615 i_upper_bdry_cnt;
616 lower_bdry_cnt =
617 i_lower_bdry_cnt;
618 err = n_n_err;
619 boundary_moderation_en = 1;
620 tu_size_desired = tu_size;
621 valid_boundary_link =
622 new_valid_boundary_link;
623 effective_valid_recorded
624 = effective_valid;
625 delay_start_link
626 = delay_start_link_tmp;
627 filler_size = filler_size_tmp;
628 min_hblank = min_hblank_tmp;
629 n_tus = n_tus_tmp;
630 even_distribution_bf = 1;
631
632 pr_debug("upper_bdry_cnt=%d, lower_boundary_cnt=%d, err=%lld, tu_size_desired=%d, valid_boundary_link=%d, effective_valid=%lld\n",
633 upper_bdry_cnt,
634 lower_bdry_cnt, err,
635 tu_size_desired,
636 valid_boundary_link,
637 effective_valid);
638 }
639 }
640 }
641 }
642
643 if (boundary_moderation_en == 1) {
644 resulting_valid = (u64)(upper_bdry_cnt
645 *valid_boundary_link + lower_bdry_cnt
646 * (valid_boundary_link - 1))
647 / (upper_bdry_cnt + lower_bdry_cnt);
648 ratio_by_tu = original_ratio * tu_size_desired;
649 valid_lower_boundary_link =
650 (valid_boundary_link / multiplier) - 1;
651
652 tu_size_minus1 = tu_size_desired - 1;
653 even_distribution_bf = 1;
654 valid_boundary_link /= multiplier;
655 pr_debug("Info: Boundary_moderation enabled\n");
656 }
657 }
658
659 min_hblank = ((int) roundup_u64(div64_u64(delay_start_link * pclk
660 * multiplier, lclk), multiplier))
661 / multiplier + hblank_margin;
662 if (h_blank < (u32)min_hblank) {
663 pr_debug(" WARNING: run_idx=%d Programmed h_blank %d is smaller than the min_hblank %d supported.\n",
664 run_idx, h_blank, min_hblank);
665 }
666
667 if (fifo_empty) {
668 tu_size_minus1 = 31;
669 valid_boundary_link = 32;
670 delay_start_link = 0;
671 boundary_moderation_en = 0;
672 }
673
674 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",
675 tu_size_minus1, valid_boundary_link, delay_start_link,
676 boundary_moderation_en, upper_bdry_cnt, lower_bdry_cnt,
677 valid_lower_boundary_link, min_hblank);
678
679 tu_table->valid_boundary_link = valid_boundary_link;
680 tu_table->delay_start_link = delay_start_link;
681 tu_table->boundary_moderation_en = boundary_moderation_en;
682 tu_table->valid_lower_boundary_link = valid_lower_boundary_link;
683 tu_table->upper_boundary_count = upper_bdry_cnt;
684 tu_table->lower_boundary_count = lower_bdry_cnt;
685 tu_table->tu_size_minus1 = tu_size_minus1;
686}
687
688static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl)
689{
690 u32 dp_tu = 0x0;
691 u32 valid_boundary = 0x0;
692 u32 valid_boundary2 = 0x0;
693 struct dp_vc_tu_mapping_table tu_calc_table;
694
695 dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
696
697 dp_tu |= tu_calc_table.tu_size_minus1;
698 valid_boundary |= tu_calc_table.valid_boundary_link;
699 valid_boundary |= (tu_calc_table.delay_start_link << 16);
700
701 valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1);
702 valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16);
703 valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20);
704
705 if (tu_calc_table.boundary_moderation_en)
706 valid_boundary2 |= BIT(0);
707
708 pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n",
709 dp_tu, valid_boundary, valid_boundary2);
710
711 ctrl->catalog->dp_tu = dp_tu;
712 ctrl->catalog->valid_boundary = valid_boundary;
713 ctrl->catalog->valid_boundary2 = valid_boundary2;
714
715 ctrl->catalog->update_transfer_unit(ctrl->catalog);
716}
717
718static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
719{
720 int ret = 0;
721
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700722 ret = wait_for_completion_timeout(&ctrl->video_comp, HZ / 2);
723 if (ret <= 0) {
724 pr_err("Link Train timedout\n");
725 ret = -EINVAL;
726 }
727
728 return ret;
729}
730
731static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl,
732 u32 voltage_level, u32 pre_emphasis_level)
733{
734 int i;
735 u8 buf[4];
736 u32 max_level_reached = 0;
737
738 if (voltage_level == DP_LINK_VOLTAGE_MAX) {
739 pr_debug("max. voltage swing level reached %d\n",
740 voltage_level);
741 max_level_reached |= BIT(2);
742 }
743
744 if (pre_emphasis_level == DP_LINK_PRE_EMPHASIS_MAX) {
745 pr_debug("max. pre-emphasis level reached %d\n",
746 pre_emphasis_level);
747 max_level_reached |= BIT(5);
748 }
749
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700750 pre_emphasis_level <<= 3;
751
752 for (i = 0; i < 4; i++)
753 buf[i] = voltage_level | pre_emphasis_level | max_level_reached;
754
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700755 pr_debug("sink: p|v=0x%x\n", voltage_level | pre_emphasis_level);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700756 return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700757}
758
759static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
760{
761 struct dp_link *link = ctrl->link;
762
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700763 ctrl->catalog->update_vx_px(ctrl->catalog,
764 link->v_level, link->p_level);
765
766 dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level);
767}
768
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700769static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
770 u8 pattern)
771{
772 u8 buf[4];
773
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700774 pr_debug("sink: pattern=%x\n", pattern);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700775
776 buf[0] = pattern;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700777 drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700778}
779
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700780static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
781 u8 *link_status)
782{
783 int ret = 0, len;
784 u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS;
785 u32 link_status_read_max_retries = 100;
786
787 while (--link_status_read_max_retries) {
788 len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
789 link_status);
790 if (len != DP_LINK_STATUS_SIZE) {
791 pr_err("DP link status read failed, err: %d\n", len);
792 ret = len;
793 break;
794 }
795
796 if (!(link_status[offset] & DP_LINK_STATUS_UPDATED))
797 break;
798 }
799
800 return ret;
801}
802
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700803static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
804{
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700805 int tries, old_v_level, ret = 0;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700806 u8 link_status[DP_LINK_STATUS_SIZE];
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700807 int const maximum_retries = 5;
808
809 dp_ctrl_state_ctrl(ctrl, 0);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700810 /* Make sure to clear the current pattern before starting a new one */
811 wmb();
812
813 ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700814 dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700815 DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700816 dp_ctrl_update_vx_px(ctrl);
817
818 tries = 0;
819 old_v_level = ctrl->link->v_level;
820 while (1) {
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700821 drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700822
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700823 ret = dp_ctrl_read_link_status(ctrl, link_status);
824 if (ret)
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700825 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700826
827 if (drm_dp_clock_recovery_ok(link_status,
828 ctrl->link->lane_count)) {
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700829 break;
830 }
831
832 if (ctrl->link->v_level == DP_LINK_VOLTAGE_MAX) {
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700833 pr_err_ratelimited("max v_level reached\n");
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700834 ret = -EAGAIN;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700835 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700836 }
837
838 if (old_v_level == ctrl->link->v_level) {
839 tries++;
840 if (tries >= maximum_retries) {
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700841 pr_err("max tries reached\n");
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700842 ret = -EAGAIN;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700843 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700844 }
845 } else {
846 tries = 0;
847 old_v_level = ctrl->link->v_level;
848 }
849
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700850 pr_debug("clock recovery not done, adjusting vx px\n");
851
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700852 ctrl->link->adjust_levels(ctrl->link, link_status);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700853 dp_ctrl_update_vx_px(ctrl);
854 }
855
856 return ret;
857}
858
859static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
860{
861 int ret = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700862 u32 min_req_link_rate_khz;
863 u32 new_proposed_link_bw_code;
864 u32 new_proposed_link_rate_khz;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700865
866 if (!ctrl)
867 return -EINVAL;
868
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700869 min_req_link_rate_khz = ctrl->panel->get_min_req_link_rate(ctrl->panel);
870
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700871 switch (ctrl->link->bw_code) {
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700872 case DP_LINK_RATE_810:
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700873 new_proposed_link_bw_code = DP_LINK_BW_5_4;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700874 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700875 case DP_LINK_BW_5_4:
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700876 new_proposed_link_bw_code = DP_LINK_BW_2_7;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700877 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700878 case DP_LINK_BW_2_7:
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700879 case DP_LINK_BW_1_62:
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700880 default:
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700881 new_proposed_link_bw_code = DP_LINK_BW_1_62;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700882 break;
883 };
884
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700885 new_proposed_link_rate_khz = drm_dp_bw_code_to_link_rate(
886 new_proposed_link_bw_code);
887
888 pr_debug("new proposed link rate=%d khz\n", new_proposed_link_rate_khz);
889 pr_debug("min required link rate=%d khz\n", min_req_link_rate_khz);
890
891 if (new_proposed_link_rate_khz >= min_req_link_rate_khz)
892 ctrl->link->bw_code = new_proposed_link_bw_code;
893 else
894 pr_debug("can't go below min required link rate\n");
895
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700896 pr_debug("new bw code=0x%x\n", ctrl->link->bw_code);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700897
898 return ret;
899}
900
901static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
902{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700903 dp_ctrl_train_pattern_set(ctrl, 0);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700904 drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700905}
906
907static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
908{
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700909 int tries = 0, ret = 0;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700910 char pattern;
911 int const maximum_retries = 5;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700912 u8 link_status[DP_LINK_STATUS_SIZE];
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700913
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700914 dp_ctrl_state_ctrl(ctrl, 0);
915 /* Make sure to clear the current pattern before starting a new one */
916 wmb();
917
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700918 if (drm_dp_tps3_supported(ctrl->panel->dpcd))
919 pattern = DP_TRAINING_PATTERN_3;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700920 else
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700921 pattern = DP_TRAINING_PATTERN_2;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700922
923 dp_ctrl_update_vx_px(ctrl);
924 ctrl->catalog->set_pattern(ctrl->catalog, pattern);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700925 dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700926
927 do {
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700928 drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700929
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700930 ret = dp_ctrl_read_link_status(ctrl, link_status);
931 if (ret)
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700932 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700933
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700934 if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count))
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700935 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700936
937 if (tries > maximum_retries) {
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700938 ret = -EAGAIN;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700939 break;
940 }
941 tries++;
942
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700943 ctrl->link->adjust_levels(ctrl->link, link_status);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700944 dp_ctrl_update_vx_px(ctrl);
945 } while (1);
946
947 return ret;
948}
949
950static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
951{
952 int ret = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700953 u8 encoding = 0x1;
954 struct drm_dp_link link_info = {0};
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700955
956 ctrl->link->p_level = 0;
957 ctrl->link->v_level = 0;
958
959 dp_ctrl_config_ctrl(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700960
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700961 link_info.num_lanes = ctrl->link->lane_count;
962 link_info.rate = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code);
963 link_info.capabilities = ctrl->panel->link_info.capabilities;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700964
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700965 drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700966 drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
967 &encoding, 1);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700968
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700969 ret = dp_ctrl_link_train_1(ctrl);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700970 if (ret) {
971 pr_err("link training #1 failed\n");
972 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700973 }
974
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700975 /* print success info as this is a result of user initiated action */
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700976 pr_info("link training #1 successful\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700977
978 ret = dp_ctrl_link_training_2(ctrl);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700979 if (ret) {
980 pr_err("link training #2 failed\n");
981 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700982 }
983
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700984 /* print success info as this is a result of user initiated action */
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700985 pr_debug("link training #2 successful\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700986
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700987end:
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700988 dp_ctrl_state_ctrl(ctrl, 0);
989 /* Make sure to clear the current pattern before starting a new one */
990 wmb();
991
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700992 dp_ctrl_clear_training_pattern(ctrl);
993 return ret;
994}
995
996static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)
997{
998 bool mainlink_ready = false;
999 int ret = 0;
1000
1001 ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
1002
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001003 drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001004
1005 if (ctrl->link->phy_pattern_requested(ctrl->link))
1006 goto end;
1007
1008 if (!train)
1009 goto send_video;
1010
1011 /*
1012 * As part of previous calls, DP controller state might have
1013 * transitioned to PUSH_IDLE. In order to start transmitting a link
1014 * training pattern, we have to first to a DP software reset.
1015 */
1016 ctrl->catalog->reset(ctrl->catalog);
1017
1018 ret = dp_ctrl_link_train(ctrl);
1019 if (ret)
1020 goto end;
1021
1022send_video:
1023 /*
1024 * Set up transfer unit values and set controller state to send
1025 * video.
1026 */
1027 dp_ctrl_setup_tr_unit(ctrl);
1028 ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO);
1029
1030 dp_ctrl_wait4video_ready(ctrl);
1031 mainlink_ready = ctrl->catalog->mainlink_ready(ctrl->catalog);
1032 pr_debug("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
1033end:
1034 return ret;
1035}
1036
1037static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
1038 char *name, u32 rate)
1039{
1040 u32 num = ctrl->parser->mp[DP_CTRL_PM].num_clk;
1041 struct dss_clk *cfg = ctrl->parser->mp[DP_CTRL_PM].clk_config;
1042
1043 while (num && strcmp(cfg->clk_name, name)) {
1044 num--;
1045 cfg++;
1046 }
1047
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001048 pr_debug("setting rate=%d on clk=%s\n", rate, name);
1049
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001050 if (num)
1051 cfg->rate = rate;
1052 else
1053 pr_err("%s clock could not be set with rate %d\n", name, rate);
1054}
1055
1056static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
1057{
1058 int ret = 0;
1059
1060 ctrl->power->set_pixel_clk_parent(ctrl->power);
1061
1062 dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001063 drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001064
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001065 dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate);
1066
1067 ret = ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, true);
1068 if (ret) {
1069 pr_err("Unabled to start link clocks\n");
1070 ret = -EINVAL;
1071 }
1072
1073 return ret;
1074}
1075
1076static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl)
1077{
1078 return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false);
1079}
1080
1081static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip)
1082{
1083 struct dp_ctrl_private *ctrl;
1084 struct dp_catalog_ctrl *catalog;
1085
1086 if (!dp_ctrl) {
1087 pr_err("Invalid input data\n");
1088 return -EINVAL;
1089 }
1090
1091 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1092
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001093 ctrl->orientation = flip;
1094 catalog = ctrl->catalog;
1095
1096 catalog->reset(ctrl->catalog);
1097 catalog->phy_reset(ctrl->catalog);
1098 catalog->enable_irq(ctrl->catalog, true);
1099
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001100 return 0;
1101}
1102
1103/**
1104 * dp_ctrl_host_deinit() - Uninitialize DP controller
1105 * @ctrl: Display Port Driver data
1106 *
1107 * Perform required steps to uninitialize DP controller
1108 * and its resources.
1109 */
1110static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
1111{
1112 struct dp_ctrl_private *ctrl;
1113
1114 if (!dp_ctrl) {
1115 pr_err("Invalid input data\n");
1116 return;
1117 }
1118
1119 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1120
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001121 ctrl->catalog->enable_irq(ctrl->catalog, false);
1122 ctrl->catalog->reset(ctrl->catalog);
1123
1124 /* Make sure DP is disabled before clk disable */
1125 wmb();
1126
1127 dp_ctrl_disable_mainlink_clocks(ctrl);
1128
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001129 pr_debug("Host deinitialized successfully\n");
1130}
1131
Aravind Venkateswaran7599a992017-08-10 14:17:57 -07001132static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
1133{
1134 u8 *dpcd = ctrl->panel->dpcd;
1135
1136 /*
1137 * For better interop experience, used a fixed NVID=0x8000
1138 * whenever connected to a VGA dongle downstream.
1139 */
1140 if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) {
1141 u8 type = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
1142 DP_DWN_STRM_PORT_TYPE_MASK;
1143 if (type == DP_DWN_STRM_PORT_TYPE_ANALOG)
1144 return true;
1145 }
1146
1147 return false;
1148}
1149
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001150static int dp_ctrl_on_irq(struct dp_ctrl_private *ctrl, bool lt_needed)
1151{
1152 int ret = 0;
1153
1154 do {
1155 if (ret == -EAGAIN)
1156 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
1157
1158 ctrl->catalog->phy_lane_cfg(ctrl->catalog,
1159 ctrl->orientation, ctrl->link->lane_count);
1160
1161 if (lt_needed) {
1162 /*
1163 * Diasable and re-enable the mainlink clock since the
1164 * link clock might have been adjusted as part of the
1165 * link maintenance.
1166 */
1167 if (!ctrl->link->phy_pattern_requested(
1168 ctrl->link))
1169 dp_ctrl_disable_mainlink_clocks(ctrl);
1170
1171 ret = dp_ctrl_enable_mainlink_clocks(ctrl);
1172 if (ret)
1173 continue;
1174 }
1175
1176 dp_ctrl_configure_source_params(ctrl);
1177
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001178 ctrl->catalog->config_msa(ctrl->catalog,
Aravind Venkateswaran7599a992017-08-10 14:17:57 -07001179 drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
1180 ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001181
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001182 reinit_completion(&ctrl->idle_comp);
1183
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001184 if (ctrl->psm_enabled) {
1185 ret = ctrl->link->send_psm_request(ctrl->link, false);
1186 if (ret) {
1187 pr_err("failed to exit low power mode, rc=%d\n",
1188 ret);
1189 continue;
1190 }
1191 }
1192
1193 ret = dp_ctrl_setup_main_link(ctrl, lt_needed);
1194 } while (ret == -EAGAIN);
1195
1196 return ret;
1197}
1198
1199static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)
1200{
1201 int ret = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001202 u32 rate = ctrl->panel->link_info.rate;
1203 u32 link_train_max_retries = 100;
1204
1205 atomic_set(&ctrl->aborted, 0);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001206
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001207 ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
1208 ctrl->catalog->hpd_config(ctrl->catalog, true);
1209
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001210 ctrl->link->bw_code = drm_dp_link_rate_to_bw_code(rate);
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001211 ctrl->link->lane_count = ctrl->panel->link_info.num_lanes;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001212 ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
1213
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001214 pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n",
1215 ctrl->link->bw_code, ctrl->link->lane_count,
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001216 ctrl->pixel_rate);
1217
1218 ctrl->catalog->phy_lane_cfg(ctrl->catalog,
1219 ctrl->orientation, ctrl->link->lane_count);
1220
1221 ret = dp_ctrl_enable_mainlink_clocks(ctrl);
1222 if (ret)
1223 goto exit;
1224
1225 reinit_completion(&ctrl->idle_comp);
1226
1227 dp_ctrl_configure_source_params(ctrl);
1228
1229 if (ctrl->psm_enabled)
1230 ret = ctrl->link->send_psm_request(ctrl->link, false);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001231
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001232 while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
1233 ctrl->catalog->config_msa(ctrl->catalog,
Aravind Venkateswaran7599a992017-08-10 14:17:57 -07001234 drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
1235 ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001236
1237 ret = dp_ctrl_setup_main_link(ctrl, true);
1238 if (!ret)
1239 break;
1240
1241 /* try with lower link rate */
1242 dp_ctrl_link_rate_down_shift(ctrl);
1243
1244 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
1245
1246 dp_ctrl_disable_mainlink_clocks(ctrl);
1247 /* hw recommended delay before re-enabling clocks */
1248 msleep(20);
1249
1250 dp_ctrl_enable_mainlink_clocks(ctrl);
1251 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001252
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001253 pr_debug("End-\n");
1254
1255exit:
1256 return ret;
1257}
1258
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001259static void dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001260{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001261 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
1262
1263 /* Make sure DP mainlink and audio engines are disabled */
1264 wmb();
1265
1266 complete_all(&ctrl->irq_comp);
1267 pr_debug("end\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001268}
1269
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001270static void dp_ctrl_off_hpd(struct dp_ctrl_private *ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001271{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001272 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001273 pr_debug("DP off done\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001274}
1275
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001276static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool hpd_irq)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001277{
1278 int rc = 0;
1279 struct dp_ctrl_private *ctrl;
1280
1281 if (!dp_ctrl) {
1282 rc = -EINVAL;
1283 goto end;
1284 }
1285
1286 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1287
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001288 if (hpd_irq)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001289 rc = dp_ctrl_on_irq(ctrl, false);
1290 else
1291 rc = dp_ctrl_on_hpd(ctrl);
1292end:
1293 return rc;
1294}
1295
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001296static void dp_ctrl_off(struct dp_ctrl *dp_ctrl, bool hpd_irq)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001297{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001298 struct dp_ctrl_private *ctrl;
1299
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001300 if (!dp_ctrl)
1301 return;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001302
1303 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1304
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001305 if (hpd_irq)
1306 dp_ctrl_off_irq(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001307 else
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001308 dp_ctrl_off_hpd(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001309}
1310
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001311static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001312{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001313 struct dp_ctrl_private *ctrl;
1314
1315 if (!dp_ctrl)
1316 return;
1317
1318 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1319
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001320 ctrl->catalog->get_interrupt(ctrl->catalog);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001321
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001322 if (ctrl->catalog->isr & DP_CTRL_INTR_READY_FOR_VIDEO)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001323 dp_ctrl_video_ready(ctrl);
1324
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001325 if (ctrl->catalog->isr & DP_CTRL_INTR_IDLE_PATTERN_SENT)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001326 dp_ctrl_idle_patterns_sent(ctrl);
1327}
1328
1329struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
1330{
1331 int rc = 0;
1332 struct dp_ctrl_private *ctrl;
1333 struct dp_ctrl *dp_ctrl;
1334
1335 if (!in->dev || !in->panel || !in->aux ||
1336 !in->link || !in->catalog) {
1337 pr_err("invalid input\n");
1338 rc = -EINVAL;
1339 goto error;
1340 }
1341
1342 ctrl = devm_kzalloc(in->dev, sizeof(*ctrl), GFP_KERNEL);
1343 if (!ctrl) {
1344 rc = -ENOMEM;
1345 goto error;
1346 }
1347
1348 init_completion(&ctrl->idle_comp);
1349 init_completion(&ctrl->video_comp);
1350 init_completion(&ctrl->irq_comp);
1351
1352 /* in parameters */
1353 ctrl->parser = in->parser;
1354 ctrl->panel = in->panel;
1355 ctrl->power = in->power;
1356 ctrl->aux = in->aux;
1357 ctrl->link = in->link;
1358 ctrl->catalog = in->catalog;
1359
1360 dp_ctrl = &ctrl->dp_ctrl;
1361
1362 /* out parameters */
1363 dp_ctrl->init = dp_ctrl_host_init;
1364 dp_ctrl->deinit = dp_ctrl_host_deinit;
1365 dp_ctrl->on = dp_ctrl_on;
1366 dp_ctrl->off = dp_ctrl_off;
1367 dp_ctrl->push_idle = dp_ctrl_push_idle;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001368 dp_ctrl->abort = dp_ctrl_abort;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001369 dp_ctrl->isr = dp_ctrl_isr;
1370
1371 return dp_ctrl;
1372error:
1373 return ERR_PTR(rc);
1374}
1375
1376void dp_ctrl_put(struct dp_ctrl *dp_ctrl)
1377{
1378 struct dp_ctrl_private *ctrl;
1379
1380 if (!dp_ctrl)
1381 return;
1382
1383 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1384
1385 devm_kfree(ctrl->dev, ctrl);
1386}