diff options
Diffstat (limited to 'common/recipes-kernel/linux/files/0661-drm-amd-dal-Refactor-DCE11-timing-generator.patch')
-rw-r--r-- | common/recipes-kernel/linux/files/0661-drm-amd-dal-Refactor-DCE11-timing-generator.patch | 1270 |
1 files changed, 1270 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0661-drm-amd-dal-Refactor-DCE11-timing-generator.patch b/common/recipes-kernel/linux/files/0661-drm-amd-dal-Refactor-DCE11-timing-generator.patch new file mode 100644 index 00000000..a4a031d0 --- /dev/null +++ b/common/recipes-kernel/linux/files/0661-drm-amd-dal-Refactor-DCE11-timing-generator.patch @@ -0,0 +1,1270 @@ +From fc2a45ea5855721d7cf2c891e9592b4c63dd612c Mon Sep 17 00:00:00 2001 +From: Jun Lei <Jun.Lei@amd.com> +Date: Tue, 29 Dec 2015 19:25:37 -0500 +Subject: [PATCH 0661/1110] drm/amd/dal: Refactor DCE11 timing generator + +Refactor timing generator for DCE11 to be called directly from DC rather than +exclusively through HWSS. + +This is meant as a template to avoid always going through HWSS for all calls to HW. +This creates a better defined role for HWSS to only implement actual +sequences rather than as a generic layer. + +Signed-off-by: Jordan Lazare <Jordan.Lazare@amd.com> +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Acked-by: Harry Wentland <Harry.Wentland@amd.com> +--- + .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c | 87 +++-- + .../gpu/drm/amd/dal/dc/dce110/dce110_resource.c | 71 +++- + .../amd/dal/dc/dce110/dce110_timing_generator.c | 363 +++++++++++++-------- + .../amd/dal/dc/dce110/dce110_timing_generator.h | 55 +++- + .../amd/dal/include/timing_generator_interface.h | 30 ++ + .../drm/amd/dal/include/timing_generator_types.h | 50 ++- + 6 files changed, 470 insertions(+), 186 deletions(-) + create mode 100644 drivers/gpu/drm/amd/dal/include/timing_generator_interface.h + +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 fa6b9b4..1085137 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 +@@ -671,7 +671,7 @@ static void enable_stream(struct core_stream *stream) + if (early_control == 0) + early_control = lane_count; + +- dce110_timing_generator_set_early_control(tg, early_control); ++ tg->funcs->set_early_control(tg, early_control); + + /* enable audio only within mode set */ + if (stream->audio != NULL) { +@@ -800,7 +800,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx, + /* Must blank CRTC after disabling power gating and before any + * programming, otherwise CRTC will be hung in bad state + */ +- dce110_timing_generator_blank_crtc(stream->tg); ++ stream->tg->funcs->set_blank(stream->tg, true); + + core_link_disable_stream( + stream->sink->link, stream); +@@ -815,12 +815,10 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx, + } + + +- if (false == dce110_timing_generator_program_timing_generator( ++ stream->tg->funcs->program_timing( + stream->tg, +- &stream->public.timing)) { +- BREAK_TO_DEBUGGER(); +- return DC_ERROR_UNEXPECTED; +- } ++ &stream->public.timing, ++ true); + } + + /*TODO: mst support - use total stream count*/ +@@ -829,7 +827,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx, + context->target_count); + + if (timing_changed) { +- if (false == dce110_timing_generator_enable_crtc( ++ if (false == stream->tg->funcs->enable_crtc( + stream->tg)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; +@@ -896,7 +894,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx, + color_space = get_output_color_space( + &stream->public.timing); + +- dce110_timing_generator_program_blank_color( ++ stream->tg->funcs->set_blank_color( + context->res_ctx.pool.timing_generators[controller_idx], + color_space); + +@@ -928,7 +926,7 @@ static void power_down_controllers(struct dc *dc) + int i; + + for (i = 0; i < dc->res_pool.controller_count; i++) { +- dce110_timing_generator_disable_crtc( ++ dc->res_pool.timing_generators[i]->funcs->disable_crtc( + dc->res_pool.timing_generators[i]); + } + } +@@ -972,7 +970,7 @@ static void disable_vga_and_power_gate_all_controllers( + tg = dc->res_pool.timing_generators[i]; + ctx = dc->ctx; + +- dce110_timing_generator_disable_vga(tg); ++ tg->funcs->disable_vga(tg); + + /* Enable CLOCK gating for each pipe BEFORE controller + * powergating. */ +@@ -1336,7 +1334,7 @@ static bool setup_line_buffer_pixel_depth( + + if (current_depth != depth) { + if (blank) +- dce110_timing_generator_wait_for_vblank(tg); ++ tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); + + return dce110_transform_set_pixel_storage_depth(xfm, depth); + } +@@ -1421,9 +1419,7 @@ static void program_scaler( + LB_PIXEL_DEPTH_24BPP, + false); + +- dce110_timing_generator_set_overscan_color_black( +- tg, +- surface->public.colorimetry.color_space); ++ tg->funcs->set_overscan_blank_color(tg, surface->public.colorimetry.color_space); + + dce110_transform_set_scaler(xfm, &scaler_data); + +@@ -1433,8 +1429,6 @@ static void program_scaler( + false); + } + +- +- + static void configure_locking(struct dc_context *ctx, uint8_t controller_id) + { + /* main controller should be in mode 0 (master pipe) */ +@@ -1484,7 +1478,7 @@ static bool set_plane_config( + PIPE_LOCK_CONTROL_SURFACE, + true); + +- dce110_timing_generator_program_blanking(tg, dc_crtc_timing); ++ tg->funcs->program_timing(tg, dc_crtc_timing, false); + + enable_fe_clock(ctx, controller_idx, true); + +@@ -1577,8 +1571,8 @@ static void reset_single_stream_hw_ctx(struct core_stream *stream, + + core_link_disable_stream(stream->sink->link, stream); + +- dce110_timing_generator_blank_crtc(stream->tg); +- dce110_timing_generator_disable_crtc(stream->tg); ++ stream->tg->funcs->set_blank(stream->tg, true); ++ stream->tg->funcs->disable_crtc(stream->tg); + dce110_mem_input_deallocate_dmif_buffer(stream->mi, context->target_count); + dce110_transform_set_scaler_bypass(stream->xfm); + disable_stereo_mixer(stream->ctx); +@@ -1630,12 +1624,12 @@ static bool wait_for_reset_trigger_to_occur( + + for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { + +- if (!dce110_timing_generator_is_counter_moving(tg)) { ++ if (!tg->funcs->is_counter_moving(tg)) { + DC_ERROR("TG counter is not moving!\n"); + break; + } + +- if (dce110_timing_generator_did_triggered_reset_occur(tg)) { ++ if (tg->funcs->did_triggered_reset_occur(tg)) { + rc = true; + /* usually occurs at i=1 */ + DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", +@@ -1644,8 +1638,8 @@ static bool wait_for_reset_trigger_to_occur( + } + + /* Wait for one frame. */ +- dce110_timing_generator_wait_for_vactive(tg); +- dce110_timing_generator_wait_for_vblank(tg); ++ tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); ++ tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); + } + + if (false == rc) +@@ -1675,8 +1669,7 @@ static void enable_timing_synchronization( + * the 1st one in the group. */ + gsl_params.timing_server = (0 == i ? true : false); + +- dce110_timing_generator_setup_global_swap_lock(tgs[i], +- &gsl_params); ++ tgs[i]->funcs->setup_global_swap_lock(tgs[i], &gsl_params); + } + + /* Reset slave controllers on master VSync */ +@@ -1687,8 +1680,7 @@ static void enable_timing_synchronization( + trigger_params.source = SYNC_SOURCE_GSL_GROUP0; + + for (i = 1 /* skip the master */; i < timing_generator_num; i++) { +- dce110_timing_generator_enable_reset_trigger(tgs[i], +- &trigger_params); ++ tgs[i]->funcs->enable_reset_trigger(tgs[i], &trigger_params); + + DC_SYNC_INFO("GSL: waiting for reset to occur.\n"); + wait_for_reset_trigger_to_occur(dc_ctx, tgs[i]); +@@ -1696,35 +1688,60 @@ static void enable_timing_synchronization( + /* Regardless of success of the wait above, remove the reset or + * the driver will start timing out on Display requests. */ + DC_SYNC_INFO("GSL: disabling trigger-reset.\n"); +- dce110_timing_generator_disable_reset_trigger(tgs[i]); ++ tgs[i]->funcs->disable_reset_trigger(tgs[i]); + } + + /* GSL Vblank synchronization is a one time sync mechanism, assumption + * is that the sync'ed displays will not drift out of sync over time*/ + DC_SYNC_INFO("GSL: Restoring register states.\n"); + for (i = 0; i < timing_generator_num; i++) +- dce110_timing_generator_tear_down_global_swap_lock(tgs[i]); ++ tgs[i]->funcs->tear_down_global_swap_lock(tgs[i]); + + DC_SYNC_INFO("GSL: Set-up complete.\n"); + } + ++static void get_crtc_positions(struct timing_generator *tg, ++ int32_t *h_position, int32_t *v_position) ++{ ++ tg->funcs->get_position(tg, h_position, v_position); ++} ++ ++static bool enable_memory_request(struct timing_generator *tg) ++{ ++ return tg->funcs->set_blank(tg, false); ++} ++ ++static bool disable_memory_requests(struct timing_generator *tg) ++{ ++ return tg->funcs->set_blank(tg, true); ++} ++ ++static uint32_t get_vblank_counter(struct timing_generator *tg) ++{ ++ return tg->funcs->get_frame_count(tg); ++} ++ ++static void disable_vga(struct timing_generator *tg) ++{ ++ tg->funcs->disable_vga(tg); ++} + + static const struct hw_sequencer_funcs dce110_funcs = { + .apply_ctx_to_hw = apply_ctx_to_hw, + .reset_hw_ctx = reset_hw_ctx, + .set_plane_config = set_plane_config, + .update_plane_address = update_plane_address, +- .enable_memory_requests = dce110_timing_generator_unblank_crtc, +- .disable_memory_requests = dce110_timing_generator_blank_crtc, ++ .enable_memory_requests = enable_memory_request, ++ .disable_memory_requests = disable_memory_requests, + .cursor_set_attributes = dce110_ipp_cursor_set_attributes, + .cursor_set_position = dce110_ipp_cursor_set_position, + .set_gamma_ramp = set_gamma_ramp, + .power_down = power_down, + .enable_accelerated_mode = enable_accelerated_mode, +- .get_crtc_positions = dce110_timing_generator_get_crtc_positions, +- .get_vblank_counter = dce110_timing_generator_get_vblank_counter, ++ .get_crtc_positions = get_crtc_positions, ++ .get_vblank_counter = get_vblank_counter, + .enable_timing_synchronization = enable_timing_synchronization, +- .disable_vga = dce110_timing_generator_disable_vga, ++ .disable_vga = disable_vga, + .encoder_create = dce110_link_encoder_create, + .encoder_destroy = dce110_link_encoder_destroy, + .encoder_hw_init = dce110_link_encoder_hw_init, +diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c +index cb084da..d789853 100644 +--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c ++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c +@@ -30,6 +30,7 @@ + #include "resource.h" + #include "dce_base/dce_base_resource.h" + #include "include/irq_service_interface.h" ++#include "include/timing_generator_interface.h" + + #include "dce110/dce110_timing_generator.h" + #include "dce110/dce110_link_encoder.h" +@@ -39,6 +40,8 @@ + #include "dce110/dce110_stream_encoder.h" + #include "dce110/dce110_opp.h" + ++#include "dce/dce_11_0_d.h" ++ + enum dce110_clk_src_array_id { + DCE110_CLK_SRC_PLL0 = 0, + DCE110_CLK_SRC_PLL1, +@@ -47,6 +50,53 @@ enum dce110_clk_src_array_id { + DCE110_CLK_SRC_TOTAL + }; + ++static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = { ++ { ++ .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), ++ .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), ++ }, ++ { ++ .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), ++ .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), ++ }, ++ { ++ .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), ++ .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), ++ }, ++ { ++ .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), ++ .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), ++ }, ++ { ++ .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), ++ .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), ++ }, ++ { ++ .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), ++ .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), ++ } ++}; ++ ++static struct timing_generator *dce110_timing_generator_create( ++ struct adapter_service *as, ++ struct dc_context *ctx, ++ uint32_t instance, ++ const struct dce110_timing_generator_offsets *offsets) ++{ ++ struct dce110_timing_generator *tg110 = ++ dc_service_alloc(ctx, sizeof(struct dce110_timing_generator)); ++ ++ if (!tg110) ++ return NULL; ++ ++ if (dce110_timing_generator_construct(tg110, as, ctx, instance, offsets)) ++ return &tg110->base; ++ ++ BREAK_TO_DEBUGGER(); ++ dc_service_free(ctx, tg110); ++ return NULL; ++} ++ + bool dce110_construct_resource_pool( + struct adapter_service *adapter_serv, + struct dc *dc, +@@ -117,7 +167,7 @@ bool dce110_construct_resource_pool( + + for (i = 0; i < pool->controller_count; i++) { + pool->timing_generators[i] = dce110_timing_generator_create( +- adapter_serv, ctx, i + 1); ++ adapter_serv, ctx, i, &dce110_tg_offsets[i]); + if (pool->timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dal_error("DC: failed to create tg!\n"); +@@ -225,9 +275,10 @@ controller_create_fail: + if (pool->mis[i] != NULL) + dce110_mem_input_destroy(&pool->mis[i]); + +- if (pool->timing_generators[i] != NULL) +- dce110_timing_generator_destroy( +- &pool->timing_generators[i]); ++ if (pool->timing_generators[i] != NULL) { ++ dc_service_free(pool->timing_generators[i]->ctx, DCE110TG_FROM_TG(pool->timing_generators[i])); ++ pool->timing_generators[i] = NULL; ++ } + } + + filter_create_fail: +@@ -262,9 +313,10 @@ void dce110_destruct_resource_pool(struct resource_pool *pool) + if (pool->mis[i] != NULL) + dce110_mem_input_destroy(&pool->mis[i]); + +- if (pool->timing_generators[i] != NULL) +- dce110_timing_generator_destroy( +- &pool->timing_generators[i]); ++ if (pool->timing_generators[i] != NULL) { ++ dc_service_free(pool->timing_generators[i]->ctx, DCE110TG_FROM_TG(pool->timing_generators[i])); ++ pool->timing_generators[i] = NULL; ++ } + } + + for (i = 0; i < pool->stream_enc_count; i++) { +@@ -454,10 +506,7 @@ static enum dc_status validate_mapped_resource( + if (status != DC_OK) + return status; + +- if (!dce110_timing_generator_validate_timing( +- stream->tg, +- &stream->public.timing, +- SIGNAL_TYPE_HDMI_TYPE_A)) ++ if (!stream->tg->funcs->validate_timing(stream->tg, &stream->public.timing)) + return DC_FAIL_CONTROLLER_VALIDATE; + + +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 3c6c04a..b47ba61 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 +@@ -52,27 +52,16 @@ enum black_color_format { + #define MAX_H_TOTAL (CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1) + #define MAX_V_TOTAL (CRTC_V_TOTAL__CRTC_V_TOTAL_MASKhw + 1) + +- +-#define FROM_TIMING_GENERATOR(tg)\ +- container_of(tg, struct dce110_timing_generator, base) +- + #define CRTC_REG(reg) (reg + tg110->offsets.crtc) + #define DCP_REG(reg) (reg + tg110->offsets.dcp) + +-static const struct dce110_timing_generator_offsets reg_offsets[] = { +- { +- .crtc = 0, +- .dcp = 0, +- }, +- { +- .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), +- .dcp = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +- }, +- { +- .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), +- .dcp = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), +- } +-}; ++/* Flowing register offsets are same in files of ++ * dce/dce_11_0_d.h ++ * dce/vi_ellesmere_p/vi_ellesmere_d.h ++ * ++ * So we can create dce110 timing generator to use it. ++ */ ++ + /******************************************************************************* + * GSL Sync related values */ + +@@ -131,16 +120,31 @@ enum trigger_polarity_select { + + /******************************************************************************/ + +-static bool dce110_timing_generator_construct( +- struct timing_generator *tg, +- enum controller_id id) +-{ +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); +- +- tg->controller_id = id; +- tg110->offsets = reg_offsets[id - 1]; +- return true; +-} ++static struct timing_generator_funcs dce110_tg_funcs = { ++ .validate_timing = dce110_tg_validate_timing, ++ .program_timing = dce110_tg_program_timing, ++ .enable_crtc = dce110_timing_generator_enable_crtc, ++ .disable_crtc = dce110_timing_generator_disable_crtc, ++ .is_counter_moving = dce110_timing_generator_is_counter_moving, ++ .get_position = dce110_timing_generator_get_crtc_positions, ++ .get_frame_count = dce110_timing_generator_get_vblank_counter, ++ .set_early_control = dce110_timing_generator_set_early_control, ++ .wait_for_state = dce110_tg_wait_for_state, ++ .set_blank = dce110_tg_set_blank, ++ .set_colors = dce110_tg_set_colors, ++ .set_overscan_blank_color = ++ dce110_timing_generator_set_overscan_color_black, ++ .set_blank_color = dce110_timing_generator_program_blank_color, ++ .disable_vga = dce110_timing_generator_disable_vga, ++ .did_triggered_reset_occur = ++ dce110_timing_generator_did_triggered_reset_occur, ++ .setup_global_swap_lock = ++ dce110_timing_generator_setup_global_swap_lock, ++ .enable_reset_trigger = dce110_timing_generator_enable_reset_trigger, ++ .disable_reset_trigger = dce110_timing_generator_disable_reset_trigger, ++ .tear_down_global_swap_lock = ++ dce110_timing_generator_tear_down_global_swap_lock, ++}; + + static const struct crtc_black_color black_color_format[] = { + /* BlackColorFormat_RGB_FullRange */ +@@ -246,7 +250,7 @@ static bool dce110_timing_generator_is_in_vertical_blank( + uint32_t addr = 0; + uint32_t value = 0; + uint32_t field = 0; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + addr = CRTC_REG(mmCRTC_STATUS); + value = dal_read_reg(tg->ctx, addr); +@@ -259,7 +263,7 @@ void dce110_timing_generator_set_early_control( + uint32_t early_cntl) + { + uint32_t regval; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t address = CRTC_REG(mmCRTC_CONTROL); + + regval = dal_read_reg(tg->ctx, address); +@@ -279,7 +283,7 @@ bool dce110_timing_generator_enable_crtc(struct timing_generator *tg) + /* 0 value is needed by DRR and is also suggested default value for CZ + */ + uint32_t value; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + value = dal_read_reg(tg->ctx, + CRTC_REG(mmCRTC_MASTER_UPDATE_MODE)); +@@ -288,7 +292,7 @@ bool dce110_timing_generator_enable_crtc(struct timing_generator *tg) + dal_write_reg(tg->ctx, + CRTC_REG(mmCRTC_MASTER_UPDATE_MODE), value); + +- result = dal_bios_parser_enable_crtc(tg->bp, tg->controller_id, true); ++ result = dal_bios_parser_enable_crtc(tg->bp, tg110->controller_id, true); + + return result == BP_RESULT_OK; + } +@@ -298,7 +302,7 @@ void dce110_timing_generator_program_blank_color( + enum color_space color_space) + { + struct crtc_black_color black_color; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_BLACK_COLOR); + uint32_t value = dal_read_reg(tg->ctx, addr); + +@@ -332,7 +336,7 @@ void dce110_timing_generator_program_blank_color( + + bool dce110_timing_generator_blank_crtc(struct timing_generator *tg) + { +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_BLANK_CONTROL); + uint32_t value = dal_read_reg(tg->ctx, addr); + uint8_t counter = 100; +@@ -372,7 +376,7 @@ bool dce110_timing_generator_blank_crtc(struct timing_generator *tg) + dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR, + LOG_MINOR_COMPONENT_CONTROLLER, + "timing generator %d blank timing out.\n", +- tg->controller_id); ++ tg110->controller_id); + return false; + } + +@@ -385,7 +389,7 @@ bool dce110_timing_generator_blank_crtc(struct timing_generator *tg) + */ + bool dce110_timing_generator_unblank_crtc(struct timing_generator *tg) + { +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_BLANK_CONTROL); + uint32_t value = dal_read_reg(tg->ctx, addr); + +@@ -419,7 +423,7 @@ bool dce110_timing_generator_unblank_crtc(struct timing_generator *tg) + @TODOSTEREO + static void disable_stereo(struct timing_generator *tg) + { +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_3D_STRUCTURE_CONTROL); + uint32_t value = 0; + uint32_t test = 0; +@@ -465,7 +469,9 @@ bool dce110_timing_generator_disable_crtc(struct timing_generator *tg) + { + enum bp_result result; + +- result = dal_bios_parser_enable_crtc(tg->bp, tg->controller_id, false); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); ++ ++ result = dal_bios_parser_enable_crtc(tg->bp, tg110->controller_id, false); + + /* Need to make sure stereo is disabled according to the DCE5.0 spec */ + +@@ -487,7 +493,7 @@ static void program_horz_count_by_2( + const struct dc_crtc_timing *timing) + { + uint32_t regval; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + regval = dal_read_reg(tg->ctx, + CRTC_REG(mmCRTC_COUNT_CONTROL)); +@@ -510,12 +516,13 @@ static void program_horz_count_by_2( + */ + bool dce110_timing_generator_program_timing_generator( + struct timing_generator *tg, +- struct dc_crtc_timing *dc_crtc_timing) ++ const struct dc_crtc_timing *dc_crtc_timing) + { + enum bp_result result; + struct bp_hw_crtc_timing_parameters bp_params; ++ struct dc_crtc_timing patched_crtc_timing; + uint32_t regval; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + uint32_t vsync_offset = dc_crtc_timing->v_border_bottom + + dc_crtc_timing->v_front_porch; +@@ -530,52 +537,54 @@ bool dce110_timing_generator_program_timing_generator( + /* Due to an asic bug we need to apply the Front Porch workaround prior + * to programming the timing. + */ +- dce110_timing_generator_apply_front_porch_workaround(tg, dc_crtc_timing); + +- bp_params.controller_id = tg->controller_id; ++ patched_crtc_timing = *dc_crtc_timing; ++ ++ dce110_timing_generator_apply_front_porch_workaround(tg, &patched_crtc_timing); ++ ++ bp_params.controller_id = tg110->controller_id; + +- bp_params.h_total = dc_crtc_timing->h_total; ++ bp_params.h_total = patched_crtc_timing.h_total; + bp_params.h_addressable = +- dc_crtc_timing->h_addressable; +- bp_params.v_total = dc_crtc_timing->v_total; +- bp_params.v_addressable = dc_crtc_timing->v_addressable; ++ patched_crtc_timing.h_addressable; ++ bp_params.v_total = patched_crtc_timing.v_total; ++ bp_params.v_addressable = patched_crtc_timing.v_addressable; + + bp_params.h_sync_start = h_sync_start; +- bp_params.h_sync_width = dc_crtc_timing->h_sync_width; ++ bp_params.h_sync_width = patched_crtc_timing.h_sync_width; + bp_params.v_sync_start = v_sync_start; +- bp_params.v_sync_width = dc_crtc_timing->v_sync_width; ++ bp_params.v_sync_width = patched_crtc_timing.v_sync_width; + + /* Set overscan */ + bp_params.h_overscan_left = +- dc_crtc_timing->h_border_left; ++ patched_crtc_timing.h_border_left; + bp_params.h_overscan_right = +- dc_crtc_timing->h_border_right; +- bp_params.v_overscan_top = dc_crtc_timing->v_border_top; ++ patched_crtc_timing.h_border_right; ++ bp_params.v_overscan_top = patched_crtc_timing.v_border_top; + bp_params.v_overscan_bottom = +- dc_crtc_timing->v_border_bottom; ++ patched_crtc_timing.v_border_bottom; + + /* Set flags */ +- if (dc_crtc_timing->flags.HSYNC_POSITIVE_POLARITY == 1) ++ if (patched_crtc_timing.flags.HSYNC_POSITIVE_POLARITY == 1) + bp_params.flags.HSYNC_POSITIVE_POLARITY = 1; + +- if (dc_crtc_timing->flags.VSYNC_POSITIVE_POLARITY == 1) ++ if (patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY == 1) + bp_params.flags.VSYNC_POSITIVE_POLARITY = 1; + +- if (dc_crtc_timing->flags.INTERLACE == 1) ++ if (patched_crtc_timing.flags.INTERLACE == 1) + bp_params.flags.INTERLACE = 1; + +- if (dc_crtc_timing->flags.HORZ_COUNT_BY_TWO == 1) ++ if (patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1) + bp_params.flags.HORZ_COUNT_BY_TWO = 1; + + result = dal_bios_parser_program_crtc_timing(tg->bp, &bp_params); + +- program_horz_count_by_2(tg, dc_crtc_timing); +- ++ program_horz_count_by_2(tg, &patched_crtc_timing); + + regval = dal_read_reg(tg->ctx, + CRTC_REG(mmCRTC_START_LINE_CONTROL)); + +- if (dce110_timing_generator_get_vsynch_and_front_porch_size(dc_crtc_timing) <= 3) { ++ if (dce110_timing_generator_get_vsynch_and_front_porch_size(&patched_crtc_timing) <= 3) { + set_reg_field_value(regval, 3, + CRTC_START_LINE_CONTROL, + CRTC_ADVANCED_START_LINE_POSITION); +@@ -632,7 +641,7 @@ void dce110_timing_generator_program_drr( + uint32_t v_total_max = 0; + uint32_t v_total_cntl = 0; + uint32_t static_screen_cntl = 0; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + uint32_t addr = 0; + +@@ -796,7 +805,7 @@ void dce110_timing_generator_program_drr( + */ + uint32_t dce110_timing_generator_get_vblank_counter(struct timing_generator *tg) + { +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_STATUS_FRAME_COUNT); + uint32_t value = dal_read_reg(tg->ctx, addr); + uint32_t field = get_reg_field_value( +@@ -822,7 +831,7 @@ void dce110_timing_generator_get_crtc_positions( + int32_t *v_position) + { + uint32_t value; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + value = dal_read_reg(tg->ctx, CRTC_REG(mmCRTC_STATUS_POSITION)); + +@@ -852,7 +861,7 @@ uint32_t dce110_timing_generator_get_crtc_scanoutpos( + int32_t *vbl, + int32_t *position) + { +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + /* TODO 1: Update the implementation once caller is updated + * WARNING!! This function is returning the whole register value + * because the caller is expecting it instead of proper vertical and +@@ -887,7 +896,7 @@ void dce110_timing_generator_program_blanking( + 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 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + struct dc_context *ctx = tg->ctx; + uint32_t value = 0; +@@ -969,7 +978,7 @@ void dce110_timing_generator_set_test_pattern( + struct dc_context *ctx = tg->ctx; + uint32_t value; + uint32_t addr; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + /* TODO: add support for other test patterns */ + switch (test_pattern) { +@@ -1037,6 +1046,8 @@ bool dce110_timing_generator_validate_timing( + timing->h_front_porch; + uint32_t h_sync_start = timing->h_addressable + hsync_offset; + ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); ++ + ASSERT(timing != NULL); + + if (!timing) +@@ -1047,18 +1058,18 @@ bool dce110_timing_generator_validate_timing( + * needs more than 8192 horizontal and + * more than 8192 vertical total pixels) + */ +- if (timing->h_total > tg->max_h_total || +- timing->v_total > tg->max_v_total) ++ if (timing->h_total > tg110->max_h_total || ++ timing->v_total > tg110->max_v_total) + return false; + + h_blank = (timing->h_total - timing->h_addressable - + timing->h_border_right - + timing->h_border_left); + +- if (h_blank < tg->min_h_blank) ++ if (h_blank < tg110->min_h_blank) + return false; + +- if (timing->h_front_porch < tg->min_h_front_porch) ++ if (timing->h_front_porch < tg110->min_h_front_porch) + return false; + + h_back_porch = h_blank - (h_sync_start - +@@ -1066,7 +1077,7 @@ bool dce110_timing_generator_validate_timing( + timing->h_border_right - + timing->h_sync_width); + +- if (h_back_porch < tg->min_h_back_porch) ++ if (h_back_porch < tg110->min_h_back_porch) + return false; + + return true; +@@ -1109,63 +1120,35 @@ void dce110_timing_generator_wait_for_vactive(struct timing_generator *tg) + } + } + +-void dce110_timing_generator_destroy(struct timing_generator **tg) +-{ +- dc_service_free((*tg)->ctx, FROM_TIMING_GENERATOR(*tg)); +- *tg = NULL; +-} +- +-static bool timing_generator_dce110_construct(struct timing_generator *tg, +- struct dc_context *ctx, ++bool dce110_timing_generator_construct( ++ struct dce110_timing_generator *tg110, + struct adapter_service *as, +- enum controller_id id) ++ struct dc_context *ctx, ++ uint32_t instance, ++ const struct dce110_timing_generator_offsets *offsets) + { +- if (!as) ++ if (!tg110) + return false; + +- switch (id) { +- case CONTROLLER_ID_D0: +- case CONTROLLER_ID_D1: +- case CONTROLLER_ID_D2: +- break; +- default: ++ if (!as) + return false; +- } + +- if (!dce110_timing_generator_construct(tg, id)) +- return false; ++ tg110->controller_id = CONTROLLER_ID_D0 + instance; ++ tg110->offsets = *offsets; + +- tg->ctx = ctx; +- tg->bp = dal_adapter_service_get_bios_parser(as); ++ tg110->base.funcs = &dce110_tg_funcs; + +- tg->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; +- tg->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; ++ tg110->base.ctx = ctx; ++ tg110->base.bp = dal_adapter_service_get_bios_parser(as); + +- tg->min_h_blank = 56; +- tg->min_h_front_porch = 4; +- tg->min_h_back_porch = 4; ++ tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; ++ tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; + +- return true; +-} ++ tg110->min_h_blank = 56; ++ tg110->min_h_front_porch = 4; ++ tg110->min_h_back_porch = 4; + +-struct timing_generator *dce110_timing_generator_create( +- struct adapter_service *as, +- struct dc_context *ctx, +- enum controller_id id) +-{ +- struct dce110_timing_generator *tg = +- dc_service_alloc(ctx, sizeof(struct dce110_timing_generator)); +- +- if (!tg) +- return NULL; +- +- if (timing_generator_dce110_construct(&tg->base, ctx, +- as, id)) +- return &tg->base; +- +- BREAK_TO_DEBUGGER(); +- dc_service_free(ctx, tg); +- return NULL; ++ return true; + } + + /** +@@ -1185,7 +1168,7 @@ void dce110_timing_generator_setup_global_swap_lock( + const struct dcp_gsl_params *gsl_params) + { + uint32_t value; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t address = DCP_REG(mmDCP_GSL_CONTROL); + uint32_t check_point = FLIP_READY_BACK_LOOKUP; + +@@ -1267,7 +1250,7 @@ void dce110_timing_generator_tear_down_global_swap_lock( + */ + + uint32_t value; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t address = DCP_REG(mmDCP_GSL_CONTROL); + + value = 0; +@@ -1365,11 +1348,11 @@ void dce110_timing_generator_enable_advanced_request( + bool enable, + const struct dc_crtc_timing *timing) + { +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_START_LINE_CONTROL); + uint32_t value = dal_read_reg(tg->ctx, addr); + +- if (enable && FROM_TIMING_GENERATOR(tg)->advanced_request_enable) { ++ if (enable && DCE110TG_FROM_TG(tg)->advanced_request_enable) { + set_reg_field_value( + value, + 0, +@@ -1427,7 +1410,7 @@ void dce110_timing_generator_set_lock_master(struct timing_generator *tg, + bool lock) + { + struct dc_context *ctx = tg->ctx; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t addr = CRTC_REG(mmCRTC_MASTER_UPDATE_LOCK); + uint32_t value = dal_read_reg(ctx, addr); + +@@ -1449,7 +1432,7 @@ void dce110_timing_generator_enable_reset_trigger( + uint32_t rising_edge = 0; + uint32_t falling_edge = 0; + enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + /* Setup trigger edge */ + switch (trigger_params->edge) { +@@ -1560,7 +1543,7 @@ void dce110_timing_generator_disable_reset_trigger( + struct timing_generator *tg) + { + uint32_t value; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + value = dal_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL)); + +@@ -1609,7 +1592,7 @@ void dce110_timing_generator_disable_reset_trigger( + bool dce110_timing_generator_did_triggered_reset_occur( + struct timing_generator *tg) + { +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + uint32_t value = dal_read_reg(tg->ctx, + CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL)); + +@@ -1629,7 +1612,9 @@ void dce110_timing_generator_disable_vga( + uint32_t addr = 0; + uint32_t value = 0; + +- switch (tg->controller_id) { ++ struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); ++ ++ switch (tg110->controller_id) { + case CONTROLLER_ID_D0: + addr = mmD1VGA_CONTROL; + break; +@@ -1653,7 +1638,6 @@ void dce110_timing_generator_disable_vga( + dal_write_reg(tg->ctx, addr, value); + } + +- + /** + * set_overscan_color_black + * +@@ -1669,7 +1653,7 @@ void dce110_timing_generator_set_overscan_color_black( + struct dc_context *ctx = tg->ctx; + uint32_t value = 0; + uint32_t addr; +- struct dce110_timing_generator *tg110 = FROM_TIMING_GENERATOR(tg); ++ 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: */ +@@ -1788,3 +1772,126 @@ void dce110_timing_generator_set_overscan_color_black( + + } + ++void dce110_tg_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 = CRTC_REG(mmCRTC_BLACK_COLOR); ++ uint32_t value = dal_read_reg(tg->ctx, addr); ++ ++ set_reg_field_value( ++ value, ++ black_color->black_color_b_cb, ++ CRTC_BLACK_COLOR, ++ CRTC_BLACK_COLOR_B_CB); ++ set_reg_field_value( ++ value, ++ black_color->black_color_g_y, ++ CRTC_BLACK_COLOR, ++ CRTC_BLACK_COLOR_G_Y); ++ set_reg_field_value( ++ value, ++ black_color->black_color_r_cr, ++ CRTC_BLACK_COLOR, ++ CRTC_BLACK_COLOR_R_CR); ++ ++ dal_write_reg(tg->ctx, addr, value); ++ ++ addr = CRTC_REG(mmCRTC_BLANK_DATA_COLOR); ++ dal_write_reg(tg->ctx, addr, value); ++} ++ ++void dce110_tg_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, ++ CRTC_OVERSCAN_COLOR, ++ CRTC_OVERSCAN_COLOR_BLUE); ++ ++ set_reg_field_value( ++ value, ++ overscan_color->black_color_g_y, ++ CRTC_OVERSCAN_COLOR, ++ CRTC_OVERSCAN_COLOR_GREEN); ++ ++ set_reg_field_value( ++ value, ++ overscan_color->black_color_r_cr, ++ CRTC_OVERSCAN_COLOR, ++ CRTC_OVERSCAN_COLOR_RED); ++ ++ addr = CRTC_REG(mmCRTC_OVERSCAN_COLOR); ++ dal_write_reg(ctx, addr, value); ++} ++ ++void dce110_tg_get_position(struct timing_generator *tg, ++ struct crtc_position *position) ++{ ++ int32_t h_position; ++ int32_t v_position; ++ ++ dce110_timing_generator_get_crtc_positions(tg, &h_position, &v_position); ++ ++ position->horizontal_count = (uint32_t)h_position; ++ position->vertical_count = (uint32_t)v_position; ++} ++ ++void dce110_tg_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_program_blanking(tg, timing); ++} ++ ++bool dce110_tg_set_blank(struct timing_generator *tg, ++ bool enable_blanking) ++{ ++ if (enable_blanking) ++ return dce110_timing_generator_blank_crtc(tg); ++ else ++ return dce110_timing_generator_unblank_crtc(tg); ++} ++ ++bool dce110_tg_validate_timing(struct timing_generator *tg, ++ const struct dc_crtc_timing *timing) ++{ ++ return dce110_timing_generator_validate_timing(tg, timing, SIGNAL_TYPE_NONE); ++} ++ ++ ++void dce110_tg_wait_for_state(struct timing_generator *tg, ++ enum crtc_state state) ++{ ++ switch (state) { ++ case CRTC_STATE_VBLANK: ++ dce110_timing_generator_wait_for_vblank(tg); ++ break; ++ ++ case CRTC_STATE_VACTIVE: ++ dce110_timing_generator_wait_for_vactive(tg); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++void dce110_tg_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_program_blank_color(tg, blank_color); ++ if (overscan_color != NULL) ++ dce110_tg_set_overscan_color(tg, overscan_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 c4a815f..4192972 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 +@@ -58,16 +58,29 @@ struct dce110_timing_generator_offsets { + struct dce110_timing_generator { + struct timing_generator base; + struct dce110_timing_generator_offsets offsets; ++ ++ enum controller_id controller_id; ++ ++ uint32_t max_h_total; ++ uint32_t max_v_total; ++ ++ uint32_t min_h_blank; ++ uint32_t min_h_front_porch; ++ uint32_t min_h_back_porch; ++ + enum sync_source cached_gsl_group; + bool advanced_request_enable; + }; + +-/********** Create and destroy **********/ +-struct timing_generator *dce110_timing_generator_create( ++#define DCE110TG_FROM_TG(tg)\ ++ container_of(tg, struct dce110_timing_generator, base) ++ ++bool dce110_timing_generator_construct( ++ struct dce110_timing_generator *tg, + struct adapter_service *as, + struct dc_context *ctx, +- enum controller_id id); +-void dce110_timing_generator_destroy(struct timing_generator **tg); ++ enum controller_id id, ++ const struct dce110_timing_generator_offsets *offsets); + + /* determine if given timing can be supported by TG */ + bool dce110_timing_generator_validate_timing( +@@ -80,7 +93,7 @@ bool dce110_timing_generator_validate_timing( + /* Program timing generator with given timing */ + bool dce110_timing_generator_program_timing_generator( + struct timing_generator *tg, +- struct dc_crtc_timing *dc_crtc_timing); ++ const struct dc_crtc_timing *dc_crtc_timing); + + /* Disable/Enable Timing Generator */ + bool dce110_timing_generator_enable_crtc(struct timing_generator *tg); +@@ -140,17 +153,20 @@ bool dce110_timing_generator_did_triggered_reset_occur( + /* 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); ++/* Move to enable accelerated mode */ + void dce110_timing_generator_disable_vga(struct timing_generator *tg); +- + /* TODO: Should we move it to transform */ ++/* Fully program CRTC timing in timing generator */ + void dce110_timing_generator_program_blanking( + struct timing_generator *tg, + const struct dc_crtc_timing *timing); + + /* TODO: Should we move it to opp? */ ++/* Combine with below and move YUV/RGB color conversion to SW layer */ + void dce110_timing_generator_program_blank_color( + struct timing_generator *tg, + enum color_space color_space); ++/* Combine with above and move YUV/RGB color conversion to SW layer */ + void dce110_timing_generator_set_overscan_color_black( + struct timing_generator *tg, + enum color_space black_color); +@@ -183,4 +199,31 @@ void dce110_timing_generator_enable_advanced_request( + void dce110_timing_generator_set_lock_master(struct timing_generator *tg, + bool lock); + ++void dce110_tg_program_blank_color(struct timing_generator *tg, ++ const struct crtc_black_color *black_color); ++ ++void dce110_tg_set_overscan_color(struct timing_generator *tg, ++ const struct crtc_black_color *overscan_color); ++ ++void dce110_tg_get_position(struct timing_generator *tg, ++ struct crtc_position *position); ++ ++void dce110_tg_program_timing(struct timing_generator *tg, ++ const struct dc_crtc_timing *timing, ++ bool use_vbios); ++ ++bool dce110_tg_set_blank(struct timing_generator *tg, ++ bool enable_blanking); ++ ++bool dce110_tg_validate_timing(struct timing_generator *tg, ++ const struct dc_crtc_timing *timing); ++ ++ ++void dce110_tg_wait_for_state(struct timing_generator *tg, ++ enum crtc_state state); ++ ++void dce110_tg_set_colors(struct timing_generator *tg, ++ const struct crtc_black_color *blank_color, ++ const struct crtc_black_color *overscan_color); ++ + #endif /* __DC_TIMING_GENERATOR_DCE110_H__ */ +diff --git a/drivers/gpu/drm/amd/dal/include/timing_generator_interface.h b/drivers/gpu/drm/amd/dal/include/timing_generator_interface.h +new file mode 100644 +index 0000000..da3e694 +--- /dev/null ++++ b/drivers/gpu/drm/amd/dal/include/timing_generator_interface.h +@@ -0,0 +1,30 @@ ++/* ++ * 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 __DAL_TIMING_GENERATOR_INTERFACE_H__ ++#define __DAL_TIMING_GENERATOR_TNTERFACE_H__ ++#include "timing_generator_types.h" ++ ++#endif /* AMD_DAL_DEV_INCLUDE_TIMING_GENERATOR_INTERFACE_H_ */ +diff --git a/drivers/gpu/drm/amd/dal/include/timing_generator_types.h b/drivers/gpu/drm/amd/dal/include/timing_generator_types.h +index bc04acd..15773c0 100644 +--- a/drivers/gpu/drm/amd/dal/include/timing_generator_types.h ++++ b/drivers/gpu/drm/amd/dal/include/timing_generator_types.h +@@ -28,6 +28,7 @@ + + #include "include/grph_csc_types.h" + ++ + /** + * These parameters are required as input when doing blanking/Unblanking + */ +@@ -134,16 +135,53 @@ enum controller_dp_test_pattern { + CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA + }; + ++enum crtc_state { ++ CRTC_STATE_VBLANK = 0, ++ CRTC_STATE_VACTIVE ++}; ++ + struct timing_generator { ++ struct timing_generator_funcs *funcs; + struct bios_parser *bp; +- enum controller_id controller_id; + struct dc_context *ctx; +- uint32_t max_h_total; +- uint32_t max_v_total; ++}; ++ + +- uint32_t min_h_blank; +- uint32_t min_h_front_porch; +- uint32_t min_h_back_porch; ++struct dc_crtc_timing; ++ ++struct timing_generator_funcs { ++ bool (*validate_timing)(struct timing_generator *tg, ++ const struct dc_crtc_timing *timing); ++ void (*program_timing)(struct timing_generator *tg, ++ const struct dc_crtc_timing *timing, ++ bool use_vbios); ++ bool (*enable_crtc)(struct timing_generator *tg); ++ bool (*disable_crtc)(struct timing_generator *tg); ++ bool (*is_counter_moving)(struct timing_generator *tg); ++ void (*get_position)(struct timing_generator *tg, ++ int32_t *h_position, ++ int32_t *v_position); ++ uint32_t (*get_frame_count)(struct timing_generator *tg); ++ void (*set_early_control)(struct timing_generator *tg, ++ uint32_t early_cntl); ++ void (*wait_for_state)(struct timing_generator *tg, ++ enum crtc_state state); ++ bool (*set_blank)(struct timing_generator *tg, ++ bool enable_blanking); ++ void (*set_overscan_blank_color) (struct timing_generator *tg, enum color_space black_color); ++ void (*set_blank_color)(struct timing_generator *tg, enum color_space black_color); ++ void (*set_colors)(struct timing_generator *tg, ++ const struct crtc_black_color *blank_color, ++ const struct crtc_black_color *overscan_color); ++ ++ void (*disable_vga)(struct timing_generator *tg); ++ bool (*did_triggered_reset_occur)(struct timing_generator *tg); ++ void (*setup_global_swap_lock)(struct timing_generator *tg, ++ const struct dcp_gsl_params *gsl_params); ++ void (*enable_reset_trigger)(struct timing_generator *tg, ++ const struct trigger_params *trigger_params); ++ void (*disable_reset_trigger)(struct timing_generator *tg); ++ void (*tear_down_global_swap_lock)(struct timing_generator *tg); + }; + + #endif +-- +2.7.4 + |