From 7da2abf1b61ca0b039d2d1683aff6cef8f086934 Mon Sep 17 00:00:00 2001 From: Eric Yang Date: Wed, 3 Feb 2016 16:13:11 -0500 Subject: [PATCH 0778/1110] drm/amd/dal: Add timing generator for underlay pipe Signed-off-by: Eric Yang Acked-by: Jordan Lazare --- .../amd/dal/dc/dce110/dce110_timing_generator.c | 2 +- .../amd/dal/dc/dce110/dce110_timing_generator.h | 3 + .../amd/dal/dc/dce110/dce110_timing_generator_v.c | 785 +++++++++++++++++++++ .../amd/dal/dc/dce110/dce110_timing_generator_v.h | 34 + 4 files changed, 823 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.c create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.h diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c index d7cdd91..8fb90c0 100644 --- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c @@ -190,7 +190,7 @@ static void dce110_timing_generator_apply_front_porch_workaround( } } -static void dce110_timing_generator_color_space_to_black_color( +void dce110_timing_generator_color_space_to_black_color( enum color_space colorspace, struct crtc_black_color *black_color) { diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h index 163fadd..3579736 100644 --- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h +++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h @@ -175,6 +175,9 @@ void dce110_timing_generator_program_blank_color( void dce110_timing_generator_set_overscan_color_black( struct timing_generator *tg, enum color_space black_color); +void dce110_timing_generator_color_space_to_black_color( + enum color_space colorspace, + struct crtc_black_color *black_color); /*************** End-of-move ********************/ diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.c new file mode 100644 index 0000000..722f636 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.c @@ -0,0 +1,785 @@ + + +#include "dm_services.h" + +/* include DCE11 register header files */ +#include "dce/dce_11_0_d.h" +#include "dce/dce_11_0_sh_mask.h" + +#include "dc_types.h" +#include "dc_bios_types.h" + +#include "include/grph_object_id.h" +#include "include/adapter_service_interface.h" +#include "include/logger_interface.h" +#include "dce110_timing_generator.h" +#include "dce110_timing_generator_v.h" + +#include "../inc/timing_generator.h" + + +/** ******************************************************************************** + * + * DCE11 Timing Generator Implementation + * + **********************************************************************************/ + +/** +* Enable CRTCV +*/ + +static bool dce110_timing_generator_v_enable_crtc(struct timing_generator *tg) +{ + /* + * Set MASTER_UPDATE_MODE to 0 + * This is needed for DRR, and also suggested to be default value by Syed. + */ + + uint32_t value; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + value = dm_read_reg(tg->ctx, + mmCRTCV_MASTER_UPDATE_MODE); + set_reg_field_value(value, 0, + CRTCV_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE); + dm_write_reg(tg->ctx, + mmCRTCV_MASTER_UPDATE_MODE, value); + + value = dm_read_reg(tg->ctx, + mmCRTCV_MASTER_EN); + set_reg_field_value(value, 1, + CRTCV_MASTER_EN, CRTC_MASTER_EN); + dm_write_reg(tg->ctx, + mmCRTCV_MASTER_EN, value); + + return true; +} + +static bool dce110_timing_generator_v_disable_crtc(struct timing_generator *tg) +{ + uint32_t value; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + value = dm_read_reg(tg->ctx, + mmCRTCV_CONTROL); + set_reg_field_value(value, 0, + CRTCV_CONTROL, CRTC_DISABLE_POINT_CNTL); + set_reg_field_value(value, 0, + CRTCV_CONTROL, CRTC_MASTER_EN); + dm_write_reg(tg->ctx, + mmCRTCV_CONTROL, value); + /* + * TODO: call this when adding stereo support + * tg->funcs->disable_stereo(tg); + */ + return true; +} + +static bool dce110_timing_generator_v_blank_crtc(struct timing_generator *tg) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = mmCRTCV_BLANK_CONTROL; + uint32_t value = dm_read_reg(tg->ctx, addr); + uint8_t counter = 100; + + set_reg_field_value( + value, + 1, + CRTCV_BLANK_CONTROL, + CRTC_BLANK_DATA_EN); + + set_reg_field_value( + value, + 1, + CRTCV_BLANK_CONTROL, + CRTC_BLANK_DE_MODE); + + dm_write_reg(tg->ctx, addr, value); + + while (counter > 0) { + value = dm_read_reg(tg->ctx, addr); + + if (get_reg_field_value( + value, + CRTCV_BLANK_CONTROL, + CRTC_BLANK_DATA_EN) == 1 && + get_reg_field_value( + value, + CRTCV_BLANK_CONTROL, + CRTC_CURRENT_BLANK_STATE) == 1) + break; + + dm_sleep_in_milliseconds(tg->ctx, 1); + counter--; + } + + if (!counter) { + dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_CONTROLLER, + "timing generator %d blank timing out.\n", + tg110->controller_id); + return false; + } + + return true; +} + +static bool dce110_timing_generator_v_unblank_crtc(struct timing_generator *tg) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = mmCRTCV_BLANK_CONTROL; + uint32_t value = dm_read_reg(tg->ctx, addr); + + set_reg_field_value( + value, + 0, + CRTCV_BLANK_CONTROL, + CRTC_BLANK_DATA_EN); + + set_reg_field_value( + value, + 0, + CRTCV_BLANK_CONTROL, + CRTC_BLANK_DE_MODE); + + dm_write_reg(tg->ctx, addr, value); + + return true; +} + +static bool dce110_timing_generator_v_is_in_vertical_blank( + struct timing_generator *tg) +{ + uint32_t addr = 0; + uint32_t value = 0; + uint32_t field = 0; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + addr = mmCRTCV_STATUS; + value = dm_read_reg(tg->ctx, addr); + field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK); + return field == 1; +} + +static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg) +{ + uint32_t value; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + uint32_t h1 = 0; + uint32_t h2 = 0; + uint32_t v1 = 0; + uint32_t v2 = 0; + + value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION); + + h1 = get_reg_field_value( + value, + CRTCV_STATUS_POSITION, + CRTC_HORZ_COUNT); + + v1 = get_reg_field_value( + value, + CRTCV_STATUS_POSITION, + CRTC_VERT_COUNT); + + value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION); + + h2 = get_reg_field_value( + value, + CRTCV_STATUS_POSITION, + CRTC_HORZ_COUNT); + + v2 = get_reg_field_value( + value, + CRTCV_STATUS_POSITION, + CRTC_VERT_COUNT); + + if (h1 == h2 && v1 == v2) + return false; + else + return true; +} + +static void dce110_timing_generator_v_wait_for_vblank(struct timing_generator *tg) +{ + /* We want to catch beginning of VBlank here, so if the first try are + * in VBlank, we might be very close to Active, in this case wait for + * another frame + */ + while (dce110_timing_generator_v_is_in_vertical_blank(tg)) { + if (!dce110_timing_generator_v_is_counter_moving(tg)) { + /* error - no point to wait if counter is not moving */ + break; + } + } + + while (!dce110_timing_generator_v_is_in_vertical_blank(tg)) { + if (!dce110_timing_generator_v_is_counter_moving(tg)) { + /* error - no point to wait if counter is not moving */ + break; + } + } +} + +/** +* Wait till we are in VActive (anywhere in VActive) +*/ +static void dce110_timing_generator_v_wait_for_vactive(struct timing_generator *tg) +{ + while (dce110_timing_generator_v_is_in_vertical_blank(tg)) { + if (!dce110_timing_generator_v_is_counter_moving(tg)) { + /* error - no point to wait if counter is not moving */ + break; + } + } +} + +static void dce110_timing_generator_v_wait_for_state(struct timing_generator *tg, + enum crtc_state state) +{ + switch (state) { + case CRTC_STATE_VBLANK: + dce110_timing_generator_v_wait_for_vblank(tg); + break; + + case CRTC_STATE_VACTIVE: + dce110_timing_generator_v_wait_for_vactive(tg); + break; + + default: + break; + } +} + +static void dce110_timing_generator_v_program_blanking( + struct timing_generator *tg, + const struct dc_crtc_timing *timing) +{ + uint32_t vsync_offset = timing->v_border_bottom + + timing->v_front_porch; + uint32_t v_sync_start = timing->v_addressable + vsync_offset; + + uint32_t hsync_offset = timing->h_border_right + + timing->h_front_porch; + uint32_t h_sync_start = timing->h_addressable + hsync_offset; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + struct dc_context *ctx = tg->ctx; + uint32_t value = 0; + uint32_t addr = 0; + uint32_t tmp = 0; + + addr = mmCRTCV_H_TOTAL; + value = dm_read_reg(ctx, addr); + set_reg_field_value( + value, + timing->h_total - 1, + CRTCV_H_TOTAL, + CRTC_H_TOTAL); + dm_write_reg(ctx, addr, value); + + addr = mmCRTCV_V_TOTAL; + value = dm_read_reg(ctx, addr); + set_reg_field_value( + value, + timing->v_total - 1, + CRTCV_V_TOTAL, + CRTC_V_TOTAL); + dm_write_reg(ctx, addr, value); + + addr = mmCRTCV_H_BLANK_START_END; + value = dm_read_reg(ctx, addr); + + tmp = timing->h_total - + (h_sync_start + timing->h_border_left); + + set_reg_field_value( + value, + tmp, + CRTCV_H_BLANK_START_END, + CRTC_H_BLANK_END); + + tmp = tmp + timing->h_addressable + + timing->h_border_left + timing->h_border_right; + + set_reg_field_value( + value, + tmp, + CRTCV_H_BLANK_START_END, + CRTC_H_BLANK_START); + + dm_write_reg(ctx, addr, value); + + addr = mmCRTCV_V_BLANK_START_END; + value = dm_read_reg(ctx, addr); + + tmp = timing->v_total - (v_sync_start + timing->v_border_top); + + set_reg_field_value( + value, + tmp, + CRTCV_V_BLANK_START_END, + CRTC_V_BLANK_END); + + tmp = tmp + timing->v_addressable + timing->v_border_top + + timing->v_border_bottom; + + set_reg_field_value( + value, + tmp, + CRTCV_V_BLANK_START_END, + CRTC_V_BLANK_START); + + dm_write_reg(ctx, addr, value); +} + +static void dce110_timing_generator_v_enable_advanced_request( + struct timing_generator *tg, + bool enable, + const struct dc_crtc_timing *timing) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = mmCRTCV_START_LINE_CONTROL; + uint32_t value = dm_read_reg(tg->ctx, addr); + + if (enable) { + if ((timing->v_sync_width + timing->v_front_porch) <= 3) { + set_reg_field_value( + value, + 3, + CRTCV_START_LINE_CONTROL, + CRTC_ADVANCED_START_LINE_POSITION); + } else { + set_reg_field_value( + value, + 4, + CRTCV_START_LINE_CONTROL, + CRTC_ADVANCED_START_LINE_POSITION); + } + set_reg_field_value( + value, + 0, + CRTCV_START_LINE_CONTROL, + CRTC_LEGACY_REQUESTOR_EN); + } else { + set_reg_field_value( + value, + 2, + CRTCV_START_LINE_CONTROL, + CRTC_ADVANCED_START_LINE_POSITION); + set_reg_field_value( + value, + 1, + CRTCV_START_LINE_CONTROL, + CRTC_LEGACY_REQUESTOR_EN); + } + + dm_write_reg(tg->ctx, addr, value); +} + +static bool dce110_timing_generator_v_set_blank(struct timing_generator *tg, + bool enable_blanking) +{ + if (enable_blanking) + return dce110_timing_generator_v_blank_crtc(tg); + else + return dce110_timing_generator_v_unblank_crtc(tg); +} + +static void dce110_timing_generator_v_program_timing(struct timing_generator *tg, + const struct dc_crtc_timing *timing, + bool use_vbios) +{ + if (use_vbios) + dce110_timing_generator_program_timing_generator(tg, timing); + else + dce110_timing_generator_v_program_blanking(tg, timing); +} + +static void dce110_timing_generator_v_program_blank_color( + struct timing_generator *tg, + enum color_space color_space) +{ + struct crtc_black_color black_color; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = mmCRTCV_BLACK_COLOR; + uint32_t value = dm_read_reg(tg->ctx, addr); + + dce110_timing_generator_color_space_to_black_color( + color_space, + &black_color); + + set_reg_field_value( + value, + black_color.black_color_b_cb, + CRTCV_BLACK_COLOR, + CRTC_BLACK_COLOR_B_CB); + set_reg_field_value( + value, + black_color.black_color_g_y, + CRTCV_BLACK_COLOR, + CRTC_BLACK_COLOR_G_Y); + set_reg_field_value( + value, + black_color.black_color_r_cr, + CRTCV_BLACK_COLOR, + CRTC_BLACK_COLOR_R_CR); + + dm_write_reg(tg->ctx, addr, value); +} + +static void dce110_timing_generator_v_set_overscan_color_black( + struct timing_generator *tg, + enum color_space black_color) +{ + struct dc_context *ctx = tg->ctx; + uint32_t value = 0; + uint32_t addr; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + /* Overscan Color for YUV display modes: + * to achieve a black color for both the explicit and implicit overscan, + * the overscan color registers should be programmed to: */ + + switch (black_color) { + case COLOR_SPACE_YPBPR601: + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4TV, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_BLUE); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4TV, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_GREEN); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4TV, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_RED); + break; + + case COLOR_SPACE_YPBPR709: + case COLOR_SPACE_YCBCR601: + case COLOR_SPACE_YCBCR709: + case COLOR_SPACE_YCBCR601_YONLY: + case COLOR_SPACE_YCBCR709_YONLY: + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4CV, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_BLUE); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4TV, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_GREEN); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4CV, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_RED); + break; + + case COLOR_SPACE_N_MVPU_SUPER_AA: + /* In crossfire SuperAA mode, the slave overscan data is forced + * to 0 in the pixel mixer on the master. As a result, we need + * to adjust the blank color so that after blending the + * master+slave, it will appear black */ + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4SUPERAA, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_BLUE); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4SUPERAA, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_GREEN); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4SUPERAA, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_RED); + break; + + case COLOR_SPACE_SRGB_LIMITED_RANGE: + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_RGB_LIMITED_RANGE, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_BLUE); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_RGB_LIMITED_RANGE, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_GREEN); + + set_reg_field_value( + value, + CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_RGB_LIMITED_RANGE, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_RED); + break; + + default: + /* default is sRGB black 0. */ + break; + } + addr = mmCRTCV_OVERSCAN_COLOR; + dm_write_reg(ctx, addr, value); + addr = mmCRTCV_BLACK_COLOR; + dm_write_reg(ctx, addr, value); + /* This is desirable to have a constant DAC output voltage during the + * blank time that is higher than the 0 volt reference level that the + * DAC outputs when the NBLANK signal + * is asserted low, such as for output to an analog TV. */ + addr = mmCRTCV_BLANK_DATA_COLOR; + dm_write_reg(ctx, addr, value); + + /* TO DO we have to program EXT registers and we need to know LB DATA + * format because it is used when more 10 , i.e. 12 bits per color + * + * m_mmDxCRTC_OVERSCAN_COLOR_EXT + * m_mmDxCRTC_BLACK_COLOR_EXT + * m_mmDxCRTC_BLANK_DATA_COLOR_EXT + */ + +} + +static void dce110_tg_v_program_blank_color(struct timing_generator *tg, + const struct crtc_black_color *black_color) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = mmCRTCV_BLACK_COLOR; + uint32_t value = dm_read_reg(tg->ctx, addr); + + set_reg_field_value( + value, + black_color->black_color_b_cb, + CRTCV_BLACK_COLOR, + CRTC_BLACK_COLOR_B_CB); + set_reg_field_value( + value, + black_color->black_color_g_y, + CRTCV_BLACK_COLOR, + CRTC_BLACK_COLOR_G_Y); + set_reg_field_value( + value, + black_color->black_color_r_cr, + CRTCV_BLACK_COLOR, + CRTC_BLACK_COLOR_R_CR); + + dm_write_reg(tg->ctx, addr, value); + + addr = mmCRTCV_BLANK_DATA_COLOR; + dm_write_reg(tg->ctx, addr, value); +} + +static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg, + const struct crtc_black_color *overscan_color) +{ + struct dc_context *ctx = tg->ctx; + uint32_t value = 0; + uint32_t addr; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + set_reg_field_value( + value, + overscan_color->black_color_b_cb, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_BLUE); + + set_reg_field_value( + value, + overscan_color->black_color_g_y, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_GREEN); + + set_reg_field_value( + value, + overscan_color->black_color_r_cr, + CRTCV_OVERSCAN_COLOR, + CRTC_OVERSCAN_COLOR_RED); + + addr = mmCRTCV_OVERSCAN_COLOR; + dm_write_reg(ctx, addr, value); +} + +static void dce110_timing_generator_v_set_colors(struct timing_generator *tg, + const struct crtc_black_color *blank_color, + const struct crtc_black_color *overscan_color) +{ + if (blank_color != NULL) + dce110_tg_v_program_blank_color(tg, blank_color); + if (overscan_color != NULL) + dce110_timing_generator_v_set_overscan_color(tg, overscan_color); +} + + +static void dce110_timing_generator_v_set_early_control( + struct timing_generator *tg, + uint32_t early_cntl) +{ + uint32_t regval; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t address = mmCRTC_CONTROL; + + regval = dm_read_reg(tg->ctx, address); + set_reg_field_value(regval, early_cntl, + CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL); + dm_write_reg(tg->ctx, address, regval); +} + +static void dce110_timing_generator_v_get_crtc_positions( + struct timing_generator *tg, + int32_t *h_position, + int32_t *v_position) +{ + uint32_t value; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION); + + *h_position = get_reg_field_value( + value, + CRTCV_STATUS_POSITION, + CRTC_HORZ_COUNT); + + *v_position = get_reg_field_value( + value, + CRTCV_STATUS_POSITION, + CRTC_VERT_COUNT); +} + +static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg) +{ + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT; + uint32_t value = dm_read_reg(tg->ctx, addr); + uint32_t field = get_reg_field_value( + value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT); + + return field; +} + +static bool dce110_timing_generator_v_did_triggered_reset_occur( + struct timing_generator *tg) +{ + dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_CONTROLLER, + "Timing Sync not supported on underlay pipe\n"); + return false; +} + +static void dce110_timing_generator_v_setup_global_swap_lock( + struct timing_generator *tg, + const struct dcp_gsl_params *gsl_params) +{ + dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_CONTROLLER, + "Timing Sync not supported on underlay pipe\n"); + return; +} + +static void dce110_timing_generator_v_enable_reset_trigger( + struct timing_generator *tg, + const struct trigger_params *trigger_params) +{ + dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_CONTROLLER, + "Timing Sync not supported on underlay pipe\n"); + return; +} + +static void dce110_timing_generator_v_disable_reset_trigger( + struct timing_generator *tg) +{ + dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_CONTROLLER, + "Timing Sync not supported on underlay pipe\n"); + return; +} + +static void dce110_timing_generator_v_tear_down_global_swap_lock( + struct timing_generator *tg) +{ + dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_CONTROLLER, + "Timing Sync not supported on underlay pipe\n"); + return; +} + +static void dce110_timing_generator_v_disable_vga( + struct timing_generator *tg) +{ + return; +} +/** ******************************************************************************************** + * + * DCE11 Timing Generator Constructor / Destructor + * + *********************************************************************************************/ +static struct timing_generator_funcs dce110_tg_v_funcs = { + .validate_timing = dce110_tg_validate_timing, + .program_timing = dce110_timing_generator_v_program_timing, + .enable_crtc = dce110_timing_generator_v_enable_crtc, + .disable_crtc = dce110_timing_generator_v_disable_crtc, + .is_counter_moving = dce110_timing_generator_v_is_counter_moving, + .get_position = dce110_timing_generator_v_get_crtc_positions, + .get_frame_count = dce110_timing_generator_v_get_vblank_counter, + .set_early_control = dce110_timing_generator_v_set_early_control, + .wait_for_state = dce110_timing_generator_v_wait_for_state, + .set_blank = dce110_timing_generator_v_set_blank, + .set_colors = dce110_timing_generator_v_set_colors, + .set_overscan_blank_color = + dce110_timing_generator_v_set_overscan_color_black, + .set_blank_color = dce110_timing_generator_v_program_blank_color, + .disable_vga = dce110_timing_generator_v_disable_vga, + .did_triggered_reset_occur = + dce110_timing_generator_v_did_triggered_reset_occur, + .setup_global_swap_lock = + dce110_timing_generator_v_setup_global_swap_lock, + .enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger, + .disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger, + .tear_down_global_swap_lock = + dce110_timing_generator_v_tear_down_global_swap_lock, + .enable_advanced_request = + dce110_timing_generator_v_enable_advanced_request +}; + +bool dce110_timing_generator_v_construct( + struct dce110_timing_generator *tg110, + struct adapter_service *as, + struct dc_context *ctx) +{ + if (!tg110) + return false; + + if (!as) + return false; + + tg110->controller_id = CONTROLLER_ID_UNDERLAY0; + + tg110->base.funcs = &dce110_tg_v_funcs; + + tg110->base.ctx = ctx; + tg110->base.bp = dal_adapter_service_get_bios_parser(as); + + tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; + tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; + + tg110->min_h_blank = 56; + tg110->min_h_front_porch = 4; + tg110->min_h_back_porch = 4; + + return true; +} diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.h new file mode 100644 index 0000000..fe3fb81 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator_v.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_TIMING_GENERATOR_V_DCE110_H__ +#define __DC_TIMING_GENERATOR_V_DCE110_H__ + +bool dce110_timing_generator_v_construct( + struct dce110_timing_generator *tg110, + struct adapter_service *as, + struct dc_context *ctx); + +#endif /* __DC_TIMING_GENERATOR_V_DCE110_H__ */ -- 2.7.4