1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "dm_services.h"
25
26
27#include "dce/dce_11_0_d.h"
28#include "dce/dce_11_0_sh_mask.h"
29
30#include "dc_types.h"
31#include "dc_bios_types.h"
32#include "dc.h"
33
34#include "include/grph_object_id.h"
35#include "include/logger_interface.h"
36#include "dce110_timing_generator.h"
37#include "dce110_timing_generator_v.h"
38
39#include "timing_generator.h"
40
41#define DC_LOGGER \
42 tg->ctx->logger
43
44
45
46
47
48
49
50
51
52
53static bool dce110_timing_generator_v_enable_crtc(struct timing_generator *tg)
54{
55
56
57
58
59
60 uint32_t value;
61
62 value = 0;
63 set_reg_field_value(value, 0,
64 CRTCV_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE);
65 dm_write_reg(tg->ctx,
66 mmCRTCV_MASTER_UPDATE_MODE, value);
67
68
69 value = 0;
70 dm_write_reg(tg->ctx, mmCRTCV_MASTER_UPDATE_MODE, value);
71
72 value = 0;
73 set_reg_field_value(value, 1,
74 CRTCV_MASTER_EN, CRTC_MASTER_EN);
75 dm_write_reg(tg->ctx,
76 mmCRTCV_MASTER_EN, value);
77
78 return true;
79}
80
81static bool dce110_timing_generator_v_disable_crtc(struct timing_generator *tg)
82{
83 uint32_t value;
84
85 value = dm_read_reg(tg->ctx,
86 mmCRTCV_CONTROL);
87 set_reg_field_value(value, 0,
88 CRTCV_CONTROL, CRTC_DISABLE_POINT_CNTL);
89 set_reg_field_value(value, 0,
90 CRTCV_CONTROL, CRTC_MASTER_EN);
91 dm_write_reg(tg->ctx,
92 mmCRTCV_CONTROL, value);
93
94
95
96
97 return true;
98}
99
100static void dce110_timing_generator_v_blank_crtc(struct timing_generator *tg)
101{
102 uint32_t addr = mmCRTCV_BLANK_CONTROL;
103 uint32_t value = dm_read_reg(tg->ctx, addr);
104
105 set_reg_field_value(
106 value,
107 1,
108 CRTCV_BLANK_CONTROL,
109 CRTC_BLANK_DATA_EN);
110
111 set_reg_field_value(
112 value,
113 0,
114 CRTCV_BLANK_CONTROL,
115 CRTC_BLANK_DE_MODE);
116
117 dm_write_reg(tg->ctx, addr, value);
118}
119
120static void dce110_timing_generator_v_unblank_crtc(struct timing_generator *tg)
121{
122 uint32_t addr = mmCRTCV_BLANK_CONTROL;
123 uint32_t value = dm_read_reg(tg->ctx, addr);
124
125 set_reg_field_value(
126 value,
127 0,
128 CRTCV_BLANK_CONTROL,
129 CRTC_BLANK_DATA_EN);
130
131 set_reg_field_value(
132 value,
133 0,
134 CRTCV_BLANK_CONTROL,
135 CRTC_BLANK_DE_MODE);
136
137 dm_write_reg(tg->ctx, addr, value);
138}
139
140static bool dce110_timing_generator_v_is_in_vertical_blank(
141 struct timing_generator *tg)
142{
143 uint32_t addr = 0;
144 uint32_t value = 0;
145 uint32_t field = 0;
146
147 addr = mmCRTCV_STATUS;
148 value = dm_read_reg(tg->ctx, addr);
149 field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK);
150 return field == 1;
151}
152
153static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg)
154{
155 uint32_t value;
156 uint32_t h1 = 0;
157 uint32_t h2 = 0;
158 uint32_t v1 = 0;
159 uint32_t v2 = 0;
160
161 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
162
163 h1 = get_reg_field_value(
164 value,
165 CRTCV_STATUS_POSITION,
166 CRTC_HORZ_COUNT);
167
168 v1 = get_reg_field_value(
169 value,
170 CRTCV_STATUS_POSITION,
171 CRTC_VERT_COUNT);
172
173 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
174
175 h2 = get_reg_field_value(
176 value,
177 CRTCV_STATUS_POSITION,
178 CRTC_HORZ_COUNT);
179
180 v2 = get_reg_field_value(
181 value,
182 CRTCV_STATUS_POSITION,
183 CRTC_VERT_COUNT);
184
185 if (h1 == h2 && v1 == v2)
186 return false;
187 else
188 return true;
189}
190
191static void dce110_timing_generator_v_wait_for_vblank(struct timing_generator *tg)
192{
193
194
195
196
197 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
198 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
199
200 break;
201 }
202 }
203
204 while (!dce110_timing_generator_v_is_in_vertical_blank(tg)) {
205 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
206
207 break;
208 }
209 }
210}
211
212
213
214
215static void dce110_timing_generator_v_wait_for_vactive(struct timing_generator *tg)
216{
217 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
218 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
219
220 break;
221 }
222 }
223}
224
225static void dce110_timing_generator_v_wait_for_state(struct timing_generator *tg,
226 enum crtc_state state)
227{
228 switch (state) {
229 case CRTC_STATE_VBLANK:
230 dce110_timing_generator_v_wait_for_vblank(tg);
231 break;
232
233 case CRTC_STATE_VACTIVE:
234 dce110_timing_generator_v_wait_for_vactive(tg);
235 break;
236
237 default:
238 break;
239 }
240}
241
242static void dce110_timing_generator_v_program_blanking(
243 struct timing_generator *tg,
244 const struct dc_crtc_timing *timing)
245{
246 uint32_t vsync_offset = timing->v_border_bottom +
247 timing->v_front_porch;
248 uint32_t v_sync_start = timing->v_addressable + vsync_offset;
249
250 uint32_t hsync_offset = timing->h_border_right +
251 timing->h_front_porch;
252 uint32_t h_sync_start = timing->h_addressable + hsync_offset;
253
254 struct dc_context *ctx = tg->ctx;
255 uint32_t value = 0;
256 uint32_t addr = 0;
257 uint32_t tmp = 0;
258
259 addr = mmCRTCV_H_TOTAL;
260 value = dm_read_reg(ctx, addr);
261 set_reg_field_value(
262 value,
263 timing->h_total - 1,
264 CRTCV_H_TOTAL,
265 CRTC_H_TOTAL);
266 dm_write_reg(ctx, addr, value);
267
268 addr = mmCRTCV_V_TOTAL;
269 value = dm_read_reg(ctx, addr);
270 set_reg_field_value(
271 value,
272 timing->v_total - 1,
273 CRTCV_V_TOTAL,
274 CRTC_V_TOTAL);
275 dm_write_reg(ctx, addr, value);
276
277 addr = mmCRTCV_H_BLANK_START_END;
278 value = dm_read_reg(ctx, addr);
279
280 tmp = timing->h_total -
281 (h_sync_start + timing->h_border_left);
282
283 set_reg_field_value(
284 value,
285 tmp,
286 CRTCV_H_BLANK_START_END,
287 CRTC_H_BLANK_END);
288
289 tmp = tmp + timing->h_addressable +
290 timing->h_border_left + timing->h_border_right;
291
292 set_reg_field_value(
293 value,
294 tmp,
295 CRTCV_H_BLANK_START_END,
296 CRTC_H_BLANK_START);
297
298 dm_write_reg(ctx, addr, value);
299
300 addr = mmCRTCV_V_BLANK_START_END;
301 value = dm_read_reg(ctx, addr);
302
303 tmp = timing->v_total - (v_sync_start + timing->v_border_top);
304
305 set_reg_field_value(
306 value,
307 tmp,
308 CRTCV_V_BLANK_START_END,
309 CRTC_V_BLANK_END);
310
311 tmp = tmp + timing->v_addressable + timing->v_border_top +
312 timing->v_border_bottom;
313
314 set_reg_field_value(
315 value,
316 tmp,
317 CRTCV_V_BLANK_START_END,
318 CRTC_V_BLANK_START);
319
320 dm_write_reg(ctx, addr, value);
321
322 addr = mmCRTCV_H_SYNC_A;
323 value = 0;
324 set_reg_field_value(
325 value,
326 timing->h_sync_width,
327 CRTCV_H_SYNC_A,
328 CRTC_H_SYNC_A_END);
329 dm_write_reg(ctx, addr, value);
330
331 addr = mmCRTCV_H_SYNC_A_CNTL;
332 value = dm_read_reg(ctx, addr);
333 if (timing->flags.HSYNC_POSITIVE_POLARITY) {
334 set_reg_field_value(
335 value,
336 0,
337 CRTCV_H_SYNC_A_CNTL,
338 CRTC_H_SYNC_A_POL);
339 } else {
340 set_reg_field_value(
341 value,
342 1,
343 CRTCV_H_SYNC_A_CNTL,
344 CRTC_H_SYNC_A_POL);
345 }
346 dm_write_reg(ctx, addr, value);
347
348 addr = mmCRTCV_V_SYNC_A;
349 value = 0;
350 set_reg_field_value(
351 value,
352 timing->v_sync_width,
353 CRTCV_V_SYNC_A,
354 CRTC_V_SYNC_A_END);
355 dm_write_reg(ctx, addr, value);
356
357 addr = mmCRTCV_V_SYNC_A_CNTL;
358 value = dm_read_reg(ctx, addr);
359 if (timing->flags.VSYNC_POSITIVE_POLARITY) {
360 set_reg_field_value(
361 value,
362 0,
363 CRTCV_V_SYNC_A_CNTL,
364 CRTC_V_SYNC_A_POL);
365 } else {
366 set_reg_field_value(
367 value,
368 1,
369 CRTCV_V_SYNC_A_CNTL,
370 CRTC_V_SYNC_A_POL);
371 }
372 dm_write_reg(ctx, addr, value);
373
374 addr = mmCRTCV_INTERLACE_CONTROL;
375 value = dm_read_reg(ctx, addr);
376 set_reg_field_value(
377 value,
378 timing->flags.INTERLACE,
379 CRTCV_INTERLACE_CONTROL,
380 CRTC_INTERLACE_ENABLE);
381 dm_write_reg(ctx, addr, value);
382}
383
384static void dce110_timing_generator_v_enable_advanced_request(
385 struct timing_generator *tg,
386 bool enable,
387 const struct dc_crtc_timing *timing)
388{
389 uint32_t addr = mmCRTCV_START_LINE_CONTROL;
390 uint32_t value = dm_read_reg(tg->ctx, addr);
391
392 if (enable) {
393 if ((timing->v_sync_width + timing->v_front_porch) <= 3) {
394 set_reg_field_value(
395 value,
396 3,
397 CRTCV_START_LINE_CONTROL,
398 CRTC_ADVANCED_START_LINE_POSITION);
399 } else {
400 set_reg_field_value(
401 value,
402 4,
403 CRTCV_START_LINE_CONTROL,
404 CRTC_ADVANCED_START_LINE_POSITION);
405 }
406 set_reg_field_value(
407 value,
408 0,
409 CRTCV_START_LINE_CONTROL,
410 CRTC_LEGACY_REQUESTOR_EN);
411 } else {
412 set_reg_field_value(
413 value,
414 2,
415 CRTCV_START_LINE_CONTROL,
416 CRTC_ADVANCED_START_LINE_POSITION);
417 set_reg_field_value(
418 value,
419 1,
420 CRTCV_START_LINE_CONTROL,
421 CRTC_LEGACY_REQUESTOR_EN);
422 }
423
424 dm_write_reg(tg->ctx, addr, value);
425}
426
427static void dce110_timing_generator_v_set_blank(struct timing_generator *tg,
428 bool enable_blanking)
429{
430 if (enable_blanking)
431 dce110_timing_generator_v_blank_crtc(tg);
432 else
433 dce110_timing_generator_v_unblank_crtc(tg);
434}
435
436static void dce110_timing_generator_v_program_timing(struct timing_generator *tg,
437 const struct dc_crtc_timing *timing,
438 int vready_offset,
439 int vstartup_start,
440 int vupdate_offset,
441 int vupdate_width,
442 const enum signal_type signal,
443 bool use_vbios)
444{
445 if (use_vbios)
446 dce110_timing_generator_program_timing_generator(tg, timing);
447 else
448 dce110_timing_generator_v_program_blanking(tg, timing);
449}
450
451static void dce110_timing_generator_v_program_blank_color(
452 struct timing_generator *tg,
453 const struct tg_color *black_color)
454{
455 uint32_t addr = mmCRTCV_BLACK_COLOR;
456 uint32_t value = dm_read_reg(tg->ctx, addr);
457
458 set_reg_field_value(
459 value,
460 black_color->color_b_cb,
461 CRTCV_BLACK_COLOR,
462 CRTC_BLACK_COLOR_B_CB);
463 set_reg_field_value(
464 value,
465 black_color->color_g_y,
466 CRTCV_BLACK_COLOR,
467 CRTC_BLACK_COLOR_G_Y);
468 set_reg_field_value(
469 value,
470 black_color->color_r_cr,
471 CRTCV_BLACK_COLOR,
472 CRTC_BLACK_COLOR_R_CR);
473
474 dm_write_reg(tg->ctx, addr, value);
475}
476
477static void dce110_timing_generator_v_set_overscan_color_black(
478 struct timing_generator *tg,
479 const struct tg_color *color)
480{
481 struct dc_context *ctx = tg->ctx;
482 uint32_t addr;
483 uint32_t value = 0;
484
485 set_reg_field_value(
486 value,
487 color->color_b_cb,
488 CRTC_OVERSCAN_COLOR,
489 CRTC_OVERSCAN_COLOR_BLUE);
490
491 set_reg_field_value(
492 value,
493 color->color_r_cr,
494 CRTC_OVERSCAN_COLOR,
495 CRTC_OVERSCAN_COLOR_RED);
496
497 set_reg_field_value(
498 value,
499 color->color_g_y,
500 CRTC_OVERSCAN_COLOR,
501 CRTC_OVERSCAN_COLOR_GREEN);
502
503 addr = mmCRTCV_OVERSCAN_COLOR;
504 dm_write_reg(ctx, addr, value);
505 addr = mmCRTCV_BLACK_COLOR;
506 dm_write_reg(ctx, addr, value);
507
508
509
510
511 addr = mmCRTCV_BLANK_DATA_COLOR;
512 dm_write_reg(ctx, addr, value);
513
514
515
516
517
518
519
520
521}
522
523static void dce110_tg_v_program_blank_color(struct timing_generator *tg,
524 const struct tg_color *black_color)
525{
526 uint32_t addr = mmCRTCV_BLACK_COLOR;
527 uint32_t value = dm_read_reg(tg->ctx, addr);
528
529 set_reg_field_value(
530 value,
531 black_color->color_b_cb,
532 CRTCV_BLACK_COLOR,
533 CRTC_BLACK_COLOR_B_CB);
534 set_reg_field_value(
535 value,
536 black_color->color_g_y,
537 CRTCV_BLACK_COLOR,
538 CRTC_BLACK_COLOR_G_Y);
539 set_reg_field_value(
540 value,
541 black_color->color_r_cr,
542 CRTCV_BLACK_COLOR,
543 CRTC_BLACK_COLOR_R_CR);
544
545 dm_write_reg(tg->ctx, addr, value);
546
547 addr = mmCRTCV_BLANK_DATA_COLOR;
548 dm_write_reg(tg->ctx, addr, value);
549}
550
551static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg,
552 const struct tg_color *overscan_color)
553{
554 struct dc_context *ctx = tg->ctx;
555 uint32_t value = 0;
556 uint32_t addr;
557
558 set_reg_field_value(
559 value,
560 overscan_color->color_b_cb,
561 CRTCV_OVERSCAN_COLOR,
562 CRTC_OVERSCAN_COLOR_BLUE);
563
564 set_reg_field_value(
565 value,
566 overscan_color->color_g_y,
567 CRTCV_OVERSCAN_COLOR,
568 CRTC_OVERSCAN_COLOR_GREEN);
569
570 set_reg_field_value(
571 value,
572 overscan_color->color_r_cr,
573 CRTCV_OVERSCAN_COLOR,
574 CRTC_OVERSCAN_COLOR_RED);
575
576 addr = mmCRTCV_OVERSCAN_COLOR;
577 dm_write_reg(ctx, addr, value);
578}
579
580static void dce110_timing_generator_v_set_colors(struct timing_generator *tg,
581 const struct tg_color *blank_color,
582 const struct tg_color *overscan_color)
583{
584 if (blank_color != NULL)
585 dce110_tg_v_program_blank_color(tg, blank_color);
586 if (overscan_color != NULL)
587 dce110_timing_generator_v_set_overscan_color(tg, overscan_color);
588}
589
590static void dce110_timing_generator_v_set_early_control(
591 struct timing_generator *tg,
592 uint32_t early_cntl)
593{
594 uint32_t regval;
595 uint32_t address = mmCRTC_CONTROL;
596
597 regval = dm_read_reg(tg->ctx, address);
598 set_reg_field_value(regval, early_cntl,
599 CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
600 dm_write_reg(tg->ctx, address, regval);
601}
602
603static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg)
604{
605 uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT;
606 uint32_t value = dm_read_reg(tg->ctx, addr);
607 uint32_t field = get_reg_field_value(
608 value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
609
610 return field;
611}
612
613static bool dce110_timing_generator_v_did_triggered_reset_occur(
614 struct timing_generator *tg)
615{
616 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
617 return false;
618}
619
620static void dce110_timing_generator_v_setup_global_swap_lock(
621 struct timing_generator *tg,
622 const struct dcp_gsl_params *gsl_params)
623{
624 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
625 return;
626}
627
628static void dce110_timing_generator_v_enable_reset_trigger(
629 struct timing_generator *tg,
630 int source_tg_inst)
631{
632 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
633 return;
634}
635
636static void dce110_timing_generator_v_disable_reset_trigger(
637 struct timing_generator *tg)
638{
639 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
640 return;
641}
642
643static void dce110_timing_generator_v_tear_down_global_swap_lock(
644 struct timing_generator *tg)
645{
646 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
647 return;
648}
649
650static void dce110_timing_generator_v_disable_vga(
651 struct timing_generator *tg)
652{
653 return;
654}
655
656
657
658
659
660
661static const struct timing_generator_funcs dce110_tg_v_funcs = {
662 .validate_timing = dce110_tg_validate_timing,
663 .program_timing = dce110_timing_generator_v_program_timing,
664 .enable_crtc = dce110_timing_generator_v_enable_crtc,
665 .disable_crtc = dce110_timing_generator_v_disable_crtc,
666 .is_counter_moving = dce110_timing_generator_v_is_counter_moving,
667 .get_position = NULL,
668 .get_frame_count = dce110_timing_generator_v_get_vblank_counter,
669 .set_early_control = dce110_timing_generator_v_set_early_control,
670 .wait_for_state = dce110_timing_generator_v_wait_for_state,
671 .set_blank = dce110_timing_generator_v_set_blank,
672 .set_colors = dce110_timing_generator_v_set_colors,
673 .set_overscan_blank_color =
674 dce110_timing_generator_v_set_overscan_color_black,
675 .set_blank_color = dce110_timing_generator_v_program_blank_color,
676 .disable_vga = dce110_timing_generator_v_disable_vga,
677 .did_triggered_reset_occur =
678 dce110_timing_generator_v_did_triggered_reset_occur,
679 .setup_global_swap_lock =
680 dce110_timing_generator_v_setup_global_swap_lock,
681 .enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger,
682 .disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger,
683 .tear_down_global_swap_lock =
684 dce110_timing_generator_v_tear_down_global_swap_lock,
685 .enable_advanced_request =
686 dce110_timing_generator_v_enable_advanced_request
687};
688
689void dce110_timing_generator_v_construct(
690 struct dce110_timing_generator *tg110,
691 struct dc_context *ctx)
692{
693 tg110->controller_id = CONTROLLER_ID_UNDERLAY0;
694
695 tg110->base.funcs = &dce110_tg_v_funcs;
696
697 tg110->base.ctx = ctx;
698 tg110->base.bp = ctx->dc_bios;
699
700 tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
701 tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
702
703 tg110->min_h_blank = 56;
704 tg110->min_h_front_porch = 4;
705 tg110->min_h_back_porch = 4;
706}
707