summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c1978
1 files changed, 1978 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
new file mode 100644
index 000000000000..1a682996b531
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
@@ -0,0 +1,1978 @@
+/*
+ * Copyright 2015 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
+ *
+ */
+#include "dm_services.h"
+#include "dc.h"
+#include "dc_bios_types.h"
+#include "core_types.h"
+#include "core_status.h"
+#include "resource.h"
+#include "hw_sequencer.h"
+#include "dm_helpers.h"
+#include "dce110_hw_sequencer.h"
+#include "dce110_timing_generator.h"
+
+#include "bios/bios_parser_helper.h"
+#include "timing_generator.h"
+#include "mem_input.h"
+#include "opp.h"
+#include "ipp.h"
+#include "transform.h"
+#include "stream_encoder.h"
+#include "link_encoder.h"
+#include "clock_source.h"
+#include "gamma_calcs.h"
+#include "audio.h"
+#include "dce/dce_hwseq.h"
+
+/* include DCE11 register header files */
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+struct dce110_hw_seq_reg_offsets {
+ uint32_t crtc;
+};
+
+static const struct dce110_hw_seq_reg_offsets reg_offsets[] = {
+{
+ .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
+},
+{
+ .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
+},
+{
+ .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL),
+},
+{
+ .crtc = (mmCRTCV_GSL_CONTROL - mmCRTC_GSL_CONTROL),
+}
+};
+
+#define HW_REG_BLND(reg, id)\
+ (reg + reg_offsets[id].blnd)
+
+#define HW_REG_CRTC(reg, id)\
+ (reg + reg_offsets[id].crtc)
+
+#define MAX_WATERMARK 0xFFFF
+#define SAFE_NBP_MARK 0x7FFF
+
+/*******************************************************************************
+ * Private definitions
+ ******************************************************************************/
+/***************************PIPE_CONTROL***********************************/
+static void dce110_init_pte(struct dc_context *ctx)
+{
+ uint32_t addr;
+ uint32_t value = 0;
+ uint32_t chunk_int = 0;
+ uint32_t chunk_mul = 0;
+
+ addr = mmUNP_DVMM_PTE_CONTROL;
+ value = dm_read_reg(ctx, addr);
+
+ set_reg_field_value(
+ value,
+ 0,
+ DVMM_PTE_CONTROL,
+ DVMM_USE_SINGLE_PTE);
+
+ set_reg_field_value(
+ value,
+ 1,
+ DVMM_PTE_CONTROL,
+ DVMM_PTE_BUFFER_MODE0);
+
+ set_reg_field_value(
+ value,
+ 1,
+ DVMM_PTE_CONTROL,
+ DVMM_PTE_BUFFER_MODE1);
+
+ dm_write_reg(ctx, addr, value);
+
+ addr = mmDVMM_PTE_REQ;
+ value = dm_read_reg(ctx, addr);
+
+ chunk_int = get_reg_field_value(
+ value,
+ DVMM_PTE_REQ,
+ HFLIP_PTEREQ_PER_CHUNK_INT);
+
+ chunk_mul = get_reg_field_value(
+ value,
+ DVMM_PTE_REQ,
+ HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
+
+ if (chunk_int != 0x4 || chunk_mul != 0x4) {
+
+ set_reg_field_value(
+ value,
+ 255,
+ DVMM_PTE_REQ,
+ MAX_PTEREQ_TO_ISSUE);
+
+ set_reg_field_value(
+ value,
+ 4,
+ DVMM_PTE_REQ,
+ HFLIP_PTEREQ_PER_CHUNK_INT);
+
+ set_reg_field_value(
+ value,
+ 4,
+ DVMM_PTE_REQ,
+ HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
+
+ dm_write_reg(ctx, addr, value);
+ }
+}
+/**************************************************************************/
+
+static void enable_display_pipe_clock_gating(
+ struct dc_context *ctx,
+ bool clock_gating)
+{
+ /*TODO*/
+}
+
+static bool dce110_enable_display_power_gating(
+ struct core_dc *dc,
+ uint8_t controller_id,
+ struct dc_bios *dcb,
+ enum pipe_gating_control power_gating)
+{
+ enum bp_result bp_result = BP_RESULT_OK;
+ enum bp_pipe_control_action cntl;
+ struct dc_context *ctx = dc->ctx;
+ unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
+
+ if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
+ return true;
+
+ if (power_gating == PIPE_GATING_CONTROL_INIT)
+ cntl = ASIC_PIPE_INIT;
+ else if (power_gating == PIPE_GATING_CONTROL_ENABLE)
+ cntl = ASIC_PIPE_ENABLE;
+ else
+ cntl = ASIC_PIPE_DISABLE;
+
+ if (controller_id == underlay_idx)
+ controller_id = CONTROLLER_ID_UNDERLAY0 - 1;
+
+ if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0){
+
+ bp_result = dcb->funcs->enable_disp_power_gating(
+ dcb, controller_id + 1, cntl);
+
+ /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2
+ * by default when command table is called
+ *
+ * Bios parser accepts controller_id = 6 as indicative of
+ * underlay pipe in dce110. But we do not support more
+ * than 3.
+ */
+ if (controller_id < CONTROLLER_ID_MAX - 1)
+ dm_write_reg(ctx,
+ HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id),
+ 0);
+ }
+
+ if (power_gating != PIPE_GATING_CONTROL_ENABLE)
+ dce110_init_pte(ctx);
+
+ if (bp_result == BP_RESULT_OK)
+ return true;
+ else
+ return false;
+}
+
+static void build_prescale_params(struct ipp_prescale_params *prescale_params,
+ const struct core_surface *surface)
+{
+ prescale_params->mode = IPP_PRESCALE_MODE_FIXED_UNSIGNED;
+
+ switch (surface->public.format) {
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
+ case SURFACE_PIXEL_FORMAT_GRPH_BGRA8888:
+ prescale_params->scale = 0x2020;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
+ prescale_params->scale = 0x2008;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
+ prescale_params->scale = 0x2000;
+ break;
+ default:
+ ASSERT(false);
+ }
+}
+
+static bool set_gamma_ramp(
+ struct input_pixel_processor *ipp,
+ struct output_pixel_processor *opp,
+ const struct core_gamma *ramp,
+ const struct core_surface *surface)
+{
+ struct ipp_prescale_params prescale_params = { 0 };
+ struct pwl_params *regamma_params;
+ bool result = false;
+
+ regamma_params = dm_alloc(sizeof(struct pwl_params));
+ if (regamma_params == NULL)
+ goto regamma_alloc_fail;
+
+ regamma_params->hw_points_num = GAMMA_HW_POINTS_NUM;
+
+ opp->funcs->opp_power_on_regamma_lut(opp, true);
+
+ if (ipp) {
+ build_prescale_params(&prescale_params, surface);
+ ipp->funcs->ipp_program_prescale(ipp, &prescale_params);
+ }
+
+ if (ramp && calculate_regamma_params(regamma_params, ramp, surface)) {
+
+ opp->funcs->opp_program_regamma_pwl(opp, regamma_params);
+ if (ipp)
+ ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_sRGB);
+ opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER);
+ } else {
+ if (ipp)
+ ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
+ opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_BYPASS);
+ }
+
+ opp->funcs->opp_power_on_regamma_lut(opp, false);
+
+ result = true;
+
+ dm_free(regamma_params);
+
+regamma_alloc_fail:
+ return result;
+}
+
+static enum dc_status bios_parser_crtc_source_select(
+ struct pipe_ctx *pipe_ctx)
+{
+ struct dc_bios *dcb;
+ /* call VBIOS table to set CRTC source for the HW
+ * encoder block
+ * note: video bios clears all FMT setting here. */
+ struct bp_crtc_source_select crtc_source_select = {0};
+ const struct core_sink *sink = pipe_ctx->stream->sink;
+
+ crtc_source_select.engine_id = pipe_ctx->stream_enc->id;
+ crtc_source_select.controller_id = pipe_ctx->pipe_idx + 1;
+ /*TODO: Need to un-hardcode color depth, dp_audio and account for
+ * the case where signal and sink signal is different (translator
+ * encoder)*/
+ crtc_source_select.signal = pipe_ctx->stream->signal;
+ crtc_source_select.enable_dp_audio = false;
+ crtc_source_select.sink_signal = pipe_ctx->stream->signal;
+ crtc_source_select.display_output_bit_depth = PANEL_8BIT_COLOR;
+
+ dcb = sink->ctx->dc_bios;
+
+ if (BP_RESULT_OK != dcb->funcs->crtc_source_select(
+ dcb,
+ &crtc_source_select)) {
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ return DC_OK;
+}
+
+void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
+{
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->update_hdmi_info_packets(
+ pipe_ctx->stream_enc,
+ &pipe_ctx->encoder_info_frame);
+ else if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->update_dp_info_packets(
+ pipe_ctx->stream_enc,
+ &pipe_ctx->encoder_info_frame);
+}
+
+void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
+{
+ enum dc_lane_count lane_count =
+ pipe_ctx->stream->sink->link->public.cur_link_settings.lane_count;
+
+ struct dc_crtc_timing *timing = &pipe_ctx->stream->public.timing;
+ struct core_link *link = pipe_ctx->stream->sink->link;
+
+ /* 1. update AVI info frame (HDMI, DP)
+ * we always need to update info frame
+ */
+ uint32_t active_total_with_borders;
+ uint32_t early_control = 0;
+ struct timing_generator *tg = pipe_ctx->tg;
+
+ /* TODOFPGA may change to hwss.update_info_frame */
+ dce110_update_info_frame(pipe_ctx);
+ /* enable early control to avoid corruption on DP monitor*/
+ active_total_with_borders =
+ timing->h_addressable
+ + timing->h_border_left
+ + timing->h_border_right;
+
+ if (lane_count != 0)
+ early_control = active_total_with_borders % lane_count;
+
+ if (early_control == 0)
+ early_control = lane_count;
+
+ tg->funcs->set_early_control(tg, early_control);
+
+ /* enable audio only within mode set */
+ if (pipe_ctx->audio != NULL) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_enc);
+ }
+
+ /* For MST, there are multiply stream go to only one link.
+ * connect DIG back_end to front_end while enable_stream and
+ * disconnect them during disable_stream
+ * BY this, it is logic clean to separate stream and link */
+ link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
+ pipe_ctx->stream_enc->id, true);
+
+}
+
+void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
+{
+ struct core_stream *stream = pipe_ctx->stream;
+ struct core_link *link = stream->sink->link;
+
+ if (pipe_ctx->audio) {
+ pipe_ctx->audio->funcs->az_disable(pipe_ctx->audio);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->dp_audio_disable(
+ pipe_ctx->stream_enc);
+ else
+ pipe_ctx->stream_enc->funcs->hdmi_audio_disable(
+ pipe_ctx->stream_enc);
+
+ pipe_ctx->audio = NULL;
+
+ /* TODO: notify audio driver for if audio modes list changed
+ * add audio mode list change flag */
+ /* dal_audio_disable_azalia_audio_jack_presence(stream->audio,
+ * stream->stream_engine_id);
+ */
+ }
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->stop_hdmi_info_packets(
+ pipe_ctx->stream_enc);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->stop_dp_info_packets(
+ pipe_ctx->stream_enc);
+
+ pipe_ctx->stream_enc->funcs->audio_mute_control(
+ pipe_ctx->stream_enc, true);
+
+
+ /* blank at encoder level */
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->dp_blank(pipe_ctx->stream_enc);
+
+ link->link_enc->funcs->connect_dig_be_to_fe(
+ link->link_enc,
+ pipe_ctx->stream_enc->id,
+ false);
+
+}
+
+void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
+ struct dc_link_settings *link_settings)
+{
+ struct encoder_unblank_param params = { { 0 } };
+
+ /* only 3 items below are used by unblank */
+ params.crtc_timing.pixel_clock =
+ pipe_ctx->stream->public.timing.pix_clk_khz;
+ params.link_settings.link_rate = link_settings->link_rate;
+ pipe_ctx->stream_enc->funcs->dp_unblank(pipe_ctx->stream_enc, &params);
+}
+
+static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
+{
+ switch (crtc_id) {
+ case CONTROLLER_ID_D0:
+ return DTO_SOURCE_ID0;
+ case CONTROLLER_ID_D1:
+ return DTO_SOURCE_ID1;
+ case CONTROLLER_ID_D2:
+ return DTO_SOURCE_ID2;
+ case CONTROLLER_ID_D3:
+ return DTO_SOURCE_ID3;
+ case CONTROLLER_ID_D4:
+ return DTO_SOURCE_ID4;
+ case CONTROLLER_ID_D5:
+ return DTO_SOURCE_ID5;
+ default:
+ return DTO_SOURCE_UNKNOWN;
+ }
+}
+
+static void build_audio_output(
+ const struct pipe_ctx *pipe_ctx,
+ struct audio_output *audio_output)
+{
+ const struct core_stream *stream = pipe_ctx->stream;
+ audio_output->engine_id = pipe_ctx->stream_enc->id;
+
+ audio_output->signal = pipe_ctx->stream->signal;
+
+ /* audio_crtc_info */
+
+ audio_output->crtc_info.h_total =
+ stream->public.timing.h_total;
+
+ /*
+ * Audio packets are sent during actual CRTC blank physical signal, we
+ * need to specify actual active signal portion
+ */
+ audio_output->crtc_info.h_active =
+ stream->public.timing.h_addressable
+ + stream->public.timing.h_border_left
+ + stream->public.timing.h_border_right;
+
+ audio_output->crtc_info.v_active =
+ stream->public.timing.v_addressable
+ + stream->public.timing.v_border_top
+ + stream->public.timing.v_border_bottom;
+
+ audio_output->crtc_info.pixel_repetition = 1;
+
+ audio_output->crtc_info.interlaced =
+ stream->public.timing.flags.INTERLACE;
+
+ audio_output->crtc_info.refresh_rate =
+ (stream->public.timing.pix_clk_khz*1000)/
+ (stream->public.timing.h_total*stream->public.timing.v_total);
+
+ audio_output->crtc_info.color_depth =
+ stream->public.timing.display_color_depth;
+
+ audio_output->crtc_info.requested_pixel_clock =
+ pipe_ctx->pix_clk_params.requested_pix_clk;
+
+ /*
+ * TODO - Investigate why calculated pixel clk has to be
+ * requested pixel clk
+ */
+ audio_output->crtc_info.calculated_pixel_clock =
+ pipe_ctx->pix_clk_params.requested_pix_clk;
+
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
+ pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ audio_output->pll_info.dp_dto_source_clock_in_khz =
+ dal_display_clock_get_dp_ref_clk_frequency(
+ pipe_ctx->dis_clk);
+ }
+
+ audio_output->pll_info.feed_back_divider =
+ pipe_ctx->pll_settings.feedback_divider;
+
+ audio_output->pll_info.dto_source =
+ translate_to_dto_source(
+ pipe_ctx->pipe_idx + 1);
+
+ /* TODO hard code to enable for now. Need get from stream */
+ audio_output->pll_info.ss_enabled = true;
+
+ audio_output->pll_info.ss_percentage =
+ pipe_ctx->pll_settings.ss_percentage;
+}
+
+static void get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx,
+ struct tg_color *color)
+{
+ uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->pipe_idx) / 4;
+
+ switch (pipe_ctx->scl_data.format) {
+ case PIXEL_FORMAT_ARGB8888:
+ /* set boarder color to red */
+ color->color_r_cr = color_value;
+ break;
+
+ case PIXEL_FORMAT_ARGB2101010:
+ /* set boarder color to blue */
+ color->color_b_cb = color_value;
+ break;
+ case PIXEL_FORMAT_420BPP12:
+ /* set boarder color to green */
+ color->color_g_y = color_value;
+ break;
+ case PIXEL_FORMAT_FP16:
+ /* set boarder color to white */
+ color->color_r_cr = color_value;
+ color->color_b_cb = color_value;
+ color->color_g_y = color_value;
+ break;
+ default:
+ break;
+ }
+}
+
+static void program_scaler(const struct core_dc *dc,
+ const struct pipe_ctx *pipe_ctx)
+{
+ struct tg_color color = {0};
+
+ if (dc->public.debug.surface_visual_confirm)
+ get_surface_visual_confirm_color(pipe_ctx, &color);
+ else
+ color_space_to_black_color(dc,
+ pipe_ctx->stream->public.output_color_space,
+ &color);
+
+ pipe_ctx->xfm->funcs->transform_set_pixel_storage_depth(
+ pipe_ctx->xfm,
+ pipe_ctx->scl_data.lb_params.depth,
+ &pipe_ctx->stream->bit_depth_params);
+
+ if (pipe_ctx->tg->funcs->set_overscan_blank_color)
+ pipe_ctx->tg->funcs->set_overscan_blank_color(
+ pipe_ctx->tg,
+ &color);
+
+ pipe_ctx->xfm->funcs->transform_set_scaler(pipe_ctx->xfm,
+ &pipe_ctx->scl_data);
+}
+
+static enum dc_status prog_pixclk_crtc_otg(
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context,
+ struct core_dc *dc)
+{
+ struct core_stream *stream = pipe_ctx->stream;
+ struct pipe_ctx *pipe_ctx_old = &dc->current_context->res_ctx.
+ pipe_ctx[pipe_ctx->pipe_idx];
+ struct tg_color black_color = {0};
+
+ if (!pipe_ctx_old->stream) {
+
+ /* program blank color */
+ color_space_to_black_color(dc,
+ stream->public.output_color_space, &black_color);
+ pipe_ctx->tg->funcs->set_blank_color(
+ pipe_ctx->tg,
+ &black_color);
+ /*
+ * Must blank CRTC after disabling power gating and before any
+ * programming, otherwise CRTC will be hung in bad state
+ */
+ pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
+
+ if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
+ pipe_ctx->clock_source,
+ &pipe_ctx->pix_clk_params,
+ &pipe_ctx->pll_settings)) {
+ BREAK_TO_DEBUGGER();
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ pipe_ctx->tg->funcs->program_timing(
+ pipe_ctx->tg,
+ &stream->public.timing,
+ true);
+ }
+
+ if (!pipe_ctx_old->stream) {
+ if (false == pipe_ctx->tg->funcs->enable_crtc(
+ pipe_ctx->tg)) {
+ BREAK_TO_DEBUGGER();
+ return DC_ERROR_UNEXPECTED;
+ }
+ }
+
+ return DC_OK;
+}
+
+static enum dc_status apply_single_controller_ctx_to_hw(
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context,
+ struct core_dc *dc)
+{
+ struct core_stream *stream = pipe_ctx->stream;
+ struct pipe_ctx *pipe_ctx_old = &dc->current_context->res_ctx.
+ pipe_ctx[pipe_ctx->pipe_idx];
+
+ /* */
+ dc->hwss.prog_pixclk_crtc_otg(pipe_ctx, context, dc);
+
+ pipe_ctx->opp->funcs->opp_set_dyn_expansion(
+ pipe_ctx->opp,
+ COLOR_SPACE_YCBCR601,
+ stream->public.timing.display_color_depth,
+ pipe_ctx->stream->signal);
+
+ pipe_ctx->opp->funcs->opp_program_fmt(
+ pipe_ctx->opp,
+ &stream->bit_depth_params,
+ &stream->clamping);
+
+ /* FPGA does not program backend */
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ return DC_OK;
+
+ /* TODO: move to stream encoder */
+ if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL)
+ if (DC_OK != bios_parser_crtc_source_select(pipe_ctx)) {
+ BREAK_TO_DEBUGGER();
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL)
+ stream->sink->link->link_enc->funcs->setup(
+ stream->sink->link->link_enc,
+ pipe_ctx->stream->signal);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->dp_set_stream_attribute(
+ pipe_ctx->stream_enc,
+ &stream->public.timing,
+ stream->public.output_color_space);
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->hdmi_set_stream_attribute(
+ pipe_ctx->stream_enc,
+ &stream->public.timing,
+ stream->phy_pix_clk,
+ pipe_ctx->audio != NULL);
+
+ if (dc_is_dvi_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->dvi_set_stream_attribute(
+ pipe_ctx->stream_enc,
+ &stream->public.timing,
+ (pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
+ true : false);
+
+ if (!pipe_ctx_old->stream) {
+ core_link_enable_stream(pipe_ctx);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dce110_unblank_stream(pipe_ctx,
+ &stream->sink->link->public.cur_link_settings);
+ }
+
+ pipe_ctx->scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
+ /* program_scaler and allocate_mem_input are not new asic */
+ if (!pipe_ctx_old || memcmp(&pipe_ctx_old->scl_data,
+ &pipe_ctx->scl_data,
+ sizeof(struct scaler_data)) != 0)
+ program_scaler(dc, pipe_ctx);
+
+ /* mst support - use total stream count */
+ pipe_ctx->mi->funcs->allocate_mem_input(
+ pipe_ctx->mi,
+ stream->public.timing.h_total,
+ stream->public.timing.v_total,
+ stream->public.timing.pix_clk_khz,
+ context->target_count);
+
+ return DC_OK;
+}
+
+/******************************************************************************/
+
+static void power_down_encoders(struct core_dc *dc)
+{
+ int i;
+
+ for (i = 0; i < dc->link_count; i++) {
+ dc->links[i]->link_enc->funcs->disable_output(
+ dc->links[i]->link_enc, SIGNAL_TYPE_NONE);
+ }
+}
+
+static void power_down_controllers(struct core_dc *dc)
+{
+ int i;
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ dc->res_pool->timing_generators[i]->funcs->disable_crtc(
+ dc->res_pool->timing_generators[i]);
+ }
+}
+
+static void power_down_clock_sources(struct core_dc *dc)
+{
+ int i;
+
+ if (dc->res_pool->dp_clock_source->funcs->cs_power_down(
+ dc->res_pool->dp_clock_source) == false)
+ dm_error("Failed to power down pll! (dp clk src)\n");
+
+ for (i = 0; i < dc->res_pool->clk_src_count; i++) {
+ if (dc->res_pool->clock_sources[i]->funcs->cs_power_down(
+ dc->res_pool->clock_sources[i]) == false)
+ dm_error("Failed to power down pll! (clk src index=%d)\n", i);
+ }
+}
+
+static void power_down_all_hw_blocks(struct core_dc *dc)
+{
+ power_down_encoders(dc);
+
+ power_down_controllers(dc);
+
+ power_down_clock_sources(dc);
+}
+
+static void disable_vga_and_power_gate_all_controllers(
+ struct core_dc *dc)
+{
+ int i;
+ struct timing_generator *tg;
+ struct dc_context *ctx = dc->ctx;
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ tg = dc->res_pool->timing_generators[i];
+
+ tg->funcs->disable_vga(tg);
+
+ /* Enable CLOCK gating for each pipe BEFORE controller
+ * powergating. */
+ enable_display_pipe_clock_gating(ctx,
+ true);
+
+ dc->hwss.power_down_front_end(
+ dc, &dc->current_context->res_ctx.pipe_ctx[i]);
+ }
+}
+
+/**
+ * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need:
+ * 1. Power down all DC HW blocks
+ * 2. Disable VGA engine on all controllers
+ * 3. Enable power gating for controller
+ * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS)
+ */
+void dce110_enable_accelerated_mode(struct core_dc *dc)
+{
+ power_down_all_hw_blocks(dc);
+
+ disable_vga_and_power_gate_all_controllers(dc);
+ bios_set_scratch_acc_mode_change(dc->ctx->dc_bios);
+}
+
+/**
+ * Call display_engine_clock_dce80 to perform the Dclk programming.
+ */
+void dce110_set_display_clock(struct validate_context *context)
+{
+ /* Program the display engine clock.
+ * Check DFS bypass mode support or not. DFSbypass feature is only when
+ * BIOS GPU info table reports support. */
+
+ if (/*dal_adapter_service_is_dfs_bypass_enabled()*/ false) {
+ /*TODO: set_display_clock_dfs_bypass(
+ hws,
+ path_set,
+ context->res_ctx.pool->display_clock,
+ context->res_ctx.min_clocks.min_dclk_khz);*/
+ } else {
+ /*
+ * TODO: need to either port work around from DAL2 function
+ * getActualRequiredDisplayClock or program displayclock without
+ * calling vbios. Currently temporily work
+ * around by increasing the displclk by 15 percent
+ */
+ dal_display_clock_set_clock(
+ context->res_ctx.pool->display_clock,
+ context->bw_results.dispclk_khz * 115 / 100);
+ }
+
+
+ /* TODO: When changing display engine clock, DMCU WaitLoop must be
+ * reconfigured in order to maintain the same delays within DMCU
+ * programming sequences. */
+}
+
+static uint32_t compute_pstate_blackout_duration(
+ struct bw_fixed blackout_duration,
+ const struct core_stream *stream)
+{
+ uint32_t total_dest_line_time_ns;
+ uint32_t pstate_blackout_duration_ns;
+
+ pstate_blackout_duration_ns = 1000 * blackout_duration.value >> 24;
+
+ total_dest_line_time_ns = 1000000UL *
+ stream->public.timing.h_total /
+ stream->public.timing.pix_clk_khz +
+ pstate_blackout_duration_ns;
+
+ return total_dest_line_time_ns;
+}
+
+/* get the index of the pipe_ctx if there were no gaps in the pipe_ctx array*/
+int get_bw_result_idx(
+ struct resource_context *res_ctx,
+ int pipe_idx)
+{
+ int i, collapsed_idx;
+
+ if (res_ctx->pipe_ctx[pipe_idx].top_pipe)
+ return 3;
+
+ collapsed_idx = 0;
+ for (i = 0; i < pipe_idx; i++) {
+ if (res_ctx->pipe_ctx[i].stream)
+ collapsed_idx++;
+ }
+
+ return collapsed_idx;
+}
+
+static bool is_watermark_set_a_greater(
+ const struct bw_watermarks *set_a,
+ const struct bw_watermarks *set_b)
+{
+ if (set_a->a_mark > set_b->a_mark
+ || set_a->b_mark > set_b->b_mark
+ || set_a->c_mark > set_b->c_mark
+ || set_a->d_mark > set_b->d_mark)
+ return true;
+ return false;
+}
+
+static bool did_watermarks_increase(
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context,
+ struct validate_context *old_context)
+{
+ int collapsed_pipe_idx = get_bw_result_idx(&context->res_ctx,
+ pipe_ctx->pipe_idx);
+ int old_collapsed_pipe_idx = get_bw_result_idx(&old_context->res_ctx,
+ pipe_ctx->pipe_idx);
+ struct pipe_ctx *old_pipe_ctx = &old_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
+
+ if (!old_pipe_ctx->stream)
+ return true;
+
+ if (is_watermark_set_a_greater(
+ &context->bw_results.nbp_state_change_wm_ns[collapsed_pipe_idx],
+ &old_context->bw_results.nbp_state_change_wm_ns[old_collapsed_pipe_idx]))
+ return true;
+ if (is_watermark_set_a_greater(
+ &context->bw_results.stutter_exit_wm_ns[collapsed_pipe_idx],
+ &old_context->bw_results.stutter_exit_wm_ns[old_collapsed_pipe_idx]))
+ return true;
+ if (is_watermark_set_a_greater(
+ &context->bw_results.urgent_wm_ns[collapsed_pipe_idx],
+ &old_context->bw_results.urgent_wm_ns[old_collapsed_pipe_idx]))
+ return true;
+
+ return false;
+}
+
+static void program_wm_for_pipe(struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context)
+{
+ int total_dest_line_time_ns = compute_pstate_blackout_duration(
+ dc->bw_vbios.blackout_duration,
+ pipe_ctx->stream);
+ int bw_result_idx = get_bw_result_idx(&context->res_ctx,
+ pipe_ctx->pipe_idx);
+
+ pipe_ctx->mi->funcs->mem_input_program_display_marks(
+ pipe_ctx->mi,
+ context->bw_results.nbp_state_change_wm_ns[bw_result_idx],
+ context->bw_results.stutter_exit_wm_ns[bw_result_idx],
+ context->bw_results.urgent_wm_ns[bw_result_idx],
+ total_dest_line_time_ns);
+
+ if (pipe_ctx->top_pipe)
+ pipe_ctx->mi->funcs->mem_input_program_chroma_display_marks(
+ pipe_ctx->mi,
+ context->bw_results.nbp_state_change_wm_ns[bw_result_idx + 1],
+ context->bw_results.stutter_exit_wm_ns[bw_result_idx + 1],
+ context->bw_results.urgent_wm_ns[bw_result_idx + 1],
+ total_dest_line_time_ns);
+}
+
+void dce110_set_displaymarks(
+ const struct core_dc *dc,
+ struct validate_context *context)
+{
+ uint8_t i, num_pipes;
+ unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
+
+ for (i = 0, num_pipes = 0; i < MAX_PIPES; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+ uint32_t total_dest_line_time_ns;
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ total_dest_line_time_ns = compute_pstate_blackout_duration(
+ dc->bw_vbios.blackout_duration, pipe_ctx->stream);
+ pipe_ctx->mi->funcs->mem_input_program_display_marks(
+ pipe_ctx->mi,
+ context->bw_results.nbp_state_change_wm_ns[num_pipes],
+ context->bw_results.stutter_exit_wm_ns[num_pipes],
+ context->bw_results.urgent_wm_ns[num_pipes],
+ total_dest_line_time_ns);
+ if (i == underlay_idx) {
+ num_pipes++;
+ pipe_ctx->mi->funcs->mem_input_program_chroma_display_marks(
+ pipe_ctx->mi,
+ context->bw_results.nbp_state_change_wm_ns[num_pipes],
+ context->bw_results.stutter_exit_wm_ns[num_pipes],
+ context->bw_results.urgent_wm_ns[num_pipes],
+ total_dest_line_time_ns);
+ }
+ num_pipes++;
+ }
+}
+
+static void set_safe_displaymarks(struct resource_context *res_ctx)
+{
+ int i;
+ int underlay_idx = res_ctx->pool->underlay_pipe_index;
+ struct bw_watermarks max_marks = {
+ MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK };
+ struct bw_watermarks nbp_marks = {
+ SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK };
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (res_ctx->pipe_ctx[i].stream == NULL)
+ continue;
+
+ res_ctx->pipe_ctx[i].mi->funcs->mem_input_program_display_marks(
+ res_ctx->pipe_ctx[i].mi,
+ nbp_marks,
+ max_marks,
+ max_marks,
+ MAX_WATERMARK);
+ if (i == underlay_idx)
+ res_ctx->pipe_ctx[i].mi->funcs->mem_input_program_chroma_display_marks(
+ res_ctx->pipe_ctx[i].mi,
+ nbp_marks,
+ max_marks,
+ max_marks,
+ MAX_WATERMARK);
+ }
+}
+
+static void switch_dp_clock_sources(
+ const struct core_dc *dc,
+ struct resource_context *res_ctx)
+{
+ uint8_t i;
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe)
+ continue;
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
+ struct clock_source *clk_src =
+ resource_find_used_clk_src_for_sharing(
+ res_ctx, pipe_ctx);
+
+ if (clk_src &&
+ clk_src != pipe_ctx->clock_source) {
+ resource_unreference_clock_source(
+ res_ctx, pipe_ctx->clock_source);
+ pipe_ctx->clock_source = clk_src;
+ resource_reference_clock_source(res_ctx, clk_src);
+
+ dce_crtc_switch_to_clk_src(dc->hwseq, clk_src, i);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ * Public functions
+ ******************************************************************************/
+
+static void reset_single_pipe_hw_ctx(
+ const struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context)
+{
+ core_link_disable_stream(pipe_ctx);
+ if (!pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true)) {
+ dm_error("DC: failed to blank crtc!\n");
+ BREAK_TO_DEBUGGER();
+ }
+ pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
+ pipe_ctx->mi->funcs->free_mem_input(
+ pipe_ctx->mi, context->target_count);
+ resource_unreference_clock_source(
+ &context->res_ctx, pipe_ctx->clock_source);
+
+ dc->hwss.power_down_front_end((struct core_dc *)dc, pipe_ctx);
+
+ pipe_ctx->stream = NULL;
+}
+
+static void set_drr(struct pipe_ctx **pipe_ctx,
+ int num_pipes, int vmin, int vmax)
+{
+ int i = 0;
+ struct drr_params params = {0};
+
+ params.vertical_total_max = vmax;
+ params.vertical_total_min = vmin;
+
+ /* TODO: If multiple pipes are to be supported, you need
+ * some GSL stuff
+ */
+
+ for (i = 0; i < num_pipes; i++) {
+ pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
+ }
+}
+
+static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
+ int num_pipes, int value)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_pipes; i++)
+ pipe_ctx[i]->tg->funcs->
+ set_static_screen_control(pipe_ctx[i]->tg, value);
+}
+
+/* unit: in_khz before mode set, get pixel clock from context. ASIC register
+ * may not be programmed yet.
+ * TODO: after mode set, pre_mode_set = false,
+ * may read PLL register to get pixel clock
+ */
+static uint32_t get_max_pixel_clock_for_all_paths(
+ struct core_dc *dc,
+ struct validate_context *context,
+ bool pre_mode_set)
+{
+ uint32_t max_pix_clk = 0;
+ int i;
+
+ if (!pre_mode_set) {
+ /* TODO: read ASIC register to get pixel clock */
+ ASSERT(0);
+ }
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ /* do not check under lay */
+ if (pipe_ctx->top_pipe)
+ continue;
+
+ if (pipe_ctx->pix_clk_params.requested_pix_clk > max_pix_clk)
+ max_pix_clk =
+ pipe_ctx->pix_clk_params.requested_pix_clk;
+ }
+
+ if (max_pix_clk == 0)
+ ASSERT(0);
+
+ return max_pix_clk;
+}
+
+/*
+ * Find clock state based on clock requested. if clock value is 0, simply
+ * set clock state as requested without finding clock state by clock value
+ */
+static void apply_min_clocks(
+ struct core_dc *dc,
+ struct validate_context *context,
+ enum clocks_state *clocks_state,
+ bool pre_mode_set)
+{
+ struct state_dependent_clocks req_clocks = {0};
+ struct pipe_ctx *pipe_ctx;
+ int i;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &context->res_ctx.pipe_ctx[i];
+ if (pipe_ctx->dis_clk != NULL)
+ break;
+ }
+
+ if (!pre_mode_set) {
+ /* set clock_state without verification */
+ if (dal_display_clock_set_min_clocks_state(
+ pipe_ctx->dis_clk, *clocks_state))
+ return;
+
+ /* TODOFPGA */
+ }
+
+ /* get the required state based on state dependent clocks:
+ * display clock and pixel clock
+ */
+ req_clocks.display_clk_khz = context->bw_results.dispclk_khz;
+
+ req_clocks.pixel_clk_khz = get_max_pixel_clock_for_all_paths(
+ dc, context, true);
+
+ if (dal_display_clock_get_required_clocks_state(
+ pipe_ctx->dis_clk, &req_clocks, clocks_state)) {
+ dal_display_clock_set_min_clocks_state(
+ pipe_ctx->dis_clk, *clocks_state);
+ } else {
+ }
+}
+
+static enum dc_status apply_ctx_to_hw_fpga(
+ struct core_dc *dc,
+ struct validate_context *context)
+{
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+ int i;
+
+ for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx_old =
+ &dc->current_context->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ if (pipe_ctx->stream == pipe_ctx_old->stream)
+ continue;
+
+ status = apply_single_controller_ctx_to_hw(
+ pipe_ctx,
+ context,
+ dc);
+
+ if (status != DC_OK)
+ return status;
+ }
+
+ return DC_OK;
+}
+
+static void reset_hw_ctx_wrap(
+ struct core_dc *dc,
+ struct validate_context *context)
+{
+ int i;
+
+ /* Reset old context */
+ /* look up the targets that have been removed since last commit */
+ for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx_old =
+ &dc->current_context->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ /* Note: We need to disable output if clock sources change,
+ * since bios does optimization and doesn't apply if changing
+ * PHY when not already disabled.
+ */
+
+ /* Skip underlay pipe since it will be handled in commit surface*/
+ if (!pipe_ctx_old->stream || pipe_ctx_old->top_pipe)
+ continue;
+
+ if (!pipe_ctx->stream ||
+ pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
+ reset_single_pipe_hw_ctx(
+ dc, pipe_ctx_old, dc->current_context);
+ }
+}
+
+/*TODO: const validate_context*/
+enum dc_status dce110_apply_ctx_to_hw(
+ struct core_dc *dc,
+ struct validate_context *context)
+{
+ struct dc_bios *dcb = dc->ctx->dc_bios;
+ enum dc_status status;
+ int i;
+ bool programmed_audio_dto = false;
+ enum clocks_state clocks_state = CLOCKS_STATE_INVALID;
+
+ /* Reset old context */
+ /* look up the targets that have been removed since last commit */
+ dc->hwss.reset_hw_ctx_wrap(dc, context);
+
+ /* Skip applying if no targets */
+ if (context->target_count <= 0)
+ return DC_OK;
+
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ apply_ctx_to_hw_fpga(dc, context);
+ return DC_OK;
+ }
+
+ /* Apply new context */
+ dcb->funcs->set_scratch_critical_state(dcb, true);
+
+ /* below is for real asic only */
+ for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx_old =
+ &dc->current_context->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe)
+ continue;
+
+ if (pipe_ctx->stream == pipe_ctx_old->stream) {
+ if (pipe_ctx_old->clock_source != pipe_ctx->clock_source)
+ dce_crtc_switch_to_clk_src(dc->hwseq,
+ pipe_ctx->clock_source, i);
+ continue;
+ }
+
+ dc->hwss.enable_display_power_gating(
+ dc, i, dc->ctx->dc_bios,
+ PIPE_GATING_CONTROL_DISABLE);
+ }
+
+ set_safe_displaymarks(&context->res_ctx);
+ /*TODO: when pplib works*/
+ apply_min_clocks(dc, context, &clocks_state, true);
+
+ if (context->bw_results.dispclk_khz
+ > dc->current_context->bw_results.dispclk_khz)
+ dc->hwss.set_display_clock(context);
+
+ for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx_old =
+ &dc->current_context->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream == NULL)
+ continue;
+
+ if (pipe_ctx->stream == pipe_ctx_old->stream)
+ continue;
+
+ if (pipe_ctx->top_pipe)
+ continue;
+
+ if (context->res_ctx.pipe_ctx[i].audio != NULL) {
+ /* Setup audio rate clock source */
+ /* Issue:
+ * Audio lag happened on DP monitor when unplug a HDMI monitor
+ *
+ * Cause:
+ * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL
+ * is set to either dto0 or dto1, audio should work fine.
+ * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1,
+ * set to dto0 will cause audio lag.
+ *
+ * Solution:
+ * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx,
+ * find first available pipe with audio, setup audio wall DTO per topology
+ * instead of per pipe.
+ */
+ struct audio_output audio_output;
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ build_audio_output(pipe_ctx, &audio_output);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ pipe_ctx->stream_enc->funcs->dp_audio_setup(
+ pipe_ctx->stream_enc,
+ pipe_ctx->audio->inst,
+ &pipe_ctx->stream->public.audio_info);
+ else
+ pipe_ctx->stream_enc->funcs->hdmi_audio_setup(
+ pipe_ctx->stream_enc,
+ pipe_ctx->audio->inst,
+ &pipe_ctx->stream->public.audio_info,
+ &audio_output.crtc_info);
+
+ pipe_ctx->audio->funcs->az_configure(
+ pipe_ctx->audio,
+ pipe_ctx->stream->signal,
+ &audio_output.crtc_info,
+ &pipe_ctx->stream->public.audio_info);
+
+ if (!programmed_audio_dto) {
+ pipe_ctx->audio->funcs->wall_dto_setup(
+ pipe_ctx->audio,
+ pipe_ctx->stream->signal,
+ &audio_output.crtc_info,
+ &audio_output.pll_info);
+ programmed_audio_dto = true;
+ }
+ }
+
+ status = apply_single_controller_ctx_to_hw(
+ pipe_ctx,
+ context,
+ dc);
+
+ if (DC_OK != status)
+ return status;
+ }
+
+ dc->hwss.set_displaymarks(dc, context);
+
+ /* to save power */
+ apply_min_clocks(dc, context, &clocks_state, false);
+
+ dcb->funcs->set_scratch_critical_state(dcb, false);
+
+ switch_dp_clock_sources(dc, &context->res_ctx);
+
+ return DC_OK;
+}
+
+/*******************************************************************************
+ * Front End programming
+ ******************************************************************************/
+static void set_default_colors(struct pipe_ctx *pipe_ctx)
+{
+ struct default_adjustment default_adjust = { 0 };
+
+ default_adjust.force_hw_default = false;
+ if (pipe_ctx->surface == NULL)
+ default_adjust.in_color_space = COLOR_SPACE_SRGB;
+ else
+ default_adjust.in_color_space =
+ pipe_ctx->surface->public.color_space;
+ if (pipe_ctx->stream == NULL)
+ default_adjust.out_color_space = COLOR_SPACE_SRGB;
+ else
+ default_adjust.out_color_space =
+ pipe_ctx->stream->public.output_color_space;
+ default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW;
+ default_adjust.surface_pixel_format = pipe_ctx->scl_data.format;
+
+ /* display color depth */
+ default_adjust.color_depth =
+ pipe_ctx->stream->public.timing.display_color_depth;
+
+ /* Lb color depth */
+ default_adjust.lb_color_depth = pipe_ctx->scl_data.lb_params.depth;
+
+ pipe_ctx->opp->funcs->opp_set_csc_default(
+ pipe_ctx->opp, &default_adjust);
+}
+
+static void program_blender(const struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ enum blnd_mode blender_mode = BLND_MODE_CURRENT_PIPE;
+
+ if (pipe_ctx->bottom_pipe) {
+ if (pipe_ctx->bottom_pipe->surface->public.visible) {
+ if (pipe_ctx->surface->public.visible)
+ blender_mode = BLND_MODE_BLENDING;
+ else
+ blender_mode = BLND_MODE_OTHER_PIPE;
+ }
+ }
+ dce_set_blender_mode(dc->hwseq, pipe_ctx->pipe_idx, blender_mode);
+}
+
+/**
+ * TODO REMOVE, USE UPDATE INSTEAD
+ */
+static void set_plane_config(
+ const struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct resource_context *res_ctx)
+{
+ struct mem_input *mi = pipe_ctx->mi;
+ struct core_surface *surface = pipe_ctx->surface;
+ struct xfm_grph_csc_adjustment adjust;
+ struct out_csc_color_matrix tbl_entry;
+ unsigned int i;
+
+ memset(&adjust, 0, sizeof(adjust));
+ memset(&tbl_entry, 0, sizeof(tbl_entry));
+ adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
+
+ dce_enable_fe_clock(dc->hwseq, pipe_ctx->pipe_idx, true);
+
+ set_default_colors(pipe_ctx);
+ if (pipe_ctx->stream->public.csc_color_matrix.enable_adjustment
+ == true) {
+ tbl_entry.color_space =
+ pipe_ctx->stream->public.output_color_space;
+
+ for (i = 0; i < 12; i++)
+ tbl_entry.regval[i] =
+ pipe_ctx->stream->public.csc_color_matrix.matrix[i];
+
+ pipe_ctx->opp->funcs->opp_set_csc_adjustment
+ (pipe_ctx->opp, &tbl_entry);
+ }
+
+ if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
+ adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
+ adjust.temperature_matrix[0] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[0];
+ adjust.temperature_matrix[1] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[1];
+ adjust.temperature_matrix[2] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[2];
+ adjust.temperature_matrix[3] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[4];
+ adjust.temperature_matrix[4] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[5];
+ adjust.temperature_matrix[5] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[6];
+ adjust.temperature_matrix[6] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[8];
+ adjust.temperature_matrix[7] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[9];
+ adjust.temperature_matrix[8] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[10];
+ }
+
+ pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
+
+ pipe_ctx->scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
+ program_scaler(dc, pipe_ctx);
+
+ program_blender(dc, pipe_ctx);
+
+ mi->funcs->mem_input_program_surface_config(
+ mi,
+ surface->public.format,
+ &surface->public.tiling_info,
+ &surface->public.plane_size,
+ surface->public.rotation,
+ NULL,
+ false);
+
+ if (dc->public.config.gpu_vm_support)
+ mi->funcs->mem_input_program_pte_vm(
+ pipe_ctx->mi,
+ surface->public.format,
+ &surface->public.tiling_info,
+ surface->public.rotation);
+}
+
+static void update_plane_addr(const struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ struct core_surface *surface = pipe_ctx->surface;
+
+ if (surface == NULL)
+ return;
+
+ pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
+ pipe_ctx->mi,
+ &surface->public.address,
+ surface->public.flip_immediate);
+
+ surface->status.requested_address = surface->public.address;
+
+ if (surface->public.visible)
+ pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, false);
+}
+
+void dce110_update_pending_status(struct pipe_ctx *pipe_ctx)
+{
+ struct core_surface *surface = pipe_ctx->surface;
+
+ if (surface == NULL)
+ return;
+
+ surface->status.is_flip_pending =
+ pipe_ctx->mi->funcs->mem_input_is_flip_pending(
+ pipe_ctx->mi);
+
+ if (surface->status.is_flip_pending && !surface->public.visible)
+ pipe_ctx->mi->current_address = pipe_ctx->mi->request_address;
+
+ surface->status.current_address = pipe_ctx->mi->current_address;
+}
+
+void dce110_power_down(struct core_dc *dc)
+{
+ power_down_all_hw_blocks(dc);
+ disable_vga_and_power_gate_all_controllers(dc);
+}
+
+static bool wait_for_reset_trigger_to_occur(
+ struct dc_context *dc_ctx,
+ struct timing_generator *tg)
+{
+ bool rc = false;
+
+ /* To avoid endless loop we wait at most
+ * frames_to_wait_on_triggered_reset frames for the reset to occur. */
+ const uint32_t frames_to_wait_on_triggered_reset = 10;
+ uint32_t i;
+
+ for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
+
+ if (!tg->funcs->is_counter_moving(tg)) {
+ DC_ERROR("TG counter is not moving!\n");
+ break;
+ }
+
+ 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",
+ i);
+ break;
+ }
+
+ /* Wait for one frame. */
+ tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
+ tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
+ }
+
+ if (false == rc)
+ DC_ERROR("GSL: Timeout on reset trigger!\n");
+
+ return rc;
+}
+
+/* Enable timing synchronization for a group of Timing Generators. */
+static void dce110_enable_timing_synchronization(
+ struct core_dc *dc,
+ int group_index,
+ int group_size,
+ struct pipe_ctx *grouped_pipes[])
+{
+ struct dc_context *dc_ctx = dc->ctx;
+ struct dcp_gsl_params gsl_params = { 0 };
+ int i;
+
+ DC_SYNC_INFO("GSL: Setting-up...\n");
+
+ /* Designate a single TG in the group as a master.
+ * Since HW doesn't care which one, we always assign
+ * the 1st one in the group. */
+ gsl_params.gsl_group = 0;
+ gsl_params.gsl_master = grouped_pipes[0]->tg->inst;
+
+ for (i = 0; i < group_size; i++)
+ grouped_pipes[i]->tg->funcs->setup_global_swap_lock(
+ grouped_pipes[i]->tg, &gsl_params);
+
+ /* Reset slave controllers on master VSync */
+ DC_SYNC_INFO("GSL: enabling trigger-reset\n");
+
+ for (i = 1 /* skip the master */; i < group_size; i++)
+ grouped_pipes[i]->tg->funcs->enable_reset_trigger(
+ grouped_pipes[i]->tg, gsl_params.gsl_group);
+
+
+
+ for (i = 1 /* skip the master */; i < group_size; i++) {
+ DC_SYNC_INFO("GSL: waiting for reset to occur.\n");
+ wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->tg);
+ /* 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");
+ grouped_pipes[i]->tg->funcs->disable_reset_trigger(grouped_pipes[i]->tg);
+ }
+
+
+ /* 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 < group_size; i++)
+ grouped_pipes[i]->tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->tg);
+
+ DC_SYNC_INFO("GSL: Set-up complete.\n");
+}
+
+static void init_hw(struct core_dc *dc)
+{
+ int i;
+ struct dc_bios *bp;
+ struct transform *xfm;
+
+ bp = dc->ctx->dc_bios;
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ xfm = dc->res_pool->transforms[i];
+ xfm->funcs->transform_reset(xfm);
+
+ dc->hwss.enable_display_power_gating(
+ dc, i, bp,
+ PIPE_GATING_CONTROL_INIT);
+ dc->hwss.enable_display_power_gating(
+ dc, i, bp,
+ PIPE_GATING_CONTROL_DISABLE);
+ dc->hwss.enable_display_pipe_clock_gating(
+ dc->ctx,
+ true);
+ }
+
+ dce_clock_gating_power_up(dc->hwseq, false);;
+ /***************************************/
+
+ for (i = 0; i < dc->link_count; i++) {
+ /****************************************/
+ /* Power up AND update implementation according to the
+ * required signal (which may be different from the
+ * default signal on connector). */
+ struct core_link *link = dc->links[i];
+ link->link_enc->funcs->hw_init(link->link_enc);
+ }
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct timing_generator *tg = dc->res_pool->timing_generators[i];
+
+ tg->funcs->disable_vga(tg);
+
+ /* Blank controller using driver code instead of
+ * command table. */
+ tg->funcs->set_blank(tg, true);
+ }
+
+ for (i = 0; i < dc->res_pool->audio_count; i++) {
+ struct audio *audio = dc->res_pool->audios[i];
+ audio->funcs->hw_init(audio);
+ }
+}
+
+/* TODO: move this to apply_ctx_tohw some how?*/
+static void dce110_power_on_pipe_if_needed(
+ struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context)
+{
+ struct pipe_ctx *old_pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
+ struct dc_bios *dcb = dc->ctx->dc_bios;
+ struct tg_color black_color = {0};
+
+ if (!old_pipe_ctx->stream && pipe_ctx->stream) {
+ dc->hwss.enable_display_power_gating(
+ dc,
+ pipe_ctx->pipe_idx,
+ dcb, PIPE_GATING_CONTROL_DISABLE);
+
+ /*
+ * This is for powering on underlay, so crtc does not
+ * need to be enabled
+ */
+
+ pipe_ctx->tg->funcs->program_timing(pipe_ctx->tg,
+ &pipe_ctx->stream->public.timing,
+ false);
+
+ pipe_ctx->tg->funcs->enable_advanced_request(
+ pipe_ctx->tg,
+ true,
+ &pipe_ctx->stream->public.timing);
+
+ pipe_ctx->mi->funcs->allocate_mem_input(pipe_ctx->mi,
+ pipe_ctx->stream->public.timing.h_total,
+ pipe_ctx->stream->public.timing.v_total,
+ pipe_ctx->stream->public.timing.pix_clk_khz,
+ context->target_count);
+
+ /* TODO unhardcode*/
+ color_space_to_black_color(dc,
+ COLOR_SPACE_YCBCR601, &black_color);
+ pipe_ctx->tg->funcs->set_blank_color(
+ pipe_ctx->tg,
+ &black_color);
+ }
+}
+
+static void dce110_increase_watermarks_for_pipe(
+ struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context)
+{
+ if (did_watermarks_increase(pipe_ctx, context, dc->current_context))
+ program_wm_for_pipe(dc, pipe_ctx, context);
+}
+
+static void dce110_set_bandwidth(struct core_dc *dc)
+{
+ int i;
+
+ for (i = 0; i < dc->current_context->res_ctx.pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[i];
+
+ if (!pipe_ctx->stream)
+ continue;
+
+ program_wm_for_pipe(dc, pipe_ctx, dc->current_context);
+ }
+
+ dc->hwss.set_display_clock(dc->current_context);
+}
+
+static void dce110_program_front_end_for_pipe(
+ struct core_dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ struct mem_input *mi = pipe_ctx->mi;
+ struct pipe_ctx *old_pipe = NULL;
+ struct core_surface *surface = pipe_ctx->surface;
+ struct xfm_grph_csc_adjustment adjust;
+ struct out_csc_color_matrix tbl_entry;
+ unsigned int i;
+
+ memset(&tbl_entry, 0, sizeof(tbl_entry));
+
+ if (dc->current_context)
+ old_pipe = &dc->current_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
+
+ memset(&adjust, 0, sizeof(adjust));
+ adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
+
+ dce_enable_fe_clock(dc->hwseq, pipe_ctx->pipe_idx, true);
+
+ set_default_colors(pipe_ctx);
+ if (pipe_ctx->stream->public.csc_color_matrix.enable_adjustment
+ == true) {
+ tbl_entry.color_space =
+ pipe_ctx->stream->public.output_color_space;
+
+ for (i = 0; i < 12; i++)
+ tbl_entry.regval[i] =
+ pipe_ctx->stream->public.csc_color_matrix.matrix[i];
+
+ pipe_ctx->opp->funcs->opp_set_csc_adjustment
+ (pipe_ctx->opp, &tbl_entry);
+ }
+
+ if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
+ adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
+ adjust.temperature_matrix[0] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[0];
+ adjust.temperature_matrix[1] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[1];
+ adjust.temperature_matrix[2] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[2];
+ adjust.temperature_matrix[3] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[4];
+ adjust.temperature_matrix[4] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[5];
+ adjust.temperature_matrix[5] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[6];
+ adjust.temperature_matrix[6] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[8];
+ adjust.temperature_matrix[7] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[9];
+ adjust.temperature_matrix[8] =
+ pipe_ctx->stream->
+ public.gamut_remap_matrix.matrix[10];
+ }
+
+ pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
+
+ pipe_ctx->scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
+ if (old_pipe && memcmp(&old_pipe->scl_data,
+ &pipe_ctx->scl_data,
+ sizeof(struct scaler_data)) != 0)
+ program_scaler(dc, pipe_ctx);
+
+ mi->funcs->mem_input_program_surface_config(
+ mi,
+ surface->public.format,
+ &surface->public.tiling_info,
+ &surface->public.plane_size,
+ surface->public.rotation,
+ false,
+ false);
+
+ if (dc->public.config.gpu_vm_support)
+ mi->funcs->mem_input_program_pte_vm(
+ pipe_ctx->mi,
+ surface->public.format,
+ &surface->public.tiling_info,
+ surface->public.rotation);
+
+ dm_logger_write(dc->ctx->logger, LOG_SURFACE,
+ "Pipe:%d 0x%x: addr hi:0x%x, "
+ "addr low:0x%x, "
+ "src: %d, %d, %d,"
+ " %d; dst: %d, %d, %d, %d;"
+ "clip: %d, %d, %d, %d\n",
+ pipe_ctx->pipe_idx,
+ pipe_ctx->surface,
+ pipe_ctx->surface->public.address.grph.addr.high_part,
+ pipe_ctx->surface->public.address.grph.addr.low_part,
+ pipe_ctx->surface->public.src_rect.x,
+ pipe_ctx->surface->public.src_rect.y,
+ pipe_ctx->surface->public.src_rect.width,
+ pipe_ctx->surface->public.src_rect.height,
+ pipe_ctx->surface->public.dst_rect.x,
+ pipe_ctx->surface->public.dst_rect.y,
+ pipe_ctx->surface->public.dst_rect.width,
+ pipe_ctx->surface->public.dst_rect.height,
+ pipe_ctx->surface->public.clip_rect.x,
+ pipe_ctx->surface->public.clip_rect.y,
+ pipe_ctx->surface->public.clip_rect.width,
+ pipe_ctx->surface->public.clip_rect.height);
+
+ dm_logger_write(dc->ctx->logger, LOG_SURFACE,
+ "Pipe %d: width, height, x, y\n"
+ "viewport:%d, %d, %d, %d\n"
+ "recout: %d, %d, %d, %d\n",
+ pipe_ctx->pipe_idx,
+ pipe_ctx->scl_data.viewport.width,
+ pipe_ctx->scl_data.viewport.height,
+ pipe_ctx->scl_data.viewport.x,
+ pipe_ctx->scl_data.viewport.y,
+ pipe_ctx->scl_data.recout.width,
+ pipe_ctx->scl_data.recout.height,
+ pipe_ctx->scl_data.recout.x,
+ pipe_ctx->scl_data.recout.y);
+}
+
+
+
+static void dce110_prepare_pipe_for_surface_commit(
+ struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context) {
+ struct core_gamma *gamma = NULL;
+
+ dc->hwss.increase_watermarks_for_pipe(dc, pipe_ctx, context);
+
+ if (pipe_ctx->surface->public.gamma_correction)
+ gamma = DC_GAMMA_TO_CORE(
+ pipe_ctx->surface->public.gamma_correction);
+
+ dc->hwss.set_gamma_correction(
+ pipe_ctx->ipp,
+ pipe_ctx->opp,
+ gamma, pipe_ctx->surface);
+}
+
+static void dce110_prepare_pipe_for_context(
+ struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context)
+{
+ dce110_power_on_pipe_if_needed(dc, pipe_ctx, context);
+ dce110_prepare_pipe_for_surface_commit(dc, pipe_ctx, context);
+}
+
+static void dce110_apply_ctx_for_surface(
+ struct core_dc *dc,
+ struct core_surface *surface,
+ struct validate_context *context)
+{
+ int i;
+
+ /* TODO remove when removing the surface reset workaroud*/
+ if (!surface)
+ return;
+
+ for (i = 0; i < context->res_ctx.pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->surface != surface)
+ continue;
+
+ dce110_program_front_end_for_pipe(dc, pipe_ctx);
+ program_blender(dc, pipe_ctx);
+
+ }
+
+}
+
+static void dce110_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe)
+{
+ int i;
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++)
+ if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe)
+ break;
+
+ if (i == dc->res_pool->pipe_count)
+ return;
+
+ dc->hwss.enable_display_power_gating(
+ dc, i, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE);
+ if (pipe->xfm)
+ pipe->xfm->funcs->transform_reset(pipe->xfm);
+ memset(&pipe->scl_data, 0, sizeof(struct scaler_data));
+}
+
+static const struct hw_sequencer_funcs dce110_funcs = {
+ .init_hw = init_hw,
+ .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
+ .prepare_pipe_for_context = dce110_prepare_pipe_for_context,
+ .apply_ctx_for_surface = dce110_apply_ctx_for_surface,
+ .set_plane_config = set_plane_config,
+ .update_plane_addr = update_plane_addr,
+ .update_pending_status = dce110_update_pending_status,
+ .set_gamma_correction = set_gamma_ramp,
+ .power_down = dce110_power_down,
+ .enable_accelerated_mode = dce110_enable_accelerated_mode,
+ .enable_timing_synchronization = dce110_enable_timing_synchronization,
+ .update_info_frame = dce110_update_info_frame,
+ .enable_stream = dce110_enable_stream,
+ .disable_stream = dce110_disable_stream,
+ .unblank_stream = dce110_unblank_stream,
+ .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating,
+ .enable_display_power_gating = dce110_enable_display_power_gating,
+ .power_down_front_end = dce110_power_down_fe,
+ .pipe_control_lock = dce_pipe_control_lock,
+ .set_display_clock = dce110_set_display_clock,
+ .set_displaymarks = dce110_set_displaymarks,
+ .increase_watermarks_for_pipe = dce110_increase_watermarks_for_pipe,
+ .set_bandwidth = dce110_set_bandwidth,
+ .set_drr = set_drr,
+ .set_static_screen_control = set_static_screen_control,
+ .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
+ .prog_pixclk_crtc_otg = prog_pixclk_crtc_otg,
+};
+
+bool dce110_hw_sequencer_construct(struct core_dc *dc)
+{
+ dc->hwss = dce110_funcs;
+
+ return true;
+}
+