diff options
author | Maxime Ripard <mripard@kernel.org> | 2019-10-03 17:38:50 +0300 |
---|---|---|
committer | Maxime Ripard <mripard@kernel.org> | 2019-10-03 17:38:50 +0300 |
commit | 4092de1ba34eb376791809fb366bc15f8a9e0b7c (patch) | |
tree | 6262d4dfcfa7ff9eda8e8d1d0a711711fcae8785 /drivers/gpu/drm/amd/display/dc/dcn20 | |
parent | a00d17e0a71ae2e4fdaac46e1c12785d3346c3f2 (diff) | |
parent | 54ecb8f7028c5eb3d740bb82b0f1d90f2df63c5c (diff) | |
download | linux-4092de1ba34eb376791809fb366bc15f8a9e0b7c.tar.xz |
Merge drm/drm-next into drm-misc-next
We haven't done any backmerge for a while due to the merge window, and it
starts to become an issue for komeda. Let's bring 5.4-rc1 in.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn20')
25 files changed, 2217 insertions, 886 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index e9721a906592..ddb8d5649e79 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -16,7 +16,11 @@ else ifneq ($(call cc-option, -mstack-alignment=16),) cc_stack_align := -mstack-alignment=16 endif -CFLAGS_dcn20_resource.o := -mhard-float -msse $(cc_stack_align) +CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -msse $(cc_stack_align) + +ifdef CONFIG_CC_IS_CLANG +CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o += -msse2 +endif AMD_DAL_DCN20 = $(addprefix $(AMDDALPATH)/dc/dcn20/,$(DCN20)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c index 51a3dfe97f0e..16476ed25536 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c @@ -44,12 +44,16 @@ #define DC_LOGGER \ dccg->ctx->logger -void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) +void dccg2_update_dpp_dto(struct dccg *dccg, + int dpp_inst, + int req_dppclk, + bool reduce_divider_only) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); if (dccg->ref_dppclk && req_dppclk) { int ref_dppclk = dccg->ref_dppclk; + int current_phase, current_modulo; ASSERT(req_dppclk <= ref_dppclk); /* need to clamp to 8 bits */ @@ -61,9 +65,28 @@ void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) if (req_dppclk > ref_dppclk) req_dppclk = ref_dppclk; } - REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, - DPPCLK0_DTO_PHASE, req_dppclk, - DPPCLK0_DTO_MODULO, ref_dppclk); + + REG_GET_2(DPPCLK_DTO_PARAM[dpp_inst], + DPPCLK0_DTO_PHASE, ¤t_phase, + DPPCLK0_DTO_MODULO, ¤t_modulo); + + if (reduce_divider_only) { + // requested phase/modulo greater than current + if (req_dppclk * current_modulo >= current_phase * ref_dppclk) { + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, req_dppclk, + DPPCLK0_DTO_MODULO, ref_dppclk); + } else { + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, current_phase, + DPPCLK0_DTO_MODULO, current_modulo); + } + } else { + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, req_dppclk, + DPPCLK0_DTO_MODULO, ref_dppclk); + } + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 1); } else { @@ -102,14 +125,19 @@ void dccg2_init(struct dccg *dccg) switch (dccg_dcn->base.ctx->dc->res_pool->pipe_count) { case 6: REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[5], 1); + /* Fall through */ case 5: REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[4], 1); + /* Fall through */ case 4: REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[3], 1); + /* Fall through */ case 3: REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[2], 1); + /* Fall through */ case 2: REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[1], 1); + /* Fall through */ case 1: REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[0], 1); break; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index 2205cb0204e7..74a074a873cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -97,7 +97,7 @@ struct dcn_dccg { const struct dccg_mask *dccg_mask; }; -void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk); +void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk, bool raise_divider_only); void dccg2_get_dccg_ref_freq(struct dccg *dccg, unsigned int xtalin_freq_inKhz, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c index 9bc5dd23d297..2f5aade1e882 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c @@ -72,6 +72,21 @@ void dpp20_read_state(struct dpp *dpp_base, } } +void dpp2_power_on_obuf( + struct dpp *dpp_base, + bool power_on) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(CM_MEM_PWR_CTRL, SHARED_MEM_PWR_DIS, power_on == true ? 1:0); + + REG_UPDATE(OBUF_MEM_PWR_CTRL, + OBUF_MEM_PWR_FORCE, power_on == true ? 0:1); + + REG_UPDATE(DSCL_MEM_PWR_CTRL, + LUT_MEM_PWR_FORCE, power_on == true ? 0:1); +} + void dpp2_dummy_program_input_lut( struct dpp *dpp_base, const struct dc_gamma *gamma) @@ -227,6 +242,7 @@ static void dpp2_cnv_setup ( CUR0_ENABLE, 0); } + dpp2_power_on_obuf(dpp_base, true); } @@ -326,14 +342,18 @@ void dpp2_cnv_set_alpha_keyer( void dpp2_set_cursor_attributes( struct dpp *dpp_base, - enum dc_cursor_color_format color_format) + struct dc_cursor_attributes *cursor_attributes) { + enum dc_cursor_color_format color_format = cursor_attributes->color_format; struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); int cur_rom_en = 0; if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA || - color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) - cur_rom_en = 1; + color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) { + if (cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) { + cur_rom_en = 1; + } + } REG_UPDATE_3(CURSOR0_CONTROL, CUR0_MODE, color_format, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h index 59b67ed57c19..290b2854bd2c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h @@ -162,7 +162,9 @@ SRI(COLOR_KEYER_GREEN, CNVC_CFG, id), \ SRI(COLOR_KEYER_BLUE, CNVC_CFG, id), \ SRI(CM_SHAPER_LUT_DATA, CM, id), \ - SRI(CURSOR_CONTROL, CURSOR0_, id) + SRI(CURSOR_CONTROL, CURSOR0_, id),\ + SRI(OBUF_MEM_PWR_CTRL, DSCL, id),\ + SRI(DSCL_MEM_PWR_CTRL, DSCL, id) #define TF_REG_LIST_SH_MASK_DCN20(mask_sh)\ TF_REG_LIST_SH_MASK_DCN(mask_sh), \ @@ -554,7 +556,9 @@ TF_SF(CNVC_CFG0_COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_HIGH, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_PIX_INV_MODE, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_PIXEL_ALPHA_MOD_EN, mask_sh), \ - TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ROM_EN, mask_sh) + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ROM_EN, mask_sh),\ + TF_SF(DSCL0_OBUF_MEM_PWR_CTRL, OBUF_MEM_PWR_FORCE, mask_sh),\ + TF_SF(DSCL0_DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, mask_sh) #define TF_REG_FIELD_LIST_DCN2_0(type) \ TF_REG_FIELD_LIST(type) \ @@ -585,7 +589,9 @@ type COLOR_KEYER_BLUE_HIGH; \ type CUR0_PIX_INV_MODE; \ type CUR0_PIXEL_ALPHA_MOD_EN; \ - type CUR0_ROM_EN + type CUR0_ROM_EN;\ + type OBUF_MEM_PWR_FORCE;\ + type LUT_MEM_PWR_FORCE struct dcn2_dpp_shift { TF_REG_FIELD_LIST_DCN2_0(uint8_t); @@ -609,7 +615,9 @@ struct dcn2_dpp_mask { uint32_t COLOR_KEYER_ALPHA; \ uint32_t COLOR_KEYER_RED; \ uint32_t COLOR_KEYER_GREEN; \ - uint32_t COLOR_KEYER_BLUE + uint32_t COLOR_KEYER_BLUE; \ + uint32_t OBUF_MEM_PWR_CTRL;\ + uint32_t DSCL_MEM_PWR_CTRL struct dcn2_dpp_registers { DPP_DCN2_REG_VARIABLE_LIST; @@ -668,7 +676,7 @@ void dscl2_calc_lb_num_partitions( void dpp2_set_cursor_attributes( struct dpp *dpp_base, - enum dc_cursor_color_format color_format); + struct dc_cursor_attributes *cursor_attributes); void dpp2_dummy_program_input_lut( struct dpp *dpp_base, @@ -695,4 +703,7 @@ bool dpp2_construct(struct dcn20_dpp *dpp2, const struct dcn2_dpp_shift *tf_shift, const struct dcn2_dpp_mask *tf_mask); +void dpp2_power_on_obuf( + struct dpp *dpp_base, + bool power_on); #endif /* __DC_HWSS_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c index e28b8e7bedf5..2d112c316424 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c @@ -52,7 +52,12 @@ static void dpp2_enable_cm_block( { struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); - REG_UPDATE(CM_CONTROL, CM_BYPASS, 0); + unsigned int cm_bypass_mode = 0; + //Temp, put CM in bypass mode + if (dpp_base->ctx->dc->debug.cm_in_bypass) + cm_bypass_mode = 1; + + REG_UPDATE(CM_CONTROL, CM_BYPASS, cm_bypass_mode); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c index ffd0014ec3b5..1b419407af94 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c @@ -29,7 +29,7 @@ #include "dsc/dscc_types.h" static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps); -static bool dsc_prepare_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, +static bool dsc_prepare_config(const struct dsc_config *dsc_cfg, struct dsc_reg_values *dsc_reg_vals, struct dsc_optc_config *dsc_optc_cfg); static void dsc_init_reg_values(struct dsc_reg_values *reg_vals); static void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params); @@ -42,7 +42,8 @@ static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s); static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg); static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, - struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps); + struct dsc_optc_config *dsc_optc_cfg); +static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, uint8_t *dsc_packed_pps); static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe); static void dsc2_disable(struct display_stream_compressor *dsc); @@ -51,6 +52,7 @@ const struct dsc_funcs dcn20_dsc_funcs = { .dsc_read_state = dsc2_read_state, .dsc_validate_stream = dsc2_validate_stream, .dsc_set_config = dsc2_set_config, + .dsc_get_packed_pps = dsc2_get_packed_pps, .dsc_enable = dsc2_enable, .dsc_disable = dsc2_disable, }; @@ -116,8 +118,8 @@ static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock dsc_enc_caps->color_formats.bits.RGB = 1; dsc_enc_caps->color_formats.bits.YCBCR_444 = 1; - dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1; - dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1; + dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 0; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 0; dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; @@ -162,40 +164,61 @@ static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_ds static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg) { struct dsc_optc_config dsc_optc_cfg; + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - if (dsc_cfg->pic_width > TO_DCN20_DSC(dsc)->max_image_width) + if (dsc_cfg->pic_width > dsc20->max_image_width) return false; - return dsc_prepare_config(dsc, dsc_cfg, &dsc_optc_cfg); + return dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, &dsc_optc_cfg); } -static void dsc_config_log(struct display_stream_compressor *dsc, - const struct dsc_config *config) +static void dsc_config_log(struct display_stream_compressor *dsc, const struct dsc_config *config) { - DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst); - DC_LOG_DSC("\n\tnum_slices_h %d\n\tnum_slices_v %d\n\tbits_per_pixel %d\n\tcolor_depth %d", - config->dc_dsc_cfg.num_slices_h, - config->dc_dsc_cfg.num_slices_v, + DC_LOG_DSC("\tnum_slices_h %d", config->dc_dsc_cfg.num_slices_h); + DC_LOG_DSC("\tnum_slices_v %d", config->dc_dsc_cfg.num_slices_v); + DC_LOG_DSC("\tbits_per_pixel %d (%d.%04d)", config->dc_dsc_cfg.bits_per_pixel, - config->color_depth); + config->dc_dsc_cfg.bits_per_pixel / 16, + ((config->dc_dsc_cfg.bits_per_pixel % 16) * 10000) / 16); + DC_LOG_DSC("\tcolor_depth %d", config->color_depth); } static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, - struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps) + struct dsc_optc_config *dsc_optc_cfg) { bool is_config_ok; struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + DC_LOG_DSC(" "); + DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst); dsc_config_log(dsc, dsc_cfg); - is_config_ok = dsc_prepare_config(dsc, dsc_cfg, dsc_optc_cfg); + is_config_ok = dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, dsc_optc_cfg); ASSERT(is_config_ok); - drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)dsc_packed_pps, &dsc20->reg_vals.pps); + DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):"); dsc_log_pps(dsc, &dsc20->reg_vals.pps); dsc_write_to_registers(dsc, &dsc20->reg_vals); } +static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, uint8_t *dsc_packed_pps) +{ + bool is_config_ok; + struct dsc_reg_values dsc_reg_vals; + struct dsc_optc_config dsc_optc_cfg; + + DC_LOG_DSC("Getting packed DSC PPS for DSC Config:"); + dsc_config_log(dsc, dsc_cfg); + DC_LOG_DSC("DSC Picture Parameter Set (PPS):"); + is_config_ok = dsc_prepare_config(dsc_cfg, &dsc_reg_vals, &dsc_optc_cfg); + ASSERT(is_config_ok); + drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)dsc_packed_pps, &dsc_reg_vals.pps); + dsc_log_pps(dsc, &dsc_reg_vals.pps); + + return is_config_ok; +} + + static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe) { struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); @@ -232,7 +255,6 @@ static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_co int i; int bits_per_pixel = pps->bits_per_pixel; - DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):"); DC_LOG_DSC("\tdsc_version_major %d", pps->dsc_version_major); DC_LOG_DSC("\tdsc_version_minor %d", pps->dsc_version_minor); DC_LOG_DSC("\tbits_per_component %d", pps->bits_per_component); @@ -282,13 +304,11 @@ static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_co } } -static bool dsc_prepare_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, +static bool dsc_prepare_config(const struct dsc_config *dsc_cfg, struct dsc_reg_values *dsc_reg_vals, struct dsc_optc_config *dsc_optc_cfg) { struct dsc_parameters dsc_params; - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - /* Validate input parameters */ ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_h); ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_v); @@ -302,7 +322,7 @@ static bool dsc_prepare_config(struct display_stream_compressor *dsc, const stru dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))); ASSERT(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff); // 6.0 <= bits_per_pixel <= 63.9375 - if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_v || + if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_h || !(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2) || !dsc_cfg->pic_width || !dsc_cfg->pic_height || !((dsc_cfg->dc_dsc_cfg.version_minor == 1 && // v1.1 line buffer depth range: @@ -315,54 +335,54 @@ static bool dsc_prepare_config(struct display_stream_compressor *dsc, const stru return false; } - dsc_init_reg_values(&dsc20->reg_vals); + dsc_init_reg_values(dsc_reg_vals); /* Copy input config */ - dsc20->reg_vals.pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple); - dsc20->reg_vals.num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h; - dsc20->reg_vals.num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v; - dsc20->reg_vals.pps.dsc_version_minor = dsc_cfg->dc_dsc_cfg.version_minor; - dsc20->reg_vals.pps.pic_width = dsc_cfg->pic_width; - dsc20->reg_vals.pps.pic_height = dsc_cfg->pic_height; - dsc20->reg_vals.pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth); - dsc20->reg_vals.pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable; - dsc20->reg_vals.pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth; - dsc20->reg_vals.alternate_ich_encoding_en = dsc20->reg_vals.pps.dsc_version_minor == 1 ? 0 : 1; + dsc_reg_vals->pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple); + dsc_reg_vals->num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc_reg_vals->num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v; + dsc_reg_vals->pps.dsc_version_minor = dsc_cfg->dc_dsc_cfg.version_minor; + dsc_reg_vals->pps.pic_width = dsc_cfg->pic_width; + dsc_reg_vals->pps.pic_height = dsc_cfg->pic_height; + dsc_reg_vals->pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth); + dsc_reg_vals->pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable; + dsc_reg_vals->pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth; + dsc_reg_vals->alternate_ich_encoding_en = dsc_reg_vals->pps.dsc_version_minor == 1 ? 0 : 1; // TODO: in addition to validating slice height (pic height must be divisible by slice height), // see what happens when the same condition doesn't apply for slice_width/pic_width. - dsc20->reg_vals.pps.slice_width = dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h; - dsc20->reg_vals.pps.slice_height = dsc_cfg->pic_height / dsc_cfg->dc_dsc_cfg.num_slices_v; + dsc_reg_vals->pps.slice_width = dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc_reg_vals->pps.slice_height = dsc_cfg->pic_height / dsc_cfg->dc_dsc_cfg.num_slices_v; - ASSERT(dsc20->reg_vals.pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height); - if (!(dsc20->reg_vals.pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height)) { + ASSERT(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height); + if (!(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height)) { dm_output_to_console("%s: pix height %d not divisible by num_slices_v %d\n\n", __func__, dsc_cfg->pic_height, dsc_cfg->dc_dsc_cfg.num_slices_v); return false; } - dsc20->reg_vals.bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1; - if (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) - dsc20->reg_vals.pps.bits_per_pixel = dsc20->reg_vals.bpp_x32; + dsc_reg_vals->bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1; + if (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) + dsc_reg_vals->pps.bits_per_pixel = dsc_reg_vals->bpp_x32; else - dsc20->reg_vals.pps.bits_per_pixel = dsc20->reg_vals.bpp_x32 >> 1; + dsc_reg_vals->pps.bits_per_pixel = dsc_reg_vals->bpp_x32 >> 1; - dsc20->reg_vals.pps.convert_rgb = dsc20->reg_vals.pixel_format == DSC_PIXFMT_RGB ? 1 : 0; - dsc20->reg_vals.pps.native_422 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR422); - dsc20->reg_vals.pps.native_420 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR420); - dsc20->reg_vals.pps.simple_422 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422); + dsc_reg_vals->pps.convert_rgb = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB ? 1 : 0; + dsc_reg_vals->pps.native_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422); + dsc_reg_vals->pps.native_420 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420); + dsc_reg_vals->pps.simple_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422); - if (dscc_compute_dsc_parameters(&dsc20->reg_vals.pps, &dsc_params)) { + if (dscc_compute_dsc_parameters(&dsc_reg_vals->pps, &dsc_params)) { dm_output_to_console("%s: DSC config failed\n", __func__); return false; } - dsc_update_from_dsc_parameters(&dsc20->reg_vals, &dsc_params); + dsc_update_from_dsc_parameters(dsc_reg_vals, &dsc_params); dsc_optc_cfg->bytes_per_pixel = dsc_params.bytes_per_pixel; - dsc_optc_cfg->slice_width = dsc20->reg_vals.pps.slice_width; - dsc_optc_cfg->is_pixel_format_444 = dsc20->reg_vals.pixel_format == DSC_PIXFMT_RGB || - dsc20->reg_vals.pixel_format == DSC_PIXFMT_YCBCR444 || - dsc20->reg_vals.pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422; + dsc_optc_cfg->slice_width = dsc_reg_vals->pps.slice_width; + dsc_optc_cfg->is_pixel_format_444 = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB || + dsc_reg_vals->pixel_format == DSC_PIXFMT_YCBCR444 || + dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422; return true; } @@ -427,6 +447,8 @@ static void dsc_init_reg_values(struct dsc_reg_values *reg_vals) { int i; + memset(reg_vals, 0, sizeof(struct dsc_reg_values)); + /* Non-PPS values */ reg_vals->dsc_clock_enable = 1; reg_vals->dsc_clock_gating_disable = 0; @@ -436,7 +458,7 @@ static void dsc_init_reg_values(struct dsc_reg_values *reg_vals) reg_vals->ich_reset_at_eol = 0; reg_vals->alternate_ich_encoding_en = 0; reg_vals->rc_buffer_model_size = 0; - reg_vals->disable_ich = 0; + /*reg_vals->disable_ich = 0;*/ reg_vals->dsc_dbg_en = 0; for (i = 0; i < 4; i++) @@ -518,9 +540,11 @@ static void dsc_write_to_registers(struct display_stream_compressor *dsc, const ALTERNATE_ICH_ENCODING_EN, reg_vals->alternate_ich_encoding_en, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, reg_vals->num_slices_v - 1); - REG_SET_2(DSCC_CONFIG1, 0, + REG_SET(DSCC_CONFIG1, 0, + DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size); + /*REG_SET_2(DSCC_CONFIG1, 0, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size, - DSCC_DISABLE_ICH, reg_vals->disable_ich); + DSCC_DISABLE_ICH, reg_vals->disable_ich);*/ REG_SET_4(DSCC_INTERRUPT_CONTROL_STATUS, 0, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[0], diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h index 168865a16288..4e2fb38390a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h @@ -103,7 +103,7 @@ DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \ DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, mask_sh), \ DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_DISABLE_ICH, mask_sh), \ + /*DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_DISABLE_ICH, mask_sh),*/ \ DSC_SF(DSCC0_DSCC_STATUS, DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED, mask_sh), \ DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED, mask_sh), \ @@ -278,7 +278,7 @@ type ALTERNATE_ICH_ENCODING_EN; \ type NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION; \ type DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE; \ - type DSCC_DISABLE_ICH; \ + /*type DSCC_DISABLE_ICH;*/ \ type DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING; \ type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED; \ type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED; \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c index ece6e136437b..b83c022e2c6f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c @@ -26,6 +26,7 @@ #include "dcn20_hubbub.h" #include "reg_helper.h" +#include "clk_mgr.h" #define REG(reg)\ hubbub1->regs->reg @@ -337,6 +338,7 @@ static enum dcn_hubbub_page_table_block_size page_table_block_size_to_hw(unsigne break; default: ASSERT(false); + block_size = page_table_block_size; break; } @@ -366,25 +368,29 @@ int hubbub2_init_dchub_sys_ctx(struct hubbub *hubbub, struct dcn_vmid_page_table_config phys_config; REG_SET(DCN_VM_FB_LOCATION_BASE, 0, - FB_BASE, pa_config->system_aperture.fb_base); + FB_BASE, pa_config->system_aperture.fb_base >> 24); REG_SET(DCN_VM_FB_LOCATION_TOP, 0, - FB_TOP, pa_config->system_aperture.fb_top); + FB_TOP, pa_config->system_aperture.fb_top >> 24); REG_SET(DCN_VM_FB_OFFSET, 0, - FB_OFFSET, pa_config->system_aperture.fb_offset); + FB_OFFSET, pa_config->system_aperture.fb_offset >> 24); REG_SET(DCN_VM_AGP_BOT, 0, - AGP_BOT, pa_config->system_aperture.agp_bot); + AGP_BOT, pa_config->system_aperture.agp_bot >> 24); REG_SET(DCN_VM_AGP_TOP, 0, - AGP_TOP, pa_config->system_aperture.agp_top); + AGP_TOP, pa_config->system_aperture.agp_top >> 24); REG_SET(DCN_VM_AGP_BASE, 0, - AGP_BASE, pa_config->system_aperture.agp_base); + AGP_BASE, pa_config->system_aperture.agp_base >> 24); + + REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, 0, + DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, (pa_config->page_table_default_page_addr >> 44) & 0xF); + REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, 0, + DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, (pa_config->page_table_default_page_addr >> 12) & 0xFFFFFFFF); if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) { - phys_config.depth = 1; - phys_config.block_size = 4096; phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12; phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12; phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; - + phys_config.depth = 0; + phys_config.block_size = 0; // Init VMID 0 based on PA config dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config); } @@ -397,54 +403,67 @@ void hubbub2_update_dchub(struct hubbub *hubbub, { struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); - if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { - ASSERT(false); - /*should not come here*/ + if (REG(DCN_VM_FB_LOCATION_TOP) == 0) return; - } - /* TODO: port code from dal2 */ + switch (dh_data->fb_mode) { case FRAME_BUFFER_MODE_ZFB_ONLY: /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ - REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP, - SDPIF_FB_TOP, 0); - - REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE, - SDPIF_FB_BASE, 0x0FFFF); - - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, - SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); - - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, - SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); - - REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, - SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + - dh_data->zfb_size_in_byte - 1) >> 22); + REG_UPDATE(DCN_VM_FB_LOCATION_TOP, + FB_TOP, 0); + + REG_UPDATE(DCN_VM_FB_LOCATION_BASE, + FB_BASE, 0xFFFFFF); + + /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ + REG_UPDATE(DCN_VM_AGP_BASE, + AGP_BASE, dh_data->zfb_phys_addr_base >> 24); + + /*This field defines the bottom range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_BOT, + AGP_BOT, dh_data->zfb_mc_base_addr >> 24); + + /*This field defines the top range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_TOP, + AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 24); break; case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, - SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ + REG_UPDATE(DCN_VM_AGP_BASE, + AGP_BASE, dh_data->zfb_phys_addr_base >> 24); - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, - SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + /*This field defines the bottom range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_BOT, + AGP_BOT, dh_data->zfb_mc_base_addr >> 24); - REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, - SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + - dh_data->zfb_size_in_byte - 1) >> 22); + /*This field defines the top range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_TOP, + AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 24); break; case FRAME_BUFFER_MODE_LOCAL_ONLY: - /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, - SDPIF_AGP_BASE, 0); + /*Should not touch FB LOCATION (should be done by VBIOS)*/ - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, - SDPIF_AGP_BOT, 0X03FFFF); + /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ + REG_UPDATE(DCN_VM_AGP_BASE, + AGP_BASE, 0); - REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, - SDPIF_AGP_TOP, 0); + /*This field defines the bottom range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_BOT, + AGP_BOT, 0xFFFFFF); + + /*This field defines the top range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_TOP, + AGP_TOP, 0); break; default: break; @@ -553,6 +572,16 @@ static void hubbub2_program_watermarks( */ hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + + /* + * There's a special case when going from p-state support to p-state unsupported + * here we are going to LOWER watermarks to go to dummy p-state only, but this has + * to be done prepare_bandwidth, not optimize + */ + if (hubbub1->base.ctx->dc->clk_mgr->clks.prev_p_state_change_support == true && + hubbub1->base.ctx->dc->clk_mgr->clks.p_state_change_support == false) + safe_to_lower = true; + hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, @@ -571,7 +600,7 @@ static const struct hubbub_funcs hubbub2_funcs = { .get_dcc_compression_cap = hubbub2_get_dcc_compression_cap, .wm_read_state = hubbub2_wm_read_state, .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq, - .program_watermarks = hubbub2_program_watermarks, + .program_watermarks = hubbub2_program_watermarks }; void hubbub2_construct(struct dcn20_hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h index a7b6ca26a9ad..626117d3b4e9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h @@ -29,13 +29,21 @@ #include "dcn10/dcn10_hubbub.h" #include "dcn20_vmid.h" +#define HUBBUB_REG_LIST_DCN20_COMMON()\ + HUBBUB_REG_LIST_DCN_COMMON(), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DCN_VM_FB_LOCATION_BASE),\ + SR(DCN_VM_FB_LOCATION_TOP),\ + SR(DCN_VM_FB_OFFSET),\ + SR(DCN_VM_AGP_BOT),\ + SR(DCN_VM_AGP_TOP),\ + SR(DCN_VM_AGP_BASE) + #define TO_DCN20_HUBBUB(hubbub)\ container_of(hubbub, struct dcn20_hubbub, base) -#define HUBBUB_REG_LIST_DCN20(id)\ +#define HUBBUB_REG_LIST_DCN20_COMMON()\ HUBBUB_REG_LIST_DCN_COMMON(), \ - HUBBUB_VM_REG_LIST(), \ - HUBBUB_SR_WATERMARK_REG_LIST(), \ SR(DCHUBBUB_CRC_CTRL), \ SR(DCN_VM_FB_LOCATION_BASE),\ SR(DCN_VM_FB_LOCATION_TOP),\ @@ -44,6 +52,14 @@ SR(DCN_VM_AGP_TOP),\ SR(DCN_VM_AGP_BASE) +#define HUBBUB_REG_LIST_DCN20(id)\ + HUBBUB_REG_LIST_DCN20_COMMON(), \ + HUBBUB_SR_WATERMARK_REG_LIST(), \ + HUBBUB_VM_REG_LIST(),\ + SR(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB),\ + SR(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB) + + #define HUBBUB_MASK_SH_LIST_DCN20(mask_sh)\ HUBBUB_MASK_SH_LIST_DCN_COMMON(mask_sh), \ HUBBUB_MASK_SH_LIST_STUTTER(mask_sh), \ @@ -53,7 +69,9 @@ HUBBUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET, mask_sh), \ HUBBUB_SF(DCN_VM_AGP_BOT, AGP_BOT, mask_sh), \ HUBBUB_SF(DCN_VM_AGP_TOP, AGP_TOP, mask_sh), \ - HUBBUB_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh) + HUBBUB_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh), \ + HUBBUB_SF(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, mask_sh), \ + HUBBUB_SF(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, mask_sh) struct dcn20_hubbub { struct hubbub base; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c index d3f7dd374d50..69e2aae42394 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c @@ -40,81 +40,6 @@ #define FN(reg_name, field_name) \ hubp2->hubp_shift->field_name, hubp2->hubp_mask->field_name -void hubp2_update_dchub( - struct hubp *hubp, - struct dchub_init_data *dh_data) -{ - struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); - if (REG(DCN_VM_FB_LOCATION_TOP) == 0) - return; - - switch (dh_data->fb_mode) { - case FRAME_BUFFER_MODE_ZFB_ONLY: - /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ - REG_UPDATE(DCN_VM_FB_LOCATION_TOP, - FB_TOP, 0); - - REG_UPDATE(DCN_VM_FB_LOCATION_BASE, - FB_BASE, 0xFFFFFF); - - /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ - REG_UPDATE(DCN_VM_AGP_BASE, - AGP_BASE, dh_data->zfb_phys_addr_base >> 24); - - /*This field defines the bottom range of the AGP aperture and represents the 24*/ - /*MSBs, bits [47:24] of the 48 address bits*/ - REG_UPDATE(DCN_VM_AGP_BOT, - AGP_BOT, dh_data->zfb_mc_base_addr >> 24); - - /*This field defines the top range of the AGP aperture and represents the 24*/ - /*MSBs, bits [47:24] of the 48 address bits*/ - REG_UPDATE(DCN_VM_AGP_TOP, - AGP_TOP, (dh_data->zfb_mc_base_addr + - dh_data->zfb_size_in_byte - 1) >> 24); - break; - case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: - /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ - - /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ - REG_UPDATE(DCN_VM_AGP_BASE, - AGP_BASE, dh_data->zfb_phys_addr_base >> 24); - - /*This field defines the bottom range of the AGP aperture and represents the 24*/ - /*MSBs, bits [47:24] of the 48 address bits*/ - REG_UPDATE(DCN_VM_AGP_BOT, - AGP_BOT, dh_data->zfb_mc_base_addr >> 24); - - /*This field defines the top range of the AGP aperture and represents the 24*/ - /*MSBs, bits [47:24] of the 48 address bits*/ - REG_UPDATE(DCN_VM_AGP_TOP, - AGP_TOP, (dh_data->zfb_mc_base_addr + - dh_data->zfb_size_in_byte - 1) >> 24); - break; - case FRAME_BUFFER_MODE_LOCAL_ONLY: - /*Should not touch FB LOCATION (should be done by VBIOS)*/ - - /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ - REG_UPDATE(DCN_VM_AGP_BASE, - AGP_BASE, 0); - - /*This field defines the bottom range of the AGP aperture and represents the 24*/ - /*MSBs, bits [47:24] of the 48 address bits*/ - REG_UPDATE(DCN_VM_AGP_BOT, - AGP_BOT, 0xFFFFFF); - - /*This field defines the top range of the AGP aperture and represents the 24*/ - /*MSBs, bits [47:24] of the 48 address bits*/ - REG_UPDATE(DCN_VM_AGP_TOP, - AGP_TOP, 0); - break; - default: - break; - } - - dh_data->dchub_initialzied = true; - dh_data->dchub_info_valid = false; -} - void hubp2_set_vm_system_aperture_settings(struct hubp *hubp, struct vm_system_aperture_param *apt) { @@ -156,7 +81,85 @@ void hubp2_program_deadline( { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); - hubp1_program_deadline(hubp, dlg_attr, ttu_attr); + /* DLG - Per hubp */ + REG_SET_2(BLANK_OFFSET_0, 0, + REFCYC_H_BLANK_END, dlg_attr->refcyc_h_blank_end, + DLG_V_BLANK_END, dlg_attr->dlg_vblank_end); + + REG_SET(BLANK_OFFSET_1, 0, + MIN_DST_Y_NEXT_START, dlg_attr->min_dst_y_next_start); + + REG_SET(DST_DIMENSIONS, 0, + REFCYC_PER_HTOTAL, dlg_attr->refcyc_per_htotal); + + REG_SET_2(DST_AFTER_SCALER, 0, + REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler, + DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler); + + REG_SET(REF_FREQ_TO_PIX_FREQ, 0, + REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq); + + /* DLG - Per luma/chroma */ + REG_SET(VBLANK_PARAMETERS_1, 0, + REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l); + + if (REG(NOM_PARAMETERS_0)) + REG_SET(NOM_PARAMETERS_0, 0, + DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l); + + if (REG(NOM_PARAMETERS_1)) + REG_SET(NOM_PARAMETERS_1, 0, + REFCYC_PER_PTE_GROUP_NOM_L, dlg_attr->refcyc_per_pte_group_nom_l); + + REG_SET(NOM_PARAMETERS_4, 0, + DST_Y_PER_META_ROW_NOM_L, dlg_attr->dst_y_per_meta_row_nom_l); + + REG_SET(NOM_PARAMETERS_5, 0, + REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l); + + REG_SET_2(PER_LINE_DELIVERY, 0, + REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l, + REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c); + + REG_SET(VBLANK_PARAMETERS_2, 0, + REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c); + + if (REG(NOM_PARAMETERS_2)) + REG_SET(NOM_PARAMETERS_2, 0, + DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c); + + if (REG(NOM_PARAMETERS_3)) + REG_SET(NOM_PARAMETERS_3, 0, + REFCYC_PER_PTE_GROUP_NOM_C, dlg_attr->refcyc_per_pte_group_nom_c); + + REG_SET(NOM_PARAMETERS_6, 0, + DST_Y_PER_META_ROW_NOM_C, dlg_attr->dst_y_per_meta_row_nom_c); + + REG_SET(NOM_PARAMETERS_7, 0, + REFCYC_PER_META_CHUNK_NOM_C, dlg_attr->refcyc_per_meta_chunk_nom_c); + + /* TTU - per hubp */ + REG_SET_2(DCN_TTU_QOS_WM, 0, + QoS_LEVEL_LOW_WM, ttu_attr->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, ttu_attr->qos_level_high_wm); + + /* TTU - per luma/chroma */ + /* Assumed surf0 is luma and 1 is chroma */ + + REG_SET_3(DCN_SURF0_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_l, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_l, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_l); + + REG_SET_3(DCN_SURF1_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_c, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_c); + + REG_SET_3(DCN_CUR0_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_cur0, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_cur0, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_cur0); REG_SET(FLIP_PARAMETERS_1, 0, REFCYC_PER_PTE_GROUP_FLIP_L, dlg_attr->refcyc_per_pte_group_flip_l); @@ -184,6 +187,39 @@ void hubp2_vready_at_or_After_vsync(struct hubp *hubp, REG_UPDATE(DCHUBP_CNTL, HUBP_VREADY_AT_OR_AFTER_VSYNC, value); } +void hubp2_program_requestor( + struct hubp *hubp, + struct _vcs_dpi_display_rq_regs_st *rq_regs) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, rq_regs->plane1_base_address); + REG_SET_4(DCN_EXPANSION_MODE, 0, + DRQ_EXPANSION_MODE, rq_regs->drq_expansion_mode, + PRQ_EXPANSION_MODE, rq_regs->prq_expansion_mode, + MRQ_EXPANSION_MODE, rq_regs->mrq_expansion_mode, + CRQ_EXPANSION_MODE, rq_regs->crq_expansion_mode); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG, 0, + CHUNK_SIZE, rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, rq_regs->rq_regs_l.dpte_group_size, + MPTE_GROUP_SIZE, rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, rq_regs->rq_regs_l.pte_row_height_linear); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG_C, 0, + CHUNK_SIZE_C, rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.dpte_group_size, + MPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.mpte_group_size, + SWATH_HEIGHT_C, rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, rq_regs->rq_regs_c.pte_row_height_linear); +} + static void hubp2_setup( struct hubp *hubp, struct _vcs_dpi_display_dlg_regs_st *dlg_attr, @@ -196,7 +232,7 @@ static void hubp2_setup( */ hubp2_vready_at_or_After_vsync(hubp, pipe_dest); - hubp1_program_requestor(hubp, rq_regs); + hubp2_program_requestor(hubp, rq_regs); hubp2_program_deadline(hubp, dlg_attr, ttu_attr); } @@ -283,11 +319,205 @@ static void hubp2_program_tiling( PIPE_ALIGNED, 0); } +void hubp2_program_size( + struct hubp *hubp, + enum surface_pixel_format format, + const struct plane_size *plane_size, + struct dc_plane_dcc_param *dcc) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t pitch, meta_pitch, pitch_c, meta_pitch_c; + bool use_pitch_c = false; + + /* Program data and meta surface pitch (calculation from addrlib) + * 444 or 420 luma + */ + use_pitch_c = format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN + && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END; + if (use_pitch_c) { + ASSERT(plane_size->chroma_pitch != 0); + /* Chroma pitch zero can cause system hang! */ + + pitch = plane_size->surface_pitch - 1; + meta_pitch = dcc->meta_pitch - 1; + pitch_c = plane_size->chroma_pitch - 1; + meta_pitch_c = dcc->meta_pitch_c - 1; + } else { + pitch = plane_size->surface_pitch - 1; + meta_pitch = dcc->meta_pitch - 1; + pitch_c = 0; + meta_pitch_c = 0; + } + + if (!dcc->enable) { + meta_pitch = 0; + meta_pitch_c = 0; + } + + REG_UPDATE_2(DCSURF_SURFACE_PITCH, + PITCH, pitch, META_PITCH, meta_pitch); + + use_pitch_c = format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN; + if (use_pitch_c) + REG_UPDATE_2(DCSURF_SURFACE_PITCH_C, + PITCH_C, pitch_c, META_PITCH_C, meta_pitch_c); +} + +void hubp2_program_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, + bool horizontal_mirror) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t mirror; + + + if (horizontal_mirror) + mirror = 1; + else + mirror = 0; + + /* Program rotation angle and horz mirror - no mirror */ + if (rotation == ROTATION_ANGLE_0) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 0, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_90) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 1, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_180) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 2, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_270) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 3, + H_MIRROR_EN, mirror); +} + +void hubp2_dcc_control(struct hubp *hubp, bool enable, + enum hubp_ind_block_size independent_64b_blks) +{ + uint32_t dcc_en = enable ? 1 : 0; + uint32_t dcc_ind_64b_blk = independent_64b_blks ? 1 : 0; + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE_4(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_DCC_EN, dcc_en, + PRIMARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk, + SECONDARY_SURFACE_DCC_EN, dcc_en, + SECONDARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk); +} + +void hubp2_program_pixel_format( + struct hubp *hubp, + enum surface_pixel_format format) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t red_bar = 3; + uint32_t blue_bar = 2; + + /* swap for ABGR format */ + if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) { + red_bar = 2; + blue_bar = 3; + } + + REG_UPDATE_2(HUBPRET_CONTROL, + CROSSBAR_SRC_CB_B, blue_bar, + CROSSBAR_SRC_CR_R, red_bar); + + /* Mapping is same as ipp programming (cnvc) */ + + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 1); + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 3); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 8); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 10); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 22); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:/*we use crossbar already*/ + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 24); + break; + + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 65); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 64); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 67); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 66); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 12); + break; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 112); + break; + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 113); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 114); + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 118); + break; + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 119); + break; +#endif + default: + BREAK_TO_DEBUGGER(); + break; + } + + /* don't see the need of program the xbar in DCN 1.0 */ +} + void hubp2_program_surface_config( struct hubp *hubp, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror, @@ -295,11 +525,11 @@ void hubp2_program_surface_config( { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); - hubp1_dcc_control(hubp, dcc->enable, dcc->grph.independent_64b_blks); + hubp2_dcc_control(hubp, dcc->enable, dcc->independent_64b_blks); hubp2_program_tiling(hubp2, tiling_info, format); - hubp1_program_size(hubp, format, plane_size, dcc); - hubp1_program_rotation(hubp, rotation, horizontal_mirror); - hubp1_program_pixel_format(hubp, format); + hubp2_program_size(hubp, format, plane_size, dcc); + hubp2_program_rotation(hubp, rotation, horizontal_mirror); + hubp2_program_pixel_format(hubp, format); } enum cursor_lines_per_chunk hubp2_get_lines_per_chunk( @@ -652,28 +882,388 @@ void hubp2_set_flip_control_surface_gsl(struct hubp *hubp, bool enable) REG_UPDATE(DCSURF_FLIP_CONTROL2, SURFACE_GSL_ENABLE, enable ? 1 : 0); } +bool hubp2_is_flip_pending(struct hubp *hubp) +{ + uint32_t flip_pending = 0; + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + struct dc_plane_address earliest_inuse_address; + + REG_GET(DCSURF_FLIP_CONTROL, + SURFACE_FLIP_PENDING, &flip_pending); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE, + SURFACE_EARLIEST_INUSE_ADDRESS, &earliest_inuse_address.grph.addr.low_part); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, + SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, &earliest_inuse_address.grph.addr.high_part); + + if (flip_pending) + return true; + + if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part) + return true; + + return false; +} + +void hubp2_set_blank(struct hubp *hubp, bool blank) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t blank_en = blank ? 1 : 0; + + REG_UPDATE_2(DCHUBP_CNTL, + HUBP_BLANK_EN, blank_en, + HUBP_TTU_DISABLE, blank_en); + + if (blank) { + uint32_t reg_val = REG_READ(DCHUBP_CNTL); + + if (reg_val) { + /* init sequence workaround: in case HUBP is + * power gated, this wait would timeout. + * + * we just wrote reg_val to non-0, if it stay 0 + * it means HUBP is gated + */ + REG_WAIT(DCHUBP_CNTL, + HUBP_NO_OUTSTANDING_REQ, 1, + 1, 200); + } + + hubp->mpcc_id = 0xf; + hubp->opp_id = OPP_ID_INVALID; + } +} + +void hubp2_cursor_set_position( + struct hubp *hubp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x; + int src_y_offset = pos->y - pos->y_hotspot - param->viewport.y; + int x_hotspot = pos->x_hotspot; + int y_hotspot = pos->y_hotspot; + int cursor_height = (int)hubp->curs_attr.height; + int cursor_width = (int)hubp->curs_attr.width; + uint32_t dst_x_offset; + uint32_t cur_en = pos->enable ? 1 : 0; + + /* + * Guard aganst cursor_set_position() from being called with invalid + * attributes + * + * TODO: Look at combining cursor_set_position() and + * cursor_set_attributes() into cursor_update() + */ + if (hubp->curs_attr.address.quad_part == 0) + return; + + // Rotated cursor width/height and hotspots tweaks for offset calculation + if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) { + swap(cursor_height, cursor_width); + if (param->rotation == ROTATION_ANGLE_90) { + src_x_offset = pos->x - pos->y_hotspot - param->viewport.x; + src_y_offset = pos->y - pos->x_hotspot - param->viewport.y; + } + } else if (param->rotation == ROTATION_ANGLE_180) { + src_x_offset = pos->x - param->viewport.x; + src_y_offset = pos->y - param->viewport.y; + } + + if (param->mirror) { + x_hotspot = param->viewport.width - x_hotspot; + src_x_offset = param->viewport.x + param->viewport.width - src_x_offset; + } + + dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; + dst_x_offset *= param->ref_clk_khz; + dst_x_offset /= param->pixel_clk_khz; + + ASSERT(param->h_scale_ratio.value); + + if (param->h_scale_ratio.value) + dst_x_offset = dc_fixpt_floor(dc_fixpt_div( + dc_fixpt_from_int(dst_x_offset), + param->h_scale_ratio)); + + if (src_x_offset >= (int)param->viewport.width) + cur_en = 0; /* not visible beyond right edge*/ + + if (src_x_offset + cursor_width <= 0) + cur_en = 0; /* not visible beyond left edge*/ + + if (src_y_offset >= (int)param->viewport.height) + cur_en = 0; /* not visible beyond bottom edge*/ + + if (src_y_offset + cursor_height <= 0) + cur_en = 0; /* not visible beyond top edge*/ + + if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) + hubp->funcs->set_cursor_attributes(hubp, &hubp->curs_attr); + + REG_UPDATE(CURSOR_CONTROL, + CURSOR_ENABLE, cur_en); + + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, pos->x, + CURSOR_Y_POSITION, pos->y); + + REG_SET_2(CURSOR_HOT_SPOT, 0, + CURSOR_HOT_SPOT_X, x_hotspot, + CURSOR_HOT_SPOT_Y, y_hotspot); + + REG_SET(CURSOR_DST_OFFSET, 0, + CURSOR_DST_X_OFFSET, dst_x_offset); + /* TODO Handle surface pixel formats other than 4:4:4 */ +} + +void hubp2_clk_cntl(struct hubp *hubp, bool enable) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t clk_enable = enable ? 1 : 0; + + REG_UPDATE(HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, clk_enable); +} + +void hubp2_vtg_sel(struct hubp *hubp, uint32_t otg_inst) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_VTG_SEL, otg_inst); +} + +void hubp2_clear_underflow(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, 1); +} + +void hubp2_read_state_common(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + struct dcn_hubp_state *s = &hubp2->state; + struct _vcs_dpi_display_dlg_regs_st *dlg_attr = &s->dlg_attr; + struct _vcs_dpi_display_ttu_regs_st *ttu_attr = &s->ttu_attr; + struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; + + /* Requester */ + REG_GET(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, &rq_regs->plane1_base_address); + REG_GET_4(DCN_EXPANSION_MODE, + DRQ_EXPANSION_MODE, &rq_regs->drq_expansion_mode, + PRQ_EXPANSION_MODE, &rq_regs->prq_expansion_mode, + MRQ_EXPANSION_MODE, &rq_regs->mrq_expansion_mode, + CRQ_EXPANSION_MODE, &rq_regs->crq_expansion_mode); + + /* DLG - Per hubp */ + REG_GET_2(BLANK_OFFSET_0, + REFCYC_H_BLANK_END, &dlg_attr->refcyc_h_blank_end, + DLG_V_BLANK_END, &dlg_attr->dlg_vblank_end); + + REG_GET(BLANK_OFFSET_1, + MIN_DST_Y_NEXT_START, &dlg_attr->min_dst_y_next_start); + + REG_GET(DST_DIMENSIONS, + REFCYC_PER_HTOTAL, &dlg_attr->refcyc_per_htotal); + + REG_GET_2(DST_AFTER_SCALER, + REFCYC_X_AFTER_SCALER, &dlg_attr->refcyc_x_after_scaler, + DST_Y_AFTER_SCALER, &dlg_attr->dst_y_after_scaler); + + if (REG(PREFETCH_SETTINS)) + REG_GET_2(PREFETCH_SETTINS, + DST_Y_PREFETCH, &dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, &dlg_attr->vratio_prefetch); + else + REG_GET_2(PREFETCH_SETTINGS, + DST_Y_PREFETCH, &dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, &dlg_attr->vratio_prefetch); + + REG_GET_2(VBLANK_PARAMETERS_0, + DST_Y_PER_VM_VBLANK, &dlg_attr->dst_y_per_vm_vblank, + DST_Y_PER_ROW_VBLANK, &dlg_attr->dst_y_per_row_vblank); + + REG_GET(REF_FREQ_TO_PIX_FREQ, + REF_FREQ_TO_PIX_FREQ, &dlg_attr->ref_freq_to_pix_freq); + + /* DLG - Per luma/chroma */ + REG_GET(VBLANK_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_VBLANK_L, &dlg_attr->refcyc_per_pte_group_vblank_l); + + REG_GET(VBLANK_PARAMETERS_3, + REFCYC_PER_META_CHUNK_VBLANK_L, &dlg_attr->refcyc_per_meta_chunk_vblank_l); + + if (REG(NOM_PARAMETERS_0)) + REG_GET(NOM_PARAMETERS_0, + DST_Y_PER_PTE_ROW_NOM_L, &dlg_attr->dst_y_per_pte_row_nom_l); + + if (REG(NOM_PARAMETERS_1)) + REG_GET(NOM_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_NOM_L, &dlg_attr->refcyc_per_pte_group_nom_l); + + REG_GET(NOM_PARAMETERS_4, + DST_Y_PER_META_ROW_NOM_L, &dlg_attr->dst_y_per_meta_row_nom_l); + + REG_GET(NOM_PARAMETERS_5, + REFCYC_PER_META_CHUNK_NOM_L, &dlg_attr->refcyc_per_meta_chunk_nom_l); + + REG_GET_2(PER_LINE_DELIVERY_PRE, + REFCYC_PER_LINE_DELIVERY_PRE_L, &dlg_attr->refcyc_per_line_delivery_pre_l, + REFCYC_PER_LINE_DELIVERY_PRE_C, &dlg_attr->refcyc_per_line_delivery_pre_c); + + REG_GET_2(PER_LINE_DELIVERY, + REFCYC_PER_LINE_DELIVERY_L, &dlg_attr->refcyc_per_line_delivery_l, + REFCYC_PER_LINE_DELIVERY_C, &dlg_attr->refcyc_per_line_delivery_c); + + if (REG(PREFETCH_SETTINS_C)) + REG_GET(PREFETCH_SETTINS_C, + VRATIO_PREFETCH_C, &dlg_attr->vratio_prefetch_c); + else + REG_GET(PREFETCH_SETTINGS_C, + VRATIO_PREFETCH_C, &dlg_attr->vratio_prefetch_c); + + REG_GET(VBLANK_PARAMETERS_2, + REFCYC_PER_PTE_GROUP_VBLANK_C, &dlg_attr->refcyc_per_pte_group_vblank_c); + + REG_GET(VBLANK_PARAMETERS_4, + REFCYC_PER_META_CHUNK_VBLANK_C, &dlg_attr->refcyc_per_meta_chunk_vblank_c); + + if (REG(NOM_PARAMETERS_2)) + REG_GET(NOM_PARAMETERS_2, + DST_Y_PER_PTE_ROW_NOM_C, &dlg_attr->dst_y_per_pte_row_nom_c); + + if (REG(NOM_PARAMETERS_3)) + REG_GET(NOM_PARAMETERS_3, + REFCYC_PER_PTE_GROUP_NOM_C, &dlg_attr->refcyc_per_pte_group_nom_c); + + REG_GET(NOM_PARAMETERS_6, + DST_Y_PER_META_ROW_NOM_C, &dlg_attr->dst_y_per_meta_row_nom_c); + + REG_GET(NOM_PARAMETERS_7, + REFCYC_PER_META_CHUNK_NOM_C, &dlg_attr->refcyc_per_meta_chunk_nom_c); + + /* TTU - per hubp */ + REG_GET_2(DCN_TTU_QOS_WM, + QoS_LEVEL_LOW_WM, &ttu_attr->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, &ttu_attr->qos_level_high_wm); + + REG_GET_2(DCN_GLOBAL_TTU_CNTL, + MIN_TTU_VBLANK, &ttu_attr->min_ttu_vblank, + QoS_LEVEL_FLIP, &ttu_attr->qos_level_flip); + + /* TTU - per luma/chroma */ + /* Assumed surf0 is luma and 1 is chroma */ + + REG_GET_3(DCN_SURF0_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr->refcyc_per_req_delivery_l, + QoS_LEVEL_FIXED, &ttu_attr->qos_level_fixed_l, + QoS_RAMP_DISABLE, &ttu_attr->qos_ramp_disable_l); + + REG_GET(DCN_SURF0_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, + &ttu_attr->refcyc_per_req_delivery_pre_l); + + REG_GET_3(DCN_SURF1_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr->refcyc_per_req_delivery_c, + QoS_LEVEL_FIXED, &ttu_attr->qos_level_fixed_c, + QoS_RAMP_DISABLE, &ttu_attr->qos_ramp_disable_c); + + REG_GET(DCN_SURF1_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, + &ttu_attr->refcyc_per_req_delivery_pre_c); + + /* Rest of hubp */ + REG_GET(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, &s->pixel_format); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, + SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, &s->inuse_addr_hi); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE, + SURFACE_EARLIEST_INUSE_ADDRESS, &s->inuse_addr_lo); + + REG_GET_2(DCSURF_PRI_VIEWPORT_DIMENSION, + PRI_VIEWPORT_WIDTH, &s->viewport_width, + PRI_VIEWPORT_HEIGHT, &s->viewport_height); + + REG_GET_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, &s->rotation_angle, + H_MIRROR_EN, &s->h_mirror_en); + + REG_GET(DCSURF_TILING_CONFIG, + SW_MODE, &s->sw_mode); + + REG_GET(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_DCC_EN, &s->dcc_en); + + REG_GET_3(DCHUBP_CNTL, + HUBP_BLANK_EN, &s->blank_en, + HUBP_TTU_DISABLE, &s->ttu_disable, + HUBP_UNDERFLOW_STATUS, &s->underflow_status); + + REG_GET(DCN_GLOBAL_TTU_CNTL, + MIN_TTU_VBLANK, &s->min_ttu_vblank); + + REG_GET_2(DCN_TTU_QOS_WM, + QoS_LEVEL_LOW_WM, &s->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, &s->qos_level_high_wm); + +} + +void hubp2_read_state(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + struct dcn_hubp_state *s = &hubp2->state; + struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; + + hubp2_read_state_common(hubp); + + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG, + CHUNK_SIZE, &rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, &rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, &rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, &rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, &rq_regs->rq_regs_l.dpte_group_size, + MPTE_GROUP_SIZE, &rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, &rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, &rq_regs->rq_regs_l.pte_row_height_linear); + + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG_C, + CHUNK_SIZE_C, &rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.dpte_group_size, + MPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.mpte_group_size, + SWATH_HEIGHT_C, &rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, &rq_regs->rq_regs_c.pte_row_height_linear); + +} + static struct hubp_funcs dcn20_hubp_funcs = { .hubp_enable_tripleBuffer = hubp2_enable_triplebuffer, .hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled, .hubp_program_surface_flip_and_addr = hubp2_program_surface_flip_and_addr, .hubp_program_surface_config = hubp2_program_surface_config, - .hubp_is_flip_pending = hubp1_is_flip_pending, + .hubp_is_flip_pending = hubp2_is_flip_pending, .hubp_setup = hubp2_setup, .hubp_setup_interdependent = hubp2_setup_interdependent, .hubp_set_vm_system_aperture_settings = hubp2_set_vm_system_aperture_settings, - .set_blank = hubp1_set_blank, - .dcc_control = hubp1_dcc_control, - .hubp_update_dchub = hubp2_update_dchub, + .set_blank = hubp2_set_blank, + .dcc_control = hubp2_dcc_control, .mem_program_viewport = min_set_viewport, .set_cursor_attributes = hubp2_cursor_set_attributes, - .set_cursor_position = hubp1_cursor_set_position, - .hubp_clk_cntl = hubp1_clk_cntl, - .hubp_vtg_sel = hubp1_vtg_sel, + .set_cursor_position = hubp2_cursor_set_position, + .hubp_clk_cntl = hubp2_clk_cntl, + .hubp_vtg_sel = hubp2_vtg_sel, .dmdata_set_attributes = hubp2_dmdata_set_attributes, .dmdata_load = hubp2_dmdata_load, .dmdata_status_done = hubp2_dmdata_status_done, - .hubp_read_state = hubp1_read_state, - .hubp_clear_underflow = hubp1_clear_underflow, + .hubp_read_state = hubp2_read_state, + .hubp_clear_underflow = hubp2_clear_underflow, .hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl, .hubp_init = hubp1_init, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h index d5acc348be22..d5c8615af45e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h @@ -38,12 +38,6 @@ SRI(PREFETCH_SETTINGS_C, HUBPREQ, id),\ SRI(DCN_VM_SYSTEM_APERTURE_LOW_ADDR, HUBPREQ, id),\ SRI(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, HUBPREQ, id),\ - SR(DCN_VM_FB_LOCATION_TOP),\ - SR(DCN_VM_FB_LOCATION_BASE),\ - SR(DCN_VM_FB_OFFSET),\ - SR(DCN_VM_AGP_BASE),\ - SR(DCN_VM_AGP_BOT),\ - SR(DCN_VM_AGP_TOP),\ SRI(CURSOR_SETTINGS, HUBPREQ, id), \ SRI(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR0_, id), \ SRI(CURSOR_SURFACE_ADDRESS, CURSOR0_, id), \ @@ -72,8 +66,8 @@ SR(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB),\ SR(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB) -#define HUBP_MASK_SH_LIST_DCN2_COMMON(mask_sh)\ - HUBP_MASK_SH_LIST_DCN(mask_sh),\ +#define HUBP_MASK_SH_LIST_DCN2_SHARE_COMMON(mask_sh)\ + HUBP_MASK_SH_LIST_DCN_SHARE_COMMON(mask_sh),\ HUBP_MASK_SH_LIST_DCN_VM(mask_sh),\ HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ROTATION_ANGLE, mask_sh),\ HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, H_MIRROR_EN, mask_sh),\ @@ -82,12 +76,6 @@ HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS_C, VRATIO_PREFETCH_C, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR, MC_VM_SYSTEM_APERTURE_LOW_ADDR, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, MC_VM_SYSTEM_APERTURE_HIGH_ADDR, mask_sh),\ - HUBP_SF(DCN_VM_FB_LOCATION_TOP, FB_TOP, mask_sh),\ - HUBP_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE, mask_sh),\ - HUBP_SF(DCN_VM_FB_OFFSET, FB_OFFSET, mask_sh),\ - HUBP_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh),\ - HUBP_SF(DCN_VM_AGP_BOT, AGP_BOT, mask_sh),\ - HUBP_SF(DCN_VM_AGP_TOP, AGP_TOP, mask_sh),\ HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_DST_Y_OFFSET, mask_sh), \ HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \ HUBP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \ @@ -127,13 +115,21 @@ HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_TRIPLE_BUFFER_ENABLE, mask_sh),\ HUBP_SF(HUBPREQ0_VMID_SETTINGS_0, VMID, mask_sh) +/*DCN2.x and DCN1.x*/ +#define HUBP_MASK_SH_LIST_DCN2_COMMON(mask_sh)\ + HUBP_MASK_SH_LIST_DCN2_SHARE_COMMON(mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, RB_ALIGNED, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MPTE_GROUP_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MPTE_GROUP_SIZE_C, mask_sh) + +/*DCN2.0 specific*/ #define HUBP_MASK_SH_LIST_DCN20(mask_sh)\ HUBP_MASK_SH_LIST_DCN2_COMMON(mask_sh),\ HUBP_SF(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, DCN_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM, mask_sh),\ HUBP_SF(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, mask_sh),\ HUBP_SF(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, mask_sh) - +/*DCN2.x */ #define DCN2_HUBP_REG_COMMON_VARIABLE_LIST \ HUBP_COMMON_REG_VARIABLE_LIST; \ uint32_t DMDATA_ADDRESS_HIGH; \ @@ -149,14 +145,22 @@ uint32_t FLIP_PARAMETERS_2;\ uint32_t DCN_CUR1_TTU_CNTL0;\ uint32_t DCN_CUR1_TTU_CNTL1;\ - uint32_t VMID_SETTINGS_0;\ + uint32_t VMID_SETTINGS_0 + + +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#define DCN21_HUBP_REG_COMMON_VARIABLE_LIST \ + DCN2_HUBP_REG_COMMON_VARIABLE_LIST; \ uint32_t FLIP_PARAMETERS_3;\ uint32_t FLIP_PARAMETERS_4;\ + uint32_t FLIP_PARAMETERS_5;\ + uint32_t FLIP_PARAMETERS_6;\ uint32_t VBLANK_PARAMETERS_5;\ uint32_t VBLANK_PARAMETERS_6 +#endif #define DCN2_HUBP_REG_FIELD_VARIABLE_LIST(type) \ - DCN_HUBP_REG_FIELD_LIST(type); \ + DCN_HUBP_REG_FIELD_BASE_LIST(type); \ type DMDATA_ADDRESS_HIGH;\ type DMDATA_MODE;\ type DMDATA_UPDATED;\ @@ -180,17 +184,41 @@ type SURFACE_TRIPLE_BUFFER_ENABLE;\ type VMID +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 +#define DCN21_HUBP_REG_FIELD_VARIABLE_LIST(type) \ + DCN2_HUBP_REG_FIELD_VARIABLE_LIST(type);\ + type REFCYC_PER_VM_GROUP_FLIP;\ + type REFCYC_PER_VM_REQ_FLIP;\ + type REFCYC_PER_VM_GROUP_VBLANK;\ + type REFCYC_PER_VM_REQ_VBLANK;\ + type REFCYC_PER_PTE_GROUP_FLIP_C; \ + type REFCYC_PER_META_CHUNK_FLIP_C; \ + type VM_GROUP_SIZE +#endif + struct dcn_hubp2_registers { +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + DCN21_HUBP_REG_COMMON_VARIABLE_LIST; +#else DCN2_HUBP_REG_COMMON_VARIABLE_LIST; +#endif }; struct dcn_hubp2_shift { +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + DCN21_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); +#else DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); +#endif }; struct dcn_hubp2_mask { +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + DCN21_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); +#else DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); +#endif }; struct dcn20_hubp { @@ -217,10 +245,6 @@ void hubp2_setup_interdependent( void hubp2_vready_at_or_After_vsync(struct hubp *hubp, struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest); -void hubp2_update_dchub( - struct hubp *hubp, - struct dchub_init_data *dh_data); - void hubp2_cursor_set_attributes( struct hubp *hubp, const struct dc_cursor_attributes *attr); @@ -262,16 +286,53 @@ bool hubp2_program_surface_flip_and_addr( const struct dc_plane_address *address, bool flip_immediate); +void hubp2_dcc_control(struct hubp *hubp, bool enable, + enum hubp_ind_block_size independent_64b_blks); + +void hubp2_program_size( + struct hubp *hubp, + enum surface_pixel_format format, + const struct plane_size *plane_size, + struct dc_plane_dcc_param *dcc); + +void hubp2_program_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, + bool horizontal_mirror); + +void hubp2_program_pixel_format( + struct hubp *hubp, + enum surface_pixel_format format); + void hubp2_program_surface_config( struct hubp *hubp, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror, unsigned int compat_level); +bool hubp2_is_flip_pending(struct hubp *hubp); + +void hubp2_set_blank(struct hubp *hubp, bool blank); + +void hubp2_cursor_set_position( + struct hubp *hubp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param); + +void hubp2_clk_cntl(struct hubp *hubp, bool enable); + +void hubp2_vtg_sel(struct hubp *hubp, uint32_t otg_inst); + +void hubp2_clear_underflow(struct hubp *hubp); + +void hubp2_read_state_common(struct hubp *hubp); + +void hubp2_read_state(struct hubp *hubp); + #endif /* __DC_MEM_INPUT_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 0b84a322b8a2..1212da12c414 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -64,23 +64,7 @@ #define FN(reg_name, field_name) \ hws->shifts->field_name, hws->masks->field_name -static void bios_golden_init(struct dc *dc) -{ - struct dc_bios *bp = dc->ctx->dc_bios; - int i; - - /* initialize dcn global */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0, ASIC_PIPE_INIT); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - /* initialize dcn per pipe */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); - } -} - -static void enable_power_gating_plane( +static void dcn20_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { @@ -94,28 +78,34 @@ static void enable_power_gating_plane( REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); - /*Do not power gate DCHUB5, should be left at HW default, power on permanently*/ - /*REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN10_POWER_FORCEON, force_on);*/ + if (REG(DOMAIN8_PG_CONFIG)) + REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); + if (REG(DOMAIN10_PG_CONFIG)) + REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); /* DPP0/1/2/3/4/5 */ REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); - /*Do not power gate DPP5, should be left at HW default, power on permanently*/ - /*REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN11_POWER_FORCEON, force_on);*/ + if (REG(DOMAIN9_PG_CONFIG)) + REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); + if (REG(DOMAIN11_PG_CONFIG)) + REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); + /* DCS0/1/2/3/4/5 */ REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on); REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on); REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on); + if (REG(DOMAIN19_PG_CONFIG)) + REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on); + if (REG(DOMAIN20_PG_CONFIG)) + REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on); + if (REG(DOMAIN21_PG_CONFIG)) + REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on); } -static void dcn20_dccg_init(struct dce_hwseq *hws) +void dcn20_dccg_init(struct dce_hwseq *hws) { /* * set MICROSECOND_TIME_BASE_DIV @@ -138,8 +128,46 @@ static void dcn20_dccg_init(struct dce_hwseq *hws) /* This value is dependent on the hardware pipeline delay so set once per SOC */ REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c); } +void dcn20_display_init(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + + /* RBBMIF + * disable RBBMIF timeout detection for all clients + * Ensure RBBMIF does not drop register accesses due to the per-client timeout + */ + REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); + REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); -static void disable_vga( + /* DCCG */ + dcn20_dccg_init(hws); + + REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 0); + + /* DCHUB/MMHUBBUB + * set global timer refclk divider + * 100Mhz refclk -> 2 + * 27Mhz refclk -> 1 + * 48Mhz refclk -> 1 + */ + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + REG_WRITE(REFCLK_CNTL, 0); + + /* OPTC + * OTG_CONTROL.OTG_DISABLE_POINT_CNTL = 0x3; will be set during optc2_enable_crtc + */ + + /* AZ + * default value is 0x64 for 100Mhz ref clock, if the ref clock is 100Mhz, no need to program this regiser, + * if not, it should be programmed according to the ref clock + */ + REG_UPDATE(AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, 0x64); + /* Enable controller clock gating */ + REG_WRITE(AZALIA_CONTROLLER_CLOCK_GATING, 0x1); +} + +void dcn20_disable_vga( struct dce_hwseq *hws) { REG_WRITE(D1VGA_CONTROL, 0); @@ -163,7 +191,7 @@ void dcn20_program_tripleBuffer( } /* Blank pixel data during initialization */ -static void dcn20_init_blank( +void dcn20_init_blank( struct dc *dc, struct timing_generator *tg) { @@ -442,29 +470,6 @@ static void dcn20_hubp_pg_control( } - -static void dcn20_plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (REG(DC_IP_REQUEST_CNTL)) { - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - dcn20_dpp_pg_control(hws, dpp->inst, false); - dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); - dpp->funcs->dpp_reset(dpp); - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - DC_LOG_DEBUG( - "Power gated front end %d\n", pipe_ctx->pipe_idx); - } -} - - - /* disable HW used by plane. * note: cannot disable until disconnect is complete */ @@ -490,7 +495,9 @@ static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - dcn20_plane_atomic_power_down(dc, pipe_ctx); + dc->hwss.plane_atomic_power_down(dc, + pipe_ctx->plane_res.dpp, + pipe_ctx->plane_res.hubp); pipe_ctx->stream = NULL; memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); @@ -514,199 +521,6 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->pipe_idx); } -static void dcn20_init_hw(struct dc *dc) -{ - int i, j; - struct abm *abm = dc->res_pool->abm; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - struct dc_state *context = dc->current_state; - struct dc_firmware_info fw_info = { { 0 } }; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - //Enable ability to power gate / don't force power on permanently - enable_power_gating_plane(dc->hwseq, true); - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); - REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); - - dcn20_dccg_init(hws); - - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); - REG_WRITE(REFCLK_CNTL, 0); - } else { - if (!dcb->funcs->is_accelerated_mode(dcb)) { - bios_golden_init(dc); - if (dc->ctx->dc_bios->funcs->get_firmware_info( - dc->ctx->dc_bios, &fw_info) == BP_RESULT_OK) { - res_pool->ref_clocks.xtalin_clock_inKhz = fw_info.pll_info.crystal_frequency; - - if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - if (res_pool->dccg && res_pool->hubbub) { - - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } - } else - ASSERT_CRITICAL(false); - disable_vga(dc->hwseq); - } - - 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 dc_link *link = dc->links[i]; - - link->link_enc->funcs->hw_init(link->link_enc); - } - } - - /* Blank pixel data with OPP DPG */ - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) { - dcn20_init_blank(dc, tg); - } - } - - for (i = 0; i < res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->lock(tg); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct dpp *dpp = res_pool->dpps[i]; - - dpp->funcs->dpp_reset(dpp); - } - - /* Reset all MPCC muxes */ - res_pool->mpc->funcs->mpc_init(res_pool->mpc); - - /* initialize OPP mpc_tree parameter */ - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; - res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - for (j = 0; j < MAX_PIPES; j++) - res_pool->opps[i]->mpcc_disconnect_pending[j] = false; - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - struct dpp *dpp = dc->res_pool->dpps[i]; - - pipe_ctx->stream_res.tg = tg; - pipe_ctx->pipe_idx = i; - - pipe_ctx->plane_res.hubp = hubp; - pipe_ctx->plane_res.dpp = dpp; - pipe_ctx->plane_res.mpcc_inst = dpp->inst; - hubp->mpcc_id = dpp->inst; - hubp->opp_id = OPP_ID_INVALID; - hubp->power_gated = false; - pipe_ctx->stream_res.opp = NULL; - - hubp->funcs->hubp_init(hubp); - - //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; - //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - /*to do*/ - hwss1_plane_atomic_disconnect(dc, pipe_ctx); - } - - /* initialize DWB pointer to MCIF_WB */ - for (i = 0; i < res_pool->res_cap->num_dwb; i++) - res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; - - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->unlock(tg); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - dc->hwss.disable_plane(dc, pipe_ctx); - - pipe_ctx->stream_res.tg = NULL; - pipe_ctx->plane_res.hubp = NULL; - } - - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - tg->funcs->tg_init(tg); - } - - /* end of FPGA. Below if real ASIC */ - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) - return; - - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - if (abm != NULL) { - abm->funcs->init_backlight(abm); - abm->funcs->abm_init(abm); - } - - if (dmcu != NULL) - dmcu->funcs->dmcu_init(dmcu); - - if (abm != NULL && dmcu != NULL) - abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - -} - enum dc_status dcn20_enable_stream_timing( struct pipe_ctx *pipe_ctx, struct dc_state *context, @@ -715,11 +529,9 @@ enum dc_status dcn20_enable_stream_timing( struct dc_stream_state *stream = pipe_ctx->stream; struct drr_params params = {0}; unsigned int event_triggers = 0; - - -#if defined(CONFIG_DRM_AMD_DC_DCN2_0) - struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); -#endif + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; /* by upper caller loop, pipe0 is parent pipe and be called first. * back end is set up by for pipe0. Other children pipe share back end @@ -730,12 +542,17 @@ enum dc_status dcn20_enable_stream_timing( /* TODO check if timing_changed, disable stream if timing changed */ - if (odm_pipe) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; + opp_cnt++; + } + + if (opp_cnt > 1) pipe_ctx->stream_res.tg->funcs->set_odm_combine( pipe_ctx->stream_res.tg, - odm_pipe->stream_res.opp->inst, - pipe_ctx->stream->timing.h_addressable/2, - pipe_ctx->stream->timing.pixel_encoding); + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); + /* HW program guide assume display already disable * by unplug sequence. OTG assume stop. */ @@ -759,11 +576,7 @@ enum dc_status dcn20_enable_stream_timing( pipe_ctx->stream->signal, true); - if (pipe_ctx->stream_res.tg->funcs->setup_global_lock) - pipe_ctx->stream_res.tg->funcs->setup_global_lock( - pipe_ctx->stream_res.tg); - - if (odm_pipe) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( odm_pipe->stream_res.opp, true); @@ -784,6 +597,8 @@ enum dc_status dcn20_enable_stream_timing( params.vertical_total_min = stream->adjust.v_total_min; params.vertical_total_max = stream->adjust.v_total_max; + params.vertical_total_mid = stream->adjust.v_total_mid; + params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num; if (pipe_ctx->stream_res.tg->funcs->set_drr) pipe_ctx->stream_res.tg->funcs->set_drr( pipe_ctx->stream_res.tg, ¶ms); @@ -814,6 +629,10 @@ void dcn20_program_output_csc(struct dc *dc, { struct mpc *mpc = dc->res_pool->mpc; enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + + if (mpc->funcs->power_on_mpc_mem_pwr) + mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { if (mpc->funcs->set_output_csc != NULL) @@ -843,7 +662,9 @@ bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, * if programming for all pipes is required then remove condition * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic. */ - if ((pipe_ctx->top_pipe == NULL || dc_res_is_odm_head_pipe(pipe_ctx)) + if (mpc->funcs->power_on_mpc_mem_pwr) + mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); + if (pipe_ctx->top_pipe == NULL && mpc->funcs->set_output_gamma && stream->out_transfer_func) { if (stream->out_transfer_func->type == TF_TYPE_HWPWL) params = &stream->out_transfer_func->pwl; @@ -909,14 +730,14 @@ static bool dcn20_set_shaper_3dlut( result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); if (plane_state->lut3d_func && - plane_state->lut3d_func->initialized == true) + plane_state->lut3d_func->state.bits.initialized == 1) result = dpp_base->funcs->dpp_program_3dlut(dpp_base, &plane_state->lut3d_func->lut_3d); else result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL); if (plane_state->lut3d_func && - plane_state->lut3d_func->initialized == true && + plane_state->lut3d_func->state.bits.initialized == 1 && plane_state->lut3d_func->hdr_multiplier != 0) dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, plane_state->lut3d_func->hdr_multiplier); @@ -1005,14 +826,20 @@ bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, static void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { - struct pipe_ctx *combine_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; - if (combine_pipe) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; + opp_cnt++; + } + + if (opp_cnt > 1) pipe_ctx->stream_res.tg->funcs->set_odm_combine( pipe_ctx->stream_res.tg, - combine_pipe->stream_res.opp->inst, - pipe_ctx->plane_res.scl_data.h_active, - pipe_ctx->stream->timing.pixel_encoding); + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); else pipe_ctx->stream_res.tg->funcs->set_odm_bypass( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); @@ -1028,7 +855,8 @@ void dcn20_blank_pixel_data( struct dc_stream_state *stream = pipe_ctx->stream; enum dc_color_space color_space = stream->output_color_space; enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; - struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + struct pipe_ctx *odm_pipe; + int odm_cnt = 1; int width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; int height = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; @@ -1036,8 +864,10 @@ void dcn20_blank_pixel_data( /* get opp dpg blank color */ color_space_to_black_color(dc, color_space, &black_color); - if (bot_odm_pipe) - width = width / 2; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + odm_cnt++; + + width = width / odm_cnt; if (blank) { if (stream_res->abm) @@ -1057,10 +887,10 @@ void dcn20_blank_pixel_data( width, height); - if (bot_odm_pipe) { - bot_odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator( - bot_odm_pipe->stream_res.opp, - dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE ? + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator( + odm_pipe->stream_res.opp, + dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE && blank ? CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern, stream->timing.display_color_depth, &black_color, @@ -1106,6 +936,9 @@ void dcn20_enable_plane( /* enable DCFCLK current DCHUB */ pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); + /* initialize HUBP on power up */ + pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp); + /* make sure OPP_PIPE_CLOCK_EN = 1 */ pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( pipe_ctx->stream_res.opp, @@ -1153,8 +986,8 @@ void dcn20_enable_plane( apt.sys_default.quad_part = 0; - apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.start_addr; - apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.end_addr; + apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr; + apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr; // Program system aperture settings pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); @@ -1201,7 +1034,7 @@ static void dcn20_program_all_pipe_in_tree( struct pipe_ctx *pipe_ctx, struct dc_state *context) { - if (pipe_ctx->top_pipe == NULL) { + if (pipe_ctx->top_pipe == NULL && !pipe_ctx->prev_odm_pipe) { bool blank = !is_pipe_tree_visible(pipe_ctx); pipe_ctx->stream_res.tg->funcs->program_global_sync( @@ -1223,8 +1056,13 @@ static void dcn20_program_all_pipe_in_tree( if (pipe_ctx->plane_state != NULL) dcn20_program_pipe(dc, pipe_ctx, context); - if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) + if (pipe_ctx->bottom_pipe != NULL) { + ASSERT(pipe_ctx->bottom_pipe != pipe_ctx); dcn20_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); + } else if (pipe_ctx->next_odm_pipe != NULL) { + ASSERT(pipe_ctx->next_odm_pipe != pipe_ctx); + dcn20_program_all_pipe_in_tree(dc, pipe_ctx->next_odm_pipe, context); + } } void dcn20_pipe_control_lock_global( @@ -1242,6 +1080,8 @@ void dcn20_pipe_control_lock_global( CRTC_STATE_VACTIVE); pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK); + pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, + CRTC_STATE_VACTIVE); pipe->stream_res.tg->funcs->lock_doublebuffer_disable( pipe->stream_res.tg); } @@ -1290,18 +1130,32 @@ static void dcn20_apply_ctx_for_surface( int num_planes, struct dc_state *context) { - + const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS = 100; int i; struct timing_generator *tg; bool removed_pipe[6] = { false }; bool interdependent_update = false; struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); + struct pipe_ctx *prev_top_pipe_to_program = + find_top_pipe_for_stream(dc, dc->current_state, stream); DC_LOGGER_INIT(dc->ctx->logger); if (!top_pipe_to_program) return; + /* Carry over GSL groups in case the context is changing. */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == stream && + pipe_ctx->stream == old_pipe_ctx->stream) + pipe_ctx->stream_res.gsl_group = + old_pipe_ctx->stream_res.gsl_group; + } + tg = top_pipe_to_program->stream_res.tg; interdependent_update = top_pipe_to_program->plane_state && @@ -1332,7 +1186,7 @@ static void dcn20_apply_ctx_for_surface( if (old_pipe_ctx->stream_res.tg == tg && old_pipe_ctx->plane_res.hubp && old_pipe_ctx->plane_res.hubp->opp_id != OPP_ID_INVALID) - dcn20_disable_plane(dc, old_pipe_ctx); + dc->hwss.disable_plane(dc, old_pipe_ctx); } if ((!pipe_ctx->plane_state || @@ -1378,6 +1232,22 @@ static void dcn20_apply_ctx_for_surface( for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) dcn20_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + + /* + * If we are enabling a pipe, we need to wait for pending clear as this is a critical + * part of the enable operation otherwise, DM may request an immediate flip which + * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which + * is unsupported on DCN. + */ + i = 0; + if (num_planes > 0 && top_pipe_to_program && + (prev_top_pipe_to_program == NULL || prev_top_pipe_to_program->plane_state == NULL)) { + while (i < TIMEOUT_FOR_PIPE_ENABLE_MS && + top_pipe_to_program->plane_res.hubp->funcs->hubp_is_flip_pending(top_pipe_to_program->plane_res.hubp)) { + i += 1; + msleep(1); + } + } } @@ -1387,16 +1257,16 @@ void dcn20_prepare_bandwidth( { struct hubbub *hubbub = dc->res_pool->hubbub; + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + false); + /* program dchubbub watermarks */ hubbub->funcs->program_watermarks(hubbub, &context->bw_ctx.bw.dcn.watermarks, dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, false); - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - false); } void dcn20_optimize_bandwidth( @@ -1449,8 +1319,8 @@ bool dcn20_update_bandwidth( pipe_ctx->stream_res.tg->funcs->set_vtg_params( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - - dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); + if (pipe_ctx->prev_odm_pipe == NULL) + dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); } pipe_ctx->plane_res.hubp->funcs->hubp_setup( @@ -1540,12 +1410,15 @@ static void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx { #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dce_hwseq *hws = dc->hwseq; - struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true); - if (bot_odm_pipe) - dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, true); + while (odm_pipe) { + dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true); + odm_pipe = odm_pipe->next_odm_pipe; + } } #endif } @@ -1554,12 +1427,15 @@ static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) { #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT struct dce_hwseq *hws = dc->hwseq; - struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false); - if (bot_odm_pipe) - dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, false); + while (odm_pipe) { + dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false); + odm_pipe = odm_pipe->next_odm_pipe; + } } #endif } @@ -1584,9 +1460,9 @@ void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) hubp->funcs->dmdata_set_attributes(hubp, &attr); } -void dcn20_disable_stream(struct pipe_ctx *pipe_ctx, int option) +void dcn20_disable_stream(struct pipe_ctx *pipe_ctx) { - dce110_disable_stream(pipe_ctx, option); + dce110_disable_stream(pipe_ctx); } static void dcn20_init_vm_ctx( @@ -1624,6 +1500,7 @@ static int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_ph config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; + config.page_table_default_page_addr = pa_config->page_table_default_page_addr; return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); } @@ -1689,18 +1566,22 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, struct encoder_unblank_param params = { { 0 } }; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; - params.odm = dc_res_get_odm_bottom_pipe(pipe_ctx); + struct pipe_ctx *odm_pipe; + params.opp_cnt = 1; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + params.opp_cnt++; + } /* only 3 items below are used by unblank */ params.timing = pipe_ctx->stream->timing; params.link_settings.link_rate = link_settings->link_rate; if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - if (optc1_is_two_pixels_per_containter(&stream->timing) || params.odm) + if (optc1_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1) params.timing.pix_clk_100hz /= 2; pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( - pipe_ctx->stream_res.stream_enc, params.odm); + pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1); pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); } @@ -1736,12 +1617,30 @@ static void dcn20_reset_back_end_for_pipe( if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { /* DPMS may already disable */ if (!pipe_ctx->stream->dpms_off) - core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); - else if (pipe_ctx->stream_res.audio) { - dc->hwss.disable_audio_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); + core_link_disable_stream(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + /* free acquired resources */ + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } } - } +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + else if (pipe_ctx->stream_res.dsc) { + dp_set_dsc_enable(pipe_ctx, false); + } +#endif /* by upper caller loop, parent pipe: pipe0, will be reset last. * back end share by all pipes and will be disable only when disable @@ -1754,6 +1653,10 @@ static void dcn20_reset_back_end_for_pipe( if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) pipe_ctx->stream_res.tg->funcs->set_odm_bypass( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); } for (i = 0; i < dc->res_pool->pipe_count; i++) @@ -1783,7 +1686,7 @@ static void dcn20_reset_hw_ctx_wrap( if (!pipe_ctx_old->stream) continue; - if (pipe_ctx_old->top_pipe) + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) continue; if (!pipe_ctx->stream || @@ -1803,7 +1706,7 @@ static void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; struct mpcc_blnd_cfg blnd_cfg = { {0} }; - bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; + bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; int mpcc_id; struct mpcc *new_mpcc; struct mpc *mpc = dc->res_pool->mpc; @@ -1996,14 +1899,198 @@ static void dcn20_set_flip_control_gsl( } +static void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) +{ + enum dc_lane_count lane_count = + pipe_ctx->stream->link->cur_link_settings.lane_count; + + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + struct dc_link *link = pipe_ctx->stream->link; + + uint32_t active_total_with_borders; + uint32_t early_control = 0; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + + /* 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_res.stream_enc->id, true); + + if (link->dc->hwss.program_dmdata_engine) + link->dc->hwss.program_dmdata_engine(pipe_ctx); + + link->dc->hwss.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->stream_res.audio != NULL) { + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); + } +} + +static void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + bool enable = false; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) + ? dmdata_dp + : dmdata_hdmi; + + /* if using dynamic meta, don't set up generic infopackets */ + if (pipe_ctx->stream->dmdata_address.quad_part != 0) { + pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; + enable = true; + } + + if (!hubp) + return; + + if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) + return; + + stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, + hubp->inst, mode); +} + +static void dcn20_fpga_init_hw(struct dc *dc) +{ + int i, j; + struct dce_hwseq *hws = dc->hwseq; + struct resource_pool *res_pool = dc->res_pool; + struct dc_state *context = dc->current_state; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + //Enable ability to power gate / don't force power on permanently + dc->hwss.enable_power_gating_plane(hws, true); + + // Specific to FPGA dccg and registers + REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); + REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); + + dcn20_dccg_init(hws); + + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + REG_WRITE(REFCLK_CNTL, 0); + // + + + /* Blank pixel data with OPP DPG */ + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + dcn20_init_blank(dc, tg); + } + + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->lock(tg); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct dpp *dpp = res_pool->dpps[i]; + + dpp->funcs->dpp_reset(dpp); + } + + /* Reset all MPCC muxes */ + res_pool->mpc->funcs->mpc_init(res_pool->mpc); + + /* initialize OPP mpc_tree parameter */ + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { + res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; + res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + for (j = 0; j < MAX_PIPES; j++) + res_pool->opps[i]->mpcc_disconnect_pending[j] = false; + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = dc->res_pool->hubps[i]; + struct dpp *dpp = dc->res_pool->dpps[i]; + + pipe_ctx->stream_res.tg = tg; + pipe_ctx->pipe_idx = i; + + pipe_ctx->plane_res.hubp = hubp; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; + hubp->opp_id = OPP_ID_INVALID; + hubp->power_gated = false; + pipe_ctx->stream_res.opp = NULL; + + hubp->funcs->hubp_init(hubp); + + //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; + //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; + /*to do*/ + hwss1_plane_atomic_disconnect(dc, pipe_ctx); + } + + /* initialize DWB pointer to MCIF_WB */ + for (i = 0; i < res_pool->res_cap->num_dwb; i++) + res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->unlock(tg); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dc->hwss.disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + } + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + tg->funcs->tg_init(tg); + } +} + void dcn20_hw_sequencer_construct(struct dc *dc) { dcn10_hw_sequencer_construct(dc); - dc->hwss.init_hw = dcn20_init_hw; - dc->hwss.init_pipes = NULL; dc->hwss.unblank_stream = dcn20_unblank_stream; dc->hwss.update_plane_addr = dcn20_update_plane_addr; - dc->hwss.disable_plane = dcn20_disable_plane, dc->hwss.enable_stream_timing = dcn20_enable_stream_timing; dc->hwss.program_triplebuffer = dcn20_program_tripleBuffer; dc->hwss.set_input_transfer_func = dcn20_set_input_transfer_func; @@ -2020,6 +2107,8 @@ void dcn20_hw_sequencer_construct(struct dc *dc) dc->hwss.update_odm = dcn20_update_odm; dc->hwss.blank_pixel_data = dcn20_blank_pixel_data; dc->hwss.dmdata_status_done = dcn20_dmdata_status_done; + dc->hwss.program_dmdata_engine = dcn20_program_dmdata_engine; + dc->hwss.enable_stream = dcn20_enable_stream; dc->hwss.disable_stream = dcn20_disable_stream; dc->hwss.init_sys_ctx = dcn20_init_sys_ctx; dc->hwss.init_vm_ctx = dcn20_init_vm_ctx; @@ -2029,5 +2118,23 @@ void dcn20_hw_sequencer_construct(struct dc *dc) dc->hwss.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap; dc->hwss.update_mpcc = dcn20_update_mpcc; dc->hwss.set_flip_control_gsl = dcn20_set_flip_control_gsl; - dc->hwss.did_underflow_occur = dcn10_did_underflow_occur; + dc->hwss.init_blank = dcn20_init_blank; + dc->hwss.disable_plane = dcn20_disable_plane; + dc->hwss.plane_atomic_disable = dcn20_plane_atomic_disable; + dc->hwss.enable_power_gating_plane = dcn20_enable_power_gating_plane; + dc->hwss.dpp_pg_control = dcn20_dpp_pg_control; + dc->hwss.hubp_pg_control = dcn20_hubp_pg_control; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + dc->hwss.dsc_pg_control = dcn20_dsc_pg_control; +#else + dc->hwss.dsc_pg_control = NULL; +#endif + dc->hwss.disable_vga = dcn20_disable_vga; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + dc->hwss.init_hw = dcn20_fpga_init_hw; + dc->hwss.init_pipes = NULL; + } + + } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h index 2b0409454073..92ab3dd91814 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h @@ -75,7 +75,7 @@ bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx); void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx); -void dcn20_disable_stream(struct pipe_ctx *pipe_ctx, int option); +void dcn20_disable_stream(struct pipe_ctx *pipe_ctx); void dcn20_program_tripleBuffer( const struct dc *dc, @@ -91,13 +91,9 @@ void dcn20_pipe_control_lock_global( void dcn20_setup_gsl_group_as_lock(const struct dc *dc, struct pipe_ctx *pipe_ctx, bool enable); -void dcn20_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_enable_plane( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context); +void dcn20_dccg_init(struct dce_hwseq *hws); +void dcn20_init_blank( + struct dc *dc, + struct timing_generator *tg); +void dcn20_display_init(struct dc *dc); #endif /* __DC_HWSS_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c index f495582e9e87..e476f27aa3a9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c @@ -341,6 +341,7 @@ static const struct link_encoder_funcs dcn20_link_enc_funcs = { .fec_set_enable = enc2_fec_set_enable, .fec_set_ready = enc2_fec_set_ready, .fec_is_active = enc2_fec_is_active, + .get_dig_mode = dcn10_get_dig_mode, .get_dig_frontend = dcn10_get_dig_frontend, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c index 240749e4cf83..5a188b2bc033 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c @@ -233,14 +233,14 @@ static void mpc2_ogam_get_reg_field( reg->masks.exp_resion_start_segment = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B; } -static void mpc20_power_on_ogam_lut( +void mpc20_power_on_ogam_lut( struct mpc *mpc, int mpcc_id, bool power_on) { struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); REG_SET(MPCC_MEM_PWR_CTRL[mpcc_id], 0, - MPCC_OGAM_MEM_PWR_FORCE, power_on == true ? 0:1); + MPCC_OGAM_MEM_PWR_DIS, power_on == true ? 1:0); } @@ -368,6 +368,11 @@ void apply_DEDCN20_305_wa( { struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + if (mpc->ctx->dc->debug.cm_in_bypass) { + REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0); + return; + } + if (mpc->ctx->dc->work_arounds.dedcn20_305_wa == false) { /*hw fixed in new review*/ return; @@ -390,10 +395,16 @@ void mpc2_set_output_gamma( enum dc_lut_mode next_mode; struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + if (mpc->ctx->dc->debug.cm_in_bypass) { + REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0); + return; + } + if (params == NULL) { REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0); return; } + current_mode = mpc20_get_ogam_current(mpc, mpcc_id); if (current_mode == LUT_BYPASS || current_mode == LUT_RAM_A) next_mode = LUT_RAM_B; @@ -435,23 +446,22 @@ void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id) { struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); unsigned int top_sel, mpc_busy, mpc_idle, mpc_disabled; - REG_GET(MPCC_STATUS[mpcc_id], MPCC_DISABLED, &mpc_disabled); - - if (mpc_disabled) { - ASSERT(0); - return; - } REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel); - if (top_sel == 0xf) { - REG_GET_2(MPCC_STATUS[mpcc_id], - MPCC_BUSY, &mpc_busy, - MPCC_IDLE, &mpc_idle); + REG_GET_3(MPCC_STATUS[mpcc_id], + MPCC_BUSY, &mpc_busy, + MPCC_IDLE, &mpc_idle, + MPCC_DISABLED, &mpc_disabled); - ASSERT(mpc_busy == 0); - ASSERT(mpc_idle == 1); + if (top_sel == 0xf) { + ASSERT(!mpc_busy); + ASSERT(mpc_idle); + ASSERT(mpc_disabled); + } else { + ASSERT(!mpc_disabled); + ASSERT(!mpc_idle); } } @@ -488,6 +498,7 @@ const struct mpc_funcs dcn20_mpc_funcs = { .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, .mpc_init = mpc1_mpc_init, + .mpc_init_single_inst = mpc1_mpc_init_single_inst, .update_blending = mpc2_update_blending, .get_mpcc_for_dpp = mpc2_get_mpcc_for_dpp, .wait_for_idle = mpc2_assert_idle_mpcc, @@ -498,6 +509,7 @@ const struct mpc_funcs dcn20_mpc_funcs = { .set_output_csc = mpc2_set_output_csc, .set_ocsc_default = mpc2_set_ocsc_default, .set_output_gamma = mpc2_set_output_gamma, + .power_on_mpc_mem_pwr = mpc20_power_on_ogam_lut, }; void dcn20_mpc_construct(struct dcn20_mpc *mpc20, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h index 9750095d2d73..9f53192da2dc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h @@ -159,6 +159,7 @@ SF(MPCC_OGAM0_MPCC_OGAM_RAMB_START_CNTL_B, MPCC_OGAM_RAMB_EXP_REGION_START_B, mask_sh),\ SF(MPCC_OGAM0_MPCC_OGAM_RAMB_START_CNTL_B, MPCC_OGAM_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\ SF(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_PWR_FORCE, mask_sh),\ + SF(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_PWR_DIS, mask_sh),\ SF(MPCC_OGAM0_MPCC_OGAM_LUT_INDEX, MPCC_OGAM_LUT_INDEX, mask_sh),\ SF(MPCC_OGAM0_MPCC_OGAM_LUT_RAM_CONTROL, MPCC_OGAM_LUT_WRITE_EN_MASK, mask_sh),\ SF(MPCC_OGAM0_MPCC_OGAM_LUT_RAM_CONTROL, MPCC_OGAM_LUT_RAM_SEL, mask_sh),\ @@ -173,6 +174,7 @@ SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MAX_B_CB, mask_sh),\ SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MIN_B_CB, mask_sh) + #define MPC_REG_FIELD_LIST_DCN2_0(type) \ MPC_REG_FIELD_LIST(type)\ type MPCC_BG_BPC;\ @@ -217,7 +219,8 @@ type MPC_OUT_DENORM_CLAMP_MIN_G_Y;\ type MPC_OUT_DENORM_CLAMP_MAX_B_CB;\ type MPC_OUT_DENORM_CLAMP_MIN_B_CB;\ - type MPCC_DISABLED; + type MPCC_DISABLED;\ + type MPCC_OGAM_MEM_PWR_DIS; struct dcn20_mpc_registers { MPC_REG_VARIABLE_LIST_DCN2_0 @@ -282,4 +285,5 @@ void mpc2_set_output_gamma( void mpc2_assert_idle_mpcc(struct mpc *mpc, int id); void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id); +void mpc20_power_on_ogam_lut(struct mpc *mpc, int mpcc_id, bool power_on); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c index d9e7c711a71c..40164ed015ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c @@ -332,7 +332,6 @@ static struct opp_funcs dcn20_opp_funcs = { .opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator, .dpg_is_blanked = opp2_dpg_is_blanked, .opp_dpg_set_blank_color = opp2_dpg_set_blank_color, - .opp_convert_pti = NULL, .opp_destroy = opp1_destroy, .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c index 26a66ccf6e72..2137e2be2140 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c @@ -191,15 +191,6 @@ void optc2_set_dsc_config(struct timing_generator *optc, uint32_t dsc_slice_width) { struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t data_format = 0; - /* skip if dsc mode is not changed */ - data_format = dm_read_reg(CTX, REG(OPTC_DATA_FORMAT_CONTROL)); - - data_format = data_format & 0x30; /* bit5:4 */ - data_format = data_format >> 4; - - if (data_format == dsc_mode) - return; REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, dsc_mode); @@ -224,7 +215,6 @@ void optc2_set_odm_bypass(struct timing_generator *optc, struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t h_div_2 = 0; - optc1->comb_opp_id = 0xf; REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, OPTC_NUM_OF_INPUT_SEGMENT, 0, OPTC_SEG0_SRC_SEL, optc->inst, @@ -236,13 +226,16 @@ void optc2_set_odm_bypass(struct timing_generator *optc, OTG_H_TIMING_DIV_BY2, h_div_2); REG_SET(OPTC_MEMORY_CONFIG, 0, OPTC_MEM_SEL, 0); + optc1->opp_count = 1; } -void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, - int mpcc_hactive, enum dc_pixel_encoding pixel_encoding) +void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) { struct optc *optc1 = DCN10TG_FROM_TG(optc); /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192 */ + int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) + / opp_cnt; int memory_mask = mpcc_hactive <= 2560 ? 0x3 : 0xf; uint32_t data_fmt = 0; @@ -257,23 +250,24 @@ void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, REG_SET(OPTC_MEMORY_CONFIG, 0, OPTC_MEM_SEL, memory_mask << (optc->inst * 4)); - if (pixel_encoding == PIXEL_ENCODING_YCBCR422) + if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) data_fmt = 1; - else if (pixel_encoding == PIXEL_ENCODING_YCBCR420) + else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) data_fmt = 2; REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt); + ASSERT(opp_cnt == 2); REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, OPTC_NUM_OF_INPUT_SEGMENT, 1, - OPTC_SEG0_SRC_SEL, optc->inst, - OPTC_SEG1_SRC_SEL, combine_opp_id); + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); REG_UPDATE(OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mpcc_hactive); REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1); - optc1->comb_opp_id = combine_opp_id; + optc1->opp_count = opp_cnt; } void optc2_get_optc_source(struct timing_generator *optc, @@ -339,65 +333,6 @@ void optc2_triplebuffer_unlock(struct timing_generator *optc) } - -void optc2_setup_global_lock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t v_blank_start = 0; - uint32_t h_blank_start = 0, h_total = 0; - - REG_SET(OTG_GLOBAL_CONTROL1, 0, MASTER_UPDATE_LOCK_DB_EN, 1); - - REG_SET(OTG_GLOBAL_CONTROL2, 0, DIG_UPDATE_LOCATION, 20); - - REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start); - - REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start); - - REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &h_total); - REG_UPDATE_2(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_X, - h_blank_start - 200 - 1, - MASTER_UPDATE_LOCK_DB_Y, - v_blank_start - 1); -} - -void optc2_lock_global(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1); - - REG_SET(OTG_GLOBAL_CONTROL0, 0, - OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - - /* Should be fast, status does not update on maximus */ - if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, - 1, 10); -} - -void optc2_lock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0); - - REG_SET(OTG_GLOBAL_CONTROL0, 0, - OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - - /* Should be fast, status does not update on maximus */ - if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, - 1, 10); -} - void optc2_lock_doublebuffer_enable(struct timing_generator *optc) { struct optc *optc1 = DCN10TG_FROM_TG(optc); @@ -492,10 +427,8 @@ static struct timing_generator_funcs dcn20_tg_funcs = { .triplebuffer_lock = optc2_triplebuffer_lock, .triplebuffer_unlock = optc2_triplebuffer_unlock, .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc2_lock, + .lock = optc1_lock, .unlock = optc1_unlock, - .lock_global = optc2_lock_global, - .setup_global_lock = optc2_setup_global_lock, .lock_doublebuffer_enable = optc2_lock_doublebuffer_enable, .lock_doublebuffer_disable = optc2_lock_doublebuffer_disable, .enable_optc_clock = optc1_enable_optc_clock, @@ -522,7 +455,8 @@ static struct timing_generator_funcs dcn20_tg_funcs = { .set_gsl_source_select = optc2_set_gsl_source_select, .set_vtg_params = optc1_set_vtg_params, .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc2_setup_manual_trigger + .setup_manual_trigger = optc2_setup_manual_trigger, + .is_matching_timing = optc1_is_matching_timing }; void dcn20_timing_generator_init(struct optc *optc1) @@ -535,8 +469,7 @@ void dcn20_timing_generator_init(struct optc *optc1) optc1->min_h_blank = 32; optc1->min_v_blank = 3; optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 8; + optc1->min_h_sync_width = 4;// Minimum HSYNC = 8 pixels asked By HW in the first place for no actual reason. Oculus Rift S will not light up with 8 as it's hsyncWidth is 6. Changing it to 4 to fix that issue. optc1->min_v_sync_width = 1; - optc1->comb_opp_id = 0xf; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h index ebf07c582da2..32a58431fd09 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h @@ -96,8 +96,8 @@ void optc2_set_dsc_config(struct timing_generator *optc, void optc2_set_odm_bypass(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); -void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, - int mpcc_hactive, enum dc_pixel_encoding pixel_encoding); +void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing); void optc2_get_optc_source(struct timing_generator *optc, uint32_t *num_of_src_opp, @@ -106,9 +106,6 @@ void optc2_get_optc_source(struct timing_generator *optc, void optc2_triplebuffer_lock(struct timing_generator *optc); void optc2_triplebuffer_unlock(struct timing_generator *optc); -void optc2_lock(struct timing_generator *optc); -void optc2_lock_global(struct timing_generator *optc); -void optc2_setup_global_lock(struct timing_generator *optc); void optc2_lock_doublebuffer_disable(struct timing_generator *optc); void optc2_lock_doublebuffer_enable(struct timing_generator *optc); void optc2_program_manual_trigger(struct timing_generator *optc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index d200bc3cec71..b4e3ce22ed52 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -82,6 +82,7 @@ #include "amdgpu_socbb.h" +/* NV12 SOC BB is currently in FW, mark SW bounding box invalid. */ #define SOC_BOUNDING_BOX_VALID false #define DC_LOGGER_INIT(logger) @@ -156,8 +157,119 @@ struct _vcs_dpi_ip_params_st dcn2_0_ip = { .xfc_fill_constant_bytes = 0, }; -struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = { 0 }; - +struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = { + /* Defaults that get patched on driver load from firmware. */ + .clock_limits = { + { + .state = 0, + .dcfclk_mhz = 560.0, + .fabricclk_mhz = 560.0, + .dispclk_mhz = 513.0, + .dppclk_mhz = 513.0, + .phyclk_mhz = 540.0, + .socclk_mhz = 560.0, + .dscclk_mhz = 171.0, + .dram_speed_mts = 8960.0, + }, + { + .state = 1, + .dcfclk_mhz = 694.0, + .fabricclk_mhz = 694.0, + .dispclk_mhz = 642.0, + .dppclk_mhz = 642.0, + .phyclk_mhz = 600.0, + .socclk_mhz = 694.0, + .dscclk_mhz = 214.0, + .dram_speed_mts = 11104.0, + }, + { + .state = 2, + .dcfclk_mhz = 875.0, + .fabricclk_mhz = 875.0, + .dispclk_mhz = 734.0, + .dppclk_mhz = 734.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 875.0, + .dscclk_mhz = 245.0, + .dram_speed_mts = 14000.0, + }, + { + .state = 3, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 1000.0, + .dispclk_mhz = 1100.0, + .dppclk_mhz = 1100.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1000.0, + .dscclk_mhz = 367.0, + .dram_speed_mts = 16000.0, + }, + { + .state = 4, + .dcfclk_mhz = 1200.0, + .fabricclk_mhz = 1200.0, + .dispclk_mhz = 1284.0, + .dppclk_mhz = 1284.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1200.0, + .dscclk_mhz = 428.0, + .dram_speed_mts = 16000.0, + }, + /*Extra state, no dispclk ramping*/ + { + .state = 5, + .dcfclk_mhz = 1200.0, + .fabricclk_mhz = 1200.0, + .dispclk_mhz = 1284.0, + .dppclk_mhz = 1284.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1200.0, + .dscclk_mhz = 428.0, + .dram_speed_mts = 16000.0, + }, + }, + .num_states = 5, + .sr_exit_time_us = 8.6, + .sr_enter_plus_exit_time_us = 10.9, + .urgent_latency_us = 4.0, + .urgent_latency_pixel_data_only_us = 4.0, + .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, + .urgent_latency_vm_data_only_us = 4.0, + .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, + .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, + .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0, + .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, + .max_avg_sdp_bw_use_normal_percent = 40.0, + .max_avg_dram_bw_use_normal_percent = 40.0, + .writeback_latency_us = 12.0, + .ideal_dram_bw_after_urgent_percent = 40.0, + .max_request_size_bytes = 256, + .dram_channel_width_bytes = 2, + .fabric_datapath_to_dcn_data_return_bytes = 64, + .dcn_downspread_percent = 0.5, + .downspread_percent = 0.38, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 131, + .urgent_out_of_order_return_per_channel_bytes = 256, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 16, + .vmm_page_size_bytes = 4096, + .dram_clock_change_latency_us = 404.0, + .dummy_pstate_latency_us = 5.0, + .writeback_dram_clock_change_latency_us = 23.0, + .return_bus_width_bytes = 64, + .dispclk_dppclk_vco_speed_mhz = 3850, + .xfc_bus_transport_time_us = 20, + .xfc_xbuf_latency_tolerance_us = 4, + .use_urgent_burst_bw = 0 +}; + +struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { 0 }; #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f @@ -314,7 +426,7 @@ static const struct dce_audio_shift audio_shift = { DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) }; @@ -695,6 +807,16 @@ static const struct dc_plane_cap plane_cap = { .fp16 = 1 } }; +static const struct resource_caps res_cap_nv14 = { + .num_timing_generator = 5, + .num_opp = 5, + .num_video_plane = 5, + .num_audio = 6, + .num_stream_encoder = 5, + .num_pll = 5, + .num_dwb = 0, + .num_ddc = 5, +}; static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, @@ -1197,7 +1319,11 @@ static void get_pixel_clock_parameters( struct pixel_clk_params *pixel_clk_params) { const struct dc_stream_state *stream = pipe_ctx->stream; - bool odm_combine = dc_res_get_odm_bottom_pipe(pipe_ctx) != NULL; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; pixel_clk_params->encoder_object_id = stream->link->link_enc->id; @@ -1215,7 +1341,9 @@ static void get_pixel_clock_parameters( if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) pixel_clk_params->color_depth = COLOR_DEPTH_888; - if (optc1_is_two_pixels_per_containter(&stream->timing) || odm_combine) + if (opp_cnt == 4) + pixel_clk_params->requested_pix_clk_100hz /= 4; + else if (optc1_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2) pixel_clk_params->requested_pix_clk_100hz /= 2; if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) @@ -1359,22 +1487,16 @@ static enum dc_status remove_dsc_from_stream_resource(struct dc *dc, for (i = 0; i < MAX_PIPES; i++) { if (new_ctx->res_ctx.pipe_ctx[i].stream == dc_stream && !new_ctx->res_ctx.pipe_ctx[i].top_pipe) { pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; - break; + + if (pipe_ctx->stream_res.dsc) + release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc); } } if (!pipe_ctx) return DC_ERROR_UNEXPECTED; - - if (pipe_ctx->stream_res.dsc) { - struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); - - release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc); - if (odm_pipe) - release_dsc(&new_ctx->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc); - } - - return DC_OK; + else + return DC_OK; } #endif @@ -1473,17 +1595,92 @@ static void swizzle_to_dml_params( } } -static bool dcn20_split_stream_for_combine( +static bool dcn20_split_stream_for_odm( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct pipe_ctx *prev_odm_pipe, + struct pipe_ctx *next_odm_pipe) +{ + int pipe_idx = next_odm_pipe->pipe_idx; + + *next_odm_pipe = *prev_odm_pipe; + + next_odm_pipe->pipe_idx = pipe_idx; + next_odm_pipe->plane_res.mi = pool->mis[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.hubp = pool->hubps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.ipp = pool->ipps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.xfm = pool->transforms[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.dpp = pool->dpps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.mpcc_inst = pool->dpps[next_odm_pipe->pipe_idx]->inst; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + next_odm_pipe->stream_res.dsc = NULL; +#endif + if (prev_odm_pipe->next_odm_pipe && prev_odm_pipe->next_odm_pipe != next_odm_pipe) { + ASSERT(!next_odm_pipe->next_odm_pipe); + next_odm_pipe->next_odm_pipe = prev_odm_pipe->next_odm_pipe; + next_odm_pipe->next_odm_pipe->prev_odm_pipe = next_odm_pipe; + } + prev_odm_pipe->next_odm_pipe = next_odm_pipe; + next_odm_pipe->prev_odm_pipe = prev_odm_pipe; + ASSERT(next_odm_pipe->top_pipe == NULL); + + if (prev_odm_pipe->plane_state) { + struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data; + int new_width; + + /* HACTIVE halved for odm combine */ + sd->h_active /= 2; + /* Calculate new vp and recout for left pipe */ + /* Need at least 16 pixels width per side */ + if (sd->recout.x + 16 >= sd->h_active) + return false; + new_width = sd->h_active - sd->recout.x; + sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->recout.width - new_width)); + sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->recout.width - new_width)); + sd->recout.width = new_width; + + /* Calculate new vp and recout for right pipe */ + sd = &next_odm_pipe->plane_res.scl_data; + /* HACTIVE halved for odm combine */ + sd->h_active /= 2; + /* Need at least 16 pixels width per side */ + if (new_width <= 16) + return false; + new_width = sd->recout.width + sd->recout.x - sd->h_active; + sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->recout.width - new_width)); + sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->recout.width - new_width)); + sd->recout.width = new_width; + sd->viewport.x += dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->h_active - sd->recout.x)); + sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->h_active - sd->recout.x)); + sd->recout.x = 0; + } + next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (next_odm_pipe->stream->timing.flags.DSC == 1) { + acquire_dsc(res_ctx, pool, &next_odm_pipe->stream_res.dsc); + ASSERT(next_odm_pipe->stream_res.dsc); + if (next_odm_pipe->stream_res.dsc == NULL) + return false; + } +#endif + + return true; +} + +static void dcn20_split_stream_for_mpc( struct resource_context *res_ctx, const struct resource_pool *pool, struct pipe_ctx *primary_pipe, - struct pipe_ctx *secondary_pipe, - bool is_odm_combine) + struct pipe_ctx *secondary_pipe) { int pipe_idx = secondary_pipe->pipe_idx; - struct scaler_data *sd = &primary_pipe->plane_res.scl_data; struct pipe_ctx *sec_bot_pipe = secondary_pipe->bottom_pipe; - int new_width; *secondary_pipe = *primary_pipe; secondary_pipe->bottom_pipe = sec_bot_pipe; @@ -1506,57 +1703,9 @@ static bool dcn20_split_stream_for_combine( primary_pipe->bottom_pipe = secondary_pipe; secondary_pipe->top_pipe = primary_pipe; - if (is_odm_combine) { - if (primary_pipe->plane_state) { - /* HACTIVE halved for odm combine */ - sd->h_active /= 2; - /* Copy scl_data to secondary pipe */ - secondary_pipe->plane_res.scl_data = *sd; - - /* Calculate new vp and recout for left pipe */ - /* Need at least 16 pixels width per side */ - if (sd->recout.x + 16 >= sd->h_active) - return false; - new_width = sd->h_active - sd->recout.x; - sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz, sd->recout.width - new_width)); - sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz_c, sd->recout.width - new_width)); - sd->recout.width = new_width; - - /* Calculate new vp and recout for right pipe */ - sd = &secondary_pipe->plane_res.scl_data; - new_width = sd->recout.width + sd->recout.x - sd->h_active; - /* Need at least 16 pixels width per side */ - if (new_width <= 16) - return false; - sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz, sd->recout.width - new_width)); - sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz_c, sd->recout.width - new_width)); - sd->recout.width = new_width; - sd->viewport.x += dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz, sd->h_active - sd->recout.x)); - sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz_c, sd->h_active - sd->recout.x)); - sd->recout.x = 0; - } - secondary_pipe->stream_res.opp = pool->opps[secondary_pipe->pipe_idx]; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - if (secondary_pipe->stream->timing.flags.DSC == 1) { - acquire_dsc(res_ctx, pool, &secondary_pipe->stream_res.dsc); - ASSERT(secondary_pipe->stream_res.dsc); - if (secondary_pipe->stream_res.dsc == NULL) - return false; - } -#endif - } else { - ASSERT(primary_pipe->plane_state); - resource_build_scaling_params(primary_pipe); - resource_build_scaling_params(secondary_pipe); - } - - return true; + ASSERT(primary_pipe->plane_state); + resource_build_scaling_params(primary_pipe); + resource_build_scaling_params(secondary_pipe); } void dcn20_populate_dml_writeback_from_context( @@ -1669,6 +1818,19 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].dout.dp_lanes = 4; pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min; pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max; + pipes[pipe_cnt].pipe.dest.odm_combine = res_ctx->pipe_ctx[i].prev_odm_pipe + || res_ctx->pipe_ctx[i].next_odm_pipe; + pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx; + if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state + == res_ctx->pipe_ctx[i].plane_state) + pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].top_pipe->pipe_idx; + else if (res_ctx->pipe_ctx[i].prev_odm_pipe) { + struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].prev_odm_pipe; + + while (first_pipe->prev_odm_pipe) + first_pipe = first_pipe->prev_odm_pipe; + pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx; + } switch (res_ctx->pipe_ctx[i].stream->signal) { case SIGNAL_TYPE_DISPLAY_PORT_MST: @@ -1721,7 +1883,6 @@ int dcn20_populate_dml_pipes_from_context( break; } - switch (res_ctx->pipe_ctx[i].stream->timing.pixel_encoding) { case PIXEL_ENCODING_RGB: case PIXEL_ENCODING_YCBCR444: @@ -1743,10 +1904,6 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].dout.output_format = dm_444; pipes[pipe_cnt].dout.output_bpp = output_bpc * 3; } - pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx; - if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state - == res_ctx->pipe_ctx[i].plane_state) - pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].top_pipe->pipe_idx; /* todo: default max for now, until there is logic reflecting this in dc*/ pipes[pipe_cnt].dout.output_bpc = 12; @@ -1795,14 +1952,6 @@ int dcn20_populate_dml_pipes_from_context( && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln) || (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln); - pipes[pipe_cnt].pipe.dest.odm_combine = (res_ctx->pipe_ctx[i].bottom_pipe - && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln - && res_ctx->pipe_ctx[i].bottom_pipe->stream_res.opp - != res_ctx->pipe_ctx[i].stream_res.opp) - || (res_ctx->pipe_ctx[i].top_pipe - && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln - && res_ctx->pipe_ctx[i].top_pipe->stream_res.opp - != res_ctx->pipe_ctx[i].stream_res.opp); pipes[pipe_cnt].pipe.src.source_scan = pln->rotation == ROTATION_ANGLE_90 || pln->rotation == ROTATION_ANGLE_270 ? dm_vert : dm_horz; pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y; @@ -1812,13 +1961,13 @@ int dcn20_populate_dml_pipes_from_context( pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport.height; pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c.height; if (pln->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { - pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.video.luma_pitch; - pipes[pipe_cnt].pipe.src.data_pitch_c = pln->plane_size.video.chroma_pitch; - pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.video.meta_pitch_l; - pipes[pipe_cnt].pipe.src.meta_pitch_c = pln->dcc.video.meta_pitch_c; + pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch; + pipes[pipe_cnt].pipe.src.data_pitch_c = pln->plane_size.chroma_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch_c = pln->dcc.meta_pitch_c; } else { - pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.grph.surface_pitch; - pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.grph.meta_pitch; + pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch; } pipes[pipe_cnt].pipe.src.dcc = pln->dcc.enable; pipes[pipe_cnt].pipe.dest.recout_width = scl->recout.width; @@ -1986,20 +2135,24 @@ static bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; struct dc_stream_state *stream = pipe_ctx->stream; struct dsc_config dsc_cfg; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; /* Only need to validate top pipe */ - if (pipe_ctx->top_pipe || !stream || !stream->timing.flags.DSC) + if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe || !stream || !stream->timing.flags.DSC) continue; - dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left - + stream->timing.h_border_right; + dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + + stream->timing.h_border_right) / opp_cnt; dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; - if (dc_res_get_odm_bottom_pipe(pipe_ctx)) - dsc_cfg.pic_width /= 2; dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; dsc_cfg.color_depth = stream->timing.display_color_depth; dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg)) return false; @@ -2008,15 +2161,93 @@ static bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) } #endif -bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, - bool fast_validate) +static struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, + struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *primary_pipe) { - bool out = false; + struct pipe_ctx *secondary_pipe = NULL; + + if (dc && primary_pipe) { + int j; + int preferred_pipe_idx = 0; + + /* first check the prev dc state: + * if this primary pipe has a bottom pipe in prev. state + * and if the bottom pipe is still available (which it should be), + * pick that pipe as secondary + * Same logic applies for ODM pipes. Since mpo is not allowed with odm + * check in else case. + */ + if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe) { + preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe->pipe_idx; + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + } + } else if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe) { + preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe->pipe_idx; + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + } + } - BW_VAL_TRACE_SETUP(); + /* + * if this primary pipe does not have a bottom pipe in prev. state + * start backward and find a pipe that did not used to be a bottom pipe in + * prev. dc state. This way we make sure we keep the same assignment as + * last state and will not have to reprogram every pipe + */ + if (secondary_pipe == NULL) { + for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { + if (dc->current_state->res_ctx.pipe_ctx[j].top_pipe == NULL) { + preferred_pipe_idx = j; + + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + break; + } + } + } + } + /* + * We should never hit this assert unless assignments are shuffled around + * if this happens we will prob. hit a vsync tdr + */ + ASSERT(secondary_pipe); + /* + * search backwards for the second pipe to keep pipe + * assignment more consistent + */ + if (secondary_pipe == NULL) { + for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { + preferred_pipe_idx = j; + + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + break; + } + } + } + } + + return secondary_pipe; +} + +bool dcn20_fast_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out) +{ + bool out = false; int pipe_cnt, i, pipe_idx, vlevel, vlevel_unsplit; - int pipe_split_from[MAX_PIPES]; bool odm_capable = context->bw_ctx.dml.ip.odm_capable; bool force_split = false; #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT @@ -2024,15 +2255,44 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, #endif int split_threshold = dc->res_pool->pipe_count / 2; bool avoid_split = dc->debug.pipe_split_policy != MPC_SPLIT_DYNAMIC; - display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL); - DC_LOGGER_INIT(dc->ctx->logger); - BW_VAL_TRACE_COUNT(); ASSERT(pipes); if (!pipes) return false; + /* merge previously split odm pipes since mode support needs to make the decision */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *odm_pipe = pipe->next_odm_pipe; + + if (pipe->prev_odm_pipe) + continue; + + pipe->next_odm_pipe = NULL; + while (odm_pipe) { + struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; + + odm_pipe->plane_state = NULL; + odm_pipe->stream = NULL; + odm_pipe->top_pipe = NULL; + odm_pipe->bottom_pipe = NULL; + odm_pipe->prev_odm_pipe = NULL; + odm_pipe->next_odm_pipe = NULL; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (odm_pipe->stream_res.dsc) + release_dsc(&context->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc); +#endif + /* Clear plane_res and stream_res */ + memset(&odm_pipe->plane_res, 0, sizeof(odm_pipe->plane_res)); + memset(&odm_pipe->stream_res, 0, sizeof(odm_pipe->stream_res)); + odm_pipe = next_odm_pipe; + } + if (pipe->plane_state) + resource_build_scaling_params(pipe); + } + + /* merge previously mpc split pipes since mode support needs to make the decision */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; @@ -2040,7 +2300,6 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) continue; - /* merge previously split pipe since mode support needs to make the decision */ pipe->bottom_pipe = hsplit_pipe->bottom_pipe; if (hsplit_pipe->bottom_pipe) hsplit_pipe->bottom_pipe->top_pipe = pipe; @@ -2048,10 +2307,7 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, hsplit_pipe->stream = NULL; hsplit_pipe->top_pipe = NULL; hsplit_pipe->bottom_pipe = NULL; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - if (hsplit_pipe->stream_res.dsc && hsplit_pipe->stream_res.dsc != pipe->stream_res.dsc) - release_dsc(&context->res_ctx, dc->res_pool, &hsplit_pipe->stream_res.dsc); -#endif + /* Clear plane_res and stream_res */ memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res)); memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res)); @@ -2066,8 +2322,9 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, &context->res_ctx, pipes); + *pipe_cnt_out = pipe_cnt; + if (!pipe_cnt) { - BW_VAL_TRACE_SKIP(pass); out = true; goto validate_out; } @@ -2160,17 +2417,12 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, } if (force_split && context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] == 1) context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] /= 2; - if (dc->config.forced_clocks == true) { - context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] = - context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; - } if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { - hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, dc->res_pool, pipe); + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); ASSERT(hsplit_pipe); - if (!dcn20_split_stream_for_combine( + if (!dcn20_split_stream_for_odm( &context->res_ctx, dc->res_pool, - pipe, hsplit_pipe, - true)) + pipe, hsplit_pipe)) goto validate_fail; pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; dcn20_build_mapped_resource(dc, context, pipe->stream); @@ -2206,16 +2458,20 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, if (need_split3d || need_split || force_split) { if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) { /* pipe not split previously needs split */ - hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, dc->res_pool, pipe); + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); ASSERT(hsplit_pipe || force_split); if (!hsplit_pipe) continue; - if (!dcn20_split_stream_for_combine( + if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { + if (!dcn20_split_stream_for_odm( + &context->res_ctx, dc->res_pool, + pipe, hsplit_pipe)) + goto validate_fail; + } else + dcn20_split_stream_for_mpc( &context->res_ctx, dc->res_pool, - pipe, hsplit_pipe, - context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx])) - goto validate_fail; + pipe, hsplit_pipe); pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; } } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { @@ -2232,13 +2488,26 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, } #endif - BW_VAL_TRACE_END_VOLTAGE_LEVEL(); + *vlevel_out = vlevel; - if (fast_validate) { - BW_VAL_TRACE_SKIP(fast); - out = true; - goto validate_out; - } + out = true; + goto validate_out; + +validate_fail: + out = false; + +validate_out: + return out; +} + +void dcn20_calculate_wm( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *out_pipe_cnt, + int *pipe_split_from, + int vlevel) +{ + int pipe_cnt, i, pipe_idx; for (i = 0, pipe_idx = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { if (!context->res_ctx.pipe_ctx[i].stream) @@ -2265,10 +2534,16 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, else pipes[pipe_cnt].pipe.dest.odm_combine = 0; } + if (dc->config.forced_clocks) { pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; pipes[pipe_cnt].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; } + if (dc->debug.min_disp_clk_khz > pipes[pipe_cnt].clks_cfg.dispclk_mhz * 1000) + pipes[pipe_cnt].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; + if (dc->debug.min_dpp_clk_khz > pipes[pipe_cnt].clks_cfg.dppclk_mhz * 1000) + pipes[pipe_cnt].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; + pipe_cnt++; } @@ -2281,6 +2556,8 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, &context->res_ctx, pipes); } + *out_pipe_cnt = pipe_cnt; + pipes[0].clks_cfg.voltage = vlevel; pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz; pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz; @@ -2327,6 +2604,17 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; +} + +void dcn20_calculate_dlg_params( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + int i, j, pipe_idx, pipe_idx_unsplit; + bool visited[MAX_PIPES] = { 0 }; + /* Writeback MCIF_WB arbitration parameters */ dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt); @@ -2335,32 +2623,69 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, context->bw_ctx.bw.dcn.clk.socclk_khz = context->bw_ctx.dml.vba.SOCCLK * 1000; context->bw_ctx.bw.dcn.clk.dramclk_khz = context->bw_ctx.dml.vba.DRAMSpeed * 1000 / 16; context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = context->bw_ctx.dml.vba.DCFCLKDeepSleep * 1000; - context->bw_ctx.bw.dcn.clk.fclk_khz = context->bw_ctx.dml.vba.FabricClock * 1000; + context->bw_ctx.bw.dcn.clk.fclk_khz = 0; context->bw_ctx.bw.dcn.clk.p_state_change_support = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != dm_dram_clock_change_unsupported; context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; - BW_VAL_TRACE_END_WATERMARKS(); + /* + * An artifact of dml pipe split/odm is that pipes get merged back together for + * calculation. Therefore we need to only extract for first pipe in ascending index order + * and copy into the other split half. + */ + for (i = 0, pipe_idx = 0, pipe_idx_unsplit = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + if (!visited[pipe_idx]) { + display_pipe_source_params_st *src = &pipes[pipe_idx_unsplit].pipe.src; + display_pipe_dest_params_st *dst = &pipes[pipe_idx_unsplit].pipe.dest; + + dst->vstartup_start = context->bw_ctx.dml.vba.VStartup[pipe_idx_unsplit]; + dst->vupdate_offset = context->bw_ctx.dml.vba.VUpdateOffsetPix[pipe_idx_unsplit]; + dst->vupdate_width = context->bw_ctx.dml.vba.VUpdateWidthPix[pipe_idx_unsplit]; + dst->vready_offset = context->bw_ctx.dml.vba.VReadyOffsetPix[pipe_idx_unsplit]; + /* + * j iterates inside pipes array, unlike i which iterates inside + * pipe_ctx array + */ + if (src->is_hsplit) + for (j = pipe_idx + 1; j < pipe_cnt; j++) { + display_pipe_source_params_st *src_j = &pipes[j].pipe.src; + display_pipe_dest_params_st *dst_j = &pipes[j].pipe.dest; + + if (src_j->is_hsplit && !visited[j] + && src->hsplit_grp == src_j->hsplit_grp) { + dst_j->vstartup_start = context->bw_ctx.dml.vba.VStartup[pipe_idx_unsplit]; + dst_j->vupdate_offset = context->bw_ctx.dml.vba.VUpdateOffsetPix[pipe_idx_unsplit]; + dst_j->vupdate_width = context->bw_ctx.dml.vba.VUpdateWidthPix[pipe_idx_unsplit]; + dst_j->vready_offset = context->bw_ctx.dml.vba.VReadyOffsetPix[pipe_idx_unsplit]; + visited[j] = true; + } + } + visited[pipe_idx] = true; + pipe_idx_unsplit++; + } + pipe_idx++; + } for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { if (!context->res_ctx.pipe_ctx[i].stream) continue; - pipes[pipe_idx].pipe.dest.vstartup_start = context->bw_ctx.dml.vba.VStartup[pipe_idx]; - pipes[pipe_idx].pipe.dest.vupdate_offset = context->bw_ctx.dml.vba.VUpdateOffsetPix[pipe_idx]; - pipes[pipe_idx].pipe.dest.vupdate_width = context->bw_ctx.dml.vba.VUpdateWidthPix[pipe_idx]; - pipes[pipe_idx].pipe.dest.vready_offset = context->bw_ctx.dml.vba.VReadyOffsetPix[pipe_idx]; if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000; context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000; -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - context->res_ctx.pipe_ctx[i].stream_res.dscclk_khz = - context->bw_ctx.dml.vba.DSCCLK_calculated[pipe_idx] * 1000; -#endif + ASSERT(visited[pipe_idx]); context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest; pipe_idx++; } + /*save a original dppclock copy*/ + context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz; + context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz; + context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dppclk_mhz * 1000; + context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz * 1000; for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { bool cstate_en = context->bw_ctx.dml.vba.PrefetchMode[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != 2; @@ -2383,8 +2708,43 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, pipes[pipe_idx].pipe); pipe_idx++; } +} + +static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool out = false; + + BW_VAL_TRACE_SETUP(); + + int vlevel = 0; + int pipe_split_from[MAX_PIPES]; + int pipe_cnt = 0; + display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL); + DC_LOGGER_INIT(dc->ctx->logger); + + BW_VAL_TRACE_COUNT(); + + out = dcn20_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel); + + if (pipe_cnt == 0) + goto validate_out; + + if (!out) + goto validate_fail; + + BW_VAL_TRACE_END_VOLTAGE_LEVEL(); + + if (fast_validate) { + BW_VAL_TRACE_SKIP(fast); + goto validate_out; + } + + dcn20_calculate_wm(dc, context, pipes, &pipe_cnt, pipe_split_from, vlevel); + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); + + BW_VAL_TRACE_END_WATERMARKS(); - out = true; goto validate_out; validate_fail: @@ -2402,6 +2762,50 @@ validate_out: return out; } + +bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool voltage_supported = false; + bool full_pstate_supported = false; + bool dummy_pstate_supported = false; + double p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us; + + if (fast_validate) + return dcn20_validate_bandwidth_internal(dc, context, true); + + + // Best case, we support full UCLK switch latency + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + + if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 || + (voltage_supported && full_pstate_supported)) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = true; + goto restore_dml_state; + } + + // Fallback: Try to only support G6 temperature read latency + context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us; + + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + + if (voltage_supported && dummy_pstate_supported) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = false; + goto restore_dml_state; + } + + // ERROR: fallback is supposed to always work. + ASSERT(false); + +restore_dml_state: + memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); + context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us; + + return voltage_supported; +} + struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer( struct dc_state *state, const struct resource_pool *pool, @@ -2576,9 +2980,6 @@ static void cap_soc_clocks( && max_clocks.uClockInKhz != 0) bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16; - // HACK: Force every uclk to max for now to "disable" uclk switching. - bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16; - if ((bb->clock_limits[i].fabricclk_mhz > (max_clocks.fabricClockInKhz / 1000)) && max_clocks.fabricClockInKhz != 0) bb->clock_limits[i].fabricclk_mhz = (max_clocks.fabricClockInKhz / 1000); @@ -2643,6 +3044,10 @@ static void update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_ if (dc->bb_overrides.min_dcfclk_mhz > 0) min_dcfclk = dc->bb_overrides.min_dcfclk_mhz; + else + // Accounting for SOC/DCF relationship, we can go as high as + // 506Mhz in Vmin. We need to code 507 since SMU will round down to 506. + min_dcfclk = 507; for (i = 0; i < num_states; i++) { int min_fclk_required_by_uclk; @@ -2670,6 +3075,10 @@ static void update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_ num_calculated_states++; } + calculated_states[num_calculated_states - 1].socclk_mhz = max_clocks->socClockInKhz / 1000; + calculated_states[num_calculated_states - 1].fabricclk_mhz = max_clocks->socClockInKhz / 1000; + calculated_states[num_calculated_states - 1].dcfclk_mhz = max_clocks->dcfClockInKhz / 1000; + memcpy(bb->clock_limits, calculated_states, sizeof(bb->clock_limits)); bb->num_states = num_calculated_states; @@ -2707,6 +3116,27 @@ static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_s kernel_fpu_end(); } +static struct _vcs_dpi_soc_bounding_box_st *get_asic_rev_soc_bb( + uint32_t hw_internal_rev) +{ + if (ASICREV_IS_NAVI12_P(hw_internal_rev)) + return &dcn2_0_nv12_soc; + + return &dcn2_0_soc; +} + +static struct _vcs_dpi_ip_params_st *get_asic_rev_ip_params( + uint32_t hw_internal_rev) +{ + /* NV12 and NV10 */ + return &dcn2_0_ip; +} + +static enum dml_project get_dml_project_version(uint32_t hw_internal_rev) +{ + return DML_PROJECT_NAVI10v2; +} + #define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) #define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) @@ -2714,6 +3144,11 @@ static bool init_soc_bounding_box(struct dc *dc, struct dcn20_resource_pool *pool) { const struct gpu_info_soc_bounding_box_v1_0 *bb = dc->soc_bounding_box; + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = + get_asic_rev_soc_bb(dc->ctx->asic_id.hw_internal_rev); + struct _vcs_dpi_ip_params_st *loaded_ip = + get_asic_rev_ip_params(dc->ctx->asic_id.hw_internal_rev); + DC_LOGGER_INIT(dc->ctx->logger); if (!bb && !SOC_BOUNDING_BOX_VALID) { @@ -2724,103 +3159,103 @@ static bool init_soc_bounding_box(struct dc *dc, if (bb && !SOC_BOUNDING_BOX_VALID) { int i; - dcn2_0_soc.sr_exit_time_us = + dcn2_0_nv12_soc.sr_exit_time_us = fixed16_to_double_to_cpu(bb->sr_exit_time_us); - dcn2_0_soc.sr_enter_plus_exit_time_us = + dcn2_0_nv12_soc.sr_enter_plus_exit_time_us = fixed16_to_double_to_cpu(bb->sr_enter_plus_exit_time_us); - dcn2_0_soc.urgent_latency_us = + dcn2_0_nv12_soc.urgent_latency_us = fixed16_to_double_to_cpu(bb->urgent_latency_us); - dcn2_0_soc.urgent_latency_pixel_data_only_us = + dcn2_0_nv12_soc.urgent_latency_pixel_data_only_us = fixed16_to_double_to_cpu(bb->urgent_latency_pixel_data_only_us); - dcn2_0_soc.urgent_latency_pixel_mixed_with_vm_data_us = + dcn2_0_nv12_soc.urgent_latency_pixel_mixed_with_vm_data_us = fixed16_to_double_to_cpu(bb->urgent_latency_pixel_mixed_with_vm_data_us); - dcn2_0_soc.urgent_latency_vm_data_only_us = + dcn2_0_nv12_soc.urgent_latency_vm_data_only_us = fixed16_to_double_to_cpu(bb->urgent_latency_vm_data_only_us); - dcn2_0_soc.urgent_out_of_order_return_per_channel_pixel_only_bytes = + dcn2_0_nv12_soc.urgent_out_of_order_return_per_channel_pixel_only_bytes = le32_to_cpu(bb->urgent_out_of_order_return_per_channel_pixel_only_bytes); - dcn2_0_soc.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = + dcn2_0_nv12_soc.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = le32_to_cpu(bb->urgent_out_of_order_return_per_channel_pixel_and_vm_bytes); - dcn2_0_soc.urgent_out_of_order_return_per_channel_vm_only_bytes = + dcn2_0_nv12_soc.urgent_out_of_order_return_per_channel_vm_only_bytes = le32_to_cpu(bb->urgent_out_of_order_return_per_channel_vm_only_bytes); - dcn2_0_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = + dcn2_0_nv12_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = fixed16_to_double_to_cpu(bb->pct_ideal_dram_sdp_bw_after_urgent_pixel_only); - dcn2_0_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = + dcn2_0_nv12_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = fixed16_to_double_to_cpu(bb->pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm); - dcn2_0_soc.pct_ideal_dram_sdp_bw_after_urgent_vm_only = + dcn2_0_nv12_soc.pct_ideal_dram_sdp_bw_after_urgent_vm_only = fixed16_to_double_to_cpu(bb->pct_ideal_dram_sdp_bw_after_urgent_vm_only); - dcn2_0_soc.max_avg_sdp_bw_use_normal_percent = + dcn2_0_nv12_soc.max_avg_sdp_bw_use_normal_percent = fixed16_to_double_to_cpu(bb->max_avg_sdp_bw_use_normal_percent); - dcn2_0_soc.max_avg_dram_bw_use_normal_percent = + dcn2_0_nv12_soc.max_avg_dram_bw_use_normal_percent = fixed16_to_double_to_cpu(bb->max_avg_dram_bw_use_normal_percent); - dcn2_0_soc.writeback_latency_us = + dcn2_0_nv12_soc.writeback_latency_us = fixed16_to_double_to_cpu(bb->writeback_latency_us); - dcn2_0_soc.ideal_dram_bw_after_urgent_percent = + dcn2_0_nv12_soc.ideal_dram_bw_after_urgent_percent = fixed16_to_double_to_cpu(bb->ideal_dram_bw_after_urgent_percent); - dcn2_0_soc.max_request_size_bytes = + dcn2_0_nv12_soc.max_request_size_bytes = le32_to_cpu(bb->max_request_size_bytes); - dcn2_0_soc.dram_channel_width_bytes = + dcn2_0_nv12_soc.dram_channel_width_bytes = le32_to_cpu(bb->dram_channel_width_bytes); - dcn2_0_soc.fabric_datapath_to_dcn_data_return_bytes = + dcn2_0_nv12_soc.fabric_datapath_to_dcn_data_return_bytes = le32_to_cpu(bb->fabric_datapath_to_dcn_data_return_bytes); - dcn2_0_soc.dcn_downspread_percent = + dcn2_0_nv12_soc.dcn_downspread_percent = fixed16_to_double_to_cpu(bb->dcn_downspread_percent); - dcn2_0_soc.downspread_percent = + dcn2_0_nv12_soc.downspread_percent = fixed16_to_double_to_cpu(bb->downspread_percent); - dcn2_0_soc.dram_page_open_time_ns = + dcn2_0_nv12_soc.dram_page_open_time_ns = fixed16_to_double_to_cpu(bb->dram_page_open_time_ns); - dcn2_0_soc.dram_rw_turnaround_time_ns = + dcn2_0_nv12_soc.dram_rw_turnaround_time_ns = fixed16_to_double_to_cpu(bb->dram_rw_turnaround_time_ns); - dcn2_0_soc.dram_return_buffer_per_channel_bytes = + dcn2_0_nv12_soc.dram_return_buffer_per_channel_bytes = le32_to_cpu(bb->dram_return_buffer_per_channel_bytes); - dcn2_0_soc.round_trip_ping_latency_dcfclk_cycles = + dcn2_0_nv12_soc.round_trip_ping_latency_dcfclk_cycles = le32_to_cpu(bb->round_trip_ping_latency_dcfclk_cycles); - dcn2_0_soc.urgent_out_of_order_return_per_channel_bytes = + dcn2_0_nv12_soc.urgent_out_of_order_return_per_channel_bytes = le32_to_cpu(bb->urgent_out_of_order_return_per_channel_bytes); - dcn2_0_soc.channel_interleave_bytes = + dcn2_0_nv12_soc.channel_interleave_bytes = le32_to_cpu(bb->channel_interleave_bytes); - dcn2_0_soc.num_banks = + dcn2_0_nv12_soc.num_banks = le32_to_cpu(bb->num_banks); - dcn2_0_soc.num_chans = + dcn2_0_nv12_soc.num_chans = le32_to_cpu(bb->num_chans); - dcn2_0_soc.vmm_page_size_bytes = + dcn2_0_nv12_soc.vmm_page_size_bytes = le32_to_cpu(bb->vmm_page_size_bytes); - dcn2_0_soc.dram_clock_change_latency_us = + dcn2_0_nv12_soc.dram_clock_change_latency_us = fixed16_to_double_to_cpu(bb->dram_clock_change_latency_us); // HACK!! Lower uclock latency switch time so we don't switch - dcn2_0_soc.dram_clock_change_latency_us = 10; - dcn2_0_soc.writeback_dram_clock_change_latency_us = + dcn2_0_nv12_soc.dram_clock_change_latency_us = 10; + dcn2_0_nv12_soc.writeback_dram_clock_change_latency_us = fixed16_to_double_to_cpu(bb->writeback_dram_clock_change_latency_us); - dcn2_0_soc.return_bus_width_bytes = + dcn2_0_nv12_soc.return_bus_width_bytes = le32_to_cpu(bb->return_bus_width_bytes); - dcn2_0_soc.dispclk_dppclk_vco_speed_mhz = + dcn2_0_nv12_soc.dispclk_dppclk_vco_speed_mhz = le32_to_cpu(bb->dispclk_dppclk_vco_speed_mhz); - dcn2_0_soc.xfc_bus_transport_time_us = + dcn2_0_nv12_soc.xfc_bus_transport_time_us = le32_to_cpu(bb->xfc_bus_transport_time_us); - dcn2_0_soc.xfc_xbuf_latency_tolerance_us = + dcn2_0_nv12_soc.xfc_xbuf_latency_tolerance_us = le32_to_cpu(bb->xfc_xbuf_latency_tolerance_us); - dcn2_0_soc.use_urgent_burst_bw = + dcn2_0_nv12_soc.use_urgent_burst_bw = le32_to_cpu(bb->use_urgent_burst_bw); - dcn2_0_soc.num_states = + dcn2_0_nv12_soc.num_states = le32_to_cpu(bb->num_states); - for (i = 0; i < dcn2_0_soc.num_states; i++) { - dcn2_0_soc.clock_limits[i].state = + for (i = 0; i < dcn2_0_nv12_soc.num_states; i++) { + dcn2_0_nv12_soc.clock_limits[i].state = le32_to_cpu(bb->clock_limits[i].state); - dcn2_0_soc.clock_limits[i].dcfclk_mhz = + dcn2_0_nv12_soc.clock_limits[i].dcfclk_mhz = fixed16_to_double_to_cpu(bb->clock_limits[i].dcfclk_mhz); - dcn2_0_soc.clock_limits[i].fabricclk_mhz = + dcn2_0_nv12_soc.clock_limits[i].fabricclk_mhz = fixed16_to_double_to_cpu(bb->clock_limits[i].fabricclk_mhz); - dcn2_0_soc.clock_limits[i].dispclk_mhz = + dcn2_0_nv12_soc.clock_limits[i].dispclk_mhz = fixed16_to_double_to_cpu(bb->clock_limits[i].dispclk_mhz); - dcn2_0_soc.clock_limits[i].dppclk_mhz = + dcn2_0_nv12_soc.clock_limits[i].dppclk_mhz = fixed16_to_double_to_cpu(bb->clock_limits[i].dppclk_mhz); - dcn2_0_soc.clock_limits[i].phyclk_mhz = + dcn2_0_nv12_soc.clock_limits[i].phyclk_mhz = fixed16_to_double_to_cpu(bb->clock_limits[i].phyclk_mhz); - dcn2_0_soc.clock_limits[i].socclk_mhz = + dcn2_0_nv12_soc.clock_limits[i].socclk_mhz = fixed16_to_double_to_cpu(bb->clock_limits[i].socclk_mhz); - dcn2_0_soc.clock_limits[i].dscclk_mhz = + dcn2_0_nv12_soc.clock_limits[i].dscclk_mhz = fixed16_to_double_to_cpu(bb->clock_limits[i].dscclk_mhz); - dcn2_0_soc.clock_limits[i].dram_speed_mts = + dcn2_0_nv12_soc.clock_limits[i].dram_speed_mts = fixed16_to_double_to_cpu(bb->clock_limits[i].dram_speed_mts); } } @@ -2829,7 +3264,6 @@ static bool init_soc_bounding_box(struct dc *dc, struct pp_smu_nv_clock_table max_clocks = {0}; unsigned int uclk_states[8] = {0}; unsigned int num_states = 0; - int i; enum pp_smu_status status; bool clock_limits_available = false; bool uclk_states_available = false; @@ -2851,19 +3285,15 @@ static bool init_soc_bounding_box(struct dc *dc, clock_limits_available = (status == PP_SMU_RESULT_OK); } - // HACK: Use the max uclk_states value for all elements. - for (i = 0; i < num_states; i++) - uclk_states[i] = uclk_states[num_states - 1]; - if (clock_limits_available && uclk_states_available && num_states) - update_bounding_box(dc, &dcn2_0_soc, &max_clocks, uclk_states, num_states); + update_bounding_box(dc, loaded_bb, &max_clocks, uclk_states, num_states); else if (clock_limits_available) - cap_soc_clocks(&dcn2_0_soc, max_clocks); + cap_soc_clocks(loaded_bb, max_clocks); } - dcn2_0_ip.max_num_otg = pool->base.res_cap->num_timing_generator; - dcn2_0_ip.max_num_dpp = pool->base.pipe_count; - patch_bounding_box(dc, &dcn2_0_soc); + loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; + loaded_ip->max_num_dpp = pool->base.pipe_count; + patch_bounding_box(dc, loaded_bb); return true; } @@ -2876,19 +3306,30 @@ static bool construct( int i; struct dc_context *ctx = dc->ctx; struct irq_service_init_data init_data; + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = + get_asic_rev_soc_bb(ctx->asic_id.hw_internal_rev); + struct _vcs_dpi_ip_params_st *loaded_ip = + get_asic_rev_ip_params(ctx->asic_id.hw_internal_rev); + enum dml_project dml_project_version = + get_dml_project_version(ctx->asic_id.hw_internal_rev); ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_nv10; pool->base.funcs = &dcn20_res_pool_funcs; + if (ASICREV_IS_NAVI14_M(ctx->asic_id.hw_internal_rev)) { + pool->base.res_cap = &res_cap_nv14; + pool->base.pipe_count = 5; + pool->base.mpcc_count = 5; + } else { + pool->base.res_cap = &res_cap_nv10; + pool->base.pipe_count = 6; + pool->base.mpcc_count = 6; + } /************************************************* * Resource + asic cap harcoding * *************************************************/ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = 6; - pool->base.mpcc_count = 6; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 100; dc->caps.max_cursor_size = 256; @@ -2994,7 +3435,7 @@ static bool construct( goto create_fail; } - dml_init_instance(&dc->dml, &dcn2_0_soc, &dcn2_0_ip, DML_PROJECT_NAVI10); + dml_init_instance(&dc->dml, loaded_bb, loaded_ip, dml_project_version); if (!dc->debug.disable_pplib_wm_range) { struct pp_smu_wm_range_sets ranges = {0}; @@ -3002,7 +3443,7 @@ static bool construct( ranges.num_reader_wm_sets = 0; - if (dcn2_0_soc.num_states == 1) { + if (loaded_bb->num_states == 1) { ranges.reader_wm_sets[0].wm_inst = i; ranges.reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; ranges.reader_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; @@ -3010,13 +3451,13 @@ static bool construct( ranges.reader_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; ranges.num_reader_wm_sets = 1; - } else if (dcn2_0_soc.num_states > 1) { - for (i = 0; i < 4 && i < dcn2_0_soc.num_states; i++) { + } else if (loaded_bb->num_states > 1) { + for (i = 0; i < 4 && i < loaded_bb->num_states; i++) { ranges.reader_wm_sets[i].wm_inst = i; ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - ranges.reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (dcn2_0_soc.clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; - ranges.reader_wm_sets[i].max_fill_clk_mhz = dcn2_0_soc.clock_limits[i].dram_speed_mts / 16; + ranges.reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; + ranges.reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; ranges.num_reader_wm_sets = i + 1; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h index b5a75289f444..44f95aa0d61e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h @@ -116,6 +116,18 @@ void dcn20_set_mcif_arb_params( display_e2e_pipe_params_st *pipes, int pipe_cnt); bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate); +bool dcn20_fast_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out); +void dcn20_calculate_dlg_params( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel); enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c index f5bcffc426b8..5ab9d6240498 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c @@ -207,9 +207,8 @@ static void enc2_stream_encoder_stop_hdmi_info_packets( #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - /* Update GSP7 SDP 128 byte long */ -static void enc2_send_gsp7_128_info_packet( +static void enc2_update_gsp7_128_info_packet( struct dcn10_stream_encoder *enc1, const struct dc_info_packet_128 *info_packet) { @@ -277,18 +276,9 @@ static void enc2_send_gsp7_128_info_packet( static void enc2_dp_set_dsc_config(struct stream_encoder *enc, enum optc_dsc_mode dsc_mode, uint32_t dsc_bytes_per_pixel, - uint32_t dsc_slice_width, - uint8_t *dsc_packed_pps) + uint32_t dsc_slice_width) { struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); - uint32_t dsc_value = 0; - - dsc_value = REG_READ(DP_DSC_CNTL); - - /* dsc disable skip */ - if ((dsc_value & 0x3) == 0x0) - return; - REG_UPDATE_2(DP_DSC_CNTL, DP_DSC_MODE, dsc_mode, @@ -296,8 +286,16 @@ static void enc2_dp_set_dsc_config(struct stream_encoder *enc, REG_SET(DP_DSC_BYTES_PER_PIXEL, 0, DP_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel); +} + + +static void enc2_dp_set_dsc_pps_info_packet(struct stream_encoder *enc, + bool enable, + uint8_t *dsc_packed_pps) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); - if (dsc_mode != OPTC_DSC_DISABLED) { + if (enable) { struct dc_info_packet_128 pps_sdp; ASSERT(dsc_packed_pps); @@ -309,7 +307,7 @@ static void enc2_dp_set_dsc_config(struct stream_encoder *enc, pps_sdp.hb2 = 127; pps_sdp.hb3 = 0; memcpy(&pps_sdp.sb[0], dsc_packed_pps, sizeof(pps_sdp.sb)); - enc2_send_gsp7_128_info_packet(enc1, &pps_sdp); + enc2_update_gsp7_128_info_packet(enc1, &pps_sdp); /* Enable Generic Stream Packet 7 (GSP) transmission */ //REG_UPDATE(DP_SEC_CNTL, @@ -340,9 +338,8 @@ static void enc2_dp_set_dsc_config(struct stream_encoder *enc, REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP7_PPS, 0); } } -#endif -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + /* this function read dsc related register fields to be logged later in dcn10_log_hw_state * into a dcn_dsc_state struct. */ @@ -373,7 +370,7 @@ static void enc2_read_state(struct stream_encoder *enc, struct enc_state *s) * * Ensure the OTG master update lock is set when changing DME configuration. */ -static void enc2_set_dynamic_metadata(struct stream_encoder *enc, +void enc2_set_dynamic_metadata(struct stream_encoder *enc, bool enable_dme, uint32_t hubp_requestor_id, enum dynamic_metadata_mode dmdata_mode) @@ -463,7 +460,7 @@ void enc2_stream_encoder_dp_unblank( uint64_t m_vid_l = n_vid; /* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */ - if (is_two_pixels_per_containter(¶m->timing) || param->odm) { + if (is_two_pixels_per_containter(¶m->timing) || param->opp_cnt > 1) { /*this logic should be the same in get_pixel_clock_parameters() */ n_multiply = 1; } @@ -580,14 +577,14 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = { .setup_stereo_sync = enc1_setup_stereo_sync, .set_avmute = enc1_stream_encoder_set_avmute, .dig_connect_to_otg = enc1_dig_connect_to_otg, + .dig_source_otg = enc1_dig_source_otg, #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .enc_read_state = enc2_read_state, -#endif - -#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT .dp_set_dsc_config = enc2_dp_set_dsc_config, + .dp_set_dsc_pps_info_packet = enc2_dp_set_dsc_pps_info_packet, #endif .set_dynamic_metadata = enc2_set_dynamic_metadata, + .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, }; void dcn20_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h index 6d40e8c9b78f..3f94a9f13c4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h @@ -104,4 +104,9 @@ void enc2_stream_encoder_dp_unblank( struct stream_encoder *enc, const struct encoder_unblank_param *param); +void enc2_set_dynamic_metadata(struct stream_encoder *enc, + bool enable_dme, + uint32_t hubp_requestor_id, + enum dynamic_metadata_mode dmdata_mode); + #endif /* __DC_STREAM_ENCODER_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c index 27679ef6ebe8..96c263223315 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c @@ -23,6 +23,8 @@ * */ +#include <linux/delay.h> + #include "dcn20_vmid.h" #include "reg_helper.h" @@ -36,6 +38,38 @@ #define FN(reg_name, field_name) \ vmid->shifts->field_name, vmid->masks->field_name +static void dcn20_wait_for_vmid_ready(struct dcn20_vmid *vmid) +{ + /* According the hardware spec, we need to poll for the lowest + * bit of PAGE_TABLE_BASE_ADDR_LO32 = 1 any time a GPUVM + * context is updated. We can't use REG_WAIT here since we + * don't have a seperate field to wait on. + * + * TODO: Confirm timeout / poll interval with hardware team + */ + + int max_times = 10000; + int delay_us = 5; + int i; + + for (i = 0; i < max_times; ++i) { + uint32_t entry_lo32; + + REG_GET(PAGE_TABLE_BASE_ADDR_LO32, + VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_LO32, + &entry_lo32); + + if (entry_lo32 & 0x1) + return; + + udelay(delay_us); + } + + /* VM setup timed out */ + DC_LOG_WARNING("Timeout while waiting for GPUVM context update\n"); + ASSERT(0); +} + void dcn20_vmid_setup(struct dcn20_vmid *vmid, const struct dcn_vmid_page_table_config *config) { REG_SET(PAGE_TABLE_START_ADDR_HI32, 0, @@ -54,6 +88,9 @@ void dcn20_vmid_setup(struct dcn20_vmid *vmid, const struct dcn_vmid_page_table_ REG_SET(PAGE_TABLE_BASE_ADDR_HI32, 0, VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_HI32, (config->page_table_base_addr >> 32) & 0xFFFFFFFF); + /* Note: per hardware spec PAGE_TABLE_BASE_ADDR_LO32 must be programmed last in sequence */ REG_SET(PAGE_TABLE_BASE_ADDR_LO32, 0, VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_LO32, config->page_table_base_addr & 0xFFFFFFFF); + + dcn20_wait_for_vmid_ready(vmid); } |