2 * Copyright 2017 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
24 #include "dm_services.h"
26 /* include DCE11 register header files */
27 #include "dce/dce_11_0_d.h"
28 #include "dce/dce_11_0_sh_mask.h"
31 #include "dc_bios_types.h"
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"
39 #include "timing_generator.h"
43 /** ********************************************************************************
45 * DCE11 Timing Generator Implementation
47 **********************************************************************************/
53 static bool dce110_timing_generator_v_enable_crtc(struct timing_generator *tg)
56 * Set MASTER_UPDATE_MODE to 0
57 * This is needed for DRR, and also suggested to be default value by Syed.
63 set_reg_field_value(value, 0,
64 CRTCV_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE);
66 mmCRTCV_MASTER_UPDATE_MODE, value);
68 /* TODO: may want this on for looking for underflow */
70 dm_write_reg(tg->ctx, mmCRTCV_MASTER_UPDATE_MODE, value);
73 set_reg_field_value(value, 1,
74 CRTCV_MASTER_EN, CRTC_MASTER_EN);
76 mmCRTCV_MASTER_EN, value);
81 static bool dce110_timing_generator_v_disable_crtc(struct timing_generator *tg)
85 value = dm_read_reg(tg->ctx,
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);
92 mmCRTCV_CONTROL, value);
94 * TODO: call this when adding stereo support
95 * tg->funcs->disable_stereo(tg);
100 static void dce110_timing_generator_v_blank_crtc(struct timing_generator *tg)
102 uint32_t addr = mmCRTCV_BLANK_CONTROL;
103 uint32_t value = dm_read_reg(tg->ctx, addr);
117 dm_write_reg(tg->ctx, addr, value);
120 static void dce110_timing_generator_v_unblank_crtc(struct timing_generator *tg)
122 uint32_t addr = mmCRTCV_BLANK_CONTROL;
123 uint32_t value = dm_read_reg(tg->ctx, addr);
137 dm_write_reg(tg->ctx, addr, value);
140 static bool dce110_timing_generator_v_is_in_vertical_blank(
141 struct timing_generator *tg)
147 addr = mmCRTCV_STATUS;
148 value = dm_read_reg(tg->ctx, addr);
149 field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK);
153 static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg)
161 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
163 h1 = get_reg_field_value(
165 CRTCV_STATUS_POSITION,
168 v1 = get_reg_field_value(
170 CRTCV_STATUS_POSITION,
173 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
175 h2 = get_reg_field_value(
177 CRTCV_STATUS_POSITION,
180 v2 = get_reg_field_value(
182 CRTCV_STATUS_POSITION,
185 if (h1 == h2 && v1 == v2)
191 static void dce110_timing_generator_v_wait_for_vblank(struct timing_generator *tg)
193 /* We want to catch beginning of VBlank here, so if the first try are
194 * in VBlank, we might be very close to Active, in this case wait for
197 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
198 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
199 /* error - no point to wait if counter is not moving */
204 while (!dce110_timing_generator_v_is_in_vertical_blank(tg)) {
205 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
206 /* error - no point to wait if counter is not moving */
213 * Wait till we are in VActive (anywhere in VActive)
215 static void dce110_timing_generator_v_wait_for_vactive(struct timing_generator *tg)
217 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
218 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
219 /* error - no point to wait if counter is not moving */
225 static void dce110_timing_generator_v_wait_for_state(struct timing_generator *tg,
226 enum crtc_state state)
229 case CRTC_STATE_VBLANK:
230 dce110_timing_generator_v_wait_for_vblank(tg);
233 case CRTC_STATE_VACTIVE:
234 dce110_timing_generator_v_wait_for_vactive(tg);
242 static void dce110_timing_generator_v_program_blanking(
243 struct timing_generator *tg,
244 const struct dc_crtc_timing *timing)
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;
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;
254 struct dc_context *ctx = tg->ctx;
259 addr = mmCRTCV_H_TOTAL;
260 value = dm_read_reg(ctx, addr);
266 dm_write_reg(ctx, addr, value);
268 addr = mmCRTCV_V_TOTAL;
269 value = dm_read_reg(ctx, addr);
275 dm_write_reg(ctx, addr, value);
277 addr = mmCRTCV_H_BLANK_START_END;
278 value = dm_read_reg(ctx, addr);
280 tmp = timing->h_total -
281 (h_sync_start + timing->h_border_left);
286 CRTCV_H_BLANK_START_END,
289 tmp = tmp + timing->h_addressable +
290 timing->h_border_left + timing->h_border_right;
295 CRTCV_H_BLANK_START_END,
298 dm_write_reg(ctx, addr, value);
300 addr = mmCRTCV_V_BLANK_START_END;
301 value = dm_read_reg(ctx, addr);
303 tmp = timing->v_total - (v_sync_start + timing->v_border_top);
308 CRTCV_V_BLANK_START_END,
311 tmp = tmp + timing->v_addressable + timing->v_border_top +
312 timing->v_border_bottom;
317 CRTCV_V_BLANK_START_END,
320 dm_write_reg(ctx, addr, value);
322 addr = mmCRTCV_H_SYNC_A;
326 timing->h_sync_width,
329 dm_write_reg(ctx, addr, value);
331 addr = mmCRTCV_H_SYNC_A_CNTL;
332 value = dm_read_reg(ctx, addr);
333 if (timing->flags.HSYNC_POSITIVE_POLARITY) {
346 dm_write_reg(ctx, addr, value);
348 addr = mmCRTCV_V_SYNC_A;
352 timing->v_sync_width,
355 dm_write_reg(ctx, addr, value);
357 addr = mmCRTCV_V_SYNC_A_CNTL;
358 value = dm_read_reg(ctx, addr);
359 if (timing->flags.VSYNC_POSITIVE_POLARITY) {
372 dm_write_reg(ctx, addr, value);
374 addr = mmCRTCV_INTERLACE_CONTROL;
375 value = dm_read_reg(ctx, addr);
378 timing->flags.INTERLACE,
379 CRTCV_INTERLACE_CONTROL,
380 CRTC_INTERLACE_ENABLE);
381 dm_write_reg(ctx, addr, value);
384 static void dce110_timing_generator_v_enable_advanced_request(
385 struct timing_generator *tg,
387 const struct dc_crtc_timing *timing)
389 uint32_t addr = mmCRTCV_START_LINE_CONTROL;
390 uint32_t value = dm_read_reg(tg->ctx, addr);
393 if ((timing->v_sync_width + timing->v_front_porch) <= 3) {
397 CRTCV_START_LINE_CONTROL,
398 CRTC_ADVANCED_START_LINE_POSITION);
403 CRTCV_START_LINE_CONTROL,
404 CRTC_ADVANCED_START_LINE_POSITION);
409 CRTCV_START_LINE_CONTROL,
410 CRTC_LEGACY_REQUESTOR_EN);
415 CRTCV_START_LINE_CONTROL,
416 CRTC_ADVANCED_START_LINE_POSITION);
420 CRTCV_START_LINE_CONTROL,
421 CRTC_LEGACY_REQUESTOR_EN);
424 dm_write_reg(tg->ctx, addr, value);
427 static void dce110_timing_generator_v_set_blank(struct timing_generator *tg,
428 bool enable_blanking)
431 dce110_timing_generator_v_blank_crtc(tg);
433 dce110_timing_generator_v_unblank_crtc(tg);
436 static void dce110_timing_generator_v_program_timing(struct timing_generator *tg,
437 const struct dc_crtc_timing *timing,
441 dce110_timing_generator_program_timing_generator(tg, timing);
443 dce110_timing_generator_v_program_blanking(tg, timing);
446 static void dce110_timing_generator_v_program_blank_color(
447 struct timing_generator *tg,
448 const struct tg_color *black_color)
450 uint32_t addr = mmCRTCV_BLACK_COLOR;
451 uint32_t value = dm_read_reg(tg->ctx, addr);
455 black_color->color_b_cb,
457 CRTC_BLACK_COLOR_B_CB);
460 black_color->color_g_y,
462 CRTC_BLACK_COLOR_G_Y);
465 black_color->color_r_cr,
467 CRTC_BLACK_COLOR_R_CR);
469 dm_write_reg(tg->ctx, addr, value);
472 static void dce110_timing_generator_v_set_overscan_color_black(
473 struct timing_generator *tg,
474 const struct tg_color *color)
476 struct dc_context *ctx = tg->ctx;
484 CRTC_OVERSCAN_COLOR_BLUE);
490 CRTC_OVERSCAN_COLOR_RED);
496 CRTC_OVERSCAN_COLOR_GREEN);
498 addr = mmCRTCV_OVERSCAN_COLOR;
499 dm_write_reg(ctx, addr, value);
500 addr = mmCRTCV_BLACK_COLOR;
501 dm_write_reg(ctx, addr, value);
502 /* This is desirable to have a constant DAC output voltage during the
503 * blank time that is higher than the 0 volt reference level that the
504 * DAC outputs when the NBLANK signal
505 * is asserted low, such as for output to an analog TV. */
506 addr = mmCRTCV_BLANK_DATA_COLOR;
507 dm_write_reg(ctx, addr, value);
509 /* TO DO we have to program EXT registers and we need to know LB DATA
510 * format because it is used when more 10 , i.e. 12 bits per color
512 * m_mmDxCRTC_OVERSCAN_COLOR_EXT
513 * m_mmDxCRTC_BLACK_COLOR_EXT
514 * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
518 static void dce110_tg_v_program_blank_color(struct timing_generator *tg,
519 const struct tg_color *black_color)
521 uint32_t addr = mmCRTCV_BLACK_COLOR;
522 uint32_t value = dm_read_reg(tg->ctx, addr);
526 black_color->color_b_cb,
528 CRTC_BLACK_COLOR_B_CB);
531 black_color->color_g_y,
533 CRTC_BLACK_COLOR_G_Y);
536 black_color->color_r_cr,
538 CRTC_BLACK_COLOR_R_CR);
540 dm_write_reg(tg->ctx, addr, value);
542 addr = mmCRTCV_BLANK_DATA_COLOR;
543 dm_write_reg(tg->ctx, addr, value);
546 static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg,
547 const struct tg_color *overscan_color)
549 struct dc_context *ctx = tg->ctx;
555 overscan_color->color_b_cb,
556 CRTCV_OVERSCAN_COLOR,
557 CRTC_OVERSCAN_COLOR_BLUE);
561 overscan_color->color_g_y,
562 CRTCV_OVERSCAN_COLOR,
563 CRTC_OVERSCAN_COLOR_GREEN);
567 overscan_color->color_r_cr,
568 CRTCV_OVERSCAN_COLOR,
569 CRTC_OVERSCAN_COLOR_RED);
571 addr = mmCRTCV_OVERSCAN_COLOR;
572 dm_write_reg(ctx, addr, value);
575 static void dce110_timing_generator_v_set_colors(struct timing_generator *tg,
576 const struct tg_color *blank_color,
577 const struct tg_color *overscan_color)
579 if (blank_color != NULL)
580 dce110_tg_v_program_blank_color(tg, blank_color);
581 if (overscan_color != NULL)
582 dce110_timing_generator_v_set_overscan_color(tg, overscan_color);
585 static void dce110_timing_generator_v_set_early_control(
586 struct timing_generator *tg,
590 uint32_t address = mmCRTC_CONTROL;
592 regval = dm_read_reg(tg->ctx, address);
593 set_reg_field_value(regval, early_cntl,
594 CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
595 dm_write_reg(tg->ctx, address, regval);
598 static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg)
600 uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT;
601 uint32_t value = dm_read_reg(tg->ctx, addr);
602 uint32_t field = get_reg_field_value(
603 value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
608 static bool dce110_timing_generator_v_did_triggered_reset_occur(
609 struct timing_generator *tg)
611 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
615 static void dce110_timing_generator_v_setup_global_swap_lock(
616 struct timing_generator *tg,
617 const struct dcp_gsl_params *gsl_params)
619 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
623 static void dce110_timing_generator_v_enable_reset_trigger(
624 struct timing_generator *tg,
627 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
631 static void dce110_timing_generator_v_disable_reset_trigger(
632 struct timing_generator *tg)
634 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
638 static void dce110_timing_generator_v_tear_down_global_swap_lock(
639 struct timing_generator *tg)
641 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
645 static void dce110_timing_generator_v_disable_vga(
646 struct timing_generator *tg)
651 static bool dce110_tg_v_is_blanked(struct timing_generator *tg)
653 /* Signal comes from the primary pipe, underlay is never blanked. */
657 /** ********************************************************************************************
659 * DCE11 Timing Generator Constructor / Destructor
661 *********************************************************************************************/
662 static const struct timing_generator_funcs dce110_tg_v_funcs = {
663 .validate_timing = dce110_tg_validate_timing,
664 .program_timing = dce110_timing_generator_v_program_timing,
665 .enable_crtc = dce110_timing_generator_v_enable_crtc,
666 .disable_crtc = dce110_timing_generator_v_disable_crtc,
667 .is_counter_moving = dce110_timing_generator_v_is_counter_moving,
668 .get_position = NULL, /* Not to be implemented for underlay*/
669 .get_frame_count = dce110_timing_generator_v_get_vblank_counter,
670 .set_early_control = dce110_timing_generator_v_set_early_control,
671 .wait_for_state = dce110_timing_generator_v_wait_for_state,
672 .set_blank = dce110_timing_generator_v_set_blank,
673 .is_blanked = dce110_tg_v_is_blanked,
674 .set_colors = dce110_timing_generator_v_set_colors,
675 .set_overscan_blank_color =
676 dce110_timing_generator_v_set_overscan_color_black,
677 .set_blank_color = dce110_timing_generator_v_program_blank_color,
678 .disable_vga = dce110_timing_generator_v_disable_vga,
679 .did_triggered_reset_occur =
680 dce110_timing_generator_v_did_triggered_reset_occur,
681 .setup_global_swap_lock =
682 dce110_timing_generator_v_setup_global_swap_lock,
683 .enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger,
684 .disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger,
685 .tear_down_global_swap_lock =
686 dce110_timing_generator_v_tear_down_global_swap_lock,
687 .enable_advanced_request =
688 dce110_timing_generator_v_enable_advanced_request
691 void dce110_timing_generator_v_construct(
692 struct dce110_timing_generator *tg110,
693 struct dc_context *ctx)
695 tg110->controller_id = CONTROLLER_ID_UNDERLAY0;
697 tg110->base.funcs = &dce110_tg_v_funcs;
699 tg110->base.ctx = ctx;
700 tg110->base.bp = ctx->dc_bios;
702 tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
703 tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
705 tg110->min_h_blank = 56;
706 tg110->min_h_front_porch = 4;
707 tg110->min_h_back_porch = 4;