From 299c146ed1e01dc2cdcaf6ffad39b9a7c4f3b443 Mon Sep 17 00:00:00 2001 From: Yongqiang Sun Date: Wed, 23 Dec 2015 09:06:00 -0500 Subject: [PATCH 1211/1565] drm/amd/dal: Refactor timing generator, fix set_early_control bug. In case of non-DP panel, early_control need to be 0. Change-Id: I9e12f39f87893031d80203e6b81760fb79fb6e19 Signed-off-by: Yongqiang Sun Acked-by: Jordan Lazare --- drivers/gpu/drm/amd/dal/dc/core/dc_link.c | 6 +- .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c | 6 +- .../drm/amd/dal/dc/dce110/dce110_link_encoder.c | 2 +- .../amd/dal/dc/dce110/dce110_timing_generator.c | 131 +++++++++---------- .../amd/dal/dc/dce110/dce110_timing_generator.h | 140 +++++++++++---------- 5 files changed, 138 insertions(+), 147 deletions(-) diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c index 12c214f..0bb3799 100644 --- a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c @@ -1009,9 +1009,9 @@ static void enable_link_hdmi(struct core_stream *stream) normalized_pix_clk, stream->public.timing.flags.LTE_340MCSC_SCRAMBLE); - stream->sink->link->cur_link_settings.lane_count = - (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) - ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR; + dc_service_memset(&stream->sink->link->cur_link_settings, 0, + sizeof(struct link_settings)); + if (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) link->ctx->dc->hwss.encoder_enable_dual_link_tmds_output( stream->sink->link->link_enc, diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c index 6a59fc3..a34cd6d 100644 --- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c @@ -645,7 +645,8 @@ static void update_info_frame(struct core_stream *stream) static void enable_stream(struct core_stream *stream) { - enum lane_count lane_count = LANE_COUNT_ONE; + enum lane_count lane_count = + stream->sink->link->cur_link_settings.lane_count; struct dc_crtc_timing *timing = &stream->public.timing; struct core_link *link = stream->sink->link; @@ -664,7 +665,8 @@ static void enable_stream(struct core_stream *stream) + timing->h_border_left + timing->h_border_right; - early_control = active_total_with_borders % lane_count; + if (lane_count != 0) + early_control = active_total_with_borders % lane_count; if (early_control == 0) early_control = lane_count; diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c index 8fc8258..a2dd6ed 100644 --- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c +++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c @@ -1399,7 +1399,7 @@ void dce110_link_encoder_enable_tmds_output( cntl.engine_id = ENGINE_ID_UNKNOWN; cntl.transmitter = enc110->base.transmitter; cntl.pll_id = clock_source; - cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; + cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; cntl.lanes_number = 4; cntl.hpd_sel = enc110->base.hpd_source; 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 198ff28..182d23e 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 @@ -233,7 +233,7 @@ enum trigger_polarity_select { /******************************************************************************/ -bool dce110_timing_generator_construct( +static bool dce110_timing_generator_construct( struct timing_generator *tg, enum controller_id id) { @@ -262,7 +262,32 @@ static const struct crtc_black_color black_color_format[] = { CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4SUPERAA} }; -void dce110_timing_generator_color_space_to_black_color( +/** +* apply_front_porch_workaround +* +* This is a workaround for a bug that has existed since R5xx and has not been +* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. +*/ +static void dce110_timing_generator_apply_front_porch_workaround( + struct timing_generator *tg, + struct dc_crtc_timing *timing) +{ + if (timing->flags.INTERLACE == 1) { + if (timing->v_front_porch < 2) + timing->v_front_porch = 2; + } else { + if (timing->v_front_porch < 1) + timing->v_front_porch = 1; + } +} + +static int32_t dce110_timing_generator_get_vsynch_and_front_porch_size( + const struct dc_crtc_timing *timing) +{ + return timing->v_sync_width + timing->v_front_porch; +} + +static void dce110_timing_generator_color_space_to_black_color( enum color_space colorspace, struct crtc_black_color *black_color) { @@ -302,31 +327,31 @@ void dce110_timing_generator_color_space_to_black_color( } /** -* apply_front_porch_workaround -* -* This is a workaround for a bug that has existed since R5xx and has not been -* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. -*/ -void dce110_timing_generator_apply_front_porch_workaround( - struct timing_generator *tg, - struct dc_crtc_timing *timing) + ***************************************************************************** + * Function: is_in_vertical_blank + * + * @brief + * check the current status of CRTC to check if we are in Vertical Blank + * regioneased" state + * + * @return + * true if currently in blank region, false otherwise + * + ***************************************************************************** + */ +static bool dce110_timing_generator_is_in_vertical_blank( + struct timing_generator *tg) { - if (timing->flags.INTERLACE == 1) { - if (timing->v_front_porch < 2) - timing->v_front_porch = 2; - } else { - if (timing->v_front_porch < 1) - timing->v_front_porch = 1; - } -} + uint32_t addr = 0; + uint32_t value = 0; + uint32_t field = 0; -int32_t dce110_timing_generator_get_vsynch_and_front_porch_size( - const struct dc_crtc_timing *timing) -{ - return timing->v_sync_width + timing->v_front_porch; + addr = tg->regs[IDX_CRTC_STATUS]; + value = dal_read_reg(tg->ctx, addr); + field = get_reg_field_value(value, CRTC_STATUS, CRTC_V_BLANK); + return field == 1; } - void dce110_timing_generator_set_early_control( struct timing_generator *tg, uint32_t early_cntl) @@ -476,31 +501,6 @@ bool dce110_timing_generator_unblank_crtc(struct timing_generator *tg) /** ***************************************************************************** - * Function: is_in_vertical_blank - * - * @brief - * check the current status of CRTC to check if we are in Vertical Blank - * regioneased" state - * - * @return - * true if currently in blank region, false otherwise - * - ***************************************************************************** - */ -bool dce110_timing_generator_is_in_vertical_blank(struct timing_generator *tg) -{ - uint32_t addr = 0; - uint32_t value = 0; - uint32_t field = 0; - - addr = tg->regs[IDX_CRTC_STATUS]; - value = dal_read_reg(tg->ctx, addr); - field = get_reg_field_value(value, CRTC_STATUS, CRTC_V_BLANK); - return field == 1; -} - -/** - ***************************************************************************** * Function: disable_stereo * * @brief @@ -1424,33 +1424,20 @@ void dce110_timing_generator_tear_down_global_swap_lock( * ***************************************************************************** */ - bool dce110_timing_generator_is_counter_moving(struct timing_generator *tg) { - uint32_t addr = 0; - uint32_t value_1 = 0; - uint32_t field_1 = 0; - uint32_t value_2 = 0; - uint32_t field_2 = 0; - - addr = tg->regs[IDX_CRTC_STATUS_POSITION]; - value_1 = dal_read_reg(tg->ctx, addr); - value_2 = dal_read_reg(tg->ctx, addr); - - field_1 = get_reg_field_value( - value_1, CRTC_STATUS_POSITION, CRTC_HORZ_COUNT); - field_2 = get_reg_field_value( - value_2, CRTC_STATUS_POSITION, CRTC_HORZ_COUNT); - - if (field_1 == field_2) { - field_1 = get_reg_field_value( - value_1, CRTC_STATUS_POSITION, CRTC_VERT_COUNT); - field_2 = get_reg_field_value( - value_2, CRTC_STATUS_POSITION, CRTC_VERT_COUNT); - return field_1 != field_2; - } + uint32_t h1 = 0; + uint32_t h2 = 0; + uint32_t v1 = 0; + uint32_t v2 = 0; - return true; + dce110_timing_generator_get_crtc_positions(tg, &h1, &v1); + dce110_timing_generator_get_crtc_positions(tg, &h2, &v2); + + if (h1 == h2 && v1 == v2) + return false; + else + return true; } /*TODO: Figure out if we need this function. */ 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 d95a2a0..c75c659 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 @@ -56,52 +56,102 @@ struct dce110_timing_generator { bool advanced_request_enable; }; +/********** Create and destroy **********/ struct timing_generator *dce110_timing_generator_create( struct adapter_service *as, struct dc_context *ctx, enum controller_id id); - void dce110_timing_generator_destroy(struct timing_generator **tg); -bool dce110_timing_generator_construct( +/* determine if given timing can be supported by TG */ +bool dce110_timing_generator_validate_timing( struct timing_generator *tg, - enum controller_id id); + const struct dc_crtc_timing *timing, + enum signal_type signal); -void dce110_timing_generator_program_blank_color( - struct timing_generator *tg, - enum color_space color_space); +/******** HW programming ************/ -bool dce110_timing_generator_blank_crtc(struct timing_generator *tg); +/* Program timing generator with given timing */ +bool dce110_timing_generator_program_timing_generator( + struct timing_generator *tg, + struct dc_crtc_timing *dc_crtc_timing); +/* Disable/Enable Timing Generator */ bool dce110_timing_generator_enable_crtc(struct timing_generator *tg); - bool dce110_timing_generator_disable_crtc(struct timing_generator *tg); -bool dce110_timing_generator_is_in_vertical_blank(struct timing_generator *tg); +void dce110_timing_generator_set_early_control( + struct timing_generator *tg, + uint32_t early_cntl); -void dce110_timing_generator_program_blanking( +/**************** TG current status ******************/ + +/* return the current frame counter. Used by Linux kernel DRM */ +uint32_t dce110_timing_generator_get_vblank_counter( + struct timing_generator *tg); + +/* Get current H and V position */ +void dce110_timing_generator_get_crtc_positions( struct timing_generator *tg, - const struct dc_crtc_timing *timing); + int32_t *h_position, + int32_t *v_position); -bool dce110_timing_generator_program_timing_generator( +/* return true if TG counter is moving. false if TG is stopped */ +bool dce110_timing_generator_is_counter_moving(struct timing_generator *tg); + +/* wait until TG is in beginning of vertical blank region */ +void dce110_timing_generator_wait_for_vblank(struct timing_generator *tg); + +/* wait until TG is in beginning of active region */ +void dce110_timing_generator_wait_for_vactive(struct timing_generator *tg); + + +/*********** Timing Generator Synchronization routines ****/ + +/* Setups Global Swap Lock group, TimingServer or TimingClient*/ +void dce110_timing_generator_setup_global_swap_lock( struct timing_generator *tg, - struct dc_crtc_timing *dc_crtc_timing); + const struct dcp_gsl_params *gsl_params); -void dce110_timing_generator_set_early_control( - struct timing_generator *tg, - uint32_t early_cntl); +/* Clear all the register writes done by setup_global_swap_lock */ +void dce110_timing_generator_tear_down_global_swap_lock( + struct timing_generator *tg); + +/* Reset slave controllers on master VSync */ +void dce110_timing_generator_enable_reset_trigger( + struct timing_generator *tg, + const struct trigger_params *trigger_params); + +/* disabling trigger-reset */ +void dce110_timing_generator_disable_reset_trigger( + struct timing_generator *tg); + +/* Checks whether CRTC triggered reset occurred */ +bool dce110_timing_generator_did_triggered_reset_occur( + struct timing_generator *tg); +/******** Stuff to move to other virtual HW objects *****************/ +/* TODO: Should we move it to mem_input interface? */ +bool dce110_timing_generator_blank_crtc(struct timing_generator *tg); bool dce110_timing_generator_unblank_crtc(struct timing_generator *tg); +void dce110_timing_generator_disable_vga(struct timing_generator *tg); -bool dce110_timing_generator_validate_timing( +/* TODO: Should we move it to transform */ +void dce110_timing_generator_program_blanking( struct timing_generator *tg, - const struct dc_crtc_timing *timing, - enum signal_type signal); + const struct dc_crtc_timing *timing); -void dce110_timing_generator_wait_for_vblank(struct timing_generator *tg); +/* TODO: Should we move it to opp? */ +void dce110_timing_generator_program_blank_color( + struct timing_generator *tg, + enum color_space color_space); +void dce110_timing_generator_set_overscan_color_black( + struct timing_generator *tg, + enum color_space black_color); +/*************** End-of-move ********************/ -void dce110_timing_generator_wait_for_vactive(struct timing_generator *tg); +/* Not called yet */ void dce110_timing_generator_set_test_pattern( struct timing_generator *tg, /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' @@ -119,26 +169,6 @@ uint32_t dce110_timing_generator_get_crtc_scanoutpos( int32_t *vbl, int32_t *position); -uint32_t dce110_timing_generator_get_vblank_counter(struct timing_generator *tg); - -void dce110_timing_generator_color_space_to_black_color( - enum color_space colorspace, - struct crtc_black_color *black_color); -void dce110_timing_generator_apply_front_porch_workaround( - struct timing_generator *tg, - struct dc_crtc_timing *timing); -int32_t dce110_timing_generator_get_vsynch_and_front_porch_size( - const struct dc_crtc_timing *timing); - -void dce110_timing_generator_get_crtc_positions( - struct timing_generator *tg, - int32_t *h_position, - int32_t *v_position); - - -/* TODO: Figure out if we need these functions*/ -bool dce110_timing_generator_is_counter_moving(struct timing_generator *tg); - void dce110_timing_generator_enable_advanced_request( struct timing_generator *tg, bool enable, @@ -147,32 +177,4 @@ void dce110_timing_generator_enable_advanced_request( void dce110_timing_generator_set_lock_master(struct timing_generator *tg, bool lock); -void dce110_timing_generator_set_overscan_color_black( - struct timing_generator *tg, - enum color_space black_color); - - -/**** Sync-related interfaces ****/ -void dce110_timing_generator_setup_global_swap_lock( - struct timing_generator *tg, - const struct dcp_gsl_params *gsl_params); -void dce110_timing_generator_tear_down_global_swap_lock( - struct timing_generator *tg); - - -void dce110_timing_generator_enable_reset_trigger( - struct timing_generator *tg, - const struct trigger_params *trigger_params); - -void dce110_timing_generator_disable_reset_trigger( - struct timing_generator *tg); - -bool dce110_timing_generator_did_triggered_reset_occur( - struct timing_generator *tg); - -void dce110_timing_generator_disable_vga( - struct timing_generator *tg); - -/**** End-of-Sync-related interfaces ****/ - #endif /* __DC_TIMING_GENERATOR_DCE110_H__ */ -- 1.9.1