1 #include "dm_services.h"
3 /* include DCE11 register header files */
4 #include "dce/dce_11_0_d.h"
5 #include "dce/dce_11_0_sh_mask.h"
8 #include "dc_bios_types.h"
11 #include "include/grph_object_id.h"
12 #include "include/logger_interface.h"
13 #include "dce110_timing_generator.h"
14 #include "dce110_timing_generator_v.h"
16 #include "timing_generator.h"
18 /** ********************************************************************************
20 * DCE11 Timing Generator Implementation
22 **********************************************************************************/
28 static bool dce110_timing_generator_v_enable_crtc(struct timing_generator *tg)
31 * Set MASTER_UPDATE_MODE to 0
32 * This is needed for DRR, and also suggested to be default value by Syed.
38 set_reg_field_value(value, 0,
39 CRTCV_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE);
41 mmCRTCV_MASTER_UPDATE_MODE, value);
43 /* TODO: may want this on for looking for underflow */
45 dm_write_reg(tg->ctx, mmCRTCV_MASTER_UPDATE_MODE, value);
48 set_reg_field_value(value, 1,
49 CRTCV_MASTER_EN, CRTC_MASTER_EN);
51 mmCRTCV_MASTER_EN, value);
56 static bool dce110_timing_generator_v_disable_crtc(struct timing_generator *tg)
60 value = dm_read_reg(tg->ctx,
62 set_reg_field_value(value, 0,
63 CRTCV_CONTROL, CRTC_DISABLE_POINT_CNTL);
64 set_reg_field_value(value, 0,
65 CRTCV_CONTROL, CRTC_MASTER_EN);
67 mmCRTCV_CONTROL, value);
69 * TODO: call this when adding stereo support
70 * tg->funcs->disable_stereo(tg);
75 static void dce110_timing_generator_v_blank_crtc(struct timing_generator *tg)
77 uint32_t addr = mmCRTCV_BLANK_CONTROL;
78 uint32_t value = dm_read_reg(tg->ctx, addr);
92 dm_write_reg(tg->ctx, addr, value);
95 static void dce110_timing_generator_v_unblank_crtc(struct timing_generator *tg)
97 uint32_t addr = mmCRTCV_BLANK_CONTROL;
98 uint32_t value = dm_read_reg(tg->ctx, addr);
112 dm_write_reg(tg->ctx, addr, value);
115 static bool dce110_timing_generator_v_is_in_vertical_blank(
116 struct timing_generator *tg)
122 addr = mmCRTCV_STATUS;
123 value = dm_read_reg(tg->ctx, addr);
124 field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK);
128 static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg)
136 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
138 h1 = get_reg_field_value(
140 CRTCV_STATUS_POSITION,
143 v1 = get_reg_field_value(
145 CRTCV_STATUS_POSITION,
148 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
150 h2 = get_reg_field_value(
152 CRTCV_STATUS_POSITION,
155 v2 = get_reg_field_value(
157 CRTCV_STATUS_POSITION,
160 if (h1 == h2 && v1 == v2)
166 static void dce110_timing_generator_v_wait_for_vblank(struct timing_generator *tg)
168 /* We want to catch beginning of VBlank here, so if the first try are
169 * in VBlank, we might be very close to Active, in this case wait for
172 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
173 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
174 /* error - no point to wait if counter is not moving */
179 while (!dce110_timing_generator_v_is_in_vertical_blank(tg)) {
180 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
181 /* error - no point to wait if counter is not moving */
188 * Wait till we are in VActive (anywhere in VActive)
190 static void dce110_timing_generator_v_wait_for_vactive(struct timing_generator *tg)
192 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
193 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
194 /* error - no point to wait if counter is not moving */
200 static void dce110_timing_generator_v_wait_for_state(struct timing_generator *tg,
201 enum crtc_state state)
204 case CRTC_STATE_VBLANK:
205 dce110_timing_generator_v_wait_for_vblank(tg);
208 case CRTC_STATE_VACTIVE:
209 dce110_timing_generator_v_wait_for_vactive(tg);
217 static void dce110_timing_generator_v_program_blanking(
218 struct timing_generator *tg,
219 const struct dc_crtc_timing *timing)
221 uint32_t vsync_offset = timing->v_border_bottom +
222 timing->v_front_porch;
223 uint32_t v_sync_start = timing->v_addressable + vsync_offset;
225 uint32_t hsync_offset = timing->h_border_right +
226 timing->h_front_porch;
227 uint32_t h_sync_start = timing->h_addressable + hsync_offset;
229 struct dc_context *ctx = tg->ctx;
234 addr = mmCRTCV_H_TOTAL;
235 value = dm_read_reg(ctx, addr);
241 dm_write_reg(ctx, addr, value);
243 addr = mmCRTCV_V_TOTAL;
244 value = dm_read_reg(ctx, addr);
250 dm_write_reg(ctx, addr, value);
252 addr = mmCRTCV_H_BLANK_START_END;
253 value = dm_read_reg(ctx, addr);
255 tmp = timing->h_total -
256 (h_sync_start + timing->h_border_left);
261 CRTCV_H_BLANK_START_END,
264 tmp = tmp + timing->h_addressable +
265 timing->h_border_left + timing->h_border_right;
270 CRTCV_H_BLANK_START_END,
273 dm_write_reg(ctx, addr, value);
275 addr = mmCRTCV_V_BLANK_START_END;
276 value = dm_read_reg(ctx, addr);
278 tmp = timing->v_total - (v_sync_start + timing->v_border_top);
283 CRTCV_V_BLANK_START_END,
286 tmp = tmp + timing->v_addressable + timing->v_border_top +
287 timing->v_border_bottom;
292 CRTCV_V_BLANK_START_END,
295 dm_write_reg(ctx, addr, value);
297 addr = mmCRTCV_H_SYNC_A;
301 timing->h_sync_width,
304 dm_write_reg(ctx, addr, value);
306 addr = mmCRTCV_H_SYNC_A_CNTL;
307 value = dm_read_reg(ctx, addr);
308 if (timing->flags.HSYNC_POSITIVE_POLARITY) {
321 dm_write_reg(ctx, addr, value);
323 addr = mmCRTCV_V_SYNC_A;
327 timing->v_sync_width,
330 dm_write_reg(ctx, addr, value);
332 addr = mmCRTCV_V_SYNC_A_CNTL;
333 value = dm_read_reg(ctx, addr);
334 if (timing->flags.VSYNC_POSITIVE_POLARITY) {
347 dm_write_reg(ctx, addr, value);
349 addr = mmCRTCV_INTERLACE_CONTROL;
350 value = dm_read_reg(ctx, addr);
353 timing->flags.INTERLACE,
354 CRTCV_INTERLACE_CONTROL,
355 CRTC_INTERLACE_ENABLE);
356 dm_write_reg(ctx, addr, value);
359 static void dce110_timing_generator_v_enable_advanced_request(
360 struct timing_generator *tg,
362 const struct dc_crtc_timing *timing)
364 uint32_t addr = mmCRTCV_START_LINE_CONTROL;
365 uint32_t value = dm_read_reg(tg->ctx, addr);
368 if ((timing->v_sync_width + timing->v_front_porch) <= 3) {
372 CRTCV_START_LINE_CONTROL,
373 CRTC_ADVANCED_START_LINE_POSITION);
378 CRTCV_START_LINE_CONTROL,
379 CRTC_ADVANCED_START_LINE_POSITION);
384 CRTCV_START_LINE_CONTROL,
385 CRTC_LEGACY_REQUESTOR_EN);
390 CRTCV_START_LINE_CONTROL,
391 CRTC_ADVANCED_START_LINE_POSITION);
395 CRTCV_START_LINE_CONTROL,
396 CRTC_LEGACY_REQUESTOR_EN);
399 dm_write_reg(tg->ctx, addr, value);
402 static void dce110_timing_generator_v_set_blank(struct timing_generator *tg,
403 bool enable_blanking)
406 dce110_timing_generator_v_blank_crtc(tg);
408 dce110_timing_generator_v_unblank_crtc(tg);
411 static void dce110_timing_generator_v_program_timing(struct timing_generator *tg,
412 const struct dc_crtc_timing *timing,
416 dce110_timing_generator_program_timing_generator(tg, timing);
418 dce110_timing_generator_v_program_blanking(tg, timing);
421 static void dce110_timing_generator_v_program_blank_color(
422 struct timing_generator *tg,
423 const struct tg_color *black_color)
425 uint32_t addr = mmCRTCV_BLACK_COLOR;
426 uint32_t value = dm_read_reg(tg->ctx, addr);
430 black_color->color_b_cb,
432 CRTC_BLACK_COLOR_B_CB);
435 black_color->color_g_y,
437 CRTC_BLACK_COLOR_G_Y);
440 black_color->color_r_cr,
442 CRTC_BLACK_COLOR_R_CR);
444 dm_write_reg(tg->ctx, addr, value);
447 static void dce110_timing_generator_v_set_overscan_color_black(
448 struct timing_generator *tg,
449 const struct tg_color *color)
451 struct dc_context *ctx = tg->ctx;
459 CRTC_OVERSCAN_COLOR_BLUE);
465 CRTC_OVERSCAN_COLOR_RED);
471 CRTC_OVERSCAN_COLOR_GREEN);
473 addr = mmCRTCV_OVERSCAN_COLOR;
474 dm_write_reg(ctx, addr, value);
475 addr = mmCRTCV_BLACK_COLOR;
476 dm_write_reg(ctx, addr, value);
477 /* This is desirable to have a constant DAC output voltage during the
478 * blank time that is higher than the 0 volt reference level that the
479 * DAC outputs when the NBLANK signal
480 * is asserted low, such as for output to an analog TV. */
481 addr = mmCRTCV_BLANK_DATA_COLOR;
482 dm_write_reg(ctx, addr, value);
484 /* TO DO we have to program EXT registers and we need to know LB DATA
485 * format because it is used when more 10 , i.e. 12 bits per color
487 * m_mmDxCRTC_OVERSCAN_COLOR_EXT
488 * m_mmDxCRTC_BLACK_COLOR_EXT
489 * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
493 static void dce110_tg_v_program_blank_color(struct timing_generator *tg,
494 const struct tg_color *black_color)
496 uint32_t addr = mmCRTCV_BLACK_COLOR;
497 uint32_t value = dm_read_reg(tg->ctx, addr);
501 black_color->color_b_cb,
503 CRTC_BLACK_COLOR_B_CB);
506 black_color->color_g_y,
508 CRTC_BLACK_COLOR_G_Y);
511 black_color->color_r_cr,
513 CRTC_BLACK_COLOR_R_CR);
515 dm_write_reg(tg->ctx, addr, value);
517 addr = mmCRTCV_BLANK_DATA_COLOR;
518 dm_write_reg(tg->ctx, addr, value);
521 static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg,
522 const struct tg_color *overscan_color)
524 struct dc_context *ctx = tg->ctx;
530 overscan_color->color_b_cb,
531 CRTCV_OVERSCAN_COLOR,
532 CRTC_OVERSCAN_COLOR_BLUE);
536 overscan_color->color_g_y,
537 CRTCV_OVERSCAN_COLOR,
538 CRTC_OVERSCAN_COLOR_GREEN);
542 overscan_color->color_r_cr,
543 CRTCV_OVERSCAN_COLOR,
544 CRTC_OVERSCAN_COLOR_RED);
546 addr = mmCRTCV_OVERSCAN_COLOR;
547 dm_write_reg(ctx, addr, value);
550 static void dce110_timing_generator_v_set_colors(struct timing_generator *tg,
551 const struct tg_color *blank_color,
552 const struct tg_color *overscan_color)
554 if (blank_color != NULL)
555 dce110_tg_v_program_blank_color(tg, blank_color);
556 if (overscan_color != NULL)
557 dce110_timing_generator_v_set_overscan_color(tg, overscan_color);
560 static void dce110_timing_generator_v_set_early_control(
561 struct timing_generator *tg,
565 uint32_t address = mmCRTC_CONTROL;
567 regval = dm_read_reg(tg->ctx, address);
568 set_reg_field_value(regval, early_cntl,
569 CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
570 dm_write_reg(tg->ctx, address, regval);
573 static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg)
575 uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT;
576 uint32_t value = dm_read_reg(tg->ctx, addr);
577 uint32_t field = get_reg_field_value(
578 value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
583 static bool dce110_timing_generator_v_did_triggered_reset_occur(
584 struct timing_generator *tg)
586 dm_logger_write(tg->ctx->logger, LOG_ERROR,
587 "Timing Sync not supported on underlay pipe\n");
591 static void dce110_timing_generator_v_setup_global_swap_lock(
592 struct timing_generator *tg,
593 const struct dcp_gsl_params *gsl_params)
595 dm_logger_write(tg->ctx->logger, LOG_ERROR,
596 "Timing Sync not supported on underlay pipe\n");
600 static void dce110_timing_generator_v_enable_reset_trigger(
601 struct timing_generator *tg,
604 dm_logger_write(tg->ctx->logger, LOG_ERROR,
605 "Timing Sync not supported on underlay pipe\n");
609 static void dce110_timing_generator_v_disable_reset_trigger(
610 struct timing_generator *tg)
612 dm_logger_write(tg->ctx->logger, LOG_ERROR,
613 "Timing Sync not supported on underlay pipe\n");
617 static void dce110_timing_generator_v_tear_down_global_swap_lock(
618 struct timing_generator *tg)
620 dm_logger_write(tg->ctx->logger, LOG_ERROR,
621 "Timing Sync not supported on underlay pipe\n");
625 static void dce110_timing_generator_v_disable_vga(
626 struct timing_generator *tg)
631 static bool dce110_tg_v_is_blanked(struct timing_generator *tg)
633 /* Signal comes from the primary pipe, underlay is never blanked. */
637 /** ********************************************************************************************
639 * DCE11 Timing Generator Constructor / Destructor
641 *********************************************************************************************/
642 static const struct timing_generator_funcs dce110_tg_v_funcs = {
643 .validate_timing = dce110_tg_validate_timing,
644 .program_timing = dce110_timing_generator_v_program_timing,
645 .enable_crtc = dce110_timing_generator_v_enable_crtc,
646 .disable_crtc = dce110_timing_generator_v_disable_crtc,
647 .is_counter_moving = dce110_timing_generator_v_is_counter_moving,
648 .get_position = NULL, /* Not to be implemented for underlay*/
649 .get_frame_count = dce110_timing_generator_v_get_vblank_counter,
650 .set_early_control = dce110_timing_generator_v_set_early_control,
651 .wait_for_state = dce110_timing_generator_v_wait_for_state,
652 .set_blank = dce110_timing_generator_v_set_blank,
653 .is_blanked = dce110_tg_v_is_blanked,
654 .set_colors = dce110_timing_generator_v_set_colors,
655 .set_overscan_blank_color =
656 dce110_timing_generator_v_set_overscan_color_black,
657 .set_blank_color = dce110_timing_generator_v_program_blank_color,
658 .disable_vga = dce110_timing_generator_v_disable_vga,
659 .did_triggered_reset_occur =
660 dce110_timing_generator_v_did_triggered_reset_occur,
661 .setup_global_swap_lock =
662 dce110_timing_generator_v_setup_global_swap_lock,
663 .enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger,
664 .disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger,
665 .tear_down_global_swap_lock =
666 dce110_timing_generator_v_tear_down_global_swap_lock,
667 .enable_advanced_request =
668 dce110_timing_generator_v_enable_advanced_request
671 void dce110_timing_generator_v_construct(
672 struct dce110_timing_generator *tg110,
673 struct dc_context *ctx)
675 tg110->controller_id = CONTROLLER_ID_UNDERLAY0;
677 tg110->base.funcs = &dce110_tg_v_funcs;
679 tg110->base.ctx = ctx;
680 tg110->base.bp = ctx->dc_bios;
682 tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
683 tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
685 tg110->min_h_blank = 56;
686 tg110->min_h_front_porch = 4;
687 tg110->min_h_back_porch = 4;