blob: befbc5c7f9f9dae7f7b3032ed576dcb4be43b144 [file] [log] [blame]
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001/*
Sankeerth Billakanti4223e132019-03-08 12:09:59 +05302 * Copyright (c) 2012-2019, 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
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
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -070039#define MR_LINK_TRAINING1 0x8
40#define MR_LINK_SYMBOL_ERM 0x80
41#define MR_LINK_PRBS7 0x100
42#define MR_LINK_CUSTOM80 0x200
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -070043#define MR_LINK_TRAINING4 0x40
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -070044
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070045struct dp_vc_tu_mapping_table {
46 u32 vic;
47 u8 lanes;
48 u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */
49 u8 bpp;
50 u8 valid_boundary_link;
51 u16 delay_start_link;
52 bool boundary_moderation_en;
53 u8 valid_lower_boundary_link;
54 u8 upper_boundary_count;
55 u8 lower_boundary_count;
56 u8 tu_size_minus1;
57};
58
59struct dp_ctrl_private {
60 struct dp_ctrl dp_ctrl;
61
62 struct device *dev;
63 struct dp_aux *aux;
64 struct dp_panel *panel;
65 struct dp_link *link;
66 struct dp_power *power;
67 struct dp_parser *parser;
68 struct dp_catalog_ctrl *catalog;
69
70 struct completion idle_comp;
71 struct completion video_comp;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070072
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070073 bool orientation;
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -080074 bool power_on;
75
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -070076 atomic_t aborted;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -070077
78 u32 pixel_rate;
79 u32 vic;
80};
81
82enum notification_status {
83 NOTIFY_UNKNOWN,
84 NOTIFY_CONNECT,
85 NOTIFY_DISCONNECT,
86 NOTIFY_CONNECT_IRQ_HPD,
87 NOTIFY_DISCONNECT_IRQ_HPD,
88};
89
90static void dp_ctrl_idle_patterns_sent(struct dp_ctrl_private *ctrl)
91{
92 pr_debug("idle_patterns_sent\n");
93 complete(&ctrl->idle_comp);
94}
95
96static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl)
97{
98 pr_debug("dp_video_ready\n");
99 complete(&ctrl->video_comp);
100}
101
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700102static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl)
103{
104 struct dp_ctrl_private *ctrl;
105
106 if (!dp_ctrl) {
107 pr_err("Invalid input data\n");
108 return;
109 }
110
111 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
112
113 atomic_set(&ctrl->aborted, 1);
114}
115
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700116static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
117{
118 ctrl->catalog->state_ctrl(ctrl->catalog, state);
119}
120
121static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
122{
123 int const idle_pattern_completion_timeout_ms = 3 * HZ / 100;
124 struct dp_ctrl_private *ctrl;
125
126 if (!dp_ctrl) {
127 pr_err("Invalid input data\n");
128 return;
129 }
130
131 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
132
Tatenda Chipeperekwa449be112018-04-03 16:15:31 -0700133 if (!ctrl->power_on) {
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800134 pr_err("CTRL off, return\n");
135 return;
136 }
137
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700138 reinit_completion(&ctrl->idle_comp);
139 dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
140
141 if (!wait_for_completion_timeout(&ctrl->idle_comp,
142 idle_pattern_completion_timeout_ms))
143 pr_warn("PUSH_IDLE pattern timedout\n");
144
145 pr_debug("mainlink off done\n");
146}
147
148static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
149{
150 u32 config = 0, tbd;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700151 u8 *dpcd = ctrl->panel->dpcd;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700152
153 config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */
154 config |= (0 << 11); /* RGB */
155
156 /* Scrambler reset enable */
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700157 if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700158 config |= (1 << 10);
159
160 tbd = ctrl->link->get_test_bits_depth(ctrl->link,
161 ctrl->panel->pinfo.bpp);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700162
163 if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN)
164 tbd = DP_TEST_BIT_DEPTH_8;
165
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700166 config |= tbd << 8;
167
168 /* Num of Lanes */
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530169 config |= ((ctrl->link->link_params.lane_count - 1) << 4);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700170
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700171 if (drm_dp_enhanced_frame_cap(dpcd))
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700172 config |= 0x40;
173
174 config |= 0x04; /* progressive video */
175
176 config |= 0x03; /* sycn clock & static Mvid */
177
178 ctrl->catalog->config_ctrl(ctrl->catalog, config);
179}
180
181/**
182 * dp_ctrl_configure_source_params() - configures DP transmitter source params
183 * @ctrl: Display Port Driver data
184 *
185 * Configures the DP transmitter source params including details such as lane
186 * configuration, output format and sink/panel timing information.
187 */
188static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
189{
190 u32 cc, tb;
191
192 ctrl->catalog->lane_mapping(ctrl->catalog);
193 ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
194
195 dp_ctrl_config_ctrl(ctrl);
196
197 tb = ctrl->link->get_test_bits_depth(ctrl->link,
198 ctrl->panel->pinfo.bpp);
199 cc = ctrl->link->get_colorimetry_config(ctrl->link);
200 ctrl->catalog->config_misc(ctrl->catalog, cc, tb);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700201 ctrl->panel->timing_cfg(ctrl->panel);
202}
203
204static void dp_ctrl_get_extra_req_bytes(u64 result_valid,
205 int valid_bdary_link,
206 u64 value1, u64 value2,
207 bool *negative, u64 *result,
208 u64 compare)
209{
210 *negative = false;
211 if (result_valid >= compare) {
212 if (valid_bdary_link
213 >= compare)
214 *result = value1 + value2;
215 else {
216 if (value1 < value2)
217 *negative = true;
218 *result = (value1 >= value2) ?
219 (value1 - value2) : (value2 - value1);
220 }
221 } else {
222 if (valid_bdary_link
223 >= compare) {
224 if (value1 >= value2)
225 *negative = true;
226 *result = (value1 >= value2) ?
227 (value1 - value2) : (value2 - value1);
228 } else {
229 *result = value1 + value2;
230 *negative = true;
231 }
232 }
233}
234
235static u64 roundup_u64(u64 x, u64 y)
236{
237 x += (y - 1);
238 return (div64_ul(x, y) * y);
239}
240
241static u64 rounddown_u64(u64 x, u64 y)
242{
243 u64 rem;
244
245 div64_u64_rem(x, y, &rem);
246 return (x - rem);
247}
248
249static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
250 struct dp_vc_tu_mapping_table *tu_table)
251{
252 u32 const multiplier = 1000000;
253 u64 pclk, lclk;
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700254 u8 bpp, ln_cnt;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700255 int run_idx = 0;
256 u32 lwidth, h_blank;
257 u32 fifo_empty = 0;
258 u32 ratio_scale = 1001;
259 u64 temp, ratio, original_ratio;
260 u64 temp2, reminder;
261 u64 temp3, temp4, result = 0;
262
263 u64 err = multiplier;
264 u64 n_err = 0, n_n_err = 0;
265 bool n_err_neg, nn_err_neg;
266 u8 hblank_margin = 16;
267
268 u8 tu_size, tu_size_desired = 0, tu_size_minus1;
269 int valid_boundary_link;
270 u64 resulting_valid;
271 u64 total_valid;
272 u64 effective_valid;
273 u64 effective_valid_recorded;
274 int n_tus;
275 int n_tus_per_lane;
276 int paired_tus;
277 int remainder_tus;
278 int remainder_tus_upper, remainder_tus_lower;
279 int extra_bytes;
280 int filler_size;
281 int delay_start_link;
282 int boundary_moderation_en = 0;
283 int upper_bdry_cnt = 0;
284 int lower_bdry_cnt = 0;
285 int i_upper_bdry_cnt = 0;
286 int i_lower_bdry_cnt = 0;
287 int valid_lower_boundary_link = 0;
288 int even_distribution_bf = 0;
289 int even_distribution_legacy = 0;
290 int even_distribution = 0;
291 int min_hblank = 0;
292 int extra_pclk_cycles;
293 u8 extra_pclk_cycle_delay = 4;
294 int extra_pclk_cycles_in_link_clk;
295 u64 ratio_by_tu;
296 u64 average_valid2;
297 u64 extra_buffer_margin;
298 int new_valid_boundary_link;
299
300 u64 resulting_valid_tmp;
301 u64 ratio_by_tu_tmp;
302 int n_tus_tmp;
303 int extra_pclk_cycles_tmp;
304 int extra_pclk_cycles_in_lclk_tmp;
305 int extra_req_bytes_new_tmp;
306 int filler_size_tmp;
307 int lower_filler_size_tmp;
308 int delay_start_link_tmp;
309 int min_hblank_tmp = 0;
310 bool extra_req_bytes_is_neg = false;
311 struct dp_panel_info *pinfo = &ctrl->panel->pinfo;
312
313 u8 dp_brute_force = 1;
314 u64 brute_force_threshold = 10;
315 u64 diff_abs;
316
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530317 ln_cnt = ctrl->link->link_params.lane_count;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700318
319 bpp = pinfo->bpp;
320 lwidth = pinfo->h_active;
321 h_blank = pinfo->h_back_porch + pinfo->h_front_porch +
322 pinfo->h_sync_width;
323 pclk = pinfo->pixel_clk_khz * 1000;
324
325 boundary_moderation_en = 0;
326 upper_bdry_cnt = 0;
327 lower_bdry_cnt = 0;
328 i_upper_bdry_cnt = 0;
329 i_lower_bdry_cnt = 0;
330 valid_lower_boundary_link = 0;
331 even_distribution_bf = 0;
332 even_distribution_legacy = 0;
333 even_distribution = 0;
334 min_hblank = 0;
335
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530336 lclk = drm_dp_bw_code_to_link_rate(
337 ctrl->link->link_params.bw_code) * DP_KHZ_TO_HZ;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700338
339 pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
340 pclk, lwidth, h_blank);
341 pr_debug("lclk = %lld, ln_cnt = %d\n", lclk, ln_cnt);
342 ratio = div64_u64_rem(pclk * bpp * multiplier,
343 8 * ln_cnt * lclk, &reminder);
344 ratio = div64_u64((pclk * bpp * multiplier), (8 * ln_cnt * lclk));
345 original_ratio = ratio;
346
347 extra_buffer_margin = roundup_u64(div64_u64(extra_pclk_cycle_delay
348 * lclk * multiplier, pclk), multiplier);
349 extra_buffer_margin = div64_u64(extra_buffer_margin, multiplier);
350
351 /* To deal with cases where lines are not distributable */
352 if (((lwidth % ln_cnt) != 0) && ratio < multiplier) {
353 ratio = ratio * ratio_scale;
354 ratio = ratio < (1000 * multiplier)
355 ? ratio : (1000 * multiplier);
356 }
357 pr_debug("ratio = %lld\n", ratio);
358
359 for (tu_size = 32; tu_size <= 64; tu_size++) {
360 temp = ratio * tu_size;
361 temp2 = ((temp / multiplier) + 1) * multiplier;
362 n_err = roundup_u64(temp, multiplier) - temp;
363
364 if (n_err < err) {
365 err = n_err;
366 tu_size_desired = tu_size;
367 }
368 }
369 pr_debug("Info: tu_size_desired = %d\n", tu_size_desired);
370
371 tu_size_minus1 = tu_size_desired - 1;
372
373 valid_boundary_link = roundup_u64(ratio * tu_size_desired, multiplier);
374 valid_boundary_link /= multiplier;
375 n_tus = rounddown((lwidth * bpp * multiplier)
376 / (8 * valid_boundary_link), multiplier) / multiplier;
377 even_distribution_legacy = n_tus % ln_cnt == 0 ? 1 : 0;
378 pr_debug("Info: n_symbol_per_tu=%d, number_of_tus=%d\n",
379 valid_boundary_link, n_tus);
380
381 extra_bytes = roundup_u64((n_tus + 1)
382 * ((valid_boundary_link * multiplier)
383 - (original_ratio * tu_size_desired)), multiplier);
384 extra_bytes /= multiplier;
385 extra_pclk_cycles = roundup(extra_bytes * 8 * multiplier / bpp,
386 multiplier);
387 extra_pclk_cycles /= multiplier;
388 extra_pclk_cycles_in_link_clk = roundup_u64(div64_u64(extra_pclk_cycles
389 * lclk * multiplier, pclk), multiplier);
390 extra_pclk_cycles_in_link_clk /= multiplier;
391 filler_size = roundup_u64((tu_size_desired - valid_boundary_link)
392 * multiplier, multiplier);
393 filler_size /= multiplier;
394 ratio_by_tu = div64_u64(ratio * tu_size_desired, multiplier);
395
396 pr_debug("extra_pclk_cycles_in_link_clk=%d, extra_bytes=%d\n",
397 extra_pclk_cycles_in_link_clk, extra_bytes);
398 pr_debug("extra_pclk_cycles_in_link_clk=%d\n",
399 extra_pclk_cycles_in_link_clk);
400 pr_debug("filler_size=%d, extra_buffer_margin=%lld\n",
401 filler_size, extra_buffer_margin);
402
403 delay_start_link = ((extra_bytes > extra_pclk_cycles_in_link_clk)
404 ? extra_bytes
405 : extra_pclk_cycles_in_link_clk)
406 + filler_size + extra_buffer_margin;
407 resulting_valid = valid_boundary_link;
408 pr_debug("Info: delay_start_link=%d, filler_size=%d\n",
409 delay_start_link, filler_size);
410 pr_debug("valid_boundary_link=%d ratio_by_tu=%lld\n",
411 valid_boundary_link, ratio_by_tu);
412
413 diff_abs = (resulting_valid >= ratio_by_tu)
414 ? (resulting_valid - ratio_by_tu)
415 : (ratio_by_tu - resulting_valid);
416
417 if (err != 0 && ((diff_abs > brute_force_threshold)
418 || (even_distribution_legacy == 0)
419 || (dp_brute_force == 1))) {
420 err = multiplier;
421 for (tu_size = 32; tu_size <= 64; tu_size++) {
422 for (i_upper_bdry_cnt = 1; i_upper_bdry_cnt <= 15;
423 i_upper_bdry_cnt++) {
424 for (i_lower_bdry_cnt = 1;
425 i_lower_bdry_cnt <= 15;
426 i_lower_bdry_cnt++) {
427 new_valid_boundary_link =
428 roundup_u64(ratio
429 * tu_size, multiplier);
430 average_valid2 = (i_upper_bdry_cnt
431 * new_valid_boundary_link
432 + i_lower_bdry_cnt
433 * (new_valid_boundary_link
434 - multiplier))
435 / (i_upper_bdry_cnt
436 + i_lower_bdry_cnt);
437 n_tus = rounddown_u64(div64_u64(lwidth
438 * multiplier * multiplier
439 * (bpp / 8), average_valid2),
440 multiplier);
441 n_tus /= multiplier;
442 n_tus_per_lane
443 = rounddown(n_tus
444 * multiplier
445 / ln_cnt, multiplier);
446 n_tus_per_lane /= multiplier;
447 paired_tus =
448 rounddown((n_tus_per_lane)
449 * multiplier
450 / (i_upper_bdry_cnt
451 + i_lower_bdry_cnt),
452 multiplier);
453 paired_tus /= multiplier;
454 remainder_tus = n_tus_per_lane
455 - paired_tus
456 * (i_upper_bdry_cnt
457 + i_lower_bdry_cnt);
458 if ((remainder_tus
459 - i_upper_bdry_cnt) > 0) {
460 remainder_tus_upper
461 = i_upper_bdry_cnt;
462 remainder_tus_lower =
463 remainder_tus
464 - i_upper_bdry_cnt;
465 } else {
466 remainder_tus_upper
467 = remainder_tus;
468 remainder_tus_lower = 0;
469 }
470 total_valid = paired_tus
471 * (i_upper_bdry_cnt
472 * new_valid_boundary_link
473 + i_lower_bdry_cnt
474 * (new_valid_boundary_link
475 - multiplier))
476 + (remainder_tus_upper
477 * new_valid_boundary_link)
478 + (remainder_tus_lower
479 * (new_valid_boundary_link
480 - multiplier));
481 n_err_neg = nn_err_neg = false;
482 effective_valid
483 = div_u64(total_valid,
484 n_tus_per_lane);
485 n_n_err = (effective_valid
486 >= (ratio * tu_size))
487 ? (effective_valid
488 - (ratio * tu_size))
489 : ((ratio * tu_size)
490 - effective_valid);
491 if (effective_valid < (ratio * tu_size))
492 nn_err_neg = true;
493 n_err = (average_valid2
494 >= (ratio * tu_size))
495 ? (average_valid2
496 - (ratio * tu_size))
497 : ((ratio * tu_size)
498 - average_valid2);
499 if (average_valid2 < (ratio * tu_size))
500 n_err_neg = true;
501 even_distribution =
502 n_tus % ln_cnt == 0 ? 1 : 0;
503 diff_abs =
504 resulting_valid >= ratio_by_tu
505 ? (resulting_valid
506 - ratio_by_tu)
507 : (ratio_by_tu
508 - resulting_valid);
509
510 resulting_valid_tmp = div64_u64(
511 (i_upper_bdry_cnt
512 * new_valid_boundary_link
513 + i_lower_bdry_cnt
514 * (new_valid_boundary_link
515 - multiplier)),
516 (i_upper_bdry_cnt
517 + i_lower_bdry_cnt));
518 ratio_by_tu_tmp =
519 original_ratio * tu_size;
520 ratio_by_tu_tmp /= multiplier;
521 n_tus_tmp = rounddown_u64(
522 div64_u64(lwidth
523 * multiplier * multiplier
524 * bpp / 8,
525 resulting_valid_tmp),
526 multiplier);
527 n_tus_tmp /= multiplier;
528
529 temp3 = (resulting_valid_tmp
530 >= (original_ratio * tu_size))
531 ? (resulting_valid_tmp
532 - original_ratio * tu_size)
533 : (original_ratio * tu_size)
534 - resulting_valid_tmp;
535 temp3 = (n_tus_tmp + 1) * temp3;
536 temp4 = (new_valid_boundary_link
537 >= (original_ratio * tu_size))
538 ? (new_valid_boundary_link
539 - original_ratio
540 * tu_size)
541 : (original_ratio * tu_size)
542 - new_valid_boundary_link;
543 temp4 = (i_upper_bdry_cnt
544 * ln_cnt * temp4);
545
546 temp3 = roundup_u64(temp3, multiplier);
547 temp4 = roundup_u64(temp4, multiplier);
548 dp_ctrl_get_extra_req_bytes
549 (resulting_valid_tmp,
550 new_valid_boundary_link,
551 temp3, temp4,
552 &extra_req_bytes_is_neg,
553 &result,
554 (original_ratio * tu_size));
555 extra_req_bytes_new_tmp
556 = div64_ul(result, multiplier);
557 if ((extra_req_bytes_is_neg)
558 && (extra_req_bytes_new_tmp
559 > 1))
560 extra_req_bytes_new_tmp
561 = extra_req_bytes_new_tmp - 1;
562 if (extra_req_bytes_new_tmp == 0)
563 extra_req_bytes_new_tmp = 1;
564 extra_pclk_cycles_tmp =
565 (u64)(extra_req_bytes_new_tmp
566 * 8 * multiplier) / bpp;
567 extra_pclk_cycles_tmp /= multiplier;
568
569 if (extra_pclk_cycles_tmp <= 0)
570 extra_pclk_cycles_tmp = 1;
571 extra_pclk_cycles_in_lclk_tmp =
572 roundup_u64(div64_u64(
573 extra_pclk_cycles_tmp
574 * lclk * multiplier,
575 pclk), multiplier);
576 extra_pclk_cycles_in_lclk_tmp
577 /= multiplier;
578 filler_size_tmp = roundup_u64(
579 (tu_size * multiplier *
580 new_valid_boundary_link),
581 multiplier);
582 filler_size_tmp /= multiplier;
583 lower_filler_size_tmp =
584 filler_size_tmp + 1;
585 if (extra_req_bytes_is_neg)
586 temp3 = (extra_req_bytes_new_tmp
587 > extra_pclk_cycles_in_lclk_tmp
588 ? extra_pclk_cycles_in_lclk_tmp
589 : extra_req_bytes_new_tmp);
590 else
591 temp3 = (extra_req_bytes_new_tmp
592 > extra_pclk_cycles_in_lclk_tmp
593 ? extra_req_bytes_new_tmp :
594 extra_pclk_cycles_in_lclk_tmp);
595
596 temp4 = lower_filler_size_tmp
597 + extra_buffer_margin;
598 if (extra_req_bytes_is_neg)
599 delay_start_link_tmp
600 = (temp3 >= temp4)
601 ? (temp3 - temp4)
602 : (temp4 - temp3);
603 else
604 delay_start_link_tmp
605 = temp3 + temp4;
606
607 min_hblank_tmp = (int)div64_u64(
608 roundup_u64(
609 div64_u64(delay_start_link_tmp
610 * pclk * multiplier, lclk),
611 multiplier), multiplier)
612 + hblank_margin;
613
614 if (((even_distribution == 1)
615 || ((even_distribution_bf == 0)
616 && (even_distribution_legacy
617 == 0)))
618 && !n_err_neg && !nn_err_neg
619 && n_n_err < err
620 && (n_n_err < diff_abs
621 || (dp_brute_force == 1))
622 && (new_valid_boundary_link
623 - 1) > 0
624 && (h_blank >=
625 (u32)min_hblank_tmp)) {
626 upper_bdry_cnt =
627 i_upper_bdry_cnt;
628 lower_bdry_cnt =
629 i_lower_bdry_cnt;
630 err = n_n_err;
631 boundary_moderation_en = 1;
632 tu_size_desired = tu_size;
633 valid_boundary_link =
634 new_valid_boundary_link;
635 effective_valid_recorded
636 = effective_valid;
637 delay_start_link
638 = delay_start_link_tmp;
639 filler_size = filler_size_tmp;
640 min_hblank = min_hblank_tmp;
641 n_tus = n_tus_tmp;
642 even_distribution_bf = 1;
643
644 pr_debug("upper_bdry_cnt=%d, lower_boundary_cnt=%d, err=%lld, tu_size_desired=%d, valid_boundary_link=%d, effective_valid=%lld\n",
645 upper_bdry_cnt,
646 lower_bdry_cnt, err,
647 tu_size_desired,
648 valid_boundary_link,
649 effective_valid);
650 }
651 }
652 }
653 }
654
655 if (boundary_moderation_en == 1) {
656 resulting_valid = (u64)(upper_bdry_cnt
657 *valid_boundary_link + lower_bdry_cnt
658 * (valid_boundary_link - 1))
659 / (upper_bdry_cnt + lower_bdry_cnt);
660 ratio_by_tu = original_ratio * tu_size_desired;
661 valid_lower_boundary_link =
662 (valid_boundary_link / multiplier) - 1;
663
664 tu_size_minus1 = tu_size_desired - 1;
665 even_distribution_bf = 1;
666 valid_boundary_link /= multiplier;
667 pr_debug("Info: Boundary_moderation enabled\n");
668 }
669 }
670
671 min_hblank = ((int) roundup_u64(div64_u64(delay_start_link * pclk
672 * multiplier, lclk), multiplier))
673 / multiplier + hblank_margin;
674 if (h_blank < (u32)min_hblank) {
675 pr_debug(" WARNING: run_idx=%d Programmed h_blank %d is smaller than the min_hblank %d supported.\n",
676 run_idx, h_blank, min_hblank);
677 }
678
679 if (fifo_empty) {
680 tu_size_minus1 = 31;
681 valid_boundary_link = 32;
682 delay_start_link = 0;
683 boundary_moderation_en = 0;
684 }
685
686 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",
687 tu_size_minus1, valid_boundary_link, delay_start_link,
688 boundary_moderation_en, upper_bdry_cnt, lower_bdry_cnt,
689 valid_lower_boundary_link, min_hblank);
690
691 tu_table->valid_boundary_link = valid_boundary_link;
692 tu_table->delay_start_link = delay_start_link;
693 tu_table->boundary_moderation_en = boundary_moderation_en;
694 tu_table->valid_lower_boundary_link = valid_lower_boundary_link;
695 tu_table->upper_boundary_count = upper_bdry_cnt;
696 tu_table->lower_boundary_count = lower_bdry_cnt;
697 tu_table->tu_size_minus1 = tu_size_minus1;
698}
699
700static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl)
701{
702 u32 dp_tu = 0x0;
703 u32 valid_boundary = 0x0;
704 u32 valid_boundary2 = 0x0;
705 struct dp_vc_tu_mapping_table tu_calc_table;
706
707 dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table);
708
709 dp_tu |= tu_calc_table.tu_size_minus1;
710 valid_boundary |= tu_calc_table.valid_boundary_link;
711 valid_boundary |= (tu_calc_table.delay_start_link << 16);
712
713 valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1);
714 valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16);
715 valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20);
716
717 if (tu_calc_table.boundary_moderation_en)
718 valid_boundary2 |= BIT(0);
719
720 pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n",
721 dp_tu, valid_boundary, valid_boundary2);
722
723 ctrl->catalog->dp_tu = dp_tu;
724 ctrl->catalog->valid_boundary = valid_boundary;
725 ctrl->catalog->valid_boundary2 = valid_boundary2;
726
727 ctrl->catalog->update_transfer_unit(ctrl->catalog);
728}
729
730static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
731{
732 int ret = 0;
733
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700734 ret = wait_for_completion_timeout(&ctrl->video_comp, HZ / 2);
735 if (ret <= 0) {
736 pr_err("Link Train timedout\n");
737 ret = -EINVAL;
738 }
739
740 return ret;
741}
742
743static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl,
744 u32 voltage_level, u32 pre_emphasis_level)
745{
746 int i;
747 u8 buf[4];
748 u32 max_level_reached = 0;
749
750 if (voltage_level == DP_LINK_VOLTAGE_MAX) {
751 pr_debug("max. voltage swing level reached %d\n",
752 voltage_level);
753 max_level_reached |= BIT(2);
754 }
755
756 if (pre_emphasis_level == DP_LINK_PRE_EMPHASIS_MAX) {
757 pr_debug("max. pre-emphasis level reached %d\n",
758 pre_emphasis_level);
759 max_level_reached |= BIT(5);
760 }
761
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700762 pre_emphasis_level <<= 3;
763
764 for (i = 0; i < 4; i++)
765 buf[i] = voltage_level | pre_emphasis_level | max_level_reached;
766
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700767 pr_debug("sink: p|v=0x%x\n", voltage_level | pre_emphasis_level);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700768 return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700769}
770
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530771static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700772{
773 struct dp_link *link = ctrl->link;
774
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700775 ctrl->catalog->update_vx_px(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530776 link->phy_params.v_level, link->phy_params.p_level);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700777
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530778 return dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530779 link->phy_params.p_level);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700780}
781
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530782static int dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700783 u8 pattern)
784{
785 u8 buf[4];
786
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700787 pr_debug("sink: pattern=%x\n", pattern);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700788
789 buf[0] = pattern;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530790 return drm_dp_dpcd_write(ctrl->aux->drm_aux,
791 DP_TRAINING_PATTERN_SET, buf, 1);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700792}
793
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700794static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
795 u8 *link_status)
796{
797 int ret = 0, len;
798 u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS;
799 u32 link_status_read_max_retries = 100;
800
801 while (--link_status_read_max_retries) {
802 len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
803 link_status);
804 if (len != DP_LINK_STATUS_SIZE) {
805 pr_err("DP link status read failed, err: %d\n", len);
806 ret = len;
807 break;
808 }
809
810 if (!(link_status[offset] & DP_LINK_STATUS_UPDATED))
811 break;
812 }
813
814 return ret;
815}
816
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700817static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
818{
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700819 int tries, old_v_level, ret = 0;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700820 u8 link_status[DP_LINK_STATUS_SIZE];
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700821 int const maximum_retries = 5;
822
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800823 ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED;
824 ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED;
825 ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED;
826
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700827 dp_ctrl_state_ctrl(ctrl, 0);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700828 /* Make sure to clear the current pattern before starting a new one */
829 wmb();
830
831 ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530832 ret = dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700833 DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530834 if (ret <= 0) {
835 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800836 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530837 }
838
839 ret = dp_ctrl_update_vx_px(ctrl);
840 if (ret <= 0) {
841 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800842 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530843 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700844
845 tries = 0;
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530846 old_v_level = ctrl->link->phy_params.v_level;
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800847 while (!atomic_read(&ctrl->aborted)) {
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700848 drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700849
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700850 ret = dp_ctrl_read_link_status(ctrl, link_status);
851 if (ret)
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700852 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700853
854 if (drm_dp_clock_recovery_ok(link_status,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530855 ctrl->link->link_params.lane_count)) {
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700856 break;
857 }
858
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530859 if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) {
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700860 pr_err_ratelimited("max v_level reached\n");
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700861 ret = -EAGAIN;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700862 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700863 }
864
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530865 if (old_v_level == ctrl->link->phy_params.v_level) {
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700866 tries++;
867 if (tries >= maximum_retries) {
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700868 pr_err("max tries reached\n");
Tatenda Chipeperekwaf7d82ce2017-08-22 19:13:47 -0700869 ret = -ETIMEDOUT;
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700870 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700871 }
872 } else {
873 tries = 0;
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530874 old_v_level = ctrl->link->phy_params.v_level;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700875 }
876
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700877 pr_debug("clock recovery not done, adjusting vx px\n");
878
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700879 ctrl->link->adjust_levels(ctrl->link, link_status);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530880 ret = dp_ctrl_update_vx_px(ctrl);
881 if (ret <= 0) {
882 ret = -EINVAL;
883 break;
884 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700885 }
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800886end:
887 ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED;
888
889 if (ret)
890 ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED;
891 else
892 ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700893
894 return ret;
895}
896
897static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
898{
899 int ret = 0;
900
901 if (!ctrl)
902 return -EINVAL;
903
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530904 switch (ctrl->link->link_params.bw_code) {
Aravind Venkateswaranc28b7772017-08-18 17:20:18 -0700905 case DP_LINK_BW_8_1:
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +0530906 ctrl->link->link_params.bw_code = DP_LINK_BW_5_4;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700907 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700908 case DP_LINK_BW_5_4:
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +0530909 ctrl->link->link_params.bw_code = DP_LINK_BW_2_7;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700910 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700911 case DP_LINK_BW_2_7:
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700912 case DP_LINK_BW_1_62:
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700913 default:
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +0530914 ctrl->link->link_params.bw_code = DP_LINK_BW_1_62;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700915 break;
916 };
917
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530918 pr_debug("new bw code=0x%x\n", ctrl->link->link_params.bw_code);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700919
920 return ret;
921}
922
923static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
924{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700925 dp_ctrl_train_pattern_set(ctrl, 0);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700926 drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700927}
928
929static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
930{
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700931 int tries = 0, ret = 0;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700932 char pattern;
933 int const maximum_retries = 5;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700934 u8 link_status[DP_LINK_STATUS_SIZE];
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700935
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800936 ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED;
937 ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED;
938 ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED;
939
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700940 dp_ctrl_state_ctrl(ctrl, 0);
941 /* Make sure to clear the current pattern before starting a new one */
942 wmb();
943
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700944 if (drm_dp_tps3_supported(ctrl->panel->dpcd))
945 pattern = DP_TRAINING_PATTERN_3;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700946 else
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700947 pattern = DP_TRAINING_PATTERN_2;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700948
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530949 ret = dp_ctrl_update_vx_px(ctrl);
950 if (ret <= 0) {
951 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800952 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530953 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700954 ctrl->catalog->set_pattern(ctrl->catalog, pattern);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530955 ret = dp_ctrl_train_pattern_set(ctrl,
956 pattern | DP_RECOVERED_CLOCK_OUT_EN);
957 if (ret <= 0) {
958 ret = -EINVAL;
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800959 goto end;
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530960 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700961
962 do {
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700963 drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700964
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700965 ret = dp_ctrl_read_link_status(ctrl, link_status);
966 if (ret)
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700967 break;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700968
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +0530969 if (drm_dp_channel_eq_ok(link_status,
970 ctrl->link->link_params.lane_count))
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700971 break;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700972
973 if (tries > maximum_retries) {
Tatenda Chipeperekwaf7d82ce2017-08-22 19:13:47 -0700974 ret = -ETIMEDOUT;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700975 break;
976 }
977 tries++;
978
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700979 ctrl->link->adjust_levels(ctrl->link, link_status);
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +0530980 ret = dp_ctrl_update_vx_px(ctrl);
981 if (ret <= 0) {
982 ret = -EINVAL;
983 break;
984 }
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -0800985 } while (!atomic_read(&ctrl->aborted));
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800986end:
987 ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700988
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -0800989 if (ret)
990 ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED;
991 else
992 ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -0700993 return ret;
994}
995
996static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
997{
998 int ret = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -0700999 u8 encoding = 0x1;
1000 struct drm_dp_link link_info = {0};
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001001
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301002 ctrl->link->phy_params.p_level = 0;
1003 ctrl->link->phy_params.v_level = 0;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001004
1005 dp_ctrl_config_ctrl(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001006
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301007 link_info.num_lanes = ctrl->link->link_params.lane_count;
1008 link_info.rate = drm_dp_bw_code_to_link_rate(
1009 ctrl->link->link_params.bw_code);
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001010 link_info.capabilities = ctrl->panel->link_info.capabilities;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001011
Padmanabhan Komanduruece783d2017-10-11 19:50:01 +05301012 ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
1013 if (ret)
1014 goto end;
1015
1016 ret = drm_dp_dpcd_write(ctrl->aux->drm_aux,
1017 DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1);
1018 if (ret <= 0) {
1019 ret = -EINVAL;
1020 goto end;
1021 }
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -07001022
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001023 ret = dp_ctrl_link_train_1(ctrl);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001024 if (ret) {
1025 pr_err("link training #1 failed\n");
1026 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001027 }
1028
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001029 /* print success info as this is a result of user initiated action */
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001030 pr_info("link training #1 successful\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001031
1032 ret = dp_ctrl_link_training_2(ctrl);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001033 if (ret) {
1034 pr_err("link training #2 failed\n");
1035 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001036 }
1037
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001038 /* print success info as this is a result of user initiated action */
Ajay Singh Parmarfae11672017-09-01 19:49:30 -07001039 pr_info("link training #2 successful\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001040
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001041end:
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001042 dp_ctrl_state_ctrl(ctrl, 0);
1043 /* Make sure to clear the current pattern before starting a new one */
1044 wmb();
1045
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001046 dp_ctrl_clear_training_pattern(ctrl);
1047 return ret;
1048}
1049
1050static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)
1051{
1052 bool mainlink_ready = false;
1053 int ret = 0;
1054
1055 ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
1056
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001057 if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001058 goto end;
1059
1060 if (!train)
1061 goto send_video;
1062
1063 /*
1064 * As part of previous calls, DP controller state might have
1065 * transitioned to PUSH_IDLE. In order to start transmitting a link
1066 * training pattern, we have to first to a DP software reset.
1067 */
1068 ctrl->catalog->reset(ctrl->catalog);
1069
1070 ret = dp_ctrl_link_train(ctrl);
1071 if (ret)
1072 goto end;
1073
1074send_video:
1075 /*
1076 * Set up transfer unit values and set controller state to send
1077 * video.
1078 */
1079 dp_ctrl_setup_tr_unit(ctrl);
1080 ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO);
1081
1082 dp_ctrl_wait4video_ready(ctrl);
1083 mainlink_ready = ctrl->catalog->mainlink_ready(ctrl->catalog);
1084 pr_debug("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
1085end:
1086 return ret;
1087}
1088
1089static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
1090 char *name, u32 rate)
1091{
1092 u32 num = ctrl->parser->mp[DP_CTRL_PM].num_clk;
1093 struct dss_clk *cfg = ctrl->parser->mp[DP_CTRL_PM].clk_config;
1094
1095 while (num && strcmp(cfg->clk_name, name)) {
1096 num--;
1097 cfg++;
1098 }
1099
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001100 pr_debug("setting rate=%d on clk=%s\n", rate, name);
1101
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001102 if (num)
1103 cfg->rate = rate;
1104 else
1105 pr_err("%s clock could not be set with rate %d\n", name, rate);
1106}
1107
1108static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
1109{
1110 int ret = 0;
1111
1112 ctrl->power->set_pixel_clk_parent(ctrl->power);
1113
1114 dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301115 drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code));
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001116
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001117 dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate);
1118
1119 ret = ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, true);
1120 if (ret) {
1121 pr_err("Unabled to start link clocks\n");
1122 ret = -EINVAL;
1123 }
1124
1125 return ret;
1126}
1127
1128static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl)
1129{
1130 return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false);
1131}
1132
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001133static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001134{
1135 struct dp_ctrl_private *ctrl;
1136 struct dp_catalog_ctrl *catalog;
1137
1138 if (!dp_ctrl) {
1139 pr_err("Invalid input data\n");
1140 return -EINVAL;
1141 }
1142
1143 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1144
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001145 ctrl->orientation = flip;
1146 catalog = ctrl->catalog;
1147
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001148 if (reset) {
Padmanabhan Komanduru4af597e2017-11-08 08:54:08 +05301149 catalog->usb_reset(ctrl->catalog, flip);
1150 catalog->phy_reset(ctrl->catalog);
1151 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001152 catalog->enable_irq(ctrl->catalog, true);
1153
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001154 return 0;
1155}
1156
1157/**
1158 * dp_ctrl_host_deinit() - Uninitialize DP controller
1159 * @ctrl: Display Port Driver data
1160 *
1161 * Perform required steps to uninitialize DP controller
1162 * and its resources.
1163 */
1164static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
1165{
1166 struct dp_ctrl_private *ctrl;
1167
1168 if (!dp_ctrl) {
1169 pr_err("Invalid input data\n");
1170 return;
1171 }
1172
1173 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1174
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001175 ctrl->catalog->enable_irq(ctrl->catalog, false);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001176
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001177 pr_debug("Host deinitialized successfully\n");
1178}
1179
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001180static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001181{
1182 int ret = 0;
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001183 struct dp_ctrl_private *ctrl;
1184
1185 if (!dp_ctrl) {
1186 pr_err("Invalid input data\n");
1187 return -EINVAL;
1188 }
1189
1190 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301191
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001192 if (!ctrl->power_on || atomic_read(&ctrl->aborted)) {
1193 pr_err("CTRL off, return\n");
1194 return -EINVAL;
1195 }
1196
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001197 ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
1198 ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;
1199 ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;
1200
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001201 ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
1202 ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301203
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001204 ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001205
1206 do {
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +05301207 if (ret == -EAGAIN) {
1208 /* try with lower link rate */
1209 dp_ctrl_link_rate_down_shift(ctrl);
1210
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001211 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
Padmanabhan Komanduru7909c7f2017-08-28 17:05:05 +05301212 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001213
1214 ctrl->catalog->phy_lane_cfg(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301215 ctrl->orientation, ctrl->link->link_params.lane_count);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001216
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001217 /*
1218 * Disable and re-enable the mainlink clock since the
1219 * link clock might have been adjusted as part of the
1220 * link maintenance.
1221 */
1222 dp_ctrl_disable_mainlink_clocks(ctrl);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001223
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001224 ret = dp_ctrl_enable_mainlink_clocks(ctrl);
1225 if (ret)
1226 continue;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001227
1228 dp_ctrl_configure_source_params(ctrl);
1229
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001230 ctrl->catalog->config_msa(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301231 drm_dp_bw_code_to_link_rate(
Sankeerth Billakanti4223e132019-03-08 12:09:59 +05301232 ctrl->link->link_params.bw_code), ctrl->pixel_rate);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001233
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001234 reinit_completion(&ctrl->idle_comp);
1235
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301236 ret = dp_ctrl_setup_main_link(ctrl, true);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001237 } while (ret == -EAGAIN);
1238
Ajay Singh Parmar09e6af62018-01-19 17:56:21 -08001239 ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED;
1240
1241 if (ret)
1242 ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED;
1243 else
1244 ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED;
1245
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001246 return ret;
1247}
1248
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001249static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl)
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001250{
1251 int ret = 0;
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001252 struct dp_ctrl_private *ctrl;
1253
1254 if (!dp_ctrl) {
1255 pr_err("Invalid input data\n");
1256 return;
1257 }
1258
1259 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001260
1261 if (!ctrl->link->phy_params.phy_test_pattern_sel) {
1262 pr_debug("no test pattern selected by sink\n");
1263 return;
1264 }
1265
1266 pr_debug("start\n");
1267
1268 ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
1269 /*
1270 * The global reset will need DP link ralated clocks to be
1271 * running. Add the global reset just before disabling the
1272 * link clocks and core clocks.
1273 */
1274 ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
1275 ctrl->dp_ctrl.off(&ctrl->dp_ctrl);
1276
1277 ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl);
1278 if (ret)
1279 pr_err("failed to enable DP controller\n");
1280
1281 pr_debug("end\n");
1282}
1283
1284static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
1285{
1286 bool success = false;
1287 u32 pattern_sent = 0x0;
1288 u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
1289
Tatenda Chipeperekwa70fc1f12018-11-15 15:49:35 -08001290 dp_ctrl_update_vx_px(ctrl);
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001291 ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested);
1292 ctrl->link->send_test_response(ctrl->link);
1293
1294 pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog);
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001295 pr_debug("pattern_request: %s. pattern_sent: 0x%x\n",
1296 dp_link_get_phy_test_pattern(pattern_requested),
1297 pattern_sent);
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001298
1299 switch (pattern_sent) {
1300 case MR_LINK_TRAINING1:
1301 if (pattern_requested ==
1302 DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING)
1303 success = true;
1304 break;
1305 case MR_LINK_SYMBOL_ERM:
1306 if ((pattern_requested ==
1307 DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT)
1308 || (pattern_requested ==
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001309 DP_TEST_PHY_PATTERN_CP2520_PATTERN_1))
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001310 success = true;
1311 break;
1312 case MR_LINK_PRBS7:
1313 if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7)
1314 success = true;
1315 break;
1316 case MR_LINK_CUSTOM80:
1317 if (pattern_requested ==
1318 DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN)
1319 success = true;
1320 break;
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001321 case MR_LINK_TRAINING4:
1322 if (pattern_requested ==
1323 DP_TEST_PHY_PATTERN_CP2520_PATTERN_3)
1324 success = true;
1325 break;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001326 default:
1327 success = false;
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001328 break;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001329 }
1330
1331 pr_debug("%s: %s\n", success ? "success" : "failed",
1332 dp_link_get_phy_test_pattern(pattern_requested));
1333}
1334
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301335static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001336{
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301337 struct dp_ctrl_private *ctrl;
1338
1339 if (!dp_ctrl) {
1340 pr_err("invalid params\n");
1341 return;
1342 }
1343
1344 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1345 ctrl->catalog->reset(ctrl->catalog);
1346}
1347
1348static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
1349{
1350 int rc = 0;
1351 struct dp_ctrl_private *ctrl;
1352 u32 rate = 0;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001353 u32 link_train_max_retries = 100;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001354 u32 const phy_cts_pixel_clk_khz = 148500;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001355
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301356 if (!dp_ctrl) {
1357 rc = -EINVAL;
1358 goto end;
1359 }
1360
1361 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1362
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001363 atomic_set(&ctrl->aborted, 0);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301364 rate = ctrl->panel->link_info.rate;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001365
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001366 ctrl->catalog->hpd_config(ctrl->catalog, true);
1367
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001368 if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
1369 pr_debug("using phy test link parameters\n");
1370 if (!ctrl->panel->pinfo.pixel_clk_khz)
1371 ctrl->pixel_rate = phy_cts_pixel_clk_khz;
1372 } else {
1373 ctrl->link->link_params.bw_code =
1374 drm_dp_link_rate_to_bw_code(rate);
1375 ctrl->link->link_params.lane_count =
1376 ctrl->panel->link_info.num_lanes;
1377 ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
1378 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001379
Ajay Singh Parmara4b06062017-06-23 17:10:36 -07001380 pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n",
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301381 ctrl->link->link_params.bw_code,
1382 ctrl->link->link_params.lane_count, ctrl->pixel_rate);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001383
1384 ctrl->catalog->phy_lane_cfg(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301385 ctrl->orientation, ctrl->link->link_params.lane_count);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001386
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301387 rc = dp_ctrl_enable_mainlink_clocks(ctrl);
1388 if (rc)
1389 goto end;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001390
1391 reinit_completion(&ctrl->idle_comp);
1392
1393 dp_ctrl_configure_source_params(ctrl);
1394
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001395 while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
1396 ctrl->catalog->config_msa(ctrl->catalog,
Padmanabhan Komanduru0cc4e562017-08-28 17:03:06 +05301397 drm_dp_bw_code_to_link_rate(
Sankeerth Billakanti4223e132019-03-08 12:09:59 +05301398 ctrl->link->link_params.bw_code), ctrl->pixel_rate);
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001399
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301400 rc = dp_ctrl_setup_main_link(ctrl, true);
1401 if (!rc)
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001402 break;
1403
1404 /* try with lower link rate */
1405 dp_ctrl_link_rate_down_shift(ctrl);
1406
1407 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
1408
1409 dp_ctrl_disable_mainlink_clocks(ctrl);
1410 /* hw recommended delay before re-enabling clocks */
1411 msleep(20);
1412
1413 dp_ctrl_enable_mainlink_clocks(ctrl);
1414 }
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001415
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001416 if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
1417 dp_ctrl_send_phy_test_pattern(ctrl);
1418
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001419 ctrl->power_on = true;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001420 pr_debug("End-\n");
1421
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001422end:
1423 return rc;
1424}
1425
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301426static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001427{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001428 struct dp_ctrl_private *ctrl;
1429
Padmanabhan Komanduru7bf08e92017-05-23 02:56:54 -07001430 if (!dp_ctrl)
1431 return;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001432
1433 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1434
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301435 ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
Tatenda Chipeperekwa52f1d802017-08-29 18:57:48 -07001436 ctrl->catalog->reset(ctrl->catalog);
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301437
Tatenda Chipeperekwa52f1d802017-08-29 18:57:48 -07001438 /* Make sure DP is disabled before clk disable */
1439 wmb();
1440
1441 dp_ctrl_disable_mainlink_clocks(ctrl);
1442
Ajay Singh Parmar420e7e12018-01-11 21:27:16 -08001443 ctrl->power_on = false;
Tatenda Chipeperekwa52f1d802017-08-29 18:57:48 -07001444 pr_debug("DP off done\n");
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001445}
1446
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001447static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001448{
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001449 struct dp_ctrl_private *ctrl;
1450
1451 if (!dp_ctrl)
1452 return;
1453
1454 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1455
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001456 ctrl->catalog->get_interrupt(ctrl->catalog);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001457
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001458 if (ctrl->catalog->isr & DP_CTRL_INTR_READY_FOR_VIDEO)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001459 dp_ctrl_video_ready(ctrl);
1460
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001461 if (ctrl->catalog->isr & DP_CTRL_INTR_IDLE_PATTERN_SENT)
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001462 dp_ctrl_idle_patterns_sent(ctrl);
1463}
1464
1465struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
1466{
1467 int rc = 0;
1468 struct dp_ctrl_private *ctrl;
1469 struct dp_ctrl *dp_ctrl;
1470
1471 if (!in->dev || !in->panel || !in->aux ||
1472 !in->link || !in->catalog) {
1473 pr_err("invalid input\n");
1474 rc = -EINVAL;
1475 goto error;
1476 }
1477
1478 ctrl = devm_kzalloc(in->dev, sizeof(*ctrl), GFP_KERNEL);
1479 if (!ctrl) {
1480 rc = -ENOMEM;
1481 goto error;
1482 }
1483
1484 init_completion(&ctrl->idle_comp);
1485 init_completion(&ctrl->video_comp);
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001486
1487 /* in parameters */
1488 ctrl->parser = in->parser;
1489 ctrl->panel = in->panel;
1490 ctrl->power = in->power;
1491 ctrl->aux = in->aux;
1492 ctrl->link = in->link;
1493 ctrl->catalog = in->catalog;
Tatenda Chipeperekwa2bc44872017-10-18 18:26:56 -07001494 ctrl->dev = in->dev;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001495
1496 dp_ctrl = &ctrl->dp_ctrl;
1497
1498 /* out parameters */
1499 dp_ctrl->init = dp_ctrl_host_init;
1500 dp_ctrl->deinit = dp_ctrl_host_deinit;
1501 dp_ctrl->on = dp_ctrl_on;
1502 dp_ctrl->off = dp_ctrl_off;
1503 dp_ctrl->push_idle = dp_ctrl_push_idle;
Ajay Singh Parmar88617ba2017-07-03 00:12:26 -07001504 dp_ctrl->abort = dp_ctrl_abort;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001505 dp_ctrl->isr = dp_ctrl_isr;
Padmanabhan Komanduru8cf0c222017-08-16 21:11:23 +05301506 dp_ctrl->reset = dp_ctrl_reset;
Ajay Singh Parmar8a1bcde2017-11-20 12:37:39 -08001507 dp_ctrl->link_maintenance = dp_ctrl_link_maintenance;
1508 dp_ctrl->process_phy_test_request = dp_ctrl_process_phy_test_request;
Ajay Singh Parmar8c667f72017-03-24 19:50:39 -07001509
1510 return dp_ctrl;
1511error:
1512 return ERR_PTR(rc);
1513}
1514
1515void dp_ctrl_put(struct dp_ctrl *dp_ctrl)
1516{
1517 struct dp_ctrl_private *ctrl;
1518
1519 if (!dp_ctrl)
1520 return;
1521
1522 ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1523
1524 devm_kfree(ctrl->dev, ctrl);
1525}