170839da6SAurabindo Pillai // SPDX-License-Identifier: MIT
270839da6SAurabindo Pillai //
370839da6SAurabindo Pillai // Copyright 2024 Advanced Micro Devices, Inc.
470839da6SAurabindo Pillai
570839da6SAurabindo Pillai
663ab80d9SRafal Ostrowski #include "os_types.h"
770839da6SAurabindo Pillai #include "dm_services.h"
870839da6SAurabindo Pillai #include "basics/dc_common.h"
970839da6SAurabindo Pillai #include "dm_helpers.h"
1070839da6SAurabindo Pillai #include "core_types.h"
1170839da6SAurabindo Pillai #include "resource.h"
1270839da6SAurabindo Pillai #include "dccg.h"
1370839da6SAurabindo Pillai #include "dce/dce_hwseq.h"
1470839da6SAurabindo Pillai #include "reg_helper.h"
1570839da6SAurabindo Pillai #include "abm.h"
1670839da6SAurabindo Pillai #include "hubp.h"
1770839da6SAurabindo Pillai #include "dchubbub.h"
1870839da6SAurabindo Pillai #include "timing_generator.h"
1970839da6SAurabindo Pillai #include "opp.h"
2070839da6SAurabindo Pillai #include "ipp.h"
2170839da6SAurabindo Pillai #include "mpc.h"
2270839da6SAurabindo Pillai #include "mcif_wb.h"
2370839da6SAurabindo Pillai #include "dc_dmub_srv.h"
2470839da6SAurabindo Pillai #include "link_hwss.h"
2570839da6SAurabindo Pillai #include "dpcd_defs.h"
2670839da6SAurabindo Pillai #include "clk_mgr.h"
2770839da6SAurabindo Pillai #include "dsc.h"
2870839da6SAurabindo Pillai #include "link.h"
2970839da6SAurabindo Pillai
3070839da6SAurabindo Pillai #include "dce/dmub_hw_lock_mgr.h"
3170839da6SAurabindo Pillai #include "dcn10/dcn10_cm_common.h"
3270839da6SAurabindo Pillai #include "dcn20/dcn20_optc.h"
3370839da6SAurabindo Pillai #include "dcn30/dcn30_cm_common.h"
3470839da6SAurabindo Pillai #include "dcn32/dcn32_hwseq.h"
3570839da6SAurabindo Pillai #include "dcn401_hwseq.h"
36872c0de3SWenjing Liu #include "dcn401/dcn401_resource.h"
3770839da6SAurabindo Pillai #include "dc_state_priv.h"
3870839da6SAurabindo Pillai #include "link_enc_cfg.h"
3970839da6SAurabindo Pillai
4070839da6SAurabindo Pillai #define DC_LOGGER_INIT(logger)
4170839da6SAurabindo Pillai
4270839da6SAurabindo Pillai #define CTX \
4370839da6SAurabindo Pillai hws->ctx
4470839da6SAurabindo Pillai #define REG(reg)\
4570839da6SAurabindo Pillai hws->regs->reg
4670839da6SAurabindo Pillai #define DC_LOGGER \
4770839da6SAurabindo Pillai dc->ctx->logger
4870839da6SAurabindo Pillai
4970839da6SAurabindo Pillai
5070839da6SAurabindo Pillai #undef FN
5170839da6SAurabindo Pillai #define FN(reg_name, field_name) \
5270839da6SAurabindo Pillai hws->shifts->field_name, hws->masks->field_name
5370839da6SAurabindo Pillai
dcn401_initialize_min_clocks(struct dc * dc)5470839da6SAurabindo Pillai void dcn401_initialize_min_clocks(struct dc *dc)
5570839da6SAurabindo Pillai {
5670839da6SAurabindo Pillai struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk;
5770839da6SAurabindo Pillai
5870839da6SAurabindo Pillai clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
5970839da6SAurabindo Pillai clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000;
6070839da6SAurabindo Pillai clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000;
613838c673SChris Park clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000;
6270839da6SAurabindo Pillai clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000;
633838c673SChris Park if (dc->debug.disable_boot_optimizations) {
643838c673SChris Park clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000;
653838c673SChris Park } else {
663838c673SChris Park /* Even though DPG_EN = 1 for the connected display, it still requires the
673838c673SChris Park * correct timing so we cannot set DISPCLK to min freq or it could cause
683838c673SChris Park * audio corruption. Read current DISPCLK from DENTIST and request the same
693838c673SChris Park * freq to ensure that the timing is valid and unchanged.
703838c673SChris Park */
7170839da6SAurabindo Pillai clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
7270839da6SAurabindo Pillai }
7370839da6SAurabindo Pillai clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
7470839da6SAurabindo Pillai clocks->fclk_p_state_change_support = true;
7570839da6SAurabindo Pillai clocks->p_state_change_support = true;
7670839da6SAurabindo Pillai
7770839da6SAurabindo Pillai dc->clk_mgr->funcs->update_clocks(
7870839da6SAurabindo Pillai dc->clk_mgr,
7970839da6SAurabindo Pillai dc->current_state,
8070839da6SAurabindo Pillai true);
8170839da6SAurabindo Pillai }
8270839da6SAurabindo Pillai
dcn401_program_gamut_remap(struct pipe_ctx * pipe_ctx)8370839da6SAurabindo Pillai void dcn401_program_gamut_remap(struct pipe_ctx *pipe_ctx)
8470839da6SAurabindo Pillai {
8570839da6SAurabindo Pillai unsigned int i = 0;
8670839da6SAurabindo Pillai struct mpc_grph_gamut_adjustment mpc_adjust;
8770839da6SAurabindo Pillai unsigned int mpcc_id = pipe_ctx->plane_res.mpcc_inst;
8870839da6SAurabindo Pillai struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
8970839da6SAurabindo Pillai
9070839da6SAurabindo Pillai //For now assert if location is not pre-blend
9170839da6SAurabindo Pillai if (pipe_ctx->plane_state)
9270839da6SAurabindo Pillai ASSERT(pipe_ctx->plane_state->mcm_location == MPCC_MOVABLE_CM_LOCATION_BEFORE);
9370839da6SAurabindo Pillai
9470839da6SAurabindo Pillai // program MPCC_MCM_FIRST_GAMUT_REMAP
9570839da6SAurabindo Pillai memset(&mpc_adjust, 0, sizeof(mpc_adjust));
9670839da6SAurabindo Pillai mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
9770839da6SAurabindo Pillai mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_FIRST_GAMUT_REMAP;
9870839da6SAurabindo Pillai
9970839da6SAurabindo Pillai if (pipe_ctx->plane_state &&
10070839da6SAurabindo Pillai pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
10170839da6SAurabindo Pillai mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
10270839da6SAurabindo Pillai for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
10370839da6SAurabindo Pillai mpc_adjust.temperature_matrix[i] =
10470839da6SAurabindo Pillai pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
10570839da6SAurabindo Pillai }
10670839da6SAurabindo Pillai
10770839da6SAurabindo Pillai mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
10870839da6SAurabindo Pillai
10970839da6SAurabindo Pillai // program MPCC_MCM_SECOND_GAMUT_REMAP for Bypass / Disable for now
11070839da6SAurabindo Pillai mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
11170839da6SAurabindo Pillai mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_SECOND_GAMUT_REMAP;
11270839da6SAurabindo Pillai
11370839da6SAurabindo Pillai mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
11470839da6SAurabindo Pillai
11570839da6SAurabindo Pillai // program MPCC_OGAM_GAMUT_REMAP same as is currently used on DCN3x
11670839da6SAurabindo Pillai memset(&mpc_adjust, 0, sizeof(mpc_adjust));
11770839da6SAurabindo Pillai mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
11870839da6SAurabindo Pillai mpc_adjust.mpcc_gamut_remap_block_id = MPCC_OGAM_GAMUT_REMAP;
11970839da6SAurabindo Pillai
12070839da6SAurabindo Pillai if (pipe_ctx->top_pipe == NULL) {
12170839da6SAurabindo Pillai if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
12270839da6SAurabindo Pillai mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
12370839da6SAurabindo Pillai for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
12470839da6SAurabindo Pillai mpc_adjust.temperature_matrix[i] =
12570839da6SAurabindo Pillai pipe_ctx->stream->gamut_remap_matrix.matrix[i];
12670839da6SAurabindo Pillai }
12770839da6SAurabindo Pillai }
12870839da6SAurabindo Pillai
12970839da6SAurabindo Pillai mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
13070839da6SAurabindo Pillai }
13170839da6SAurabindo Pillai
dcn401_init_hw(struct dc * dc)13270839da6SAurabindo Pillai void dcn401_init_hw(struct dc *dc)
13370839da6SAurabindo Pillai {
13470839da6SAurabindo Pillai struct abm **abms = dc->res_pool->multiple_abms;
13570839da6SAurabindo Pillai struct dce_hwseq *hws = dc->hwseq;
13670839da6SAurabindo Pillai struct dc_bios *dcb = dc->ctx->dc_bios;
13770839da6SAurabindo Pillai struct resource_pool *res_pool = dc->res_pool;
13870839da6SAurabindo Pillai int i;
13970839da6SAurabindo Pillai int edp_num;
140ca0fb243SDaniel Sa uint32_t backlight = MAX_BACKLIGHT_LEVEL;
14170839da6SAurabindo Pillai uint32_t user_level = MAX_BACKLIGHT_LEVEL;
1424b6377f0SSrinivasan Shanmugam int current_dchub_ref_freq = 0;
14370839da6SAurabindo Pillai
14470839da6SAurabindo Pillai if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
1457662bc61SJoshua Aberback dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
1467662bc61SJoshua Aberback
1477662bc61SJoshua Aberback // mark dcmode limits present if any clock has distinct AC and DC values from SMU
1487662bc61SJoshua Aberback dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present &&
1497662bc61SJoshua Aberback dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr);
1507662bc61SJoshua Aberback }
1517662bc61SJoshua Aberback
1527662bc61SJoshua Aberback // Initialize the dccg
1537662bc61SJoshua Aberback if (res_pool->dccg->funcs->dccg_init)
1547662bc61SJoshua Aberback res_pool->dccg->funcs->dccg_init(res_pool->dccg);
15570839da6SAurabindo Pillai
15670839da6SAurabindo Pillai // Disable DMUB Initialization until IPS state programming is finalized
15770839da6SAurabindo Pillai //if (!dcb->funcs->is_accelerated_mode(dcb)) {
15870839da6SAurabindo Pillai // hws->funcs.bios_golden_init(dc);
15970839da6SAurabindo Pillai //}
16070839da6SAurabindo Pillai
16170839da6SAurabindo Pillai // Set default OPTC memory power states
16270839da6SAurabindo Pillai if (dc->debug.enable_mem_low_power.bits.optc) {
16370839da6SAurabindo Pillai // Shutdown when unassigned and light sleep in VBLANK
16470839da6SAurabindo Pillai REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
16570839da6SAurabindo Pillai }
16670839da6SAurabindo Pillai
16770839da6SAurabindo Pillai if (dc->debug.enable_mem_low_power.bits.vga) {
16870839da6SAurabindo Pillai // Power down VGA memory
16970839da6SAurabindo Pillai REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
17070839da6SAurabindo Pillai }
17170839da6SAurabindo Pillai
17270839da6SAurabindo Pillai if (dc->ctx->dc_bios->fw_info_valid) {
17370839da6SAurabindo Pillai res_pool->ref_clocks.xtalin_clock_inKhz =
17470839da6SAurabindo Pillai dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
17570839da6SAurabindo Pillai
17670839da6SAurabindo Pillai if (res_pool->hubbub) {
17770839da6SAurabindo Pillai (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
17870839da6SAurabindo Pillai dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
1791a664dc0SAlex Hung &res_pool->ref_clocks.dccg_ref_clock_inKhz);
18070839da6SAurabindo Pillai
18170839da6SAurabindo Pillai current_dchub_ref_freq = res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
18270839da6SAurabindo Pillai
18370839da6SAurabindo Pillai (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
184ca0fb243SDaniel Sa res_pool->ref_clocks.dccg_ref_clock_inKhz,
185ca0fb243SDaniel Sa &res_pool->ref_clocks.dchub_ref_clock_inKhz);
18670839da6SAurabindo Pillai } else {
18770839da6SAurabindo Pillai // Not all ASICs have DCCG sw component
18870839da6SAurabindo Pillai res_pool->ref_clocks.dccg_ref_clock_inKhz =
18970839da6SAurabindo Pillai res_pool->ref_clocks.xtalin_clock_inKhz;
19070839da6SAurabindo Pillai res_pool->ref_clocks.dchub_ref_clock_inKhz =
19170839da6SAurabindo Pillai res_pool->ref_clocks.xtalin_clock_inKhz;
19270839da6SAurabindo Pillai }
19370839da6SAurabindo Pillai } else
19470839da6SAurabindo Pillai ASSERT_CRITICAL(false);
19570839da6SAurabindo Pillai
19670839da6SAurabindo Pillai for (i = 0; i < dc->link_count; i++) {
19770839da6SAurabindo Pillai /* Power up AND update implementation according to the
19870839da6SAurabindo Pillai * required signal (which may be different from the
19970839da6SAurabindo Pillai * default signal on connector).
20070839da6SAurabindo Pillai */
20170839da6SAurabindo Pillai struct dc_link *link = dc->links[i];
20270839da6SAurabindo Pillai
20370839da6SAurabindo Pillai link->link_enc->funcs->hw_init(link->link_enc);
20470839da6SAurabindo Pillai
20570839da6SAurabindo Pillai /* Check for enabled DIG to identify enabled display */
20670839da6SAurabindo Pillai if (link->link_enc->funcs->is_dig_enabled &&
20770839da6SAurabindo Pillai link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
20870839da6SAurabindo Pillai link->link_status.link_active = true;
20970839da6SAurabindo Pillai link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
21070839da6SAurabindo Pillai if (link->link_enc->funcs->fec_is_active &&
21170839da6SAurabindo Pillai link->link_enc->funcs->fec_is_active(link->link_enc))
21270839da6SAurabindo Pillai link->fec_state = dc_link_fec_enabled;
21370839da6SAurabindo Pillai }
21470839da6SAurabindo Pillai }
21570839da6SAurabindo Pillai
21670839da6SAurabindo Pillai /* enable_power_gating_plane before dsc_pg_control because
21770839da6SAurabindo Pillai * FORCEON = 1 with hw default value on bootup, resume from s3
21870839da6SAurabindo Pillai */
21970839da6SAurabindo Pillai if (hws->funcs.enable_power_gating_plane)
22070839da6SAurabindo Pillai hws->funcs.enable_power_gating_plane(dc->hwseq, true);
22170839da6SAurabindo Pillai
22270839da6SAurabindo Pillai /* we want to turn off all dp displays before doing detection */
22370839da6SAurabindo Pillai dc->link_srv->blank_all_dp_displays(dc);
22470839da6SAurabindo Pillai
22570839da6SAurabindo Pillai /* If taking control over from VBIOS, we may want to optimize our first
22670839da6SAurabindo Pillai * mode set, so we need to skip powering down pipes until we know which
22770839da6SAurabindo Pillai * pipes we want to use.
22870839da6SAurabindo Pillai * Otherwise, if taking control is not possible, we need to power
22970839da6SAurabindo Pillai * everything down.
23070839da6SAurabindo Pillai */
23170839da6SAurabindo Pillai if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
23270839da6SAurabindo Pillai /* Disable boot optimizations means power down everything including PHY, DIG,
23370839da6SAurabindo Pillai * and OTG (i.e. the boot is not optimized because we do a full power down).
23470839da6SAurabindo Pillai */
235f2034ebbSJoshua Aberback if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
236f2034ebbSJoshua Aberback dc->hwss.enable_accelerated_mode(dc, dc->current_state);
237f2034ebbSJoshua Aberback else
238f2034ebbSJoshua Aberback hws->funcs.init_pipes(dc, dc->current_state);
239f2034ebbSJoshua Aberback
240f2034ebbSJoshua Aberback if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
24170839da6SAurabindo Pillai dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
242f2034ebbSJoshua Aberback !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
24370839da6SAurabindo Pillai
24470839da6SAurabindo Pillai dcn401_initialize_min_clocks(dc);
24570839da6SAurabindo Pillai
24670839da6SAurabindo Pillai /* On HW init, allow idle optimizations after pipes have been turned off.
24770839da6SAurabindo Pillai *
24870839da6SAurabindo Pillai * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
24970839da6SAurabindo Pillai * is reset (i.e. not in idle at the time hw init is called), but software state
25070839da6SAurabindo Pillai * still has idle_optimizations = true, so we must disable idle optimizations first
25170839da6SAurabindo Pillai * (i.e. set false), then re-enable (set true).
25270839da6SAurabindo Pillai */
25370839da6SAurabindo Pillai dc_allow_idle_optimizations(dc, false);
25470839da6SAurabindo Pillai dc_allow_idle_optimizations(dc, true);
25570839da6SAurabindo Pillai }
25670839da6SAurabindo Pillai
25770839da6SAurabindo Pillai /* In headless boot cases, DIG may be turned
25870839da6SAurabindo Pillai * on which causes HW/SW discrepancies.
25970839da6SAurabindo Pillai * To avoid this, power down hardware on boot
26070839da6SAurabindo Pillai * if DIG is turned on and seamless boot not enabled
26170839da6SAurabindo Pillai */
26270839da6SAurabindo Pillai if (!dc->config.seamless_boot_edp_requested) {
26370839da6SAurabindo Pillai struct dc_link *edp_links[MAX_NUM_EDP];
26470839da6SAurabindo Pillai struct dc_link *edp_link;
26570839da6SAurabindo Pillai
26670839da6SAurabindo Pillai dc_get_edp_links(dc, edp_links, &edp_num);
26770839da6SAurabindo Pillai if (edp_num) {
26870839da6SAurabindo Pillai for (i = 0; i < edp_num; i++) {
26970839da6SAurabindo Pillai edp_link = edp_links[i];
27070839da6SAurabindo Pillai if (edp_link->link_enc->funcs->is_dig_enabled &&
27170839da6SAurabindo Pillai edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
27270839da6SAurabindo Pillai dc->hwss.edp_backlight_control &&
27370839da6SAurabindo Pillai hws->funcs.power_down &&
27470839da6SAurabindo Pillai dc->hwss.edp_power_control) {
27570839da6SAurabindo Pillai dc->hwss.edp_backlight_control(edp_link, false);
27687325940SJoshua Aberback hws->funcs.power_down(dc);
27770839da6SAurabindo Pillai dc->hwss.edp_power_control(edp_link, false);
27870839da6SAurabindo Pillai }
27987325940SJoshua Aberback }
28070839da6SAurabindo Pillai } else {
28170839da6SAurabindo Pillai for (i = 0; i < dc->link_count; i++) {
28270839da6SAurabindo Pillai struct dc_link *link = dc->links[i];
28370839da6SAurabindo Pillai
28470839da6SAurabindo Pillai if (link->link_enc->funcs->is_dig_enabled &&
28570839da6SAurabindo Pillai link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
28670839da6SAurabindo Pillai hws->funcs.power_down) {
28770839da6SAurabindo Pillai hws->funcs.power_down(dc);
28870839da6SAurabindo Pillai break;
28987325940SJoshua Aberback }
29087325940SJoshua Aberback
29170839da6SAurabindo Pillai }
29270839da6SAurabindo Pillai }
29370839da6SAurabindo Pillai }
29470839da6SAurabindo Pillai
29570839da6SAurabindo Pillai for (i = 0; i < res_pool->audio_count; i++) {
29670839da6SAurabindo Pillai struct audio *audio = res_pool->audios[i];
29770839da6SAurabindo Pillai
29870839da6SAurabindo Pillai audio->funcs->hw_init(audio);
29970839da6SAurabindo Pillai }
30070839da6SAurabindo Pillai
30170839da6SAurabindo Pillai for (i = 0; i < dc->link_count; i++) {
30270839da6SAurabindo Pillai struct dc_link *link = dc->links[i];
30370839da6SAurabindo Pillai
30470839da6SAurabindo Pillai if (link->panel_cntl) {
30570839da6SAurabindo Pillai backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
30670839da6SAurabindo Pillai user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
30770839da6SAurabindo Pillai }
30870839da6SAurabindo Pillai }
30970839da6SAurabindo Pillai
31070839da6SAurabindo Pillai for (i = 0; i < dc->res_pool->pipe_count; i++) {
31170839da6SAurabindo Pillai if (abms[i] != NULL && abms[i]->funcs != NULL)
31270839da6SAurabindo Pillai abms[i]->funcs->abm_init(abms[i], backlight, user_level);
31370839da6SAurabindo Pillai }
31470839da6SAurabindo Pillai
31570839da6SAurabindo Pillai /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
31670839da6SAurabindo Pillai REG_WRITE(DIO_MEM_PWR_CTRL, 0);
31770839da6SAurabindo Pillai
31870839da6SAurabindo Pillai if (!dc->debug.disable_clock_gate) {
31970839da6SAurabindo Pillai /* enable all DCN clock gating */
32070839da6SAurabindo Pillai REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
32170839da6SAurabindo Pillai
32270839da6SAurabindo Pillai REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
32370839da6SAurabindo Pillai
32470839da6SAurabindo Pillai REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
32570839da6SAurabindo Pillai }
32670839da6SAurabindo Pillai
32770839da6SAurabindo Pillai dcn401_setup_hpo_hw_control(hws, true);
32870839da6SAurabindo Pillai
32970839da6SAurabindo Pillai if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
330a4758aa3SLeo (Hanghong) Ma dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
331a4758aa3SLeo (Hanghong) Ma
33270839da6SAurabindo Pillai if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
33370839da6SAurabindo Pillai dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
33470839da6SAurabindo Pillai
3354b6377f0SSrinivasan Shanmugam if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
33670839da6SAurabindo Pillai dc->res_pool->hubbub->funcs->force_pstate_change_control(
33770839da6SAurabindo Pillai dc->res_pool->hubbub, false, false);
33870839da6SAurabindo Pillai
33970839da6SAurabindo Pillai if (dc->res_pool->hubbub->funcs->init_crb)
34070839da6SAurabindo Pillai dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
34170839da6SAurabindo Pillai
34270839da6SAurabindo Pillai if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
34370839da6SAurabindo Pillai dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);
34470839da6SAurabindo Pillai
34570839da6SAurabindo Pillai // Get DMCUB capabilities
34670839da6SAurabindo Pillai if (dc->ctx->dmub_srv) {
34770839da6SAurabindo Pillai dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
34870839da6SAurabindo Pillai dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
34970839da6SAurabindo Pillai dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
35070839da6SAurabindo Pillai dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
35170839da6SAurabindo Pillai dc->debug.fams2_config.bits.enable &=
35270839da6SAurabindo Pillai dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support
35370839da6SAurabindo Pillai if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box)
35455eeaaecSDillon Varone || res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) {
35555eeaaecSDillon Varone /* update bounding box if FAMS2 disabled, or if dchub clk has changed */
356ca0fb243SDaniel Sa if (dc->clk_mgr)
357ca0fb243SDaniel Sa dc->res_pool->funcs->update_bw_bounding_box(dc,
358ca0fb243SDaniel Sa dc->clk_mgr->bw_params);
3594b6377f0SSrinivasan Shanmugam }
3604b6377f0SSrinivasan Shanmugam }
3614b6377f0SSrinivasan Shanmugam }
36270839da6SAurabindo Pillai
dcn401_get_mcm_lut_xable_from_pipe_ctx(struct dc * dc,struct pipe_ctx * pipe_ctx,enum MCM_LUT_XABLE * shaper_xable,enum MCM_LUT_XABLE * lut3d_xable,enum MCM_LUT_XABLE * lut1d_xable)36370839da6SAurabindo Pillai static void dcn401_get_mcm_lut_xable_from_pipe_ctx(struct dc *dc, struct pipe_ctx *pipe_ctx,
36470839da6SAurabindo Pillai enum MCM_LUT_XABLE *shaper_xable,
36570839da6SAurabindo Pillai enum MCM_LUT_XABLE *lut3d_xable,
36670839da6SAurabindo Pillai enum MCM_LUT_XABLE *lut1d_xable)
36770839da6SAurabindo Pillai {
36870839da6SAurabindo Pillai enum dc_cm2_shaper_3dlut_setting shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL;
36970839da6SAurabindo Pillai bool lut1d_enable = false;
37070839da6SAurabindo Pillai struct mpc *mpc = dc->res_pool->mpc;
37170839da6SAurabindo Pillai int mpcc_id = pipe_ctx->plane_res.hubp->inst;
37270839da6SAurabindo Pillai
37370839da6SAurabindo Pillai if (!pipe_ctx->plane_state)
37470839da6SAurabindo Pillai return;
37570839da6SAurabindo Pillai shaper_3dlut_setting = pipe_ctx->plane_state->mcm_shaper_3dlut_setting;
37670839da6SAurabindo Pillai lut1d_enable = pipe_ctx->plane_state->mcm_lut1d_enable;
37770839da6SAurabindo Pillai mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
37870839da6SAurabindo Pillai pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
37970839da6SAurabindo Pillai
38070839da6SAurabindo Pillai *lut1d_xable = lut1d_enable ? MCM_LUT_ENABLE : MCM_LUT_DISABLE;
38170839da6SAurabindo Pillai
38270839da6SAurabindo Pillai switch (shaper_3dlut_setting) {
38370839da6SAurabindo Pillai case DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL:
38470839da6SAurabindo Pillai *lut3d_xable = *shaper_xable = MCM_LUT_DISABLE;
38570839da6SAurabindo Pillai break;
38670839da6SAurabindo Pillai case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER:
38770839da6SAurabindo Pillai *lut3d_xable = MCM_LUT_DISABLE;
38870839da6SAurabindo Pillai *shaper_xable = MCM_LUT_ENABLE;
38970839da6SAurabindo Pillai break;
39070839da6SAurabindo Pillai case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT:
39170839da6SAurabindo Pillai *lut3d_xable = *shaper_xable = MCM_LUT_ENABLE;
39270839da6SAurabindo Pillai break;
39370839da6SAurabindo Pillai }
39470839da6SAurabindo Pillai }
39570839da6SAurabindo Pillai
dcn401_populate_mcm_luts(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_cm2_func_luts mcm_luts,bool lut_bank_a)39670839da6SAurabindo Pillai void dcn401_populate_mcm_luts(struct dc *dc,
39770839da6SAurabindo Pillai struct pipe_ctx *pipe_ctx,
39870839da6SAurabindo Pillai struct dc_cm2_func_luts mcm_luts,
399652968d9SYihan Zhu bool lut_bank_a)
400652968d9SYihan Zhu {
401652968d9SYihan Zhu struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
402652968d9SYihan Zhu struct hubp *hubp = pipe_ctx->plane_res.hubp;
403652968d9SYihan Zhu int mpcc_id = hubp->inst;
404652968d9SYihan Zhu struct mpc *mpc = dc->res_pool->mpc;
405652968d9SYihan Zhu union mcm_lut_params m_lut_params;
406652968d9SYihan Zhu enum dc_cm2_transfer_func_source lut3d_src = mcm_luts.lut3d_data.lut3d_src;
407652968d9SYihan Zhu enum hubp_3dlut_fl_format format = 0;
408652968d9SYihan Zhu enum hubp_3dlut_fl_mode mode;
409652968d9SYihan Zhu enum hubp_3dlut_fl_width width = 0;
410652968d9SYihan Zhu enum hubp_3dlut_fl_addressing_mode addr_mode;
411652968d9SYihan Zhu enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g = 0;
412652968d9SYihan Zhu enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b = 0;
413652968d9SYihan Zhu enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r = 0;
414652968d9SYihan Zhu enum MCM_LUT_XABLE shaper_xable = MCM_LUT_DISABLE;
415652968d9SYihan Zhu enum MCM_LUT_XABLE lut3d_xable = MCM_LUT_DISABLE;
416652968d9SYihan Zhu enum MCM_LUT_XABLE lut1d_xable = MCM_LUT_DISABLE;
417652968d9SYihan Zhu bool rval;
418652968d9SYihan Zhu
419652968d9SYihan Zhu dcn401_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable);
420652968d9SYihan Zhu
421652968d9SYihan Zhu /* 1D LUT */
422652968d9SYihan Zhu if (mcm_luts.lut1d_func) {
423652968d9SYihan Zhu memset(&m_lut_params, 0, sizeof(m_lut_params));
424652968d9SYihan Zhu if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
425652968d9SYihan Zhu m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
426652968d9SYihan Zhu else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
427652968d9SYihan Zhu rval = cm3_helper_translate_curve_to_hw_format(
428652968d9SYihan Zhu mcm_luts.lut1d_func,
429652968d9SYihan Zhu &dpp_base->regamma_params, false);
430652968d9SYihan Zhu m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
431652968d9SYihan Zhu }
432652968d9SYihan Zhu if (m_lut_params.pwl) {
433652968d9SYihan Zhu if (mpc->funcs->populate_lut)
434652968d9SYihan Zhu mpc->funcs->populate_lut(mpc, MCM_LUT_1DLUT, m_lut_params, lut_bank_a, mpcc_id);
435652968d9SYihan Zhu }
436652968d9SYihan Zhu if (mpc->funcs->program_lut_mode)
437652968d9SYihan Zhu mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable && m_lut_params.pwl, lut_bank_a, mpcc_id);
438652968d9SYihan Zhu }
439652968d9SYihan Zhu
440652968d9SYihan Zhu /* Shaper */
441652968d9SYihan Zhu if (mcm_luts.shaper && mcm_luts.lut3d_data.mpc_3dlut_enable) {
442652968d9SYihan Zhu memset(&m_lut_params, 0, sizeof(m_lut_params));
443652968d9SYihan Zhu if (mcm_luts.shaper->type == TF_TYPE_HWPWL)
444652968d9SYihan Zhu m_lut_params.pwl = &mcm_luts.shaper->pwl;
445652968d9SYihan Zhu else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
446652968d9SYihan Zhu ASSERT(false);
447652968d9SYihan Zhu rval = cm3_helper_translate_curve_to_hw_format(
448652968d9SYihan Zhu mcm_luts.shaper,
449652968d9SYihan Zhu &dpp_base->regamma_params, true);
450652968d9SYihan Zhu m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
451652968d9SYihan Zhu }
452652968d9SYihan Zhu if (m_lut_params.pwl) {
453652968d9SYihan Zhu if (mpc->funcs->mcm.populate_lut)
454652968d9SYihan Zhu mpc->funcs->mcm.populate_lut(mpc, m_lut_params, lut_bank_a, mpcc_id);
455652968d9SYihan Zhu if (mpc->funcs->program_lut_mode)
456652968d9SYihan Zhu mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_ENABLE, lut_bank_a, mpcc_id);
457652968d9SYihan Zhu }
458652968d9SYihan Zhu }
459652968d9SYihan Zhu
460652968d9SYihan Zhu /* 3DLUT */
461652968d9SYihan Zhu switch (lut3d_src) {
462652968d9SYihan Zhu case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM:
463652968d9SYihan Zhu memset(&m_lut_params, 0, sizeof(m_lut_params));
464652968d9SYihan Zhu if (hubp->funcs->hubp_enable_3dlut_fl)
465652968d9SYihan Zhu hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
466652968d9SYihan Zhu
467652968d9SYihan Zhu if (mcm_luts.lut3d_data.lut3d_func && mcm_luts.lut3d_data.lut3d_func->state.bits.initialized) {
468652968d9SYihan Zhu m_lut_params.lut3d = &mcm_luts.lut3d_data.lut3d_func->lut_3d;
469652968d9SYihan Zhu if (mpc->funcs->populate_lut)
470652968d9SYihan Zhu mpc->funcs->populate_lut(mpc, MCM_LUT_3DLUT, m_lut_params, lut_bank_a, mpcc_id);
471652968d9SYihan Zhu if (mpc->funcs->program_lut_mode)
472652968d9SYihan Zhu mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a,
473652968d9SYihan Zhu mpcc_id);
474652968d9SYihan Zhu }
475652968d9SYihan Zhu break;
476652968d9SYihan Zhu case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM:
477652968d9SYihan Zhu switch (mcm_luts.lut3d_data.gpu_mem_params.size) {
478652968d9SYihan Zhu case DC_CM2_GPU_MEM_SIZE_171717:
479652968d9SYihan Zhu width = hubp_3dlut_fl_width_17;
480652968d9SYihan Zhu break;
481652968d9SYihan Zhu case DC_CM2_GPU_MEM_SIZE_TRANSFORMED:
482652968d9SYihan Zhu width = hubp_3dlut_fl_width_transformed;
483652968d9SYihan Zhu break;
484652968d9SYihan Zhu default:
485652968d9SYihan Zhu //TODO: handle default case
486652968d9SYihan Zhu break;
487652968d9SYihan Zhu }
488652968d9SYihan Zhu
489652968d9SYihan Zhu //check for support
490652968d9SYihan Zhu if (mpc->funcs->mcm.is_config_supported &&
491652968d9SYihan Zhu !mpc->funcs->mcm.is_config_supported(width))
492652968d9SYihan Zhu break;
493652968d9SYihan Zhu
494652968d9SYihan Zhu if (mpc->funcs->program_lut_read_write_control)
495652968d9SYihan Zhu mpc->funcs->program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, mpcc_id);
496652968d9SYihan Zhu if (mpc->funcs->program_lut_mode)
497652968d9SYihan Zhu mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id);
498652968d9SYihan Zhu
499652968d9SYihan Zhu if (hubp->funcs->hubp_program_3dlut_fl_addr)
500652968d9SYihan Zhu hubp->funcs->hubp_program_3dlut_fl_addr(hubp, mcm_luts.lut3d_data.gpu_mem_params.addr);
501652968d9SYihan Zhu
502652968d9SYihan Zhu if (mpc->funcs->mcm.program_bit_depth)
503652968d9SYihan Zhu mpc->funcs->mcm.program_bit_depth(mpc, mcm_luts.lut3d_data.gpu_mem_params.bit_depth, mpcc_id);
504652968d9SYihan Zhu
505652968d9SYihan Zhu switch (mcm_luts.lut3d_data.gpu_mem_params.layout) {
506652968d9SYihan Zhu case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB:
507652968d9SYihan Zhu mode = hubp_3dlut_fl_mode_native_1;
508652968d9SYihan Zhu addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
509652968d9SYihan Zhu break;
510652968d9SYihan Zhu case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR:
511652968d9SYihan Zhu mode = hubp_3dlut_fl_mode_native_2;
512652968d9SYihan Zhu addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
513652968d9SYihan Zhu break;
514652968d9SYihan Zhu case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR:
515652968d9SYihan Zhu mode = hubp_3dlut_fl_mode_transform;
516652968d9SYihan Zhu addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear;
517652968d9SYihan Zhu break;
518652968d9SYihan Zhu default:
519652968d9SYihan Zhu mode = hubp_3dlut_fl_mode_disable;
520652968d9SYihan Zhu addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
521652968d9SYihan Zhu break;
522652968d9SYihan Zhu }
523652968d9SYihan Zhu if (hubp->funcs->hubp_program_3dlut_fl_mode)
524652968d9SYihan Zhu hubp->funcs->hubp_program_3dlut_fl_mode(hubp, mode);
525652968d9SYihan Zhu
526652968d9SYihan Zhu if (hubp->funcs->hubp_program_3dlut_fl_addressing_mode)
527652968d9SYihan Zhu hubp->funcs->hubp_program_3dlut_fl_addressing_mode(hubp, addr_mode);
528*fe1903bcSYihan Zhu
529*fe1903bcSYihan Zhu switch (mcm_luts.lut3d_data.gpu_mem_params.format_params.format) {
530*fe1903bcSYihan Zhu case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB:
531*fe1903bcSYihan Zhu format = hubp_3dlut_fl_format_unorm_12msb_bitslice;
532*fe1903bcSYihan Zhu break;
533652968d9SYihan Zhu case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB:
534652968d9SYihan Zhu format = hubp_3dlut_fl_format_unorm_12lsb_bitslice;
535652968d9SYihan Zhu break;
536652968d9SYihan Zhu case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10:
537652968d9SYihan Zhu format = hubp_3dlut_fl_format_float_fp1_5_10;
538652968d9SYihan Zhu break;
539652968d9SYihan Zhu }
540652968d9SYihan Zhu if (hubp->funcs->hubp_program_3dlut_fl_format)
541652968d9SYihan Zhu hubp->funcs->hubp_program_3dlut_fl_format(hubp, format);
542652968d9SYihan Zhu if (hubp->funcs->hubp_update_3dlut_fl_bias_scale &&
543652968d9SYihan Zhu mpc->funcs->mcm.program_bias_scale) {
544652968d9SYihan Zhu mpc->funcs->mcm.program_bias_scale(mpc,
545652968d9SYihan Zhu mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
546652968d9SYihan Zhu mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale,
547652968d9SYihan Zhu mpcc_id);
548652968d9SYihan Zhu hubp->funcs->hubp_update_3dlut_fl_bias_scale(hubp,
549652968d9SYihan Zhu mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
550652968d9SYihan Zhu mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale);
551652968d9SYihan Zhu }
552652968d9SYihan Zhu
553652968d9SYihan Zhu //navi 4x has a bug and r and blue are swapped and need to be worked around here in
554652968d9SYihan Zhu //TODO: need to make a method for get_xbar per asic OR do the workaround in program_crossbar for 4x
555652968d9SYihan Zhu switch (mcm_luts.lut3d_data.gpu_mem_params.component_order) {
556652968d9SYihan Zhu case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA:
557652968d9SYihan Zhu default:
558652968d9SYihan Zhu crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15;
559652968d9SYihan Zhu crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31;
560652968d9SYihan Zhu crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47;
561652968d9SYihan Zhu break;
562652968d9SYihan Zhu }
563652968d9SYihan Zhu
564652968d9SYihan Zhu if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
565652968d9SYihan Zhu hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp,
566652968d9SYihan Zhu crossbar_bit_slice_cr_r,
567652968d9SYihan Zhu crossbar_bit_slice_y_g,
568652968d9SYihan Zhu crossbar_bit_slice_cb_b);
569652968d9SYihan Zhu
570652968d9SYihan Zhu if (mpc->funcs->mcm.program_lut_read_write_control)
571652968d9SYihan Zhu mpc->funcs->mcm.program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, true, mpcc_id);
572652968d9SYihan Zhu
573652968d9SYihan Zhu if (mpc->funcs->mcm.program_3dlut_size)
574652968d9SYihan Zhu mpc->funcs->mcm.program_3dlut_size(mpc, width, mpcc_id);
575652968d9SYihan Zhu
576652968d9SYihan Zhu if (mpc->funcs->update_3dlut_fast_load_select)
577652968d9SYihan Zhu mpc->funcs->update_3dlut_fast_load_select(mpc, mpcc_id, hubp->inst);
578652968d9SYihan Zhu
579652968d9SYihan Zhu if (hubp->funcs->hubp_enable_3dlut_fl)
580652968d9SYihan Zhu hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
581652968d9SYihan Zhu else {
582652968d9SYihan Zhu if (mpc->funcs->program_lut_mode) {
583652968d9SYihan Zhu mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
584652968d9SYihan Zhu mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
585652968d9SYihan Zhu mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
586652968d9SYihan Zhu }
587652968d9SYihan Zhu }
588652968d9SYihan Zhu break;
589652968d9SYihan Zhu
590652968d9SYihan Zhu }
591652968d9SYihan Zhu }
592652968d9SYihan Zhu
dcn401_trigger_3dlut_dma_load(struct dc * dc,struct pipe_ctx * pipe_ctx)593652968d9SYihan Zhu void dcn401_trigger_3dlut_dma_load(struct dc *dc, struct pipe_ctx *pipe_ctx)
594652968d9SYihan Zhu {
595652968d9SYihan Zhu struct hubp *hubp = pipe_ctx->plane_res.hubp;
596652968d9SYihan Zhu
597652968d9SYihan Zhu if (hubp->funcs->hubp_enable_3dlut_fl) {
598652968d9SYihan Zhu hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
599652968d9SYihan Zhu }
600652968d9SYihan Zhu }
601652968d9SYihan Zhu
dcn401_set_mcm_luts(struct pipe_ctx * pipe_ctx,const struct dc_plane_state * plane_state)602652968d9SYihan Zhu bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
603652968d9SYihan Zhu const struct dc_plane_state *plane_state)
604652968d9SYihan Zhu {
605652968d9SYihan Zhu struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
606652968d9SYihan Zhu int mpcc_id = pipe_ctx->plane_res.hubp->inst;
607652968d9SYihan Zhu struct dc *dc = pipe_ctx->stream_res.opp->ctx->dc;
608652968d9SYihan Zhu struct mpc *mpc = dc->res_pool->mpc;
609652968d9SYihan Zhu bool result;
610652968d9SYihan Zhu const struct pwl_params *lut_params = NULL;
611652968d9SYihan Zhu bool rval;
612652968d9SYihan Zhu
613652968d9SYihan Zhu if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
614652968d9SYihan Zhu dcn401_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a);
615652968d9SYihan Zhu return true;
616652968d9SYihan Zhu }
617652968d9SYihan Zhu
618652968d9SYihan Zhu mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
619652968d9SYihan Zhu pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
620652968d9SYihan Zhu // 1D LUT
621652968d9SYihan Zhu if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
622652968d9SYihan Zhu lut_params = &plane_state->blend_tf.pwl;
623652968d9SYihan Zhu else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
624652968d9SYihan Zhu rval = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
625652968d9SYihan Zhu &dpp_base->regamma_params, false);
626652968d9SYihan Zhu lut_params = rval ? &dpp_base->regamma_params : NULL;
627652968d9SYihan Zhu }
628652968d9SYihan Zhu result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
629652968d9SYihan Zhu lut_params = NULL;
630652968d9SYihan Zhu
631652968d9SYihan Zhu // Shaper
632652968d9SYihan Zhu if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL)
633652968d9SYihan Zhu lut_params = &plane_state->in_shaper_func.pwl;
634652968d9SYihan Zhu else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
635652968d9SYihan Zhu // TODO: dpp_base replace
636652968d9SYihan Zhu rval = cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
637652968d9SYihan Zhu &dpp_base->shaper_params, true);
638652968d9SYihan Zhu lut_params = rval ? &dpp_base->shaper_params : NULL;
639652968d9SYihan Zhu }
640652968d9SYihan Zhu result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
641652968d9SYihan Zhu
64270839da6SAurabindo Pillai // 3D
64370839da6SAurabindo Pillai if (mpc->funcs->program_3dlut) {
64470839da6SAurabindo Pillai if (plane_state->lut3d_func.state.bits.initialized == 1)
64570839da6SAurabindo Pillai result &= mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id);
64670839da6SAurabindo Pillai else
64770839da6SAurabindo Pillai result &= mpc->funcs->program_3dlut(mpc, NULL, mpcc_id);
64870839da6SAurabindo Pillai }
64970839da6SAurabindo Pillai
65070839da6SAurabindo Pillai return result;
65170839da6SAurabindo Pillai }
65270839da6SAurabindo Pillai
dcn401_set_output_transfer_func(struct dc * dc,struct pipe_ctx * pipe_ctx,const struct dc_stream_state * stream)653652968d9SYihan Zhu bool dcn401_set_output_transfer_func(struct dc *dc,
65470839da6SAurabindo Pillai struct pipe_ctx *pipe_ctx,
655652968d9SYihan Zhu const struct dc_stream_state *stream)
65670839da6SAurabindo Pillai {
657*fe1903bcSYihan Zhu int mpcc_id = pipe_ctx->plane_res.hubp->inst;
658*fe1903bcSYihan Zhu struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
659*fe1903bcSYihan Zhu const struct pwl_params *params = NULL;
6609243e0e2SAlex Hung bool ret = false;
6619243e0e2SAlex Hung
6629243e0e2SAlex Hung /* program OGAM or 3DLUT only for the top pipe*/
663cead9ac8SIlya Bakoulin if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
66470839da6SAurabindo Pillai /*program shaper and 3dlut in MPC*/
66570839da6SAurabindo Pillai ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
66670839da6SAurabindo Pillai if (ret == false && mpc->funcs->set_output_gamma) {
667652968d9SYihan Zhu if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
668652968d9SYihan Zhu params = &stream->out_transfer_func.pwl;
669652968d9SYihan Zhu else if (pipe_ctx->stream->out_transfer_func.type ==
670652968d9SYihan Zhu TF_TYPE_DISTRIBUTED_POINTS &&
671652968d9SYihan Zhu cm3_helper_translate_curve_to_hw_format(
672652968d9SYihan Zhu &stream->out_transfer_func,
673652968d9SYihan Zhu &mpc->blender_params, false))
674652968d9SYihan Zhu params = &mpc->blender_params;
675652968d9SYihan Zhu /* there are no ROM LUTs in OUTGAM */
676652968d9SYihan Zhu if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)
677652968d9SYihan Zhu BREAK_TO_DEBUGGER();
678652968d9SYihan Zhu }
679652968d9SYihan Zhu }
680652968d9SYihan Zhu
681652968d9SYihan Zhu if (mpc->funcs->set_output_gamma)
682652968d9SYihan Zhu mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
683652968d9SYihan Zhu
684652968d9SYihan Zhu return ret;
685652968d9SYihan Zhu }
68670839da6SAurabindo Pillai
dcn401_calculate_dccg_tmds_div_value(struct pipe_ctx * pipe_ctx,unsigned int * tmds_div)687df60dcf5SIlya Bakoulin void dcn401_calculate_dccg_tmds_div_value(struct pipe_ctx *pipe_ctx,
68870839da6SAurabindo Pillai unsigned int *tmds_div)
68970839da6SAurabindo Pillai {
69070839da6SAurabindo Pillai struct dc_stream_state *stream = pipe_ctx->stream;
69170839da6SAurabindo Pillai
692cead9ac8SIlya Bakoulin if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
69370839da6SAurabindo Pillai if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
69470839da6SAurabindo Pillai *tmds_div = PIXEL_RATE_DIV_BY_2;
695cead9ac8SIlya Bakoulin else
69670839da6SAurabindo Pillai *tmds_div = PIXEL_RATE_DIV_BY_4;
69770839da6SAurabindo Pillai } else {
69870839da6SAurabindo Pillai *tmds_div = PIXEL_RATE_DIV_BY_1;
69970839da6SAurabindo Pillai }
700afa91e2dSIlya Bakoulin
70170839da6SAurabindo Pillai if (*tmds_div == PIXEL_RATE_DIV_NA)
702df60dcf5SIlya Bakoulin ASSERT(false);
70370839da6SAurabindo Pillai
70470839da6SAurabindo Pillai }
70570839da6SAurabindo Pillai
enable_stream_timing_calc(struct pipe_ctx * pipe_ctx,struct dc_state * context,struct dc * dc,unsigned int * tmds_div,int * opp_inst,int * opp_cnt,struct pipe_ctx * opp_heads[MAX_PIPES],bool * manual_mode,struct drr_params * params,unsigned int * event_triggers)706652968d9SYihan Zhu static void enable_stream_timing_calc(
70770839da6SAurabindo Pillai struct pipe_ctx *pipe_ctx,
70870839da6SAurabindo Pillai struct dc_state *context,
70970839da6SAurabindo Pillai struct dc *dc,
71070839da6SAurabindo Pillai unsigned int *tmds_div,
71170839da6SAurabindo Pillai int *opp_inst,
712cead9ac8SIlya Bakoulin int *opp_cnt,
71370839da6SAurabindo Pillai struct pipe_ctx *opp_heads[MAX_PIPES],
71470839da6SAurabindo Pillai bool *manual_mode,
715cead9ac8SIlya Bakoulin struct drr_params *params,
71670839da6SAurabindo Pillai unsigned int *event_triggers)
71770839da6SAurabindo Pillai {
718652968d9SYihan Zhu struct dc_stream_state *stream = pipe_ctx->stream;
719652968d9SYihan Zhu int i;
720716ad3c2SSrinivasan Shanmugam
721652968d9SYihan Zhu if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal))
722afa91e2dSIlya Bakoulin dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
72370839da6SAurabindo Pillai
72470839da6SAurabindo Pillai *opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
72570839da6SAurabindo Pillai for (i = 0; i < *opp_cnt; i++)
72670839da6SAurabindo Pillai opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
72770839da6SAurabindo Pillai
72870839da6SAurabindo Pillai if (dc_is_tmds_signal(stream->signal)) {
72970839da6SAurabindo Pillai stream->link->phy_state.symclk_ref_cnts.otg = 1;
73070839da6SAurabindo Pillai if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF)
731652968d9SYihan Zhu stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
73270839da6SAurabindo Pillai else
73370839da6SAurabindo Pillai stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
73470839da6SAurabindo Pillai }
73570839da6SAurabindo Pillai
73670839da6SAurabindo Pillai params->vertical_total_min = stream->adjust.v_total_min;
73770839da6SAurabindo Pillai params->vertical_total_max = stream->adjust.v_total_max;
73870839da6SAurabindo Pillai params->vertical_total_mid = stream->adjust.v_total_mid;
73970839da6SAurabindo Pillai params->vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
74070839da6SAurabindo Pillai
74170839da6SAurabindo Pillai // DRR should set trigger event to monitor surface update event
742652968d9SYihan Zhu if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
743652968d9SYihan Zhu *event_triggers = 0x80;
744652968d9SYihan Zhu }
745652968d9SYihan Zhu
dcn401_enable_stream_timing(struct pipe_ctx * pipe_ctx,struct dc_state * context,struct dc * dc)746652968d9SYihan Zhu enum dc_status dcn401_enable_stream_timing(
747652968d9SYihan Zhu struct pipe_ctx *pipe_ctx,
748652968d9SYihan Zhu struct dc_state *context,
749652968d9SYihan Zhu struct dc *dc)
750652968d9SYihan Zhu {
751652968d9SYihan Zhu struct dce_hwseq *hws = dc->hwseq;
752652968d9SYihan Zhu struct dc_stream_state *stream = pipe_ctx->stream;
753652968d9SYihan Zhu struct drr_params params = {0};
754652968d9SYihan Zhu unsigned int event_triggers = 0;
755652968d9SYihan Zhu int opp_cnt = 1;
756652968d9SYihan Zhu int opp_inst[MAX_PIPES] = {0};
757652968d9SYihan Zhu struct pipe_ctx *opp_heads[MAX_PIPES] = {0};
75870839da6SAurabindo Pillai struct dc_crtc_timing patched_crtc_timing = stream->timing;
75970839da6SAurabindo Pillai bool manual_mode = false;
76070839da6SAurabindo Pillai unsigned int tmds_div = PIXEL_RATE_DIV_NA;
76170839da6SAurabindo Pillai unsigned int unused_div = PIXEL_RATE_DIV_NA;
76270839da6SAurabindo Pillai int odm_slice_width;
763652968d9SYihan Zhu int last_odm_slice_width;
76470839da6SAurabindo Pillai int i;
76570839da6SAurabindo Pillai
766652968d9SYihan Zhu if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
767652968d9SYihan Zhu return DC_OK;
768652968d9SYihan Zhu
769652968d9SYihan Zhu enable_stream_timing_calc(pipe_ctx, context, dc, &tmds_div, opp_inst,
77070839da6SAurabindo Pillai &opp_cnt, opp_heads, &manual_mode, ¶ms, &event_triggers);
77170839da6SAurabindo Pillai
77270839da6SAurabindo Pillai if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
77370839da6SAurabindo Pillai dc->res_pool->dccg->funcs->set_pixel_rate_div(
77470839da6SAurabindo Pillai dc->res_pool->dccg, pipe_ctx->stream_res.tg->inst,
77570839da6SAurabindo Pillai tmds_div, unused_div);
77670839da6SAurabindo Pillai }
77770839da6SAurabindo Pillai
77870839da6SAurabindo Pillai /* TODO check if timing_changed, disable stream if timing changed */
77970839da6SAurabindo Pillai
78070839da6SAurabindo Pillai if (opp_cnt > 1) {
78170839da6SAurabindo Pillai odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
78270839da6SAurabindo Pillai last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
78370839da6SAurabindo Pillai pipe_ctx->stream_res.tg->funcs->set_odm_combine(
78470839da6SAurabindo Pillai pipe_ctx->stream_res.tg,
78570839da6SAurabindo Pillai opp_inst, opp_cnt,
78670839da6SAurabindo Pillai odm_slice_width, last_odm_slice_width);
78770839da6SAurabindo Pillai }
78870839da6SAurabindo Pillai
78970839da6SAurabindo Pillai /* set DTBCLK_P */
79070839da6SAurabindo Pillai if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) {
79170839da6SAurabindo Pillai if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
79270839da6SAurabindo Pillai dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DPREFCLK, pipe_ctx->stream_res.tg->inst);
79370839da6SAurabindo Pillai }
79470839da6SAurabindo Pillai }
79570839da6SAurabindo Pillai
79670839da6SAurabindo Pillai /* HW program guide assume display already disable
79770839da6SAurabindo Pillai * by unplug sequence. OTG assume stop.
79870839da6SAurabindo Pillai */
79970839da6SAurabindo Pillai pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
80070839da6SAurabindo Pillai
80170839da6SAurabindo Pillai if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
80270839da6SAurabindo Pillai pipe_ctx->clock_source,
80370839da6SAurabindo Pillai &pipe_ctx->stream_res.pix_clk_params,
80470839da6SAurabindo Pillai dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
80570839da6SAurabindo Pillai &pipe_ctx->pll_settings)) {
80670839da6SAurabindo Pillai BREAK_TO_DEBUGGER();
807652968d9SYihan Zhu return DC_ERROR_UNEXPECTED;
808652968d9SYihan Zhu }
809652968d9SYihan Zhu
810652968d9SYihan Zhu if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))
811652968d9SYihan Zhu dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
812652968d9SYihan Zhu
81370839da6SAurabindo Pillai /* if we are borrowing from hblank, h_addressable needs to be adjusted */
81470839da6SAurabindo Pillai if (dc->debug.enable_hblank_borrow)
81570839da6SAurabindo Pillai patched_crtc_timing.h_addressable = patched_crtc_timing.h_addressable + pipe_ctx->hblank_borrow;
81670839da6SAurabindo Pillai
81770839da6SAurabindo Pillai pipe_ctx->stream_res.tg->funcs->program_timing(
818652968d9SYihan Zhu pipe_ctx->stream_res.tg,
819652968d9SYihan Zhu &patched_crtc_timing,
820652968d9SYihan Zhu (unsigned int)pipe_ctx->global_sync.dcn4x.vready_offset_pixels,
821652968d9SYihan Zhu (unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
822652968d9SYihan Zhu (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
823652968d9SYihan Zhu (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
824652968d9SYihan Zhu (unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines,
825652968d9SYihan Zhu pipe_ctx->stream->signal,
82670839da6SAurabindo Pillai true);
82770839da6SAurabindo Pillai
828652968d9SYihan Zhu for (i = 0; i < opp_cnt; i++) {
82970839da6SAurabindo Pillai opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
830652968d9SYihan Zhu opp_heads[i]->stream_res.opp,
83170839da6SAurabindo Pillai true);
832652968d9SYihan Zhu opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
833652968d9SYihan Zhu opp_heads[i]->stream_res.opp,
834652968d9SYihan Zhu stream->timing.pixel_encoding,
835652968d9SYihan Zhu resource_is_pipe_type(opp_heads[i], OTG_MASTER));
836652968d9SYihan Zhu }
837652968d9SYihan Zhu
83870839da6SAurabindo Pillai pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
83970839da6SAurabindo Pillai pipe_ctx->stream_res.opp,
84070839da6SAurabindo Pillai true);
84170839da6SAurabindo Pillai
84270839da6SAurabindo Pillai hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
84370839da6SAurabindo Pillai
84470839da6SAurabindo Pillai /* VTG is within DCHUB command block. DCFCLK is always on */
84570839da6SAurabindo Pillai if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
84670839da6SAurabindo Pillai BREAK_TO_DEBUGGER();
84770839da6SAurabindo Pillai return DC_ERROR_UNEXPECTED;
84870839da6SAurabindo Pillai }
84970839da6SAurabindo Pillai
85070839da6SAurabindo Pillai hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);
85170839da6SAurabindo Pillai set_drr_and_clear_adjust_pending(pipe_ctx, stream, ¶ms);
85270839da6SAurabindo Pillai
85370839da6SAurabindo Pillai /* Event triggers and num frames initialized for DRR, but can be
85470839da6SAurabindo Pillai * later updated for PSR use. Note DRR trigger events are generated
855afa91e2dSIlya Bakoulin * regardless of whether num frames met.
856afa91e2dSIlya Bakoulin */
857afa91e2dSIlya Bakoulin if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
858afa91e2dSIlya Bakoulin pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
859afa91e2dSIlya Bakoulin pipe_ctx->stream_res.tg, event_triggers, 2);
860afa91e2dSIlya Bakoulin
861afa91e2dSIlya Bakoulin /* TODO program crtc source select for non-virtual signal*/
862afa91e2dSIlya Bakoulin /* TODO program FMT */
863afa91e2dSIlya Bakoulin /* TODO setup link_enc */
86470839da6SAurabindo Pillai /* TODO set stream attributes */
86570839da6SAurabindo Pillai /* TODO program audio */
86670839da6SAurabindo Pillai /* TODO enable stream if timing changed */
86770839da6SAurabindo Pillai /* TODO unblank stream if DP */
86870839da6SAurabindo Pillai
869df60dcf5SIlya Bakoulin if (dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
870df60dcf5SIlya Bakoulin if (pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable)
871c20da89eSRelja Vojvodic pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg);
87270839da6SAurabindo Pillai }
873cead9ac8SIlya Bakoulin
87470839da6SAurabindo Pillai return DC_OK;
875df60dcf5SIlya Bakoulin }
876df60dcf5SIlya Bakoulin
get_phyd32clk_src(struct dc_link * link)877df60dcf5SIlya Bakoulin static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
878df60dcf5SIlya Bakoulin {
879df60dcf5SIlya Bakoulin switch (link->link_enc->transmitter) {
88070839da6SAurabindo Pillai case TRANSMITTER_UNIPHY_A:
88170839da6SAurabindo Pillai return PHYD32CLKA;
88270839da6SAurabindo Pillai case TRANSMITTER_UNIPHY_B:
88370839da6SAurabindo Pillai return PHYD32CLKB;
88470839da6SAurabindo Pillai case TRANSMITTER_UNIPHY_C:
88570839da6SAurabindo Pillai return PHYD32CLKC;
886cead9ac8SIlya Bakoulin case TRANSMITTER_UNIPHY_D:
88770839da6SAurabindo Pillai return PHYD32CLKD;
888cead9ac8SIlya Bakoulin case TRANSMITTER_UNIPHY_E:
88970839da6SAurabindo Pillai return PHYD32CLKE;
89070839da6SAurabindo Pillai default:
89170839da6SAurabindo Pillai return PHYD32CLKA;
89270839da6SAurabindo Pillai }
89370839da6SAurabindo Pillai }
89470839da6SAurabindo Pillai
dcn401_enable_stream_calc(struct pipe_ctx * pipe_ctx,int * dp_hpo_inst,enum phyd32clk_clock_source * phyd32clk,unsigned int * tmds_div,uint32_t * early_control)89570839da6SAurabindo Pillai static void dcn401_enable_stream_calc(
89670839da6SAurabindo Pillai struct pipe_ctx *pipe_ctx,
89770839da6SAurabindo Pillai int *dp_hpo_inst,
898cead9ac8SIlya Bakoulin enum phyd32clk_clock_source *phyd32clk,
89970839da6SAurabindo Pillai unsigned int *tmds_div,
900cead9ac8SIlya Bakoulin uint32_t *early_control)
90170839da6SAurabindo Pillai {
902c20da89eSRelja Vojvodic
90370839da6SAurabindo Pillai struct dc *dc = pipe_ctx->stream->ctx->dc;
90470839da6SAurabindo Pillai struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
905c20da89eSRelja Vojvodic enum dc_lane_count lane_count =
90670839da6SAurabindo Pillai pipe_ctx->stream->link->cur_link_settings.lane_count;
907c20da89eSRelja Vojvodic uint32_t active_total_with_borders;
90870839da6SAurabindo Pillai
909c20da89eSRelja Vojvodic if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
91070839da6SAurabindo Pillai *dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
91170839da6SAurabindo Pillai
91270839da6SAurabindo Pillai *phyd32clk = get_phyd32clk_src(pipe_ctx->stream->link);
91370839da6SAurabindo Pillai
91470839da6SAurabindo Pillai if (dc_is_tmds_signal(pipe_ctx->stream->signal))
91570839da6SAurabindo Pillai dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
91670839da6SAurabindo Pillai else
91770839da6SAurabindo Pillai *tmds_div = PIXEL_RATE_DIV_BY_1;
91870839da6SAurabindo Pillai
91970839da6SAurabindo Pillai /* enable early control to avoid corruption on DP monitor*/
92070839da6SAurabindo Pillai active_total_with_borders =
92170839da6SAurabindo Pillai timing->h_addressable
92270839da6SAurabindo Pillai + timing->h_border_left
92370839da6SAurabindo Pillai + timing->h_border_right;
92470839da6SAurabindo Pillai
92570839da6SAurabindo Pillai if (lane_count != 0)
92670839da6SAurabindo Pillai *early_control = active_total_with_borders % lane_count;
92770839da6SAurabindo Pillai
92870839da6SAurabindo Pillai if (*early_control == 0)
92970839da6SAurabindo Pillai *early_control = lane_count;
93070839da6SAurabindo Pillai
93170839da6SAurabindo Pillai }
93270839da6SAurabindo Pillai
dcn401_enable_stream(struct pipe_ctx * pipe_ctx)93370839da6SAurabindo Pillai void dcn401_enable_stream(struct pipe_ctx *pipe_ctx)
93470839da6SAurabindo Pillai {
93570839da6SAurabindo Pillai uint32_t early_control = 0;
93670839da6SAurabindo Pillai struct timing_generator *tg = pipe_ctx->stream_res.tg;
93770839da6SAurabindo Pillai struct dc_link *link = pipe_ctx->stream->link;
93870839da6SAurabindo Pillai const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
93970839da6SAurabindo Pillai struct dc *dc = pipe_ctx->stream->ctx->dc;
94070839da6SAurabindo Pillai struct dccg *dccg = dc->res_pool->dccg;
94170839da6SAurabindo Pillai enum phyd32clk_clock_source phyd32clk;
94270839da6SAurabindo Pillai int dp_hpo_inst = 0;
943dd340acdSSrinivasan Shanmugam unsigned int tmds_div = PIXEL_RATE_DIV_NA;
94470839da6SAurabindo Pillai unsigned int unused_div = PIXEL_RATE_DIV_NA;
945dd340acdSSrinivasan Shanmugam struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
94670839da6SAurabindo Pillai struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
94770839da6SAurabindo Pillai
94870839da6SAurabindo Pillai if (!dc->config.unify_link_enc_assignment)
94970839da6SAurabindo Pillai link_enc = link_enc_cfg_get_link_enc(link);
95070839da6SAurabindo Pillai
95170839da6SAurabindo Pillai dcn401_enable_stream_calc(pipe_ctx, &dp_hpo_inst, &phyd32clk,
95270839da6SAurabindo Pillai &tmds_div, &early_control);
95370839da6SAurabindo Pillai
95470839da6SAurabindo Pillai if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) {
95570839da6SAurabindo Pillai if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
95670839da6SAurabindo Pillai dccg->funcs->set_dpstreamclk(dccg, DPREFCLK, tg->inst, dp_hpo_inst);
95770839da6SAurabindo Pillai if (link->cur_link_settings.link_rate == LINK_RATE_UNKNOWN) {
95870839da6SAurabindo Pillai dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
95970839da6SAurabindo Pillai } else {
96070839da6SAurabindo Pillai dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
96170839da6SAurabindo Pillai }
96270839da6SAurabindo Pillai } else {
96370839da6SAurabindo Pillai dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
96470839da6SAurabindo Pillai link_enc->transmitter - TRANSMITTER_UNIPHY_A);
96570839da6SAurabindo Pillai }
96670839da6SAurabindo Pillai }
96770839da6SAurabindo Pillai
96870839da6SAurabindo Pillai if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
96970839da6SAurabindo Pillai dc->res_pool->dccg->funcs->set_pixel_rate_div(
97070839da6SAurabindo Pillai dc->res_pool->dccg,
97170839da6SAurabindo Pillai pipe_ctx->stream_res.tg->inst,
97270839da6SAurabindo Pillai tmds_div,
97370839da6SAurabindo Pillai unused_div);
97470839da6SAurabindo Pillai }
975f9d48a88SWenjing Liu
97670839da6SAurabindo Pillai link_hwss->setup_stream_encoder(pipe_ctx);
97770839da6SAurabindo Pillai
97870839da6SAurabindo Pillai if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
97970839da6SAurabindo Pillai if (dc->hwss.program_dmdata_engine)
98070839da6SAurabindo Pillai dc->hwss.program_dmdata_engine(pipe_ctx);
981f9d48a88SWenjing Liu }
98270839da6SAurabindo Pillai
98370839da6SAurabindo Pillai dc->hwss.update_info_frame(pipe_ctx);
98470839da6SAurabindo Pillai
98570839da6SAurabindo Pillai if (dc_is_dp_signal(pipe_ctx->stream->signal))
986f9d48a88SWenjing Liu dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
987f9d48a88SWenjing Liu
988f9d48a88SWenjing Liu tg->funcs->set_early_control(tg, early_control);
98970839da6SAurabindo Pillai }
99070839da6SAurabindo Pillai
dcn401_setup_hpo_hw_control(const struct dce_hwseq * hws,bool enable)99170839da6SAurabindo Pillai void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
99270839da6SAurabindo Pillai {
99370839da6SAurabindo Pillai REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable);
99470839da6SAurabindo Pillai }
99570839da6SAurabindo Pillai
adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width,struct dc_cursor_position * pos_cpy)99670839da6SAurabindo Pillai void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy)
99770839da6SAurabindo Pillai {
99870839da6SAurabindo Pillai if (cursor_width <= 128) {
99970839da6SAurabindo Pillai pos_cpy->x_hotspot /= 2;
100070839da6SAurabindo Pillai pos_cpy->x_hotspot += 1;
100170839da6SAurabindo Pillai } else {
100270839da6SAurabindo Pillai pos_cpy->x_hotspot /= 2;
100370839da6SAurabindo Pillai pos_cpy->x_hotspot += 2;
100470839da6SAurabindo Pillai }
100570839da6SAurabindo Pillai }
100670839da6SAurabindo Pillai
disable_link_output_symclk_on_tx_off(struct dc_link * link,enum dp_link_encoding link_encoding)100770839da6SAurabindo Pillai static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding)
100870839da6SAurabindo Pillai {
100970839da6SAurabindo Pillai struct dc *dc = link->ctx->dc;
101070839da6SAurabindo Pillai struct pipe_ctx *pipe_ctx = NULL;
101170839da6SAurabindo Pillai uint8_t i;
101270839da6SAurabindo Pillai
101370839da6SAurabindo Pillai for (i = 0; i < MAX_PIPES; i++) {
101470839da6SAurabindo Pillai pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
101570839da6SAurabindo Pillai if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
101670839da6SAurabindo Pillai pipe_ctx->clock_source->funcs->program_pix_clk(
101770839da6SAurabindo Pillai pipe_ctx->clock_source,
1018f9d48a88SWenjing Liu &pipe_ctx->stream_res.pix_clk_params,
101997dc6a48SAlex Hung link_encoding,
10200c0a1943SChris Park &pipe_ctx->pll_settings);
102112e4ec5dSMeera Patel break;
102270839da6SAurabindo Pillai }
102370839da6SAurabindo Pillai }
1024f9d48a88SWenjing Liu }
1025f9d48a88SWenjing Liu
dcn401_disable_link_output(struct dc_link * link,const struct link_resource * link_res,enum signal_type signal)1026f9d48a88SWenjing Liu void dcn401_disable_link_output(struct dc_link *link,
102770839da6SAurabindo Pillai const struct link_resource *link_res,
102870839da6SAurabindo Pillai enum signal_type signal)
102970839da6SAurabindo Pillai {
103070839da6SAurabindo Pillai struct dc *dc = link->ctx->dc;
103170839da6SAurabindo Pillai const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1032f9d48a88SWenjing Liu struct dmcu *dmcu = dc->res_pool->dmcu;
103370839da6SAurabindo Pillai
103470839da6SAurabindo Pillai if (signal == SIGNAL_TYPE_EDP &&
103570839da6SAurabindo Pillai link->dc->hwss.edp_backlight_control &&
103670839da6SAurabindo Pillai !link->skip_implict_edp_power_control)
103770839da6SAurabindo Pillai link->dc->hwss.edp_backlight_control(link, false);
103870839da6SAurabindo Pillai else if (dmcu != NULL && dmcu->funcs->lock_phy)
103970839da6SAurabindo Pillai dmcu->funcs->lock_phy(dmcu);
104070839da6SAurabindo Pillai
104170839da6SAurabindo Pillai if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) {
1042f9d48a88SWenjing Liu disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
1043f9d48a88SWenjing Liu link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
1044f9d48a88SWenjing Liu } else {
104570839da6SAurabindo Pillai link_hwss->disable_link_output(link, link_res, signal);
104670839da6SAurabindo Pillai link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
104770839da6SAurabindo Pillai }
1048f9d48a88SWenjing Liu
1049f9d48a88SWenjing Liu if (signal == SIGNAL_TYPE_EDP &&
105070839da6SAurabindo Pillai link->dc->hwss.edp_backlight_control &&
10513c6c8d1aSDillon Varone !link->skip_implict_edp_power_control)
10523c6c8d1aSDillon Varone link->dc->hwss.edp_power_control(link, false);
10533c6c8d1aSDillon Varone else if (dmcu != NULL && dmcu->funcs->lock_phy)
10543c6c8d1aSDillon Varone dmcu->funcs->unlock_phy(dmcu);
10553c6c8d1aSDillon Varone
10563c6c8d1aSDillon Varone dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
10573c6c8d1aSDillon Varone }
105870839da6SAurabindo Pillai
dcn401_set_cursor_position(struct pipe_ctx * pipe_ctx)105970839da6SAurabindo Pillai void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx)
106070839da6SAurabindo Pillai {
106170839da6SAurabindo Pillai struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
106270839da6SAurabindo Pillai struct hubp *hubp = pipe_ctx->plane_res.hubp;
106370839da6SAurabindo Pillai struct dpp *dpp = pipe_ctx->plane_res.dpp;
106470839da6SAurabindo Pillai struct dc_cursor_mi_param param = {
106570839da6SAurabindo Pillai .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
106670839da6SAurabindo Pillai .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz,
106770839da6SAurabindo Pillai .viewport = pipe_ctx->plane_res.scl_data.viewport,
106870839da6SAurabindo Pillai .recout = pipe_ctx->plane_res.scl_data.recout,
106970839da6SAurabindo Pillai .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
107070839da6SAurabindo Pillai .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert,
107170839da6SAurabindo Pillai .rotation = pipe_ctx->plane_state->rotation,
107270839da6SAurabindo Pillai .mirror = pipe_ctx->plane_state->horizontal_mirror,
107370839da6SAurabindo Pillai .stream = pipe_ctx->stream
107470839da6SAurabindo Pillai };
10750c0a1943SChris Park struct rect odm_slice_src = { 0 };
10760c0a1943SChris Park bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) ||
10770c0a1943SChris Park (pipe_ctx->prev_odm_pipe != NULL);
10780c0a1943SChris Park int prev_odm_width = 0;
107970839da6SAurabindo Pillai struct pipe_ctx *prev_odm_pipe = NULL;
108070839da6SAurabindo Pillai bool mpc_combine_on = false;
10810c0a1943SChris Park int bottom_pipe_x_pos = 0;
108263ab80d9SRafal Ostrowski
108363ab80d9SRafal Ostrowski int x_pos = pos_cpy.x;
108463ab80d9SRafal Ostrowski int y_pos = pos_cpy.y;
108563ab80d9SRafal Ostrowski int recout_x_pos = 0;
108663ab80d9SRafal Ostrowski int recout_y_pos = 0;
108770839da6SAurabindo Pillai
108870839da6SAurabindo Pillai if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) {
108970839da6SAurabindo Pillai if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) ||
1090f9d48a88SWenjing Liu (pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) {
1091f9d48a88SWenjing Liu mpc_combine_on = true;
1092f9d48a88SWenjing Liu }
109370839da6SAurabindo Pillai }
1094f9d48a88SWenjing Liu
1095f9d48a88SWenjing Liu /* DCN4 moved cursor composition after Scaler, so in HW it is in
1096f9d48a88SWenjing Liu * recout space and for HW Cursor position programming need to
1097f9d48a88SWenjing Liu * translate to recout space.
1098f9d48a88SWenjing Liu *
109970839da6SAurabindo Pillai * Cursor X and Y position programmed into HW can't be negative,
110070839da6SAurabindo Pillai * in fact it is X, Y coordinate shifted for the HW Cursor Hot spot
110170839da6SAurabindo Pillai * position that goes into HW X and Y coordinates while HW Hot spot
110270839da6SAurabindo Pillai * X and Y coordinates are length relative to the cursor top left
110370839da6SAurabindo Pillai * corner, hotspot must be smaller than the cursor size.
110470839da6SAurabindo Pillai *
110570839da6SAurabindo Pillai * DMs/DC interface for Cursor position is in stream->src space, and
110670839da6SAurabindo Pillai * DMs supposed to transform Cursor coordinates to stream->src space,
110770839da6SAurabindo Pillai * then here we need to translate Cursor coordinates to stream->dst
110870839da6SAurabindo Pillai * space, as now in HW, Cursor coordinates are in per pipe recout
110970839da6SAurabindo Pillai * space, and for the given pipe valid coordinates are only in range
111070839da6SAurabindo Pillai * from 0,0 - recout width, recout height space.
111170839da6SAurabindo Pillai * If certain pipe combining is in place, need to further adjust per
111270839da6SAurabindo Pillai * pipe to make sure each pipe enabling cursor on its part of the
1113bd00b29bSDanny Wang * screen.
111470839da6SAurabindo Pillai */
111570839da6SAurabindo Pillai x_pos = pipe_ctx->stream->dst.x + x_pos * pipe_ctx->stream->dst.width /
111670839da6SAurabindo Pillai pipe_ctx->stream->src.width;
111770839da6SAurabindo Pillai y_pos = pipe_ctx->stream->dst.y + y_pos * pipe_ctx->stream->dst.height /
111870839da6SAurabindo Pillai pipe_ctx->stream->src.height;
111970839da6SAurabindo Pillai
112070839da6SAurabindo Pillai /* If the cursor's source viewport is clipped then we need to
112170839da6SAurabindo Pillai * translate the cursor to appear in the correct position on
112270839da6SAurabindo Pillai * the screen.
112370839da6SAurabindo Pillai *
112470839da6SAurabindo Pillai * This translation isn't affected by scaling so it needs to be
112570839da6SAurabindo Pillai * done *after* we adjust the position for the scale factor.
112670839da6SAurabindo Pillai *
112770839da6SAurabindo Pillai * This is only done by opt-in for now since there are still
112870839da6SAurabindo Pillai * some usecases like tiled display that might enable the
112970839da6SAurabindo Pillai * cursor on both streams while expecting dc to clip it.
113070839da6SAurabindo Pillai */
1131cd80e7eeSAlex Hung if (pos_cpy.translate_by_source) {
1132cd80e7eeSAlex Hung x_pos += pipe_ctx->plane_state->src_rect.x;
113370839da6SAurabindo Pillai y_pos += pipe_ctx->plane_state->src_rect.y;
113470839da6SAurabindo Pillai }
113570839da6SAurabindo Pillai
113670839da6SAurabindo Pillai /* Adjust for ODM Combine
113770839da6SAurabindo Pillai * next/prev_odm_offset is to account for scaled modes that have underscan
113870839da6SAurabindo Pillai */
113970839da6SAurabindo Pillai if (odm_combine_on) {
114070839da6SAurabindo Pillai prev_odm_pipe = pipe_ctx->prev_odm_pipe;
114170839da6SAurabindo Pillai
114270839da6SAurabindo Pillai while (prev_odm_pipe != NULL) {
114370839da6SAurabindo Pillai odm_slice_src = resource_get_odm_slice_src_rect(prev_odm_pipe);
114470839da6SAurabindo Pillai prev_odm_width += odm_slice_src.width;
114570839da6SAurabindo Pillai prev_odm_pipe = prev_odm_pipe->prev_odm_pipe;
114670839da6SAurabindo Pillai }
114770839da6SAurabindo Pillai
114870839da6SAurabindo Pillai x_pos -= (prev_odm_width);
114970839da6SAurabindo Pillai }
115070839da6SAurabindo Pillai
115170839da6SAurabindo Pillai /* If the position is negative then we need to add to the hotspot
115270839da6SAurabindo Pillai * to fix cursor size between ODM slices
115370839da6SAurabindo Pillai */
115470839da6SAurabindo Pillai
115570839da6SAurabindo Pillai if (x_pos < 0) {
115670839da6SAurabindo Pillai pos_cpy.x_hotspot -= x_pos;
115770839da6SAurabindo Pillai if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION)
115870839da6SAurabindo Pillai adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy);
115970839da6SAurabindo Pillai x_pos = 0;
116070839da6SAurabindo Pillai }
116170839da6SAurabindo Pillai
116270839da6SAurabindo Pillai if (y_pos < 0) {
116370839da6SAurabindo Pillai pos_cpy.y_hotspot -= y_pos;
116470839da6SAurabindo Pillai y_pos = 0;
116570839da6SAurabindo Pillai }
116670839da6SAurabindo Pillai
116770839da6SAurabindo Pillai /* If the position on bottom MPC pipe is negative then we need to add to the hotspot and
116870839da6SAurabindo Pillai * adjust x_pos on bottom pipe to make cursor visible when crossing between MPC slices.
116970839da6SAurabindo Pillai */
117070839da6SAurabindo Pillai if (mpc_combine_on &&
117170839da6SAurabindo Pillai pipe_ctx->top_pipe &&
117270839da6SAurabindo Pillai (pipe_ctx == pipe_ctx->top_pipe->bottom_pipe)) {
117370839da6SAurabindo Pillai
117470839da6SAurabindo Pillai bottom_pipe_x_pos = x_pos - pipe_ctx->plane_res.scl_data.recout.x;
117570839da6SAurabindo Pillai if (bottom_pipe_x_pos < 0) {
117670839da6SAurabindo Pillai x_pos = pipe_ctx->plane_res.scl_data.recout.x;
117770839da6SAurabindo Pillai pos_cpy.x_hotspot -= bottom_pipe_x_pos;
117870839da6SAurabindo Pillai if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION)
117970839da6SAurabindo Pillai adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy);
118070839da6SAurabindo Pillai }
118170839da6SAurabindo Pillai }
118270839da6SAurabindo Pillai
118370839da6SAurabindo Pillai pos_cpy.x = (uint32_t)x_pos;
118470839da6SAurabindo Pillai pos_cpy.y = (uint32_t)y_pos;
118570839da6SAurabindo Pillai
118670839da6SAurabindo Pillai if (pos_cpy.enable && resource_can_pipe_disable_cursor(pipe_ctx))
118770839da6SAurabindo Pillai pos_cpy.enable = false;
118870839da6SAurabindo Pillai
118970839da6SAurabindo Pillai x_pos = pos_cpy.x - param.recout.x;
119070839da6SAurabindo Pillai y_pos = pos_cpy.y - param.recout.y;
119170839da6SAurabindo Pillai
119270839da6SAurabindo Pillai recout_x_pos = x_pos - pos_cpy.x_hotspot;
119370839da6SAurabindo Pillai recout_y_pos = y_pos - pos_cpy.y_hotspot;
119470839da6SAurabindo Pillai
119570839da6SAurabindo Pillai if (recout_x_pos >= (int)param.recout.width)
119670839da6SAurabindo Pillai pos_cpy.enable = false; /* not visible beyond right edge*/
119770839da6SAurabindo Pillai
119870839da6SAurabindo Pillai if (recout_y_pos >= (int)param.recout.height)
119970839da6SAurabindo Pillai pos_cpy.enable = false; /* not visible beyond bottom edge*/
120070839da6SAurabindo Pillai
120170839da6SAurabindo Pillai if (recout_x_pos + (int)hubp->curs_attr.width <= 0)
120270839da6SAurabindo Pillai pos_cpy.enable = false; /* not visible beyond left edge*/
120370839da6SAurabindo Pillai
12049243e0e2SAlex Hung if (recout_y_pos + (int)hubp->curs_attr.height <= 0)
120570839da6SAurabindo Pillai pos_cpy.enable = false; /* not visible beyond top edge*/
120670839da6SAurabindo Pillai
1207d2957868SPeichen Huang hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m);
1208872c0de3SWenjing Liu dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height);
120970839da6SAurabindo Pillai }
1210d2957868SPeichen Huang
dcn401_check_no_memory_request_for_cab(struct dc * dc)1211d2957868SPeichen Huang static bool dcn401_check_no_memory_request_for_cab(struct dc *dc)
1212d2957868SPeichen Huang {
121370839da6SAurabindo Pillai int i;
121470839da6SAurabindo Pillai
121570839da6SAurabindo Pillai /* First, check no-memory-request case */
121670839da6SAurabindo Pillai for (i = 0; i < dc->current_state->stream_count; i++) {
121770839da6SAurabindo Pillai if ((dc->current_state->stream_status[i].plane_count) &&
121870839da6SAurabindo Pillai (dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED))
12198058061eSBrendan Tam /* Fail eligibility on a visible stream */
12208058061eSBrendan Tam return false;
12218058061eSBrendan Tam }
122270839da6SAurabindo Pillai
12238058061eSBrendan Tam return true;
122470839da6SAurabindo Pillai }
1225872c0de3SWenjing Liu
dcn401_calculate_cab_allocation(struct dc * dc,struct dc_state * ctx)1226872c0de3SWenjing Liu static uint32_t dcn401_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx)
122770839da6SAurabindo Pillai {
122870839da6SAurabindo Pillai int i;
122970839da6SAurabindo Pillai uint8_t num_ways = 0;
123070839da6SAurabindo Pillai uint32_t mall_ss_size_bytes = 0;
123170839da6SAurabindo Pillai
123270839da6SAurabindo Pillai mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes;
123370839da6SAurabindo Pillai // TODO add additional logic for PSR active stream exclusion optimization
123470839da6SAurabindo Pillai // mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes;
123570839da6SAurabindo Pillai
123670839da6SAurabindo Pillai // Include cursor size for CAB allocation
123770839da6SAurabindo Pillai for (i = 0; i < dc->res_pool->pipe_count; i++) {
123870839da6SAurabindo Pillai struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i];
123970839da6SAurabindo Pillai
124070839da6SAurabindo Pillai if (!pipe->stream || !pipe->plane_state)
124170839da6SAurabindo Pillai continue;
124270839da6SAurabindo Pillai
124370839da6SAurabindo Pillai mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false);
124470839da6SAurabindo Pillai }
124570839da6SAurabindo Pillai
124670839da6SAurabindo Pillai // Convert number of cache lines required to number of ways
124770839da6SAurabindo Pillai if (dc->debug.force_mall_ss_num_ways > 0)
124870839da6SAurabindo Pillai num_ways = dc->debug.force_mall_ss_num_ways;
124970839da6SAurabindo Pillai else if (dc->res_pool->funcs->calculate_mall_ways_from_bytes)
125070839da6SAurabindo Pillai num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, mall_ss_size_bytes);
125170839da6SAurabindo Pillai else
125270839da6SAurabindo Pillai num_ways = 0;
125370839da6SAurabindo Pillai
125470839da6SAurabindo Pillai return num_ways;
125570839da6SAurabindo Pillai }
125670839da6SAurabindo Pillai
dcn401_apply_idle_power_optimizations(struct dc * dc,bool enable)125770839da6SAurabindo Pillai bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable)
1258cbe9d7c1SNevenko Stupar {
1259cbe9d7c1SNevenko Stupar union dmub_rb_cmd cmd;
1260cbe9d7c1SNevenko Stupar uint8_t ways, i;
1261cbe9d7c1SNevenko Stupar int j;
1262cbe9d7c1SNevenko Stupar bool mall_ss_unsupported = false;
1263cbe9d7c1SNevenko Stupar struct dc_plane_state *plane = NULL;
1264cbe9d7c1SNevenko Stupar
1265cbe9d7c1SNevenko Stupar if (!dc->ctx->dmub_srv || !dc->current_state)
1266cbe9d7c1SNevenko Stupar return false;
1267cbe9d7c1SNevenko Stupar
1268cbe9d7c1SNevenko Stupar for (i = 0; i < dc->current_state->stream_count; i++) {
12699b68445eSRyan Seto /* MALL SS messaging is not supported with PSR at this time */
12709b68445eSRyan Seto if (dc->current_state->streams[i] != NULL &&
12719b68445eSRyan Seto dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) {
12729b68445eSRyan Seto DC_LOG_MALL("MALL SS not supported with PSR at this time\n");
12739b68445eSRyan Seto return false;
12749b68445eSRyan Seto }
12759b68445eSRyan Seto }
12769b68445eSRyan Seto
12779b68445eSRyan Seto memset(&cmd, 0, sizeof(cmd));
12789b68445eSRyan Seto cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
12799b68445eSRyan Seto cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
12809b68445eSRyan Seto
12819b68445eSRyan Seto if (enable) {
12829b68445eSRyan Seto if (dcn401_check_no_memory_request_for_cab(dc)) {
12839b68445eSRyan Seto /* 1. Check no memory request case for CAB.
12849b68445eSRyan Seto * If no memory request case, send CAB_ACTION NO_DCN_REQ DMUB message
12859b68445eSRyan Seto */
12869b68445eSRyan Seto DC_LOG_MALL("sending CAB action NO_DCN_REQ\n");
12879b68445eSRyan Seto cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ;
12889b68445eSRyan Seto } else {
12899b68445eSRyan Seto /* 2. Check if all surfaces can fit in CAB.
12909b68445eSRyan Seto * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message
12919b68445eSRyan Seto * and configure HUBP's to fetch from MALL
12929b68445eSRyan Seto */
12939b68445eSRyan Seto ways = dcn401_calculate_cab_allocation(dc, dc->current_state);
12949b68445eSRyan Seto
12959b68445eSRyan Seto /* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo,
12969b68445eSRyan Seto * or TMZ surface, don't try to enter MALL.
12979b68445eSRyan Seto */
12989b68445eSRyan Seto for (i = 0; i < dc->current_state->stream_count; i++) {
12999b68445eSRyan Seto for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
13009b68445eSRyan Seto plane = dc->current_state->stream_status[i].plane_states[j];
13019b68445eSRyan Seto
13029b68445eSRyan Seto if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO ||
13039b68445eSRyan Seto plane->address.tmz_surface) {
13049b68445eSRyan Seto mall_ss_unsupported = true;
13059b68445eSRyan Seto break;
13069b68445eSRyan Seto }
13079b68445eSRyan Seto }
13089b68445eSRyan Seto if (mall_ss_unsupported)
13099b68445eSRyan Seto break;
13109b68445eSRyan Seto }
13119b68445eSRyan Seto if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) {
13129b68445eSRyan Seto cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB;
13139b68445eSRyan Seto cmd.cab.cab_alloc_ways = ways;
13149b68445eSRyan Seto DC_LOG_MALL("cab allocation: %d ways. CAB action: DCN_SS_FIT_IN_CAB\n", ways);
13159b68445eSRyan Seto } else {
13169b68445eSRyan Seto cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_NOT_FIT_IN_CAB;
13179b68445eSRyan Seto DC_LOG_MALL("frame does not fit in CAB: %d ways required. CAB action: DCN_SS_NOT_FIT_IN_CAB\n", ways);
13189b68445eSRyan Seto }
13199b68445eSRyan Seto }
13209b68445eSRyan Seto } else {
132170839da6SAurabindo Pillai /* Disable CAB */
132270839da6SAurabindo Pillai cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION;
132370839da6SAurabindo Pillai DC_LOG_MALL("idle optimization disabled\n");
132470839da6SAurabindo Pillai }
132570839da6SAurabindo Pillai
132670839da6SAurabindo Pillai dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
132770839da6SAurabindo Pillai
132870839da6SAurabindo Pillai return true;
132970839da6SAurabindo Pillai }
133070839da6SAurabindo Pillai
dcn401_wait_for_dcc_meta_propagation(const struct dc * dc,const struct pipe_ctx * top_pipe)133170839da6SAurabindo Pillai void dcn401_wait_for_dcc_meta_propagation(const struct dc *dc,
133270839da6SAurabindo Pillai const struct pipe_ctx *top_pipe)
133370839da6SAurabindo Pillai {
1334ee8287e0SNevenko Stupar bool is_wait_needed = false;
1335ee8287e0SNevenko Stupar const struct pipe_ctx *pipe_ctx = top_pipe;
133670839da6SAurabindo Pillai
13374e8eac98SAlvin Lee /* check if any surfaces are updating address while using flip immediate and dcc */
133870839da6SAurabindo Pillai while (pipe_ctx != NULL) {
133970839da6SAurabindo Pillai if (pipe_ctx->plane_state &&
134070839da6SAurabindo Pillai pipe_ctx->plane_state->dcc.enable &&
1341dd9d8c61SSridevi Arvindekar pipe_ctx->plane_state->flip_immediate &&
1342cbe9d7c1SNevenko Stupar pipe_ctx->plane_state->update_flags.bits.addr_update) {
1343cbe9d7c1SNevenko Stupar is_wait_needed = true;
134470839da6SAurabindo Pillai break;
134570839da6SAurabindo Pillai }
134670839da6SAurabindo Pillai
1347ee8287e0SNevenko Stupar /* check next pipe */
1348ee8287e0SNevenko Stupar pipe_ctx = pipe_ctx->bottom_pipe;
134970839da6SAurabindo Pillai }
1350cbe9d7c1SNevenko Stupar
1351cbe9d7c1SNevenko Stupar if (is_wait_needed && dc->debug.dcc_meta_propagation_delay_us > 0) {
1352cbe9d7c1SNevenko Stupar udelay(dc->debug.dcc_meta_propagation_delay_us);
1353cbe9d7c1SNevenko Stupar }
1354cbe9d7c1SNevenko Stupar }
1355cbe9d7c1SNevenko Stupar
dcn401_prepare_bandwidth(struct dc * dc,struct dc_state * context)1356cbe9d7c1SNevenko Stupar void dcn401_prepare_bandwidth(struct dc *dc,
1357ee8287e0SNevenko Stupar struct dc_state *context)
135870839da6SAurabindo Pillai {
135970839da6SAurabindo Pillai struct hubbub *hubbub = dc->res_pool->hubbub;
136070839da6SAurabindo Pillai bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support;
136170839da6SAurabindo Pillai unsigned int compbuf_size = 0;
136270839da6SAurabindo Pillai
136370839da6SAurabindo Pillai /* Any transition into P-State support should disable MCLK switching first to avoid hangs */
136470839da6SAurabindo Pillai if (p_state_change_support) {
136570839da6SAurabindo Pillai dc->optimized_required = true;
136670839da6SAurabindo Pillai context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
136770839da6SAurabindo Pillai }
136870839da6SAurabindo Pillai
136970839da6SAurabindo Pillai if (dc->clk_mgr->dc_mode_softmax_enabled)
137070839da6SAurabindo Pillai if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
137170839da6SAurabindo Pillai context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
137270839da6SAurabindo Pillai dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
137370839da6SAurabindo Pillai
137470839da6SAurabindo Pillai /* Increase clocks */
137570839da6SAurabindo Pillai dc->clk_mgr->funcs->update_clocks(
137670839da6SAurabindo Pillai dc->clk_mgr,
1377c2edec16SSridevi context,
137870839da6SAurabindo Pillai false);
1379c2edec16SSridevi
138070839da6SAurabindo Pillai /* program dchubbub watermarks:
138170839da6SAurabindo Pillai * For assigning wm_optimized_required, use |= operator since we don't want
1382ee8287e0SNevenko Stupar * to clear the value if the optimize has not happened yet
138370839da6SAurabindo Pillai */
138470839da6SAurabindo Pillai dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub,
138570839da6SAurabindo Pillai &context->bw_ctx.bw.dcn.watermarks,
138670839da6SAurabindo Pillai dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
138770839da6SAurabindo Pillai false);
138870839da6SAurabindo Pillai /* update timeout thresholds */
138970839da6SAurabindo Pillai if (hubbub->funcs->program_arbiter) {
139070839da6SAurabindo Pillai dc->wm_optimized_required |= hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, false);
139170839da6SAurabindo Pillai }
139270839da6SAurabindo Pillai
139370839da6SAurabindo Pillai /* decrease compbuf size */
139470839da6SAurabindo Pillai if (hubbub->funcs->program_compbuf_segments) {
139570839da6SAurabindo Pillai compbuf_size = context->bw_ctx.bw.dcn.arb_regs.compbuf_size;
139670839da6SAurabindo Pillai dc->wm_optimized_required |= (compbuf_size != dc->current_state->bw_ctx.bw.dcn.arb_regs.compbuf_size);
139770839da6SAurabindo Pillai
139844b9a7cfSAlvin Lee hubbub->funcs->program_compbuf_segments(hubbub, compbuf_size, false);
139944b9a7cfSAlvin Lee }
140044b9a7cfSAlvin Lee
140170839da6SAurabindo Pillai if (dc->debug.fams2_config.bits.enable) {
1402dd9d8c61SSridevi Arvindekar dcn401_fams2_global_control_lock(dc, context, true);
140370839da6SAurabindo Pillai dcn401_fams2_update_config(dc, context, false);
140470839da6SAurabindo Pillai dcn401_fams2_global_control_lock(dc, context, false);
14054e8eac98SAlvin Lee }
14064e8eac98SAlvin Lee
140770839da6SAurabindo Pillai if (p_state_change_support != context->bw_ctx.bw.dcn.clk.p_state_change_support) {
140870839da6SAurabindo Pillai /* After disabling P-State, restore the original value to ensure we get the correct P-State
140970839da6SAurabindo Pillai * on the next optimize. */
14104e8eac98SAlvin Lee context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support;
141170839da6SAurabindo Pillai }
141270839da6SAurabindo Pillai }
141351dbe023SNevenko Stupar
dcn401_optimize_bandwidth(struct dc * dc,struct dc_state * context)141451dbe023SNevenko Stupar void dcn401_optimize_bandwidth(
141551dbe023SNevenko Stupar struct dc *dc,
141651dbe023SNevenko Stupar struct dc_state *context)
141751dbe023SNevenko Stupar {
141851dbe023SNevenko Stupar int i;
1419cbe9d7c1SNevenko Stupar struct hubbub *hubbub = dc->res_pool->hubbub;
1420cbe9d7c1SNevenko Stupar
142151dbe023SNevenko Stupar /* enable fams2 if needed */
142251dbe023SNevenko Stupar if (dc->debug.fams2_config.bits.enable) {
142351dbe023SNevenko Stupar dcn401_fams2_global_control_lock(dc, context, true);
142451dbe023SNevenko Stupar dcn401_fams2_update_config(dc, context, true);
142551dbe023SNevenko Stupar dcn401_fams2_global_control_lock(dc, context, false);
142651dbe023SNevenko Stupar }
142751dbe023SNevenko Stupar
142851dbe023SNevenko Stupar /* program dchubbub watermarks */
1429cbe9d7c1SNevenko Stupar hubbub->funcs->program_watermarks(hubbub,
1430cbe9d7c1SNevenko Stupar &context->bw_ctx.bw.dcn.watermarks,
1431cbe9d7c1SNevenko Stupar dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
1432cbe9d7c1SNevenko Stupar true);
1433cbe9d7c1SNevenko Stupar /* update timeout thresholds */
1434cbe9d7c1SNevenko Stupar if (hubbub->funcs->program_arbiter) {
1435cbe9d7c1SNevenko Stupar hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, true);
1436cbe9d7c1SNevenko Stupar }
1437cbe9d7c1SNevenko Stupar
1438cbe9d7c1SNevenko Stupar if (dc->clk_mgr->dc_mode_softmax_enabled)
1439cbe9d7c1SNevenko Stupar if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
1440cbe9d7c1SNevenko Stupar context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
1441cbe9d7c1SNevenko Stupar dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
1442cbe9d7c1SNevenko Stupar
1443cbe9d7c1SNevenko Stupar /* increase compbuf size */
1444cbe9d7c1SNevenko Stupar if (hubbub->funcs->program_compbuf_segments)
144570839da6SAurabindo Pillai hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true);
144670839da6SAurabindo Pillai
144770839da6SAurabindo Pillai dc->clk_mgr->funcs->update_clocks(
14483c50bf21SPeterson Guo dc->clk_mgr,
144970839da6SAurabindo Pillai context,
145070839da6SAurabindo Pillai true);
1451ee8287e0SNevenko Stupar if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) {
1452ee8287e0SNevenko Stupar for (i = 0; i < dc->res_pool->pipe_count; ++i) {
145370839da6SAurabindo Pillai struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1454ee8287e0SNevenko Stupar
1455ee8287e0SNevenko Stupar if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank
145670839da6SAurabindo Pillai && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max
1457ee8287e0SNevenko Stupar && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)
1458ee8287e0SNevenko Stupar pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,
145970839da6SAurabindo Pillai pipe_ctx->dlg_regs.min_dst_y_next_start);
1460ee8287e0SNevenko Stupar }
1461ee8287e0SNevenko Stupar }
146270839da6SAurabindo Pillai }
1463ee8287e0SNevenko Stupar
dcn401_fams2_global_control_lock(struct dc * dc,struct dc_state * context,bool lock)1464ee8287e0SNevenko Stupar void dcn401_fams2_global_control_lock(struct dc *dc,
146570839da6SAurabindo Pillai struct dc_state *context,
1466ee8287e0SNevenko Stupar bool lock)
1467ee8287e0SNevenko Stupar {
146870839da6SAurabindo Pillai /* use always for now */
146970839da6SAurabindo Pillai union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
147070839da6SAurabindo Pillai
147170839da6SAurabindo Pillai if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable)
147270839da6SAurabindo Pillai return;
147370839da6SAurabindo Pillai
147470839da6SAurabindo Pillai hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
147570839da6SAurabindo Pillai hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
147670839da6SAurabindo Pillai hw_lock_cmd.bits.lock = lock;
147770839da6SAurabindo Pillai hw_lock_cmd.bits.should_release = !lock;
147870839da6SAurabindo Pillai dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
147970839da6SAurabindo Pillai }
148070839da6SAurabindo Pillai
dcn401_fams2_global_control_lock_fast(union block_sequence_params * params)148170839da6SAurabindo Pillai void dcn401_fams2_global_control_lock_fast(union block_sequence_params *params)
148270839da6SAurabindo Pillai {
148370839da6SAurabindo Pillai struct dc *dc = params->fams2_global_control_lock_fast_params.dc;
148470839da6SAurabindo Pillai bool lock = params->fams2_global_control_lock_fast_params.lock;
148570839da6SAurabindo Pillai
148670839da6SAurabindo Pillai if (params->fams2_global_control_lock_fast_params.is_required) {
148770839da6SAurabindo Pillai union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
148870839da6SAurabindo Pillai
148970839da6SAurabindo Pillai hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
149070839da6SAurabindo Pillai hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
149170839da6SAurabindo Pillai hw_lock_cmd.bits.lock = lock;
149270839da6SAurabindo Pillai hw_lock_cmd.bits.should_release = !lock;
149370839da6SAurabindo Pillai dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
149470839da6SAurabindo Pillai }
149570839da6SAurabindo Pillai }
149670839da6SAurabindo Pillai
dcn401_fams2_update_config(struct dc * dc,struct dc_state * context,bool enable)149770839da6SAurabindo Pillai void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool enable)
149870839da6SAurabindo Pillai {
149970839da6SAurabindo Pillai bool fams2_required;
150070839da6SAurabindo Pillai
150170839da6SAurabindo Pillai if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable)
150270839da6SAurabindo Pillai return;
150370839da6SAurabindo Pillai
150470839da6SAurabindo Pillai fams2_required = context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
150570839da6SAurabindo Pillai
150670839da6SAurabindo Pillai dc_dmub_srv_fams2_update_config(dc, context, enable && fams2_required);
150770839da6SAurabindo Pillai }
150870839da6SAurabindo Pillai
update_dsc_for_odm_change(struct dc * dc,struct dc_state * context,struct pipe_ctx * otg_master)150970839da6SAurabindo Pillai static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context,
151070839da6SAurabindo Pillai struct pipe_ctx *otg_master)
151170839da6SAurabindo Pillai {
151270839da6SAurabindo Pillai int i;
151370839da6SAurabindo Pillai struct pipe_ctx *old_pipe;
151470839da6SAurabindo Pillai struct pipe_ctx *new_pipe;
151570839da6SAurabindo Pillai struct pipe_ctx *old_opp_heads[MAX_PIPES];
151670839da6SAurabindo Pillai struct pipe_ctx *old_otg_master;
151770839da6SAurabindo Pillai int old_opp_head_count = 0;
151870839da6SAurabindo Pillai
151970839da6SAurabindo Pillai old_otg_master = &dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx];
152070839da6SAurabindo Pillai
152170839da6SAurabindo Pillai if (resource_is_pipe_type(old_otg_master, OTG_MASTER)) {
152270839da6SAurabindo Pillai old_opp_head_count = resource_get_opp_heads_for_otg_master(old_otg_master,
152370839da6SAurabindo Pillai &dc->current_state->res_ctx,
152470839da6SAurabindo Pillai old_opp_heads);
152570839da6SAurabindo Pillai } else {
152670839da6SAurabindo Pillai // DC cannot assume that the current state and the new state
152770839da6SAurabindo Pillai // share the same OTG pipe since this is not true when called
152870839da6SAurabindo Pillai // in the context of a commit stream not checked. Hence, set
152970839da6SAurabindo Pillai // old_otg_master to NULL to skip the DSC configuration.
153070839da6SAurabindo Pillai old_otg_master = NULL;
153170839da6SAurabindo Pillai }
153270839da6SAurabindo Pillai
15338c4f9e46SAurabindo Pillai
15348c4f9e46SAurabindo Pillai if (otg_master->stream_res.dsc)
153570839da6SAurabindo Pillai dcn32_update_dsc_on_stream(otg_master,
153670839da6SAurabindo Pillai otg_master->stream->timing.flags.DSC);
15378c4f9e46SAurabindo Pillai if (old_otg_master && old_otg_master->stream_res.dsc) {
153870839da6SAurabindo Pillai for (i = 0; i < old_opp_head_count; i++) {
153970839da6SAurabindo Pillai old_pipe = old_opp_heads[i];
154070839da6SAurabindo Pillai new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx];
154170839da6SAurabindo Pillai if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc)
154270839da6SAurabindo Pillai old_pipe->stream_res.dsc->funcs->dsc_disconnect(
154370839da6SAurabindo Pillai old_pipe->stream_res.dsc);
154470839da6SAurabindo Pillai }
154570839da6SAurabindo Pillai }
15468c4f9e46SAurabindo Pillai }
154770839da6SAurabindo Pillai
dcn401_update_odm(struct dc * dc,struct dc_state * context,struct pipe_ctx * otg_master)15488c4f9e46SAurabindo Pillai void dcn401_update_odm(struct dc *dc, struct dc_state *context,
154970839da6SAurabindo Pillai struct pipe_ctx *otg_master)
155070839da6SAurabindo Pillai {
155170839da6SAurabindo Pillai struct pipe_ctx *opp_heads[MAX_PIPES];
155270839da6SAurabindo Pillai int opp_inst[MAX_PIPES] = {0};
155370839da6SAurabindo Pillai int opp_head_count;
155470839da6SAurabindo Pillai int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false);
155570839da6SAurabindo Pillai int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true);
155670839da6SAurabindo Pillai int i;
155770839da6SAurabindo Pillai
155870839da6SAurabindo Pillai opp_head_count = resource_get_opp_heads_for_otg_master(
155970839da6SAurabindo Pillai otg_master, &context->res_ctx, opp_heads);
156070839da6SAurabindo Pillai
156170839da6SAurabindo Pillai for (i = 0; i < opp_head_count; i++)
156270839da6SAurabindo Pillai opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
156370839da6SAurabindo Pillai if (opp_head_count > 1)
156470839da6SAurabindo Pillai otg_master->stream_res.tg->funcs->set_odm_combine(
156570839da6SAurabindo Pillai otg_master->stream_res.tg,
156670839da6SAurabindo Pillai opp_inst, opp_head_count,
156770839da6SAurabindo Pillai odm_slice_width, last_odm_slice_width);
156870839da6SAurabindo Pillai else
156970839da6SAurabindo Pillai otg_master->stream_res.tg->funcs->set_odm_bypass(
157070839da6SAurabindo Pillai otg_master->stream_res.tg,
157170839da6SAurabindo Pillai &otg_master->stream->timing);
157270839da6SAurabindo Pillai
157370839da6SAurabindo Pillai for (i = 0; i < opp_head_count; i++) {
157470839da6SAurabindo Pillai opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
157570839da6SAurabindo Pillai opp_heads[i]->stream_res.opp,
15768c4f9e46SAurabindo Pillai true);
157770839da6SAurabindo Pillai opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
157870839da6SAurabindo Pillai opp_heads[i]->stream_res.opp,
15798c4f9e46SAurabindo Pillai opp_heads[i]->stream->timing.pixel_encoding,
158070839da6SAurabindo Pillai resource_is_pipe_type(opp_heads[i], OTG_MASTER));
158170839da6SAurabindo Pillai }
158270839da6SAurabindo Pillai
158370839da6SAurabindo Pillai update_dsc_for_odm_change(dc, context, otg_master);
158470839da6SAurabindo Pillai
15858c4f9e46SAurabindo Pillai if (!resource_is_pipe_type(otg_master, DPP_PIPE))
158670839da6SAurabindo Pillai /*
158770839da6SAurabindo Pillai * blank pattern is generated by OPP, reprogram blank pattern
158870839da6SAurabindo Pillai * due to OPP count change
158970839da6SAurabindo Pillai */
159070839da6SAurabindo Pillai dc->hwseq->funcs.blank_pixel_data(dc, otg_master, true);
159170839da6SAurabindo Pillai }
159270839da6SAurabindo Pillai
dcn401_unblank_stream(struct pipe_ctx * pipe_ctx,struct dc_link_settings * link_settings)159378f608d7SAurabindo Pillai void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx,
159478f608d7SAurabindo Pillai struct dc_link_settings *link_settings)
159578f608d7SAurabindo Pillai {
159678f608d7SAurabindo Pillai struct encoder_unblank_param params = {0};
159778f608d7SAurabindo Pillai struct dc_stream_state *stream = pipe_ctx->stream;
159878f608d7SAurabindo Pillai struct dc_link *link = stream->link;
159978f608d7SAurabindo Pillai struct dce_hwseq *hws = link->dc->hwseq;
160078f608d7SAurabindo Pillai
160178f608d7SAurabindo Pillai /* calculate parameters for unblank */
160278f608d7SAurabindo Pillai params.opp_cnt = resource_get_odm_slice_count(pipe_ctx);
160378f608d7SAurabindo Pillai
160478f608d7SAurabindo Pillai params.timing = pipe_ctx->stream->timing;
160578f608d7SAurabindo Pillai params.link_settings.link_rate = link_settings->link_rate;
160678f608d7SAurabindo Pillai params.pix_per_cycle = pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle;
160778f608d7SAurabindo Pillai
160878f608d7SAurabindo Pillai if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
160978f608d7SAurabindo Pillai pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
161078f608d7SAurabindo Pillai pipe_ctx->stream_res.hpo_dp_stream_enc,
161178f608d7SAurabindo Pillai pipe_ctx->stream_res.tg->inst);
161278f608d7SAurabindo Pillai } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
161378f608d7SAurabindo Pillai pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms);
161478f608d7SAurabindo Pillai }
161578f608d7SAurabindo Pillai
161678f608d7SAurabindo Pillai if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
161778f608d7SAurabindo Pillai hws->funcs.edp_backlight_control(link, true);
161870839da6SAurabindo Pillai }
161970839da6SAurabindo Pillai
dcn401_hardware_release(struct dc * dc)162070839da6SAurabindo Pillai void dcn401_hardware_release(struct dc *dc)
162170839da6SAurabindo Pillai {
162270839da6SAurabindo Pillai dc_dmub_srv_fams2_update_config(dc, dc->current_state, false);
16237a1eb668SDillon Varone
162470839da6SAurabindo Pillai /* If pstate unsupported, or still supported
162567ea53a4SDillon Varone * by firmware, force it supported by dcn
162667ea53a4SDillon Varone */
162770839da6SAurabindo Pillai if (dc->current_state) {
162870839da6SAurabindo Pillai if ((!dc->clk_mgr->clks.p_state_change_support ||
162970839da6SAurabindo Pillai dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable) &&
163070839da6SAurabindo Pillai dc->res_pool->hubbub->funcs->force_pstate_change_control)
163170839da6SAurabindo Pillai dc->res_pool->hubbub->funcs->force_pstate_change_control(
163270839da6SAurabindo Pillai dc->res_pool->hubbub, true, true);
163370839da6SAurabindo Pillai
163470839da6SAurabindo Pillai dc->current_state->bw_ctx.bw.dcn.clk.p_state_change_support = true;
163570839da6SAurabindo Pillai dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, dc->current_state, true);
163670839da6SAurabindo Pillai }
163770839da6SAurabindo Pillai }
163870839da6SAurabindo Pillai
dcn401_wait_for_det_buffer_update_under_otg_master(struct dc * dc,struct dc_state * context,struct pipe_ctx * otg_master)163970839da6SAurabindo Pillai void dcn401_wait_for_det_buffer_update_under_otg_master(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master)
164070839da6SAurabindo Pillai {
164170839da6SAurabindo Pillai struct pipe_ctx *opp_heads[MAX_PIPES];
164270839da6SAurabindo Pillai struct pipe_ctx *dpp_pipes[MAX_PIPES];
164370839da6SAurabindo Pillai struct hubbub *hubbub = dc->res_pool->hubbub;
164470839da6SAurabindo Pillai int dpp_count = 0;
164570839da6SAurabindo Pillai
164670839da6SAurabindo Pillai if (!otg_master->stream)
164770839da6SAurabindo Pillai return;
164870839da6SAurabindo Pillai
164970839da6SAurabindo Pillai int slice_count = resource_get_opp_heads_for_otg_master(otg_master,
165089713ce5SDillon Varone &context->res_ctx, opp_heads);
165189713ce5SDillon Varone
165289713ce5SDillon Varone for (int slice_idx = 0; slice_idx < slice_count; slice_idx++) {
165389713ce5SDillon Varone if (opp_heads[slice_idx]->plane_state) {
165470839da6SAurabindo Pillai dpp_count = resource_get_dpp_pipes_for_opp_head(
165570839da6SAurabindo Pillai opp_heads[slice_idx],
165670839da6SAurabindo Pillai &context->res_ctx,
16577a1eb668SDillon Varone dpp_pipes);
16587a1eb668SDillon Varone for (int dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) {
165970839da6SAurabindo Pillai struct pipe_ctx *dpp_pipe = dpp_pipes[dpp_idx];
16607a1eb668SDillon Varone if (dpp_pipe && hubbub &&
166170839da6SAurabindo Pillai dpp_pipe->plane_res.hubp &&
166270839da6SAurabindo Pillai hubbub->funcs->wait_for_det_update)
166370839da6SAurabindo Pillai hubbub->funcs->wait_for_det_update(hubbub, dpp_pipe->plane_res.hubp->inst);
166470839da6SAurabindo Pillai }
166570839da6SAurabindo Pillai } else {
166670839da6SAurabindo Pillai if (hubbub && opp_heads[slice_idx]->plane_res.hubp && hubbub->funcs->wait_for_det_update)
166770839da6SAurabindo Pillai hubbub->funcs->wait_for_det_update(hubbub, opp_heads[slice_idx]->plane_res.hubp->inst);
166870839da6SAurabindo Pillai }
166967ea53a4SDillon Varone }
167070839da6SAurabindo Pillai }
167170839da6SAurabindo Pillai
dcn401_interdependent_update_lock(struct dc * dc,struct dc_state * context,bool lock)167270839da6SAurabindo Pillai void dcn401_interdependent_update_lock(struct dc *dc,
167370839da6SAurabindo Pillai struct dc_state *context, bool lock)
167470839da6SAurabindo Pillai {
167570839da6SAurabindo Pillai unsigned int i = 0;
167670839da6SAurabindo Pillai struct pipe_ctx *pipe = NULL;
167770839da6SAurabindo Pillai struct timing_generator *tg = NULL;
167870839da6SAurabindo Pillai
167970839da6SAurabindo Pillai if (lock) {
168070839da6SAurabindo Pillai for (i = 0; i < dc->res_pool->pipe_count; i++) {
168170839da6SAurabindo Pillai pipe = &context->res_ctx.pipe_ctx[i];
168270839da6SAurabindo Pillai tg = pipe->stream_res.tg;
168370839da6SAurabindo Pillai
168470839da6SAurabindo Pillai if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
168570839da6SAurabindo Pillai !tg->funcs->is_tg_enabled(tg) ||
168670839da6SAurabindo Pillai dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM)
168770839da6SAurabindo Pillai continue;
168870839da6SAurabindo Pillai dc->hwss.pipe_control_lock(dc, pipe, true);
168970839da6SAurabindo Pillai }
169070839da6SAurabindo Pillai } else {
169170839da6SAurabindo Pillai /* Need to free DET being used first and have pipe update, then unlock the remaining pipes*/
169270839da6SAurabindo Pillai for (i = 0; i < dc->res_pool->pipe_count; i++) {
169370839da6SAurabindo Pillai pipe = &context->res_ctx.pipe_ctx[i];
169470839da6SAurabindo Pillai tg = pipe->stream_res.tg;
169589713ce5SDillon Varone
169689713ce5SDillon Varone if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
169789713ce5SDillon Varone !tg->funcs->is_tg_enabled(tg) ||
169889713ce5SDillon Varone dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
169970839da6SAurabindo Pillai continue;
170070839da6SAurabindo Pillai }
170170839da6SAurabindo Pillai
170270839da6SAurabindo Pillai if (dc->scratch.pipes_to_unlock_first[i]) {
170370839da6SAurabindo Pillai struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
170470839da6SAurabindo Pillai dc->hwss.pipe_control_lock(dc, pipe, false);
170570839da6SAurabindo Pillai /* Assumes pipe of the same index in current_state is also an OTG_MASTER pipe*/
170670839da6SAurabindo Pillai dcn401_wait_for_det_buffer_update_under_otg_master(dc, dc->current_state, old_pipe);
170770839da6SAurabindo Pillai }
170870839da6SAurabindo Pillai }
170970839da6SAurabindo Pillai
171070839da6SAurabindo Pillai /* Unlocking the rest of the pipes */
171170839da6SAurabindo Pillai for (i = 0; i < dc->res_pool->pipe_count; i++) {
171270839da6SAurabindo Pillai if (dc->scratch.pipes_to_unlock_first[i])
171370839da6SAurabindo Pillai continue;
171470839da6SAurabindo Pillai
171570839da6SAurabindo Pillai pipe = &context->res_ctx.pipe_ctx[i];
171670839da6SAurabindo Pillai tg = pipe->stream_res.tg;
171770839da6SAurabindo Pillai if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
171870839da6SAurabindo Pillai !tg->funcs->is_tg_enabled(tg) ||
171970839da6SAurabindo Pillai dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
172070839da6SAurabindo Pillai continue;
172170839da6SAurabindo Pillai }
172270839da6SAurabindo Pillai
172370839da6SAurabindo Pillai dc->hwss.pipe_control_lock(dc, pipe, false);
172470839da6SAurabindo Pillai }
172570839da6SAurabindo Pillai }
172670839da6SAurabindo Pillai }
172770839da6SAurabindo Pillai
dcn401_perform_3dlut_wa_unlock(struct pipe_ctx * pipe_ctx)172870839da6SAurabindo Pillai void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx)
172970839da6SAurabindo Pillai {
173070839da6SAurabindo Pillai /* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that
173170839da6SAurabindo Pillai * HUBP will properly fetch 3DLUT contents after unlock.
173270839da6SAurabindo Pillai *
173370839da6SAurabindo Pillai * This is meant to work around a known HW issue where VREADY will cancel the pending 3DLUT_ENABLE signal regardless
173470839da6SAurabindo Pillai * of whether OTG lock is currently being held or not.
173570839da6SAurabindo Pillai */
173670839da6SAurabindo Pillai struct pipe_ctx *wa_pipes[MAX_PIPES] = { NULL };
173770839da6SAurabindo Pillai struct pipe_ctx *odm_pipe, *mpc_pipe;
173870839da6SAurabindo Pillai int i, wa_pipe_ct = 0;
173970839da6SAurabindo Pillai
174070839da6SAurabindo Pillai for (odm_pipe = pipe_ctx; odm_pipe != NULL; odm_pipe = odm_pipe->next_odm_pipe) {
174170839da6SAurabindo Pillai for (mpc_pipe = odm_pipe; mpc_pipe != NULL; mpc_pipe = mpc_pipe->bottom_pipe) {
174270839da6SAurabindo Pillai if (mpc_pipe->plane_state && mpc_pipe->plane_state->mcm_luts.lut3d_data.lut3d_src
174370839da6SAurabindo Pillai == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM
174470839da6SAurabindo Pillai && mpc_pipe->plane_state->mcm_shaper_3dlut_setting
174570839da6SAurabindo Pillai == DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT) {
174670839da6SAurabindo Pillai wa_pipes[wa_pipe_ct++] = mpc_pipe;
174770839da6SAurabindo Pillai }
174870839da6SAurabindo Pillai }
174970839da6SAurabindo Pillai }
175070839da6SAurabindo Pillai
175170839da6SAurabindo Pillai if (wa_pipe_ct > 0) {
175270839da6SAurabindo Pillai if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
175370839da6SAurabindo Pillai pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, true);
175470839da6SAurabindo Pillai
175570839da6SAurabindo Pillai for (i = 0; i < wa_pipe_ct; ++i) {
175670839da6SAurabindo Pillai if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
175770839da6SAurabindo Pillai wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
175870839da6SAurabindo Pillai }
175970839da6SAurabindo Pillai
176070839da6SAurabindo Pillai pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
176170839da6SAurabindo Pillai if (pipe_ctx->stream_res.tg->funcs->wait_update_lock_status)
176270839da6SAurabindo Pillai pipe_ctx->stream_res.tg->funcs->wait_update_lock_status(pipe_ctx->stream_res.tg, false);
176370839da6SAurabindo Pillai
176470839da6SAurabindo Pillai for (i = 0; i < wa_pipe_ct; ++i) {
176570839da6SAurabindo Pillai if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
176608cbe68dSDillon Varone wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
176770839da6SAurabindo Pillai }
176870839da6SAurabindo Pillai
176970839da6SAurabindo Pillai if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
17700127f044SDillon Varone pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, false);
1771176278d8SWenjing Liu } else {
1772176278d8SWenjing Liu pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
1773176278d8SWenjing Liu }
1774176278d8SWenjing Liu }
1775176278d8SWenjing Liu
dcn401_program_outstanding_updates(struct dc * dc,struct dc_state * context)1776176278d8SWenjing Liu void dcn401_program_outstanding_updates(struct dc *dc,
1777176278d8SWenjing Liu struct dc_state *context)
177826ec3ccaSRodrigo Siqueira {
177926ec3ccaSRodrigo Siqueira struct hubbub *hubbub = dc->res_pool->hubbub;
178026ec3ccaSRodrigo Siqueira
178126ec3ccaSRodrigo Siqueira /* update compbuf if required */
178226ec3ccaSRodrigo Siqueira if (hubbub->funcs->program_compbuf_segments)
178326ec3ccaSRodrigo Siqueira hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true);
178426ec3ccaSRodrigo Siqueira }
178526ec3ccaSRodrigo Siqueira
dcn401_reset_back_end_for_pipe(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_state * context)1786176278d8SWenjing Liu void dcn401_reset_back_end_for_pipe(
178726ec3ccaSRodrigo Siqueira struct dc *dc,
178826ec3ccaSRodrigo Siqueira struct pipe_ctx *pipe_ctx,
178926ec3ccaSRodrigo Siqueira struct dc_state *context)
179026ec3ccaSRodrigo Siqueira {
179126ec3ccaSRodrigo Siqueira struct dc_link *link = pipe_ctx->stream->link;
179226ec3ccaSRodrigo Siqueira const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
179326ec3ccaSRodrigo Siqueira
179426ec3ccaSRodrigo Siqueira DC_LOGGER_INIT(dc->ctx->logger);
1795176278d8SWenjing Liu if (pipe_ctx->stream_res.stream_enc == NULL) {
1796176278d8SWenjing Liu pipe_ctx->stream = NULL;
1797176278d8SWenjing Liu return;
1798176278d8SWenjing Liu }
179926ec3ccaSRodrigo Siqueira
1800176278d8SWenjing Liu /* DPMS may already disable or */
1801176278d8SWenjing Liu /* dpms_off status is incorrect due to fastboot
1802176278d8SWenjing Liu * feature. When system resume from S4 with second
18033c915431SWenjing Liu * screen only, the dpms_off would be true but
1804176278d8SWenjing Liu * VBIOS lit up eDP, so check link status too.
1805176278d8SWenjing Liu */
1806176278d8SWenjing Liu if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
1807176278d8SWenjing Liu dc->link_srv->set_dpms_off(pipe_ctx);
1808176278d8SWenjing Liu else if (pipe_ctx->stream_res.audio)
1809176278d8SWenjing Liu dc->hwss.disable_audio_stream(pipe_ctx);
1810176278d8SWenjing Liu
1811176278d8SWenjing Liu /* free acquired resources */
1812176278d8SWenjing Liu if (pipe_ctx->stream_res.audio) {
1813176278d8SWenjing Liu /*disable az_endpoint*/
1814176278d8SWenjing Liu pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
1815176278d8SWenjing Liu
1816f9d48a88SWenjing Liu /*free audio*/
1817f9d48a88SWenjing Liu if (dc->caps.dynamic_audio == true) {
1818176278d8SWenjing Liu /*we have to dynamic arbitrate the audio endpoints*/
1819176278d8SWenjing Liu /*we free the resource, need reset is_audio_acquired*/
1820176278d8SWenjing Liu update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
1821176278d8SWenjing Liu pipe_ctx->stream_res.audio, false);
1822176278d8SWenjing Liu pipe_ctx->stream_res.audio = NULL;
1823176278d8SWenjing Liu }
1824176278d8SWenjing Liu }
1825176278d8SWenjing Liu
1826176278d8SWenjing Liu /* by upper caller loop, parent pipe: pipe0, will be reset last.
1827176278d8SWenjing Liu * back end share by all pipes and will be disable only when disable
1828176278d8SWenjing Liu * parent pipe.
1829f9d48a88SWenjing Liu */
1830176278d8SWenjing Liu if (pipe_ctx->top_pipe == NULL) {
1831176278d8SWenjing Liu
1832176278d8SWenjing Liu dc->hwss.set_abm_immediate_disable(pipe_ctx);
1833176278d8SWenjing Liu
1834176278d8SWenjing Liu pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
1835f9d48a88SWenjing Liu
1836176278d8SWenjing Liu pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
1837176278d8SWenjing Liu if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
1838176278d8SWenjing Liu pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
1839f9d48a88SWenjing Liu pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
1840f9d48a88SWenjing Liu
1841f9d48a88SWenjing Liu set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
1842f9d48a88SWenjing Liu
1843f9d48a88SWenjing Liu /* TODO - convert symclk_ref_cnts for otg to a bit map to solve
1844176278d8SWenjing Liu * the case where the same symclk is shared across multiple otg
1845176278d8SWenjing Liu * instances
1846176278d8SWenjing Liu */
1847176278d8SWenjing Liu if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
1848176278d8SWenjing Liu link->phy_state.symclk_ref_cnts.otg = 0;
1849176278d8SWenjing Liu if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
1850176278d8SWenjing Liu link_hwss->disable_link_output(link,
1851176278d8SWenjing Liu &pipe_ctx->link_res, pipe_ctx->stream->signal);
1852176278d8SWenjing Liu link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
1853176278d8SWenjing Liu }
1854176278d8SWenjing Liu
18550127f044SDillon Varone /* reset DTBCLK_P */
18560127f044SDillon Varone if (dc->res_pool->dccg->funcs->set_dtbclk_p_src)
18570127f044SDillon Varone dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, REFCLK, pipe_ctx->stream_res.tg->inst);
18580127f044SDillon Varone }
18590127f044SDillon Varone
18600127f044SDillon Varone /*
18610127f044SDillon Varone * In case of a dangling plane, setting this to NULL unconditionally
18620127f044SDillon Varone * causes failures during reset hw ctx where, if stream is NULL,
18630127f044SDillon Varone * it is expected that the pipe_ctx pointers to pipes and plane are NULL.
18640127f044SDillon Varone */
18650127f044SDillon Varone pipe_ctx->stream = NULL;
18660127f044SDillon Varone pipe_ctx->top_pipe = NULL;
18670127f044SDillon Varone pipe_ctx->bottom_pipe = NULL;
18680127f044SDillon Varone pipe_ctx->next_odm_pipe = NULL;
18690127f044SDillon Varone pipe_ctx->prev_odm_pipe = NULL;
18700127f044SDillon Varone DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
18710127f044SDillon Varone pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
18720127f044SDillon Varone }
18730127f044SDillon Varone
dcn401_reset_hw_ctx_wrap(struct dc * dc,struct dc_state * context)18740127f044SDillon Varone void dcn401_reset_hw_ctx_wrap(
18750127f044SDillon Varone struct dc *dc,
18760127f044SDillon Varone struct dc_state *context)
18770127f044SDillon Varone {
18780127f044SDillon Varone int i;
18790127f044SDillon Varone struct dce_hwseq *hws = dc->hwseq;
18800127f044SDillon Varone
1881989947e9SAlvin Lee /* Reset Back End*/
1882989947e9SAlvin Lee for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1883989947e9SAlvin Lee struct pipe_ctx *pipe_ctx_old =
1884989947e9SAlvin Lee &dc->current_state->res_ctx.pipe_ctx[i];
1885989947e9SAlvin Lee struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1886989947e9SAlvin Lee
1887989947e9SAlvin Lee if (!pipe_ctx_old->stream)
1888989947e9SAlvin Lee continue;
1889989947e9SAlvin Lee
1890989947e9SAlvin Lee if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
189108cbe68dSDillon Varone continue;
1892989947e9SAlvin Lee
1893989947e9SAlvin Lee if (!pipe_ctx->stream ||
1894989947e9SAlvin Lee pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
1895989947e9SAlvin Lee struct clock_source *old_clk = pipe_ctx_old->clock_source;
1896989947e9SAlvin Lee
1897989947e9SAlvin Lee if (hws->funcs.reset_back_end_for_pipe)
1898989947e9SAlvin Lee hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
1899989947e9SAlvin Lee if (hws->funcs.enable_stream_gating)
1900989947e9SAlvin Lee hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
190182f8b2cfSAustin Zheng if (old_clk)
19024af0d8ebSAustin Zheng old_clk->funcs->cs_power_down(old_clk);
19034af0d8ebSAustin Zheng }
19044af0d8ebSAustin Zheng }
19054af0d8ebSAustin Zheng }
19064af0d8ebSAustin Zheng
dcn401_calculate_vready_offset_for_group(struct pipe_ctx * pipe)19074af0d8ebSAustin Zheng static unsigned int dcn401_calculate_vready_offset_for_group(struct pipe_ctx *pipe)
19084af0d8ebSAustin Zheng {
19094af0d8ebSAustin Zheng struct pipe_ctx *other_pipe;
19104af0d8ebSAustin Zheng unsigned int vready_offset = pipe->global_sync.dcn4x.vready_offset_pixels;
19114af0d8ebSAustin Zheng
19124af0d8ebSAustin Zheng /* Always use the largest vready_offset of all connected pipes */
19134af0d8ebSAustin Zheng for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {
19144af0d8ebSAustin Zheng if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
19154af0d8ebSAustin Zheng vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
19164af0d8ebSAustin Zheng }
19174af0d8ebSAustin Zheng for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {
19184af0d8ebSAustin Zheng if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
19194af0d8ebSAustin Zheng vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
19204af0d8ebSAustin Zheng }
19214af0d8ebSAustin Zheng for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {
19224af0d8ebSAustin Zheng if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
19234af0d8ebSAustin Zheng vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
19244af0d8ebSAustin Zheng }
19254af0d8ebSAustin Zheng for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {
19264af0d8ebSAustin Zheng if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
192782f8b2cfSAustin Zheng vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
192882f8b2cfSAustin Zheng }
192982f8b2cfSAustin Zheng
19304af0d8ebSAustin Zheng return vready_offset;
19314af0d8ebSAustin Zheng }
19324af0d8ebSAustin Zheng
dcn401_program_tg(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_state * context,struct dce_hwseq * hws)19334af0d8ebSAustin Zheng static void dcn401_program_tg(
19344af0d8ebSAustin Zheng struct dc *dc,
19354af0d8ebSAustin Zheng struct pipe_ctx *pipe_ctx,
19364af0d8ebSAustin Zheng struct dc_state *context,
19374af0d8ebSAustin Zheng struct dce_hwseq *hws)
19384af0d8ebSAustin Zheng {
19394af0d8ebSAustin Zheng pipe_ctx->stream_res.tg->funcs->program_global_sync(
19404af0d8ebSAustin Zheng pipe_ctx->stream_res.tg,
19414af0d8ebSAustin Zheng dcn401_calculate_vready_offset_for_group(pipe_ctx),
19424af0d8ebSAustin Zheng (unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
19434af0d8ebSAustin Zheng (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
19444af0d8ebSAustin Zheng (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
19454af0d8ebSAustin Zheng (unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines);
19464af0d8ebSAustin Zheng
19474af0d8ebSAustin Zheng if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
19484af0d8ebSAustin Zheng pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
19494af0d8ebSAustin Zheng
19504af0d8ebSAustin Zheng pipe_ctx->stream_res.tg->funcs->set_vtg_params(
19514af0d8ebSAustin Zheng pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
19524af0d8ebSAustin Zheng
19530e719a40SAustin Zheng if (hws->funcs.setup_vupdate_interrupt)
19544af0d8ebSAustin Zheng hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
19554af0d8ebSAustin Zheng }
19564af0d8ebSAustin Zheng
dcn401_program_pipe(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_state * context)19574af0d8ebSAustin Zheng void dcn401_program_pipe(
19584af0d8ebSAustin Zheng struct dc *dc,
19594af0d8ebSAustin Zheng struct pipe_ctx *pipe_ctx,
19604af0d8ebSAustin Zheng struct dc_state *context)
19614af0d8ebSAustin Zheng {
19624af0d8ebSAustin Zheng struct dce_hwseq *hws = dc->hwseq;
19634af0d8ebSAustin Zheng
19640e719a40SAustin Zheng /* Only need to unblank on top pipe */
196582f8b2cfSAustin Zheng if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) {
19664af0d8ebSAustin Zheng if (pipe_ctx->update_flags.bits.enable ||
196782f8b2cfSAustin Zheng pipe_ctx->update_flags.bits.odm ||
196882f8b2cfSAustin Zheng pipe_ctx->stream->update_flags.bits.abm_level)
19694af0d8ebSAustin Zheng hws->funcs.blank_pixel_data(dc, pipe_ctx,
19704af0d8ebSAustin Zheng !pipe_ctx->plane_state ||
19714af0d8ebSAustin Zheng !pipe_ctx->plane_state->visible);
19720e719a40SAustin Zheng }
19734af0d8ebSAustin Zheng
19740e719a40SAustin Zheng /* Only update TG on top pipe */
19754af0d8ebSAustin Zheng if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
19760e719a40SAustin Zheng && !pipe_ctx->prev_odm_pipe)
19774af0d8ebSAustin Zheng dcn401_program_tg(dc, pipe_ctx, context, hws);
19780e719a40SAustin Zheng
19790e719a40SAustin Zheng if (pipe_ctx->update_flags.bits.odm)
19800e719a40SAustin Zheng hws->funcs.update_odm(dc, context, pipe_ctx);
19810e719a40SAustin Zheng
19820e719a40SAustin Zheng if (pipe_ctx->update_flags.bits.enable) {
19830e719a40SAustin Zheng if (hws->funcs.enable_plane)
19840e719a40SAustin Zheng hws->funcs.enable_plane(dc, pipe_ctx, context);
19854af0d8ebSAustin Zheng else
19864af0d8ebSAustin Zheng dc->hwss.enable_plane(dc, pipe_ctx, context);
19874af0d8ebSAustin Zheng
19884af0d8ebSAustin Zheng if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)
19897a1eb668SDillon Varone dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);
1990df60dcf5SIlya Bakoulin }
1991df60dcf5SIlya Bakoulin
1992df60dcf5SIlya Bakoulin if (pipe_ctx->update_flags.bits.det_size) {
1993df60dcf5SIlya Bakoulin if (dc->res_pool->hubbub->funcs->program_det_size)
1994df60dcf5SIlya Bakoulin dc->res_pool->hubbub->funcs->program_det_size(
1995df60dcf5SIlya Bakoulin dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
1996df60dcf5SIlya Bakoulin if (dc->res_pool->hubbub->funcs->program_det_segments)
1997df60dcf5SIlya Bakoulin dc->res_pool->hubbub->funcs->program_det_segments(
1998df60dcf5SIlya Bakoulin dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size);
1999df60dcf5SIlya Bakoulin }
2000df60dcf5SIlya Bakoulin
2001df60dcf5SIlya Bakoulin if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw ||
2002df60dcf5SIlya Bakoulin pipe_ctx->plane_state->update_flags.raw ||
2003df60dcf5SIlya Bakoulin pipe_ctx->stream->update_flags.raw))
2004df60dcf5SIlya Bakoulin dc->hwss.update_dchubp_dpp(dc, pipe_ctx, context);
2005df60dcf5SIlya Bakoulin
2006df60dcf5SIlya Bakoulin if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable ||
2007df60dcf5SIlya Bakoulin pipe_ctx->plane_state->update_flags.bits.hdr_mult))
2008df60dcf5SIlya Bakoulin hws->funcs.set_hdr_multiplier(pipe_ctx);
2009df60dcf5SIlya Bakoulin
2010df60dcf5SIlya Bakoulin if (pipe_ctx->plane_state &&
2011df60dcf5SIlya Bakoulin (pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
2012df60dcf5SIlya Bakoulin pipe_ctx->plane_state->update_flags.bits.gamma_change ||
2013df60dcf5SIlya Bakoulin pipe_ctx->plane_state->update_flags.bits.lut_3d ||
2014df60dcf5SIlya Bakoulin pipe_ctx->update_flags.bits.enable))
2015df60dcf5SIlya Bakoulin hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
2016df60dcf5SIlya Bakoulin
2017df60dcf5SIlya Bakoulin /* dcn10_translate_regamma_to_hw_format takes 750us to finish
2018df60dcf5SIlya Bakoulin * only do gamma programming for powering on, internal memcmp to avoid
2019df60dcf5SIlya Bakoulin * updating on slave planes
2020df60dcf5SIlya Bakoulin */
2021df60dcf5SIlya Bakoulin if (pipe_ctx->update_flags.bits.enable ||
2022df60dcf5SIlya Bakoulin pipe_ctx->update_flags.bits.plane_changed ||
2023df60dcf5SIlya Bakoulin pipe_ctx->stream->update_flags.bits.out_tf ||
2024df60dcf5SIlya Bakoulin (pipe_ctx->plane_state &&
2025df60dcf5SIlya Bakoulin pipe_ctx->plane_state->update_flags.bits.output_tf_change))
2026df60dcf5SIlya Bakoulin hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
2027df60dcf5SIlya Bakoulin
2028df60dcf5SIlya Bakoulin /* If the pipe has been enabled or has a different opp, we
2029df60dcf5SIlya Bakoulin * should reprogram the fmt. This deals with cases where
2030df60dcf5SIlya Bakoulin * interation between mpc and odm combine on different streams
2031df60dcf5SIlya Bakoulin * causes a different pipe to be chosen to odm combine with.
2032df60dcf5SIlya Bakoulin */
2033df60dcf5SIlya Bakoulin if (pipe_ctx->update_flags.bits.enable
2034df60dcf5SIlya Bakoulin || pipe_ctx->update_flags.bits.opp_changed) {
2035df60dcf5SIlya Bakoulin
2036df60dcf5SIlya Bakoulin pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
2037df60dcf5SIlya Bakoulin pipe_ctx->stream_res.opp,
20387a1eb668SDillon Varone COLOR_SPACE_YCBCR601,
20397a1eb668SDillon Varone pipe_ctx->stream->timing.display_color_depth,
20407a1eb668SDillon Varone pipe_ctx->stream->signal);
20417a1eb668SDillon Varone
20427a1eb668SDillon Varone pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
20437a1eb668SDillon Varone pipe_ctx->stream_res.opp,
20447a1eb668SDillon Varone &pipe_ctx->stream->bit_depth_params,
20457a1eb668SDillon Varone &pipe_ctx->stream->clamping);
20467a1eb668SDillon Varone }
20473c6c8d1aSDillon Varone
20483c6c8d1aSDillon Varone /* Set ABM pipe after other pipe configurations done */
20493c6c8d1aSDillon Varone if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) {
20503c6c8d1aSDillon Varone if (pipe_ctx->stream_res.abm) {
20513c6c8d1aSDillon Varone dc->hwss.set_pipe(pipe_ctx);
20523c6c8d1aSDillon Varone pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,
20533c6c8d1aSDillon Varone pipe_ctx->stream->abm_level);
20543c6c8d1aSDillon Varone }
20553c6c8d1aSDillon Varone }
20563c6c8d1aSDillon Varone
20573c6c8d1aSDillon Varone if (pipe_ctx->update_flags.bits.test_pattern_changed) {
20583c6c8d1aSDillon Varone struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp;
20593c6c8d1aSDillon Varone struct bit_depth_reduction_params params;
20603c6c8d1aSDillon Varone
20613c6c8d1aSDillon Varone memset(¶ms, 0, sizeof(params));
20623c6c8d1aSDillon Varone odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms);
20633c6c8d1aSDillon Varone dc->hwss.set_disp_pattern_generator(dc,
20643c6c8d1aSDillon Varone pipe_ctx,
20653c6c8d1aSDillon Varone pipe_ctx->stream_res.test_pattern_params.test_pattern,
20663c6c8d1aSDillon Varone pipe_ctx->stream_res.test_pattern_params.color_space,
20673c6c8d1aSDillon Varone pipe_ctx->stream_res.test_pattern_params.color_depth,
20683c6c8d1aSDillon Varone NULL,
20693c6c8d1aSDillon Varone pipe_ctx->stream_res.test_pattern_params.width,
20703c6c8d1aSDillon Varone pipe_ctx->stream_res.test_pattern_params.height,
20713c6c8d1aSDillon Varone pipe_ctx->stream_res.test_pattern_params.offset);
20723c6c8d1aSDillon Varone }
20733c6c8d1aSDillon Varone }
20743c6c8d1aSDillon Varone
dcn401_program_front_end_for_ctx(struct dc * dc,struct dc_state * context)20753c6c8d1aSDillon Varone void dcn401_program_front_end_for_ctx(
20763c6c8d1aSDillon Varone struct dc *dc,
20773c6c8d1aSDillon Varone struct dc_state *context)
20783c6c8d1aSDillon Varone {
20793c6c8d1aSDillon Varone int i;
20803c6c8d1aSDillon Varone unsigned int prev_hubp_count = 0;
20813c6c8d1aSDillon Varone unsigned int hubp_count = 0;
20823c6c8d1aSDillon Varone struct dce_hwseq *hws = dc->hwseq;
20833c6c8d1aSDillon Varone struct pipe_ctx *pipe = NULL;
20843c6c8d1aSDillon Varone
20853c6c8d1aSDillon Varone DC_LOGGER_INIT(dc->ctx->logger);
20863c6c8d1aSDillon Varone
20873c6c8d1aSDillon Varone if (resource_is_pipe_topology_changed(dc->current_state, context))
20883c6c8d1aSDillon Varone resource_log_pipe_topology_update(dc, context);
20893c6c8d1aSDillon Varone
20903c6c8d1aSDillon Varone if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
20913c6c8d1aSDillon Varone for (i = 0; i < dc->res_pool->pipe_count; i++) {
20923c6c8d1aSDillon Varone pipe = &context->res_ctx.pipe_ctx[i];
20933c6c8d1aSDillon Varone
20943c6c8d1aSDillon Varone if (pipe->plane_state) {
20953c6c8d1aSDillon Varone if (pipe->plane_state->triplebuffer_flips)
20963c6c8d1aSDillon Varone BREAK_TO_DEBUGGER();
20973c6c8d1aSDillon Varone
20983c6c8d1aSDillon Varone /*turn off triple buffer for full update*/
20993c6c8d1aSDillon Varone dc->hwss.program_triplebuffer(
21003c6c8d1aSDillon Varone dc, pipe, pipe->plane_state->triplebuffer_flips);
21013c6c8d1aSDillon Varone }
21023c6c8d1aSDillon Varone }
2103bd00b29bSDanny Wang }
2104bd00b29bSDanny Wang
21053c6c8d1aSDillon Varone for (i = 0; i < dc->res_pool->pipe_count; i++) {
21063c6c8d1aSDillon Varone if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)
21073c6c8d1aSDillon Varone prev_hubp_count++;
21083c6c8d1aSDillon Varone if (context->res_ctx.pipe_ctx[i].plane_state)
21093c6c8d1aSDillon Varone hubp_count++;
21103c6c8d1aSDillon Varone }
21113c6c8d1aSDillon Varone
21123c6c8d1aSDillon Varone if (prev_hubp_count == 0 && hubp_count > 0) {
21133c6c8d1aSDillon Varone if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
21143c6c8d1aSDillon Varone dc->res_pool->hubbub->funcs->force_pstate_change_control(
21153c6c8d1aSDillon Varone dc->res_pool->hubbub, true, false);
21163c6c8d1aSDillon Varone udelay(500);
21173c6c8d1aSDillon Varone }
21183c6c8d1aSDillon Varone
21193c6c8d1aSDillon Varone /* Set pipe update flags and lock pipes */
21203c6c8d1aSDillon Varone for (i = 0; i < dc->res_pool->pipe_count; i++)
21213c6c8d1aSDillon Varone dc->hwss.detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],
21223c6c8d1aSDillon Varone &context->res_ctx.pipe_ctx[i]);
21233c6c8d1aSDillon Varone
21243c6c8d1aSDillon Varone /* When disabling phantom pipes, turn on phantom OTG first (so we can get double
21253c6c8d1aSDillon Varone * buffer updates properly)
21263c6c8d1aSDillon Varone */
21273c6c8d1aSDillon Varone for (i = 0; i < dc->res_pool->pipe_count; i++) {
2128c0933f1dSJoshua Aberback struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
2129c0933f1dSJoshua Aberback
2130c0933f1dSJoshua Aberback pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2131c0933f1dSJoshua Aberback
21323c6c8d1aSDillon Varone if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream &&
21333c6c8d1aSDillon Varone dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) {
21343c6c8d1aSDillon Varone struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
21353c6c8d1aSDillon Varone
21363c6c8d1aSDillon Varone if (tg->funcs->enable_crtc) {
21373c6c8d1aSDillon Varone if (dc->hwseq->funcs.blank_pixel_data)
21383c6c8d1aSDillon Varone dc->hwseq->funcs.blank_pixel_data(dc, pipe, true);
21393c6c8d1aSDillon Varone
21403c6c8d1aSDillon Varone tg->funcs->enable_crtc(tg);
21413c6c8d1aSDillon Varone }
21423c6c8d1aSDillon Varone }
21433c6c8d1aSDillon Varone }
21443c6c8d1aSDillon Varone /* OTG blank before disabling all front ends */
21453c6c8d1aSDillon Varone for (i = 0; i < dc->res_pool->pipe_count; i++)
21463c6c8d1aSDillon Varone if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
21473c6c8d1aSDillon Varone && !context->res_ctx.pipe_ctx[i].top_pipe
21483c6c8d1aSDillon Varone && !context->res_ctx.pipe_ctx[i].prev_odm_pipe
21493c6c8d1aSDillon Varone && context->res_ctx.pipe_ctx[i].stream)
21503c6c8d1aSDillon Varone hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
21513c6c8d1aSDillon Varone
21523c6c8d1aSDillon Varone
21533c6c8d1aSDillon Varone /* Disconnect mpcc */
21543c6c8d1aSDillon Varone for (i = 0; i < dc->res_pool->pipe_count; i++)
21553c6c8d1aSDillon Varone if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
21563c6c8d1aSDillon Varone || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
21573c6c8d1aSDillon Varone struct hubbub *hubbub = dc->res_pool->hubbub;
21583c6c8d1aSDillon Varone
21593c6c8d1aSDillon Varone /* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom
21603c6c8d1aSDillon Varone * then we want to do the programming here (effectively it's being disabled). If we do
21613c6c8d1aSDillon Varone * the programming later the DET won't be updated until the OTG for the phantom pipe is
21623c6c8d1aSDillon Varone * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with
21633c6c8d1aSDillon Varone * DET allocation.
21643c6c8d1aSDillon Varone */
21653c6c8d1aSDillon Varone if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||
21663c6c8d1aSDillon Varone (context->res_ctx.pipe_ctx[i].plane_state &&
21673c6c8d1aSDillon Varone dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) ==
216863ab80d9SRafal Ostrowski SUBVP_PHANTOM))) {
216963ab80d9SRafal Ostrowski if (hubbub->funcs->program_det_size)
217063ab80d9SRafal Ostrowski hubbub->funcs->program_det_size(hubbub,
217163ab80d9SRafal Ostrowski dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
217263ab80d9SRafal Ostrowski if (dc->res_pool->hubbub->funcs->program_det_segments)
217363ab80d9SRafal Ostrowski dc->res_pool->hubbub->funcs->program_det_segments(
217463ab80d9SRafal Ostrowski hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
217563ab80d9SRafal Ostrowski }
217663ab80d9SRafal Ostrowski hws->funcs.plane_atomic_disconnect(dc, dc->current_state,
217763ab80d9SRafal Ostrowski &dc->current_state->res_ctx.pipe_ctx[i]);
217863ab80d9SRafal Ostrowski DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
217963ab80d9SRafal Ostrowski }
218063ab80d9SRafal Ostrowski
218163ab80d9SRafal Ostrowski /* update ODM for blanked OTG master pipes */
218263ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++) {
218363ab80d9SRafal Ostrowski pipe = &context->res_ctx.pipe_ctx[i];
218463ab80d9SRafal Ostrowski if (resource_is_pipe_type(pipe, OTG_MASTER) &&
218563ab80d9SRafal Ostrowski !resource_is_pipe_type(pipe, DPP_PIPE) &&
218663ab80d9SRafal Ostrowski pipe->update_flags.bits.odm &&
218763ab80d9SRafal Ostrowski hws->funcs.update_odm)
218863ab80d9SRafal Ostrowski hws->funcs.update_odm(dc, context, pipe);
218963ab80d9SRafal Ostrowski }
219063ab80d9SRafal Ostrowski
219163ab80d9SRafal Ostrowski /*
219263ab80d9SRafal Ostrowski * Program all updated pipes, order matters for mpcc setup. Start with
219363ab80d9SRafal Ostrowski * top pipe and program all pipes that follow in order
219463ab80d9SRafal Ostrowski */
219563ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++) {
219663ab80d9SRafal Ostrowski pipe = &context->res_ctx.pipe_ctx[i];
219763ab80d9SRafal Ostrowski
219863ab80d9SRafal Ostrowski if (pipe->plane_state && !pipe->top_pipe) {
219963ab80d9SRafal Ostrowski while (pipe) {
220063ab80d9SRafal Ostrowski if (hws->funcs.program_pipe)
220163ab80d9SRafal Ostrowski hws->funcs.program_pipe(dc, pipe, context);
220263ab80d9SRafal Ostrowski else {
220363ab80d9SRafal Ostrowski /* Don't program phantom pipes in the regular front end programming sequence.
220463ab80d9SRafal Ostrowski * There is an MPO transition case where a pipe being used by a video plane is
220563ab80d9SRafal Ostrowski * transitioned directly to be a phantom pipe when closing the MPO video.
220663ab80d9SRafal Ostrowski * However the phantom pipe will program a new HUBP_VTG_SEL (update takes place
220763ab80d9SRafal Ostrowski * right away) but the MPO still exists until the double buffered update of the
220863ab80d9SRafal Ostrowski * main pipe so we will get a frame of underflow if the phantom pipe is
220963ab80d9SRafal Ostrowski * programmed here.
221063ab80d9SRafal Ostrowski */
221163ab80d9SRafal Ostrowski if (pipe->stream &&
221263ab80d9SRafal Ostrowski dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM)
221363ab80d9SRafal Ostrowski dcn401_program_pipe(dc, pipe, context);
221463ab80d9SRafal Ostrowski }
221563ab80d9SRafal Ostrowski
221663ab80d9SRafal Ostrowski pipe = pipe->bottom_pipe;
221763ab80d9SRafal Ostrowski }
221863ab80d9SRafal Ostrowski }
22198f87447aSAurabindo Pillai
222063ab80d9SRafal Ostrowski /* Program secondary blending tree and writeback pipes */
222163ab80d9SRafal Ostrowski pipe = &context->res_ctx.pipe_ctx[i];
222263ab80d9SRafal Ostrowski if (!pipe->top_pipe && !pipe->prev_odm_pipe
222363ab80d9SRafal Ostrowski && pipe->stream && pipe->stream->num_wb_info > 0
222463ab80d9SRafal Ostrowski && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw)
222563ab80d9SRafal Ostrowski || pipe->stream->update_flags.raw)
222663ab80d9SRafal Ostrowski && hws->funcs.program_all_writeback_pipes_in_tree)
222763ab80d9SRafal Ostrowski hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
222863ab80d9SRafal Ostrowski
222963ab80d9SRafal Ostrowski /* Avoid underflow by check of pipe line read when adding 2nd plane. */
223063ab80d9SRafal Ostrowski if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
223163ab80d9SRafal Ostrowski !pipe->top_pipe &&
223263ab80d9SRafal Ostrowski pipe->stream &&
223363ab80d9SRafal Ostrowski pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
223463ab80d9SRafal Ostrowski dc->current_state->stream_status[0].plane_count == 1 &&
223563ab80d9SRafal Ostrowski context->stream_status[0].plane_count > 1) {
223663ab80d9SRafal Ostrowski pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
223763ab80d9SRafal Ostrowski }
223863ab80d9SRafal Ostrowski }
223963ab80d9SRafal Ostrowski }
224063ab80d9SRafal Ostrowski
dcn401_post_unlock_program_front_end(struct dc * dc,struct dc_state * context)224163ab80d9SRafal Ostrowski void dcn401_post_unlock_program_front_end(
224263ab80d9SRafal Ostrowski struct dc *dc,
224363ab80d9SRafal Ostrowski struct dc_state *context)
224463ab80d9SRafal Ostrowski {
224563ab80d9SRafal Ostrowski // Timeout for pipe enable
224663ab80d9SRafal Ostrowski unsigned int timeout_us = 100000;
224763ab80d9SRafal Ostrowski unsigned int polling_interval_us = 1;
224863ab80d9SRafal Ostrowski struct dce_hwseq *hwseq = dc->hwseq;
224963ab80d9SRafal Ostrowski int i;
225063ab80d9SRafal Ostrowski
225163ab80d9SRafal Ostrowski DC_LOGGER_INIT(dc->ctx->logger);
225263ab80d9SRafal Ostrowski
225363ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++)
225463ab80d9SRafal Ostrowski if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
225563ab80d9SRafal Ostrowski !resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))
225663ab80d9SRafal Ostrowski dc->hwss.post_unlock_reset_opp(dc,
225763ab80d9SRafal Ostrowski &dc->current_state->res_ctx.pipe_ctx[i]);
225863ab80d9SRafal Ostrowski
225963ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++)
226063ab80d9SRafal Ostrowski if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
226163ab80d9SRafal Ostrowski dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
226263ab80d9SRafal Ostrowski
2263d8d47f73SMelissa Wen /*
2264d8d47f73SMelissa Wen * If we are enabling a pipe, we need to wait for pending clear as this is a critical
2265d8d47f73SMelissa Wen * part of the enable operation otherwise, DM may request an immediate flip which
226663ab80d9SRafal Ostrowski * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
226763ab80d9SRafal Ostrowski * is unsupported on DCN.
226863ab80d9SRafal Ostrowski */
226963ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++) {
227063ab80d9SRafal Ostrowski struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
227163ab80d9SRafal Ostrowski // Don't check flip pending on phantom pipes
227263ab80d9SRafal Ostrowski if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&
227363ab80d9SRafal Ostrowski dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
227463ab80d9SRafal Ostrowski struct hubp *hubp = pipe->plane_res.hubp;
227563ab80d9SRafal Ostrowski int j = 0;
227663ab80d9SRafal Ostrowski
227763ab80d9SRafal Ostrowski for (j = 0; j < timeout_us / polling_interval_us
227863ab80d9SRafal Ostrowski && hubp->funcs->hubp_is_flip_pending(hubp); j++)
227963ab80d9SRafal Ostrowski udelay(polling_interval_us);
228063ab80d9SRafal Ostrowski }
228163ab80d9SRafal Ostrowski }
228263ab80d9SRafal Ostrowski
228363ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++) {
228463ab80d9SRafal Ostrowski struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
228563ab80d9SRafal Ostrowski struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
228663ab80d9SRafal Ostrowski
228763ab80d9SRafal Ostrowski /* When going from a smaller ODM slice count to larger, we must ensure double
228863ab80d9SRafal Ostrowski * buffer update completes before we return to ensure we don't reduce DISPCLK
228963ab80d9SRafal Ostrowski * before we've transitioned to 2:1 or 4:1
229063ab80d9SRafal Ostrowski */
229163ab80d9SRafal Ostrowski if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) &&
229263ab80d9SRafal Ostrowski resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) &&
229363ab80d9SRafal Ostrowski dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
229463ab80d9SRafal Ostrowski int j = 0;
229563ab80d9SRafal Ostrowski struct timing_generator *tg = pipe->stream_res.tg;
229663ab80d9SRafal Ostrowski
229763ab80d9SRafal Ostrowski if (tg->funcs->get_optc_double_buffer_pending) {
229863ab80d9SRafal Ostrowski for (j = 0; j < timeout_us / polling_interval_us
229963ab80d9SRafal Ostrowski && tg->funcs->get_optc_double_buffer_pending(tg); j++)
230063ab80d9SRafal Ostrowski udelay(polling_interval_us);
230163ab80d9SRafal Ostrowski }
230263ab80d9SRafal Ostrowski }
230363ab80d9SRafal Ostrowski }
230463ab80d9SRafal Ostrowski
230563ab80d9SRafal Ostrowski if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
230663ab80d9SRafal Ostrowski dc->res_pool->hubbub->funcs->force_pstate_change_control(
230763ab80d9SRafal Ostrowski dc->res_pool->hubbub, false, false);
230863ab80d9SRafal Ostrowski
230963ab80d9SRafal Ostrowski
231063ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++) {
231163ab80d9SRafal Ostrowski struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
231263ab80d9SRafal Ostrowski
231363ab80d9SRafal Ostrowski if (pipe->plane_state && !pipe->top_pipe) {
231463ab80d9SRafal Ostrowski /* Program phantom pipe here to prevent a frame of underflow in the MPO transition
231563ab80d9SRafal Ostrowski * case (if a pipe being used for a video plane transitions to a phantom pipe, it
231663ab80d9SRafal Ostrowski * can underflow due to HUBP_VTG_SEL programming if done in the regular front end
231763ab80d9SRafal Ostrowski * programming sequence).
231863ab80d9SRafal Ostrowski */
231963ab80d9SRafal Ostrowski while (pipe) {
232063ab80d9SRafal Ostrowski if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
232163ab80d9SRafal Ostrowski /* When turning on the phantom pipe we want to run through the
232263ab80d9SRafal Ostrowski * entire enable sequence, so apply all the "enable" flags.
232363ab80d9SRafal Ostrowski */
232463ab80d9SRafal Ostrowski if (dc->hwss.apply_update_flags_for_phantom)
232563ab80d9SRafal Ostrowski dc->hwss.apply_update_flags_for_phantom(pipe);
232663ab80d9SRafal Ostrowski if (dc->hwss.update_phantom_vp_position)
232763ab80d9SRafal Ostrowski dc->hwss.update_phantom_vp_position(dc, context, pipe);
232863ab80d9SRafal Ostrowski dcn401_program_pipe(dc, pipe, context);
232963ab80d9SRafal Ostrowski }
233063ab80d9SRafal Ostrowski pipe = pipe->bottom_pipe;
233163ab80d9SRafal Ostrowski }
233263ab80d9SRafal Ostrowski }
233363ab80d9SRafal Ostrowski }
233463ab80d9SRafal Ostrowski
233563ab80d9SRafal Ostrowski if (!hwseq)
233663ab80d9SRafal Ostrowski return;
233763ab80d9SRafal Ostrowski
233863ab80d9SRafal Ostrowski /* P-State support transitions:
233963ab80d9SRafal Ostrowski * Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe
234063ab80d9SRafal Ostrowski * FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally)
234163ab80d9SRafal Ostrowski * Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe
234263ab80d9SRafal Ostrowski * FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe
234363ab80d9SRafal Ostrowski * FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes
234463ab80d9SRafal Ostrowski */
234563ab80d9SRafal Ostrowski if (hwseq->funcs.update_force_pstate)
234663ab80d9SRafal Ostrowski dc->hwseq->funcs.update_force_pstate(dc, context);
234763ab80d9SRafal Ostrowski
234863ab80d9SRafal Ostrowski /* Only program the MALL registers after all the main and phantom pipes
234963ab80d9SRafal Ostrowski * are done programming.
235063ab80d9SRafal Ostrowski */
235163ab80d9SRafal Ostrowski if (hwseq->funcs.program_mall_pipe_config)
235263ab80d9SRafal Ostrowski hwseq->funcs.program_mall_pipe_config(dc, context);
235363ab80d9SRafal Ostrowski
235463ab80d9SRafal Ostrowski /* WA to apply WM setting*/
235563ab80d9SRafal Ostrowski if (hwseq->wa.DEGVIDCN21)
235663ab80d9SRafal Ostrowski dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
235763ab80d9SRafal Ostrowski
235863ab80d9SRafal Ostrowski
235963ab80d9SRafal Ostrowski /* WA for stutter underflow during MPO transitions when adding 2nd plane */
236063ab80d9SRafal Ostrowski if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {
236163ab80d9SRafal Ostrowski
236263ab80d9SRafal Ostrowski if (dc->current_state->stream_status[0].plane_count == 1 &&
236363ab80d9SRafal Ostrowski context->stream_status[0].plane_count > 1) {
236490af9998SSung Lee
236563ab80d9SRafal Ostrowski struct timing_generator *tg = dc->res_pool->timing_generators[0];
236663ab80d9SRafal Ostrowski
236763ab80d9SRafal Ostrowski dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false);
236863ab80d9SRafal Ostrowski
236963ab80d9SRafal Ostrowski hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true;
237063ab80d9SRafal Ostrowski hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame =
237163ab80d9SRafal Ostrowski tg->funcs->get_frame_count(tg);
237263ab80d9SRafal Ostrowski }
237363ab80d9SRafal Ostrowski }
237463ab80d9SRafal Ostrowski }
237563ab80d9SRafal Ostrowski
dcn401_update_bandwidth(struct dc * dc,struct dc_state * context)237663ab80d9SRafal Ostrowski bool dcn401_update_bandwidth(
237763ab80d9SRafal Ostrowski struct dc *dc,
237863ab80d9SRafal Ostrowski struct dc_state *context)
237963ab80d9SRafal Ostrowski {
238063ab80d9SRafal Ostrowski int i;
238163ab80d9SRafal Ostrowski struct dce_hwseq *hws = dc->hwseq;
238263ab80d9SRafal Ostrowski
238363ab80d9SRafal Ostrowski /* recalculate DML parameters */
238463ab80d9SRafal Ostrowski if (dc->res_pool->funcs->validate_bandwidth(dc, context, DC_VALIDATE_MODE_AND_PROGRAMMING) != DC_OK)
238563ab80d9SRafal Ostrowski return false;
238663ab80d9SRafal Ostrowski
238763ab80d9SRafal Ostrowski /* apply updated bandwidth parameters */
238863ab80d9SRafal Ostrowski dc->hwss.prepare_bandwidth(dc, context);
238963ab80d9SRafal Ostrowski
239063ab80d9SRafal Ostrowski /* update hubp configs for all pipes */
239163ab80d9SRafal Ostrowski for (i = 0; i < dc->res_pool->pipe_count; i++) {
239263ab80d9SRafal Ostrowski struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
239363ab80d9SRafal Ostrowski
239463ab80d9SRafal Ostrowski if (pipe_ctx->plane_state == NULL)
239563ab80d9SRafal Ostrowski continue;
239663ab80d9SRafal Ostrowski
239763ab80d9SRafal Ostrowski if (pipe_ctx->top_pipe == NULL) {
239863ab80d9SRafal Ostrowski bool blank = !is_pipe_tree_visible(pipe_ctx);
239963ab80d9SRafal Ostrowski
240063ab80d9SRafal Ostrowski pipe_ctx->stream_res.tg->funcs->program_global_sync(
240163ab80d9SRafal Ostrowski pipe_ctx->stream_res.tg,
240263ab80d9SRafal Ostrowski dcn401_calculate_vready_offset_for_group(pipe_ctx),
240363ab80d9SRafal Ostrowski (unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
240463ab80d9SRafal Ostrowski (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
240563ab80d9SRafal Ostrowski (unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
240663ab80d9SRafal Ostrowski (unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines);
240763ab80d9SRafal Ostrowski
240863ab80d9SRafal Ostrowski pipe_ctx->stream_res.tg->funcs->set_vtg_params(
240963ab80d9SRafal Ostrowski pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false);
241063ab80d9SRafal Ostrowski
241163ab80d9SRafal Ostrowski if (pipe_ctx->prev_odm_pipe == NULL)
241263ab80d9SRafal Ostrowski hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
241363ab80d9SRafal Ostrowski
241463ab80d9SRafal Ostrowski if (hws->funcs.setup_vupdate_interrupt)
241563ab80d9SRafal Ostrowski hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
241663ab80d9SRafal Ostrowski }
241763ab80d9SRafal Ostrowski
241863ab80d9SRafal Ostrowski if (pipe_ctx->plane_res.hubp->funcs->hubp_setup2)
241963ab80d9SRafal Ostrowski pipe_ctx->plane_res.hubp->funcs->hubp_setup2(
242063ab80d9SRafal Ostrowski pipe_ctx->plane_res.hubp,
242163ab80d9SRafal Ostrowski &pipe_ctx->hubp_regs,
242263ab80d9SRafal Ostrowski &pipe_ctx->global_sync,
242363ab80d9SRafal Ostrowski &pipe_ctx->stream->timing);
242463ab80d9SRafal Ostrowski }
242563ab80d9SRafal Ostrowski
242663ab80d9SRafal Ostrowski return true;
242763ab80d9SRafal Ostrowski }
242863ab80d9SRafal Ostrowski
dcn401_detect_pipe_changes(struct dc_state * old_state,struct dc_state * new_state,struct pipe_ctx * old_pipe,struct pipe_ctx * new_pipe)242963ab80d9SRafal Ostrowski void dcn401_detect_pipe_changes(struct dc_state *old_state,
243063ab80d9SRafal Ostrowski struct dc_state *new_state,
243163ab80d9SRafal Ostrowski struct pipe_ctx *old_pipe,
243263ab80d9SRafal Ostrowski struct pipe_ctx *new_pipe)
243363ab80d9SRafal Ostrowski {
243463ab80d9SRafal Ostrowski bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM;
243563ab80d9SRafal Ostrowski bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM;
243663ab80d9SRafal Ostrowski
243763ab80d9SRafal Ostrowski unsigned int old_pipe_vready_offset_pixels = old_pipe->global_sync.dcn4x.vready_offset_pixels;
243863ab80d9SRafal Ostrowski unsigned int new_pipe_vready_offset_pixels = new_pipe->global_sync.dcn4x.vready_offset_pixels;
243963ab80d9SRafal Ostrowski unsigned int old_pipe_vstartup_lines = old_pipe->global_sync.dcn4x.vstartup_lines;
244063ab80d9SRafal Ostrowski unsigned int new_pipe_vstartup_lines = new_pipe->global_sync.dcn4x.vstartup_lines;
244163ab80d9SRafal Ostrowski unsigned int old_pipe_vupdate_offset_pixels = old_pipe->global_sync.dcn4x.vupdate_offset_pixels;
244263ab80d9SRafal Ostrowski unsigned int new_pipe_vupdate_offset_pixels = new_pipe->global_sync.dcn4x.vupdate_offset_pixels;
244363ab80d9SRafal Ostrowski unsigned int old_pipe_vupdate_width_pixels = old_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels;
244463ab80d9SRafal Ostrowski unsigned int new_pipe_vupdate_width_pixels = new_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels;
244563ab80d9SRafal Ostrowski
244663ab80d9SRafal Ostrowski new_pipe->update_flags.raw = 0;
244763ab80d9SRafal Ostrowski
244863ab80d9SRafal Ostrowski /* If non-phantom pipe is being transitioned to a phantom pipe,
244963ab80d9SRafal Ostrowski * set disable and return immediately. This is because the pipe
245063ab80d9SRafal Ostrowski * that was previously in use must be fully disabled before we
245163ab80d9SRafal Ostrowski * can "enable" it as a phantom pipe (since the OTG will certainly
245263ab80d9SRafal Ostrowski * be different). The post_unlock sequence will set the correct
245363ab80d9SRafal Ostrowski * update flags to enable the phantom pipe.
245463ab80d9SRafal Ostrowski */
245563ab80d9SRafal Ostrowski if (old_pipe->plane_state && !old_is_phantom &&
245663ab80d9SRafal Ostrowski new_pipe->plane_state && new_is_phantom) {
245763ab80d9SRafal Ostrowski new_pipe->update_flags.bits.disable = 1;
245863ab80d9SRafal Ostrowski return;
245963ab80d9SRafal Ostrowski }
246063ab80d9SRafal Ostrowski
246163ab80d9SRafal Ostrowski if (resource_is_pipe_type(new_pipe, OTG_MASTER) &&
246263ab80d9SRafal Ostrowski resource_is_odm_topology_changed(new_pipe, old_pipe))
246363ab80d9SRafal Ostrowski /* Detect odm changes */
246463ab80d9SRafal Ostrowski new_pipe->update_flags.bits.odm = 1;
246563ab80d9SRafal Ostrowski
246663ab80d9SRafal Ostrowski /* Exit on unchanged, unused pipe */
246763ab80d9SRafal Ostrowski if (!old_pipe->plane_state && !new_pipe->plane_state)
246863ab80d9SRafal Ostrowski return;
246963ab80d9SRafal Ostrowski /* Detect pipe enable/disable */
247063ab80d9SRafal Ostrowski if (!old_pipe->plane_state && new_pipe->plane_state) {
247163ab80d9SRafal Ostrowski new_pipe->update_flags.bits.enable = 1;
247263ab80d9SRafal Ostrowski new_pipe->update_flags.bits.mpcc = 1;
247363ab80d9SRafal Ostrowski new_pipe->update_flags.bits.dppclk = 1;
247463ab80d9SRafal Ostrowski new_pipe->update_flags.bits.hubp_interdependent = 1;
247563ab80d9SRafal Ostrowski new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
247663ab80d9SRafal Ostrowski new_pipe->update_flags.bits.unbounded_req = 1;
247763ab80d9SRafal Ostrowski new_pipe->update_flags.bits.gamut_remap = 1;
247863ab80d9SRafal Ostrowski new_pipe->update_flags.bits.scaler = 1;
247963ab80d9SRafal Ostrowski new_pipe->update_flags.bits.viewport = 1;
248063ab80d9SRafal Ostrowski new_pipe->update_flags.bits.det_size = 1;
248163ab80d9SRafal Ostrowski if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE &&
248263ab80d9SRafal Ostrowski new_pipe->stream_res.test_pattern_params.width != 0 &&
248363ab80d9SRafal Ostrowski new_pipe->stream_res.test_pattern_params.height != 0)
248463ab80d9SRafal Ostrowski new_pipe->update_flags.bits.test_pattern_changed = 1;
248563ab80d9SRafal Ostrowski if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
248663ab80d9SRafal Ostrowski new_pipe->update_flags.bits.odm = 1;
248763ab80d9SRafal Ostrowski new_pipe->update_flags.bits.global_sync = 1;
248863ab80d9SRafal Ostrowski }
248963ab80d9SRafal Ostrowski return;
249063ab80d9SRafal Ostrowski }
249163ab80d9SRafal Ostrowski
249263ab80d9SRafal Ostrowski /* For SubVP we need to unconditionally enable because any phantom pipes are
249363ab80d9SRafal Ostrowski * always removed then newly added for every full updates whenever SubVP is in use.
249463ab80d9SRafal Ostrowski * The remove-add sequence of the phantom pipe always results in the pipe
249563ab80d9SRafal Ostrowski * being blanked in enable_stream_timing (DPG).
249663ab80d9SRafal Ostrowski */
249763ab80d9SRafal Ostrowski if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM)
249863ab80d9SRafal Ostrowski new_pipe->update_flags.bits.enable = 1;
249963ab80d9SRafal Ostrowski
250063ab80d9SRafal Ostrowski /* Phantom pipes are effectively disabled, if the pipe was previously phantom
250163ab80d9SRafal Ostrowski * we have to enable
250263ab80d9SRafal Ostrowski */
250363ab80d9SRafal Ostrowski if (old_pipe->plane_state && old_is_phantom &&
250463ab80d9SRafal Ostrowski new_pipe->plane_state && !new_is_phantom)
250563ab80d9SRafal Ostrowski new_pipe->update_flags.bits.enable = 1;
250663ab80d9SRafal Ostrowski
250763ab80d9SRafal Ostrowski if (old_pipe->plane_state && !new_pipe->plane_state) {
250863ab80d9SRafal Ostrowski new_pipe->update_flags.bits.disable = 1;
250963ab80d9SRafal Ostrowski return;
251063ab80d9SRafal Ostrowski }
251163ab80d9SRafal Ostrowski
251263ab80d9SRafal Ostrowski /* Detect plane change */
251363ab80d9SRafal Ostrowski if (old_pipe->plane_state != new_pipe->plane_state)
251463ab80d9SRafal Ostrowski new_pipe->update_flags.bits.plane_changed = true;
251563ab80d9SRafal Ostrowski
251663ab80d9SRafal Ostrowski /* Detect top pipe only changes */
251763ab80d9SRafal Ostrowski if (resource_is_pipe_type(new_pipe, OTG_MASTER)) {
251863ab80d9SRafal Ostrowski /* Detect global sync changes */
251963ab80d9SRafal Ostrowski if ((old_pipe_vready_offset_pixels != new_pipe_vready_offset_pixels)
252063ab80d9SRafal Ostrowski || (old_pipe_vstartup_lines != new_pipe_vstartup_lines)
252163ab80d9SRafal Ostrowski || (old_pipe_vupdate_offset_pixels != new_pipe_vupdate_offset_pixels)
252263ab80d9SRafal Ostrowski || (old_pipe_vupdate_width_pixels != new_pipe_vupdate_width_pixels))
252363ab80d9SRafal Ostrowski new_pipe->update_flags.bits.global_sync = 1;
252463ab80d9SRafal Ostrowski }
252563ab80d9SRafal Ostrowski
252663ab80d9SRafal Ostrowski if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb)
252763ab80d9SRafal Ostrowski new_pipe->update_flags.bits.det_size = 1;
252863ab80d9SRafal Ostrowski
252963ab80d9SRafal Ostrowski /*
253063ab80d9SRafal Ostrowski * Detect opp / tg change, only set on change, not on enable
253163ab80d9SRafal Ostrowski * Assume mpcc inst = pipe index, if not this code needs to be updated
253263ab80d9SRafal Ostrowski * since mpcc is what is affected by these. In fact all of our sequence
253363ab80d9SRafal Ostrowski * makes this assumption at the moment with how hubp reset is matched to
253463ab80d9SRafal Ostrowski * same index mpcc reset.
253563ab80d9SRafal Ostrowski */
253663ab80d9SRafal Ostrowski if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)
253763ab80d9SRafal Ostrowski new_pipe->update_flags.bits.opp_changed = 1;
253863ab80d9SRafal Ostrowski if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)
253963ab80d9SRafal Ostrowski new_pipe->update_flags.bits.tg_changed = 1;
254063ab80d9SRafal Ostrowski
254163ab80d9SRafal Ostrowski /*
254263ab80d9SRafal Ostrowski * Detect mpcc blending changes, only dpp inst and opp matter here,
254363ab80d9SRafal Ostrowski * mpccs getting removed/inserted update connected ones during their own
254463ab80d9SRafal Ostrowski * programming
254563ab80d9SRafal Ostrowski */
254663ab80d9SRafal Ostrowski if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp
254763ab80d9SRafal Ostrowski || old_pipe->stream_res.opp != new_pipe->stream_res.opp)
254863ab80d9SRafal Ostrowski new_pipe->update_flags.bits.mpcc = 1;
254963ab80d9SRafal Ostrowski
255063ab80d9SRafal Ostrowski /* Detect dppclk change */
255163ab80d9SRafal Ostrowski if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)
255263ab80d9SRafal Ostrowski new_pipe->update_flags.bits.dppclk = 1;
255363ab80d9SRafal Ostrowski
255463ab80d9SRafal Ostrowski /* Check for scl update */
255563ab80d9SRafal Ostrowski if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))
255663ab80d9SRafal Ostrowski new_pipe->update_flags.bits.scaler = 1;
255763ab80d9SRafal Ostrowski /* Check for vp update */
255863ab80d9SRafal Ostrowski if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))
255963ab80d9SRafal Ostrowski || memcmp(&old_pipe->plane_res.scl_data.viewport_c,
256063ab80d9SRafal Ostrowski &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))
256163ab80d9SRafal Ostrowski new_pipe->update_flags.bits.viewport = 1;
256263ab80d9SRafal Ostrowski
256363ab80d9SRafal Ostrowski /* Detect dlg/ttu/rq updates */
256463ab80d9SRafal Ostrowski {
256563ab80d9SRafal Ostrowski struct dml2_display_dlg_regs old_dlg_regs = old_pipe->hubp_regs.dlg_regs;
256663ab80d9SRafal Ostrowski struct dml2_display_ttu_regs old_ttu_regs = old_pipe->hubp_regs.ttu_regs;
256763ab80d9SRafal Ostrowski struct dml2_display_rq_regs old_rq_regs = old_pipe->hubp_regs.rq_regs;
256863ab80d9SRafal Ostrowski struct dml2_display_dlg_regs *new_dlg_regs = &new_pipe->hubp_regs.dlg_regs;
256963ab80d9SRafal Ostrowski struct dml2_display_ttu_regs *new_ttu_regs = &new_pipe->hubp_regs.ttu_regs;
257063ab80d9SRafal Ostrowski struct dml2_display_rq_regs *new_rq_regs = &new_pipe->hubp_regs.rq_regs;
257163ab80d9SRafal Ostrowski
257263ab80d9SRafal Ostrowski /* Detect pipe interdependent updates */
257363ab80d9SRafal Ostrowski if ((old_dlg_regs.dst_y_prefetch != new_dlg_regs->dst_y_prefetch)
257463ab80d9SRafal Ostrowski || (old_dlg_regs.vratio_prefetch != new_dlg_regs->vratio_prefetch)
257563ab80d9SRafal Ostrowski || (old_dlg_regs.vratio_prefetch_c != new_dlg_regs->vratio_prefetch_c)
257663ab80d9SRafal Ostrowski || (old_dlg_regs.dst_y_per_vm_vblank != new_dlg_regs->dst_y_per_vm_vblank)
257763ab80d9SRafal Ostrowski || (old_dlg_regs.dst_y_per_row_vblank != new_dlg_regs->dst_y_per_row_vblank)
257863ab80d9SRafal Ostrowski || (old_dlg_regs.dst_y_per_vm_flip != new_dlg_regs->dst_y_per_vm_flip)
257963ab80d9SRafal Ostrowski || (old_dlg_regs.dst_y_per_row_flip != new_dlg_regs->dst_y_per_row_flip)
258063ab80d9SRafal Ostrowski || (old_dlg_regs.refcyc_per_meta_chunk_vblank_l != new_dlg_regs->refcyc_per_meta_chunk_vblank_l)
258163ab80d9SRafal Ostrowski || (old_dlg_regs.refcyc_per_meta_chunk_vblank_c != new_dlg_regs->refcyc_per_meta_chunk_vblank_c)
258263ab80d9SRafal Ostrowski || (old_dlg_regs.refcyc_per_meta_chunk_flip_l != new_dlg_regs->refcyc_per_meta_chunk_flip_l)
258363ab80d9SRafal Ostrowski || (old_dlg_regs.refcyc_per_line_delivery_pre_l != new_dlg_regs->refcyc_per_line_delivery_pre_l)
258463ab80d9SRafal Ostrowski || (old_dlg_regs.refcyc_per_line_delivery_pre_c != new_dlg_regs->refcyc_per_line_delivery_pre_c)
258563ab80d9SRafal Ostrowski || (old_ttu_regs.refcyc_per_req_delivery_pre_l != new_ttu_regs->refcyc_per_req_delivery_pre_l)
258663ab80d9SRafal Ostrowski || (old_ttu_regs.refcyc_per_req_delivery_pre_c != new_ttu_regs->refcyc_per_req_delivery_pre_c)
258763ab80d9SRafal Ostrowski || (old_ttu_regs.refcyc_per_req_delivery_pre_cur0 !=
258863ab80d9SRafal Ostrowski new_ttu_regs->refcyc_per_req_delivery_pre_cur0)
258963ab80d9SRafal Ostrowski || (old_ttu_regs.min_ttu_vblank != new_ttu_regs->min_ttu_vblank)
259063ab80d9SRafal Ostrowski || (old_ttu_regs.qos_level_flip != new_ttu_regs->qos_level_flip)) {
259163ab80d9SRafal Ostrowski old_dlg_regs.dst_y_prefetch = new_dlg_regs->dst_y_prefetch;
259263ab80d9SRafal Ostrowski old_dlg_regs.vratio_prefetch = new_dlg_regs->vratio_prefetch;
259363ab80d9SRafal Ostrowski old_dlg_regs.vratio_prefetch_c = new_dlg_regs->vratio_prefetch_c;
259463ab80d9SRafal Ostrowski old_dlg_regs.dst_y_per_vm_vblank = new_dlg_regs->dst_y_per_vm_vblank;
259563ab80d9SRafal Ostrowski old_dlg_regs.dst_y_per_row_vblank = new_dlg_regs->dst_y_per_row_vblank;
259663ab80d9SRafal Ostrowski old_dlg_regs.dst_y_per_vm_flip = new_dlg_regs->dst_y_per_vm_flip;
259763ab80d9SRafal Ostrowski old_dlg_regs.dst_y_per_row_flip = new_dlg_regs->dst_y_per_row_flip;
259863ab80d9SRafal Ostrowski old_dlg_regs.refcyc_per_meta_chunk_vblank_l = new_dlg_regs->refcyc_per_meta_chunk_vblank_l;
259963ab80d9SRafal Ostrowski old_dlg_regs.refcyc_per_meta_chunk_vblank_c = new_dlg_regs->refcyc_per_meta_chunk_vblank_c;
260063ab80d9SRafal Ostrowski old_dlg_regs.refcyc_per_meta_chunk_flip_l = new_dlg_regs->refcyc_per_meta_chunk_flip_l;
260163ab80d9SRafal Ostrowski old_dlg_regs.refcyc_per_line_delivery_pre_l = new_dlg_regs->refcyc_per_line_delivery_pre_l;
260263ab80d9SRafal Ostrowski old_dlg_regs.refcyc_per_line_delivery_pre_c = new_dlg_regs->refcyc_per_line_delivery_pre_c;
260363ab80d9SRafal Ostrowski old_ttu_regs.refcyc_per_req_delivery_pre_l = new_ttu_regs->refcyc_per_req_delivery_pre_l;
260463ab80d9SRafal Ostrowski old_ttu_regs.refcyc_per_req_delivery_pre_c = new_ttu_regs->refcyc_per_req_delivery_pre_c;
260563ab80d9SRafal Ostrowski old_ttu_regs.refcyc_per_req_delivery_pre_cur0 = new_ttu_regs->refcyc_per_req_delivery_pre_cur0;
260663ab80d9SRafal Ostrowski old_ttu_regs.min_ttu_vblank = new_ttu_regs->min_ttu_vblank;
260763ab80d9SRafal Ostrowski old_ttu_regs.qos_level_flip = new_ttu_regs->qos_level_flip;
260863ab80d9SRafal Ostrowski new_pipe->update_flags.bits.hubp_interdependent = 1;
260963ab80d9SRafal Ostrowski }
261063ab80d9SRafal Ostrowski /* Detect any other updates to ttu/rq/dlg */
261163ab80d9SRafal Ostrowski if (memcmp(&old_dlg_regs, new_dlg_regs, sizeof(old_dlg_regs)) ||
261263ab80d9SRafal Ostrowski memcmp(&old_ttu_regs, new_ttu_regs, sizeof(old_ttu_regs)) ||
261363ab80d9SRafal Ostrowski memcmp(&old_rq_regs, new_rq_regs, sizeof(old_rq_regs)))
261463ab80d9SRafal Ostrowski new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
261563ab80d9SRafal Ostrowski }
261663ab80d9SRafal Ostrowski
261763ab80d9SRafal Ostrowski if (old_pipe->unbounded_req != new_pipe->unbounded_req)
261863ab80d9SRafal Ostrowski new_pipe->update_flags.bits.unbounded_req = 1;
261963ab80d9SRafal Ostrowski
262063ab80d9SRafal Ostrowski if (memcmp(&old_pipe->stream_res.test_pattern_params,
262163ab80d9SRafal Ostrowski &new_pipe->stream_res.test_pattern_params, sizeof(struct test_pattern_params))) {
262263ab80d9SRafal Ostrowski new_pipe->update_flags.bits.test_pattern_changed = 1;
262363ab80d9SRafal Ostrowski }
262463ab80d9SRafal Ostrowski }
262563ab80d9SRafal Ostrowski
dcn401_plane_atomic_power_down(struct dc * dc,struct dpp * dpp,struct hubp * hubp)262663ab80d9SRafal Ostrowski void dcn401_plane_atomic_power_down(struct dc *dc,
262763ab80d9SRafal Ostrowski struct dpp *dpp,
262863ab80d9SRafal Ostrowski struct hubp *hubp)
262963ab80d9SRafal Ostrowski {
263063ab80d9SRafal Ostrowski struct dce_hwseq *hws = dc->hwseq;
263163ab80d9SRafal Ostrowski uint32_t org_ip_request_cntl = 0;
263263ab80d9SRafal Ostrowski
263363ab80d9SRafal Ostrowski DC_LOGGER_INIT(dc->ctx->logger);
263463ab80d9SRafal Ostrowski
263563ab80d9SRafal Ostrowski if (REG(DC_IP_REQUEST_CNTL)) {
263663ab80d9SRafal Ostrowski REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
263763ab80d9SRafal Ostrowski if (org_ip_request_cntl == 0)
263863ab80d9SRafal Ostrowski REG_SET(DC_IP_REQUEST_CNTL, 0,
263963ab80d9SRafal Ostrowski IP_REQUEST_EN, 1);
264063ab80d9SRafal Ostrowski }
264163ab80d9SRafal Ostrowski
264263ab80d9SRafal Ostrowski if (hws->funcs.dpp_pg_control)
264363ab80d9SRafal Ostrowski hws->funcs.dpp_pg_control(hws, dpp->inst, false);
264463ab80d9SRafal Ostrowski
264563ab80d9SRafal Ostrowski if (hws->funcs.hubp_pg_control)
264663ab80d9SRafal Ostrowski hws->funcs.hubp_pg_control(hws, hubp->inst, false);
264763ab80d9SRafal Ostrowski
264863ab80d9SRafal Ostrowski hubp->funcs->hubp_reset(hubp);
264963ab80d9SRafal Ostrowski dpp->funcs->dpp_reset(dpp);
265063ab80d9SRafal Ostrowski
265163ab80d9SRafal Ostrowski if (org_ip_request_cntl == 0 && REG(DC_IP_REQUEST_CNTL))
265263ab80d9SRafal Ostrowski REG_SET(DC_IP_REQUEST_CNTL, 0,
265363ab80d9SRafal Ostrowski IP_REQUEST_EN, 0);
26544465dd0eSDillon Varone
265563ab80d9SRafal Ostrowski DC_LOG_DEBUG(
265663ab80d9SRafal Ostrowski "Power gated front end %d\n", hubp->inst);
265763ab80d9SRafal Ostrowski
265863ab80d9SRafal Ostrowski if (hws->funcs.dpp_root_clock_control)
265963ab80d9SRafal Ostrowski hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
266063ab80d9SRafal Ostrowski }
266163ab80d9SRafal Ostrowski