From: Mounika Adhuri Date: Fri, 22 Sep 2023 12:53:28 +0000 (+0530) Subject: drm/amd/display: Refactor HWSS into component folder X-Git-Tag: microblaze-v6.8~11^2~16^2~84 X-Git-Url: http://git.monstr.eu/?a=commitdiff_plain;h=e53524cdcc02d089e757b668da031ba06ff665c3;p=linux-2.6-microblaze.git drm/amd/display: Refactor HWSS into component folder [why] Rename hw_sequencer to hwseq. Move all hwseq files to unique folder hwss. [how] creating hwss repo in dc, and moved the dcnxx_hwseq.c and .h files into corresponding new folders inside the hwss and cleared the linkage errors by adding relative paths in the Makefile.template. Reviewed-by: Martin Leung Acked-by: Tom Chung Signed-off-by: Mounika Adhuri Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 0d610cb376bb..af17ab8027df 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -29,6 +29,7 @@ AMDDALPATH = $(RELATIVE_AMD_DISPLAY_PATH) subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/clk_mgr +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/hwss subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 53ec7829bf81..3a169b78e7e4 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -22,7 +22,7 @@ # # Makefile for Display Core (dc) component. -DC_LIBS = basics bios clk_mgr dce gpio irq link virtual dsc +DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link virtual dsc ifdef CONFIG_DRM_AMD_DC_FP diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c index 5399b8cf6b75..c9ba7b3fd2c3 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c @@ -30,7 +30,7 @@ #include "dce110/dce110_clk_mgr.h" #include "dce120_clk_mgr.h" #include "dce100/dce_clk_mgr.h" -#include "dce120/dce120_hw_sequencer.h" +#include "dce120/dce120_hwseq.h" static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /*ClocksStateInvalid - should not be used*/ diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2bd30a777311..38e5f022558b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -35,7 +35,7 @@ #include "grph_object_ctrl_defs.h" #include -#include "inc/hw_sequencer.h" +#include "hwss/hw_sequencer.h" #include "inc/compressor.h" #include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce/Makefile b/drivers/gpu/drm/amd/display/dc/dce/Makefile index 15b64c26d5a2..986e0e7abbc2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce/Makefile @@ -26,7 +26,7 @@ # - register programming through common macros that look up register # offset/shift/mask stored in dce_hw struct -DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o dce_hwseq.o \ +DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o \ dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \ dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o \ dce_i2c.o dce_i2c_hw.o dce_i2c_sw.o dmub_psr.o dmub_abm.o dmub_abm_lcd.o dce_panel_cntl.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c deleted file mode 100644 index 4202fadb2c0e..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dce_hwseq.h" -#include "reg_helper.h" -#include "hw_sequencer_private.h" -#include "core_types.h" - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -void dce_enable_fe_clock(struct dce_hwseq *hws, - unsigned int fe_inst, bool enable) -{ - REG_UPDATE(DCFE_CLOCK_CONTROL[fe_inst], - DCFE_CLOCK_ENABLE, enable); -} - -void dce_pipe_control_lock(struct dc *dc, - struct pipe_ctx *pipe, - bool lock) -{ - uint32_t lock_val = lock ? 1 : 0; - uint32_t dcp_grph, scl, blnd, update_lock_mode, val; - struct dce_hwseq *hws = dc->hwseq; - - /* Not lock pipe when blank */ - if (lock && pipe->stream_res.tg->funcs->is_blanked && - pipe->stream_res.tg->funcs->is_blanked(pipe->stream_res.tg)) - return; - - val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], - BLND_DCP_GRPH_V_UPDATE_LOCK, &dcp_grph, - BLND_SCL_V_UPDATE_LOCK, &scl, - BLND_BLND_V_UPDATE_LOCK, &blnd, - BLND_V_UPDATE_LOCK_MODE, &update_lock_mode); - - dcp_grph = lock_val; - scl = lock_val; - blnd = lock_val; - update_lock_mode = lock_val; - - REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, - BLND_DCP_GRPH_V_UPDATE_LOCK, dcp_grph, - BLND_SCL_V_UPDATE_LOCK, scl); - - if (hws->masks->BLND_BLND_V_UPDATE_LOCK != 0) - REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, - BLND_BLND_V_UPDATE_LOCK, blnd, - BLND_V_UPDATE_LOCK_MODE, update_lock_mode); - - if (hws->wa.blnd_crtc_trigger) { - if (!lock) { - uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst]); - REG_WRITE(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst], value); - } - } -} - -#if defined(CONFIG_DRM_AMD_DC_SI) -void dce60_pipe_control_lock(struct dc *dc, - struct pipe_ctx *pipe, - bool lock) -{ - /* DCE6 has no BLND_V_UPDATE_LOCK register */ -} -#endif - -void dce_set_blender_mode(struct dce_hwseq *hws, - unsigned int blnd_inst, - enum blnd_mode mode) -{ - uint32_t feedthrough = 1; - uint32_t blnd_mode = 0; - uint32_t multiplied_mode = 0; - uint32_t alpha_mode = 2; - - switch (mode) { - case BLND_MODE_OTHER_PIPE: - feedthrough = 0; - blnd_mode = 1; - alpha_mode = 0; - break; - case BLND_MODE_BLENDING: - feedthrough = 0; - blnd_mode = 2; - alpha_mode = 0; - multiplied_mode = 1; - break; - case BLND_MODE_CURRENT_PIPE: - default: - if (REG(BLND_CONTROL[blnd_inst]) == REG(BLNDV_CONTROL) || - blnd_inst == 0) - feedthrough = 0; - break; - } - - REG_UPDATE(BLND_CONTROL[blnd_inst], - BLND_MODE, blnd_mode); - - if (hws->masks->BLND_ALPHA_MODE != 0) { - REG_UPDATE_3(BLND_CONTROL[blnd_inst], - BLND_FEEDTHROUGH_EN, feedthrough, - BLND_ALPHA_MODE, alpha_mode, - BLND_MULTIPLIED_MODE, multiplied_mode); - } -} - - -static void dce_disable_sram_shut_down(struct dce_hwseq *hws) -{ - if (REG(DC_MEM_GLOBAL_PWR_REQ_CNTL)) - REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, - DC_MEM_GLOBAL_PWR_REQ_DIS, 1); -} - -static void dce_underlay_clock_enable(struct dce_hwseq *hws) -{ - /* todo: why do we need this at boot? is dce_enable_fe_clock enough? */ - if (REG(DCFEV_CLOCK_CONTROL)) - REG_UPDATE(DCFEV_CLOCK_CONTROL, - DCFEV_CLOCK_ENABLE, 1); -} - -static void enable_hw_base_light_sleep(void) -{ - /* TODO: implement */ -} - -static void disable_sw_manual_control_light_sleep(void) -{ - /* TODO: implement */ -} - -void dce_clock_gating_power_up(struct dce_hwseq *hws, - bool enable) -{ - if (enable) { - enable_hw_base_light_sleep(); - disable_sw_manual_control_light_sleep(); - } else { - dce_disable_sram_shut_down(hws); - dce_underlay_clock_enable(hws); - } -} - -void dce_crtc_switch_to_clk_src(struct dce_hwseq *hws, - struct clock_source *clk_src, - unsigned int tg_inst) -{ - if (clk_src->id == CLOCK_SOURCE_ID_DP_DTO || clk_src->dp_clk_src) { - REG_UPDATE(PIXEL_RATE_CNTL[tg_inst], - DP_DTO0_ENABLE, 1); - - } else if (clk_src->id >= CLOCK_SOURCE_COMBO_PHY_PLL0) { - uint32_t rate_source = clk_src->id - CLOCK_SOURCE_COMBO_PHY_PLL0; - - REG_UPDATE_2(PHYPLL_PIXEL_RATE_CNTL[tg_inst], - PHYPLL_PIXEL_RATE_SOURCE, rate_source, - PIXEL_RATE_PLL_SOURCE, 0); - - REG_UPDATE(PIXEL_RATE_CNTL[tg_inst], - DP_DTO0_ENABLE, 0); - - } else if (clk_src->id <= CLOCK_SOURCE_ID_PLL2) { - uint32_t rate_source = clk_src->id - CLOCK_SOURCE_ID_PLL0; - - REG_UPDATE_2(PIXEL_RATE_CNTL[tg_inst], - PIXEL_RATE_SOURCE, rate_source, - DP_DTO0_ENABLE, 0); - - if (REG(PHYPLL_PIXEL_RATE_CNTL[tg_inst])) - REG_UPDATE(PHYPLL_PIXEL_RATE_CNTL[tg_inst], - PIXEL_RATE_PLL_SOURCE, 1); - } else { - DC_ERR("Unknown clock source. clk_src id: %d, TG_inst: %d", - clk_src->id, tg_inst); - } -} - -/* Only use LUT for 8 bit formats */ -bool dce_use_lut(enum surface_pixel_format format) -{ - switch (format) { - case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: - case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: - return true; - default: - return false; - } -} diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h deleted file mode 100644 index 2fefdf40612d..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ /dev/null @@ -1,1241 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#ifndef __DCE_HWSEQ_H__ -#define __DCE_HWSEQ_H__ - -#include "dc_types.h" - -#define HWSEQ_DCEF_REG_LIST_DCE8() \ - .DCFE_CLOCK_CONTROL[0] = mmCRTC0_CRTC_DCFE_CLOCK_CONTROL, \ - .DCFE_CLOCK_CONTROL[1] = mmCRTC1_CRTC_DCFE_CLOCK_CONTROL, \ - .DCFE_CLOCK_CONTROL[2] = mmCRTC2_CRTC_DCFE_CLOCK_CONTROL, \ - .DCFE_CLOCK_CONTROL[3] = mmCRTC3_CRTC_DCFE_CLOCK_CONTROL, \ - .DCFE_CLOCK_CONTROL[4] = mmCRTC4_CRTC_DCFE_CLOCK_CONTROL, \ - .DCFE_CLOCK_CONTROL[5] = mmCRTC5_CRTC_DCFE_CLOCK_CONTROL - -#define HWSEQ_DCEF_REG_LIST() \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 0), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 1), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 2), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 3), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 4), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 5), \ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL) - -#define HWSEQ_BLND_REG_LIST() \ - SRII(BLND_V_UPDATE_LOCK, BLND, 0), \ - SRII(BLND_V_UPDATE_LOCK, BLND, 1), \ - SRII(BLND_V_UPDATE_LOCK, BLND, 2), \ - SRII(BLND_V_UPDATE_LOCK, BLND, 3), \ - SRII(BLND_V_UPDATE_LOCK, BLND, 4), \ - SRII(BLND_V_UPDATE_LOCK, BLND, 5), \ - SRII(BLND_CONTROL, BLND, 0), \ - SRII(BLND_CONTROL, BLND, 1), \ - SRII(BLND_CONTROL, BLND, 2), \ - SRII(BLND_CONTROL, BLND, 3), \ - SRII(BLND_CONTROL, BLND, 4), \ - SRII(BLND_CONTROL, BLND, 5) - -#define HSWEQ_DCN_PIXEL_RATE_REG_LIST(blk, inst) \ - SRII(PIXEL_RATE_CNTL, blk, inst), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, inst) - -#define HWSEQ_PIXEL_RATE_REG_LIST(blk) \ - SRII(PIXEL_RATE_CNTL, blk, 0), \ - SRII(PIXEL_RATE_CNTL, blk, 1), \ - SRII(PIXEL_RATE_CNTL, blk, 2), \ - SRII(PIXEL_RATE_CNTL, blk, 3), \ - SRII(PIXEL_RATE_CNTL, blk, 4), \ - SRII(PIXEL_RATE_CNTL, blk, 5) - -#define HWSEQ_PIXEL_RATE_REG_LIST_201(blk) \ - SRII(PIXEL_RATE_CNTL, blk, 0), \ - SRII(PIXEL_RATE_CNTL, blk, 1) - -#define HWSEQ_PHYPLL_REG_LIST(blk) \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 5) - -#define HWSEQ_PIXEL_RATE_REG_LIST_3(blk) \ - SRII(PIXEL_RATE_CNTL, blk, 0), \ - SRII(PIXEL_RATE_CNTL, blk, 1),\ - SRII(PIXEL_RATE_CNTL, blk, 2),\ - SRII(PIXEL_RATE_CNTL, blk, 3), \ - SRII(PIXEL_RATE_CNTL, blk, 4), \ - SRII(PIXEL_RATE_CNTL, blk, 5) - -#define HWSEQ_PHYPLL_REG_LIST_3(blk) \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 5) - -#define HWSEQ_PIXEL_RATE_REG_LIST_302(blk) \ - SRII(PIXEL_RATE_CNTL, blk, 0), \ - SRII(PIXEL_RATE_CNTL, blk, 1),\ - SRII(PIXEL_RATE_CNTL, blk, 2),\ - SRII(PIXEL_RATE_CNTL, blk, 3), \ - SRII(PIXEL_RATE_CNTL, blk, 4) - -#define HWSEQ_PHYPLL_REG_LIST_302(blk) \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4) - -#define HWSEQ_PIXEL_RATE_REG_LIST_303(blk) \ - SRII(PIXEL_RATE_CNTL, blk, 0), \ - SRII(PIXEL_RATE_CNTL, blk, 1) - -#define HWSEQ_PHYPLL_REG_LIST_303(blk) \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1) - - -#define HWSEQ_PHYPLL_REG_LIST_201(blk) \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ - SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1) - -#define HWSEQ_DCE11_REG_LIST_BASE() \ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SR(DCFEV_CLOCK_CONTROL), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 0), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 1), \ - SRII(CRTC_H_BLANK_START_END, CRTC, 0),\ - SRII(CRTC_H_BLANK_START_END, CRTC, 1),\ - SRII(BLND_V_UPDATE_LOCK, BLND, 0),\ - SRII(BLND_V_UPDATE_LOCK, BLND, 1),\ - SRII(BLND_CONTROL, BLND, 0),\ - SRII(BLND_CONTROL, BLND, 1),\ - SR(BLNDV_CONTROL),\ - HWSEQ_PIXEL_RATE_REG_LIST(CRTC) - -#if defined(CONFIG_DRM_AMD_DC_SI) -#define HWSEQ_DCE6_REG_LIST() \ - HWSEQ_DCEF_REG_LIST_DCE8(), \ - HWSEQ_PIXEL_RATE_REG_LIST(CRTC) -#endif - -#define HWSEQ_DCE8_REG_LIST() \ - HWSEQ_DCEF_REG_LIST_DCE8(), \ - HWSEQ_BLND_REG_LIST(), \ - HWSEQ_PIXEL_RATE_REG_LIST(CRTC) - -#define HWSEQ_DCE10_REG_LIST() \ - HWSEQ_DCEF_REG_LIST(), \ - HWSEQ_BLND_REG_LIST(), \ - HWSEQ_PIXEL_RATE_REG_LIST(CRTC) - -#define HWSEQ_ST_REG_LIST() \ - HWSEQ_DCE11_REG_LIST_BASE(), \ - .DCFE_CLOCK_CONTROL[2] = mmDCFEV_CLOCK_CONTROL, \ - .CRTC_H_BLANK_START_END[2] = mmCRTCV_H_BLANK_START_END, \ - .BLND_V_UPDATE_LOCK[2] = mmBLNDV_V_UPDATE_LOCK, \ - .BLND_CONTROL[2] = mmBLNDV_CONTROL - -#define HWSEQ_CZ_REG_LIST() \ - HWSEQ_DCE11_REG_LIST_BASE(), \ - SRII(DCFE_CLOCK_CONTROL, DCFE, 2), \ - SRII(CRTC_H_BLANK_START_END, CRTC, 2), \ - SRII(BLND_V_UPDATE_LOCK, BLND, 2), \ - SRII(BLND_CONTROL, BLND, 2), \ - .DCFE_CLOCK_CONTROL[3] = mmDCFEV_CLOCK_CONTROL, \ - .CRTC_H_BLANK_START_END[3] = mmCRTCV_H_BLANK_START_END, \ - .BLND_V_UPDATE_LOCK[3] = mmBLNDV_V_UPDATE_LOCK, \ - .BLND_CONTROL[3] = mmBLNDV_CONTROL - -#define HWSEQ_DCE120_REG_LIST() \ - HWSEQ_DCE10_REG_LIST(), \ - HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \ - HWSEQ_PHYPLL_REG_LIST(CRTC), \ - SR(DCHUB_FB_LOCATION),\ - SR(DCHUB_AGP_BASE),\ - SR(DCHUB_AGP_BOT),\ - SR(DCHUB_AGP_TOP) - -#define HWSEQ_VG20_REG_LIST() \ - HWSEQ_DCE120_REG_LIST(),\ - MMHUB_SR(MC_VM_XGMI_LFB_CNTL) - -#define HWSEQ_DCE112_REG_LIST() \ - HWSEQ_DCE10_REG_LIST(), \ - HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \ - HWSEQ_PHYPLL_REG_LIST(CRTC) - -#define HWSEQ_DCN_REG_LIST()\ - SR(REFCLK_CNTL), \ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DCFCLK_CNTL), \ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL) - - -#define MMHUB_DCN_REG_LIST()\ - /* todo: get these from GVM instead of reading registers ourselves */\ - MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32),\ - MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32),\ - MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32),\ - MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32),\ - MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32),\ - MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32),\ - MMHUB_SR(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32),\ - MMHUB_SR(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32),\ - MMHUB_SR(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB),\ - MMHUB_SR(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB),\ - MMHUB_SR(MC_VM_SYSTEM_APERTURE_LOW_ADDR),\ - MMHUB_SR(MC_VM_SYSTEM_APERTURE_HIGH_ADDR) - - -#define HWSEQ_DCN1_REG_LIST()\ - HWSEQ_DCN_REG_LIST(), \ - MMHUB_DCN_REG_LIST(), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ - SR(DCHUBBUB_SDPIF_FB_BASE),\ - SR(DCHUBBUB_SDPIF_FB_OFFSET),\ - SR(DCHUBBUB_SDPIF_AGP_BASE),\ - SR(DCHUBBUB_SDPIF_AGP_BOT),\ - SR(DCHUBBUB_SDPIF_AGP_TOP),\ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN4_PG_CONFIG), \ - SR(DOMAIN5_PG_CONFIG), \ - SR(DOMAIN6_PG_CONFIG), \ - SR(DOMAIN7_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN4_PG_STATUS), \ - SR(DOMAIN5_PG_STATUS), \ - SR(DOMAIN6_PG_STATUS), \ - SR(DOMAIN7_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(VGA_TEST_CONTROL), \ - SR(DC_IP_REQUEST_CNTL) - -#define HWSEQ_DCN2_REG_LIST()\ - HWSEQ_DCN_REG_LIST(), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 4), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 5), \ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN4_PG_CONFIG), \ - SR(DOMAIN5_PG_CONFIG), \ - SR(DOMAIN6_PG_CONFIG), \ - SR(DOMAIN7_PG_CONFIG), \ - SR(DOMAIN8_PG_CONFIG), \ - SR(DOMAIN9_PG_CONFIG), \ -/* SR(DOMAIN10_PG_CONFIG), Navi1x HUBP5 not powergate-able*/\ -/* SR(DOMAIN11_PG_CONFIG), Navi1x DPP5 is not powergate-able */\ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN19_PG_CONFIG), \ - SR(DOMAIN20_PG_CONFIG), \ - SR(DOMAIN21_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN4_PG_STATUS), \ - SR(DOMAIN5_PG_STATUS), \ - SR(DOMAIN6_PG_STATUS), \ - SR(DOMAIN7_PG_STATUS), \ - SR(DOMAIN8_PG_STATUS), \ - SR(DOMAIN9_PG_STATUS), \ - SR(DOMAIN10_PG_STATUS), \ - SR(DOMAIN11_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(DOMAIN19_PG_STATUS), \ - SR(DOMAIN20_PG_STATUS), \ - SR(DOMAIN21_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL) - -#define HWSEQ_DCN21_REG_LIST()\ - HWSEQ_DCN_REG_LIST(), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ - MMHUB_DCN_REG_LIST(), \ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN4_PG_CONFIG), \ - SR(DOMAIN5_PG_CONFIG), \ - SR(DOMAIN6_PG_CONFIG), \ - SR(DOMAIN7_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN4_PG_STATUS), \ - SR(DOMAIN5_PG_STATUS), \ - SR(DOMAIN6_PG_STATUS), \ - SR(DOMAIN7_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL) - -#define HWSEQ_DCN201_REG_LIST()\ - HWSEQ_DCN_REG_LIST(), \ - HWSEQ_PIXEL_RATE_REG_LIST_201(OTG), \ - HWSEQ_PHYPLL_REG_LIST_201(OTG), \ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - MMHUB_SR(MC_VM_FB_LOCATION_BASE), \ - MMHUB_SR(MC_VM_FB_LOCATION_TOP), \ - MMHUB_SR(MC_VM_FB_OFFSET) - -#define HWSEQ_DCN30_REG_LIST()\ - HWSEQ_DCN2_REG_LIST(),\ - HWSEQ_DCN_REG_LIST(), \ - HWSEQ_PIXEL_RATE_REG_LIST_3(OTG), \ - HWSEQ_PHYPLL_REG_LIST_3(OTG), \ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_CLOCK_CONTROL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(DMU_MEM_PWR_CNTL), \ - SR(MMHUBBUB_MEM_PWR_CNTL) - -#define HWSEQ_DCN301_REG_LIST()\ - SR(REFCLK_CNTL), \ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DCFCLK_CNTL), \ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN4_PG_CONFIG), \ - SR(DOMAIN5_PG_CONFIG), \ - SR(DOMAIN6_PG_CONFIG), \ - SR(DOMAIN7_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN4_PG_STATUS), \ - SR(DOMAIN5_PG_STATUS), \ - SR(DOMAIN6_PG_STATUS), \ - SR(DOMAIN7_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING) - -#define HWSEQ_DCN302_REG_LIST()\ - HWSEQ_DCN_REG_LIST(), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 4), \ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN4_PG_CONFIG), \ - SR(DOMAIN5_PG_CONFIG), \ - SR(DOMAIN6_PG_CONFIG), \ - SR(DOMAIN7_PG_CONFIG), \ - SR(DOMAIN8_PG_CONFIG), \ - SR(DOMAIN9_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN19_PG_CONFIG), \ - SR(DOMAIN20_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN4_PG_STATUS), \ - SR(DOMAIN5_PG_STATUS), \ - SR(DOMAIN6_PG_STATUS), \ - SR(DOMAIN7_PG_STATUS), \ - SR(DOMAIN8_PG_STATUS), \ - SR(DOMAIN9_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(DOMAIN19_PG_STATUS), \ - SR(DOMAIN20_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - HWSEQ_PIXEL_RATE_REG_LIST_302(OTG), \ - HWSEQ_PHYPLL_REG_LIST_302(OTG), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_CLOCK_CONTROL) - -#define HWSEQ_DCN303_REG_LIST() \ - HWSEQ_DCN_REG_LIST(), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ - HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - HWSEQ_PIXEL_RATE_REG_LIST_303(OTG), \ - HWSEQ_PHYPLL_REG_LIST_303(OTG), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_CLOCK_CONTROL) - -struct dce_hwseq_registers { - uint32_t DCFE_CLOCK_CONTROL[6]; - uint32_t DCFEV_CLOCK_CONTROL; - uint32_t DC_MEM_GLOBAL_PWR_REQ_CNTL; - uint32_t BLND_V_UPDATE_LOCK[6]; - uint32_t BLND_CONTROL[6]; - uint32_t BLNDV_CONTROL; - uint32_t CRTC_H_BLANK_START_END[6]; - uint32_t PIXEL_RATE_CNTL[6]; - uint32_t PHYPLL_PIXEL_RATE_CNTL[6]; - /*DCHUB*/ - uint32_t DCHUB_FB_LOCATION; - uint32_t DCHUB_AGP_BASE; - uint32_t DCHUB_AGP_BOT; - uint32_t DCHUB_AGP_TOP; - - uint32_t REFCLK_CNTL; - - uint32_t DCHUBBUB_GLOBAL_TIMER_CNTL; - uint32_t DCHUBBUB_SDPIF_FB_BASE; - uint32_t DCHUBBUB_SDPIF_FB_OFFSET; - uint32_t DCHUBBUB_SDPIF_AGP_BASE; - uint32_t DCHUBBUB_SDPIF_AGP_BOT; - uint32_t DCHUBBUB_SDPIF_AGP_TOP; - uint32_t DC_IP_REQUEST_CNTL; - uint32_t DOMAIN0_PG_CONFIG; - uint32_t DOMAIN1_PG_CONFIG; - uint32_t DOMAIN2_PG_CONFIG; - uint32_t DOMAIN3_PG_CONFIG; - uint32_t DOMAIN4_PG_CONFIG; - uint32_t DOMAIN5_PG_CONFIG; - uint32_t DOMAIN6_PG_CONFIG; - uint32_t DOMAIN7_PG_CONFIG; - uint32_t DOMAIN8_PG_CONFIG; - uint32_t DOMAIN9_PG_CONFIG; - uint32_t DOMAIN10_PG_CONFIG; - uint32_t DOMAIN11_PG_CONFIG; - uint32_t DOMAIN16_PG_CONFIG; - uint32_t DOMAIN17_PG_CONFIG; - uint32_t DOMAIN18_PG_CONFIG; - uint32_t DOMAIN19_PG_CONFIG; - uint32_t DOMAIN20_PG_CONFIG; - uint32_t DOMAIN21_PG_CONFIG; - uint32_t DOMAIN0_PG_STATUS; - uint32_t DOMAIN1_PG_STATUS; - uint32_t DOMAIN2_PG_STATUS; - uint32_t DOMAIN3_PG_STATUS; - uint32_t DOMAIN4_PG_STATUS; - uint32_t DOMAIN5_PG_STATUS; - uint32_t DOMAIN6_PG_STATUS; - uint32_t DOMAIN7_PG_STATUS; - uint32_t DOMAIN8_PG_STATUS; - uint32_t DOMAIN9_PG_STATUS; - uint32_t DOMAIN10_PG_STATUS; - uint32_t DOMAIN11_PG_STATUS; - uint32_t DOMAIN16_PG_STATUS; - uint32_t DOMAIN17_PG_STATUS; - uint32_t DOMAIN18_PG_STATUS; - uint32_t DOMAIN19_PG_STATUS; - uint32_t DOMAIN20_PG_STATUS; - uint32_t DOMAIN21_PG_STATUS; - uint32_t DIO_MEM_PWR_CTRL; - uint32_t DCCG_GATE_DISABLE_CNTL; - uint32_t DCCG_GATE_DISABLE_CNTL2; - uint32_t DCFCLK_CNTL; - uint32_t MICROSECOND_TIME_BASE_DIV; - uint32_t MILLISECOND_TIME_BASE_DIV; - uint32_t DISPCLK_FREQ_CHANGE_CNTL; - uint32_t RBBMIF_TIMEOUT_DIS; - uint32_t RBBMIF_TIMEOUT_DIS_2; - uint32_t DCHUBBUB_CRC_CTRL; - uint32_t DPP_TOP0_DPP_CRC_CTRL; - uint32_t DPP_TOP0_DPP_CRC_VAL_R_G; - uint32_t DPP_TOP0_DPP_CRC_VAL_B_A; - uint32_t MPC_CRC_CTRL; - uint32_t MPC_CRC_RESULT_GB; - uint32_t MPC_CRC_RESULT_C; - uint32_t MPC_CRC_RESULT_AR; - uint32_t D1VGA_CONTROL; - uint32_t D2VGA_CONTROL; - uint32_t D3VGA_CONTROL; - uint32_t D4VGA_CONTROL; - uint32_t D5VGA_CONTROL; - uint32_t D6VGA_CONTROL; - uint32_t VGA_TEST_CONTROL; - /* MMHUB registers. read only. temporary hack */ - uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32; - uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; - uint32_t VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32; - uint32_t VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32; - uint32_t VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32; - uint32_t VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32; - uint32_t VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32; - uint32_t VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32; - uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB; - uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB; - uint32_t MC_VM_SYSTEM_APERTURE_LOW_ADDR; - uint32_t MC_VM_SYSTEM_APERTURE_HIGH_ADDR; - uint32_t MC_VM_XGMI_LFB_CNTL; - uint32_t AZALIA_AUDIO_DTO; - uint32_t AZALIA_CONTROLLER_CLOCK_GATING; - /* MMHUB VM */ - uint32_t MC_VM_FB_LOCATION_BASE; - uint32_t MC_VM_FB_LOCATION_TOP; - uint32_t MC_VM_FB_OFFSET; - uint32_t MMHUBBUB_MEM_PWR_CNTL; - uint32_t HPO_TOP_CLOCK_CONTROL; - uint32_t ODM_MEM_PWR_CTRL3; - uint32_t DMU_MEM_PWR_CNTL; - uint32_t DCHUBBUB_ARB_HOSTVM_CNTL; - uint32_t HPO_TOP_HW_CONTROL; - uint32_t DMU_CLK_CNTL; - uint32_t DCCG_GATE_DISABLE_CNTL5; -}; - /* set field name */ -#define HWS_SF(blk_name, reg_name, field_name, post_fix)\ - .field_name = blk_name ## reg_name ## __ ## field_name ## post_fix - -#define HWS_SF1(blk_name, reg_name, field_name, post_fix)\ - .field_name = blk_name ## reg_name ## __ ## blk_name ## field_name ## post_fix - - -#define HWSEQ_DCEF_MASK_SH_LIST(mask_sh, blk)\ - HWS_SF(blk, CLOCK_CONTROL, DCFE_CLOCK_ENABLE, mask_sh),\ - SF(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, mask_sh) - -#define HWSEQ_BLND_MASK_SH_LIST(mask_sh, blk)\ - HWS_SF(blk, V_UPDATE_LOCK, BLND_DCP_GRPH_V_UPDATE_LOCK, mask_sh),\ - HWS_SF(blk, V_UPDATE_LOCK, BLND_SCL_V_UPDATE_LOCK, mask_sh),\ - HWS_SF(blk, V_UPDATE_LOCK, BLND_DCP_GRPH_SURF_V_UPDATE_LOCK, mask_sh),\ - HWS_SF(blk, V_UPDATE_LOCK, BLND_BLND_V_UPDATE_LOCK, mask_sh),\ - HWS_SF(blk, V_UPDATE_LOCK, BLND_V_UPDATE_LOCK_MODE, mask_sh),\ - HWS_SF(blk, CONTROL, BLND_FEEDTHROUGH_EN, mask_sh),\ - HWS_SF(blk, CONTROL, BLND_ALPHA_MODE, mask_sh),\ - HWS_SF(blk, CONTROL, BLND_MODE, mask_sh),\ - HWS_SF(blk, CONTROL, BLND_MULTIPLIED_MODE, mask_sh) - -#define HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, blk)\ - HWS_SF1(blk, PIXEL_RATE_CNTL, PIXEL_RATE_SOURCE, mask_sh),\ - HWS_SF(blk, PIXEL_RATE_CNTL, DP_DTO0_ENABLE, mask_sh) - -#define HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, blk)\ - HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh),\ - HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PIXEL_RATE_PLL_SOURCE, mask_sh) - -#if defined(CONFIG_DRM_AMD_DC_SI) -#define HWSEQ_DCE6_MASK_SH_LIST(mask_sh)\ - .DCFE_CLOCK_ENABLE = CRTC_DCFE_CLOCK_CONTROL__CRTC_DCFE_CLOCK_ENABLE ## mask_sh, \ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) -#endif - -#define HWSEQ_DCE8_MASK_SH_LIST(mask_sh)\ - .DCFE_CLOCK_ENABLE = CRTC_DCFE_CLOCK_CONTROL__CRTC_DCFE_CLOCK_ENABLE ## mask_sh, \ - HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_V_UPDATE_LOCK, mask_sh),\ - HWS_SF(BLND_, V_UPDATE_LOCK, BLND_SCL_V_UPDATE_LOCK, mask_sh),\ - HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_SURF_V_UPDATE_LOCK, mask_sh),\ - HWS_SF(BLND_, CONTROL, BLND_MODE, mask_sh),\ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) - -#define HWSEQ_DCE10_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE_),\ - HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND_),\ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) - -#define HWSEQ_DCE11_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ - SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, mask_sh),\ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) - -#define HWSEQ_DCE112_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ - HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_) - -#define HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh)\ - SF(DCHUB_FB_LOCATION, FB_TOP, mask_sh),\ - SF(DCHUB_FB_LOCATION, FB_BASE, mask_sh),\ - SF(DCHUB_AGP_BASE, AGP_BASE, mask_sh),\ - SF(DCHUB_AGP_BOT, AGP_BOT, mask_sh),\ - SF(DCHUB_AGP_TOP, AGP_TOP, mask_sh) - -#define HWSEQ_DCE12_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE0_DCFE_),\ - HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND0_BLND_),\ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\ - HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_),\ - HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh) - -#define HWSEQ_VG20_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCE12_MASK_SH_LIST(mask_sh),\ - HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_LFB_REGION, mask_sh),\ - HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, mask_sh) - -#define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\ - HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ - HWS_SF(, DCFCLK_CNTL, DCFCLK_GATE_DIS, mask_sh), \ - HWS_SF(, DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, mask_sh) - -#define HWSEQ_DCN1_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PIXEL_RATE_PLL_SOURCE, mask_sh), \ - HWS_SF(, DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, mask_sh), \ - HWS_SF(, DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, mask_sh), \ - HWS_SF(, DCHUBBUB_SDPIF_AGP_BASE, SDPIF_AGP_BASE, mask_sh), \ - HWS_SF(, DCHUBBUB_SDPIF_AGP_BOT, SDPIF_AGP_BOT, mask_sh), \ - HWS_SF(, DCHUBBUB_SDPIF_AGP_TOP, SDPIF_AGP_TOP, mask_sh), \ - /* todo: get these from GVM instead of reading registers ourselves */\ - HWS_SF(, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, PAGE_DIRECTORY_ENTRY_HI32, mask_sh),\ - HWS_SF(, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, PAGE_DIRECTORY_ENTRY_LO32, mask_sh),\ - HWS_SF(, VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, LOGICAL_PAGE_NUMBER_HI4, mask_sh),\ - HWS_SF(, VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, LOGICAL_PAGE_NUMBER_LO32, mask_sh),\ - HWS_SF(, VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, PHYSICAL_PAGE_ADDR_HI4, mask_sh),\ - HWS_SF(, VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, PHYSICAL_PAGE_ADDR_LO32, mask_sh),\ - HWS_SF(, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, PHYSICAL_PAGE_NUMBER_MSB, mask_sh),\ - HWS_SF(, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, PHYSICAL_PAGE_NUMBER_LSB, mask_sh),\ - HWS_SF(, MC_VM_SYSTEM_APERTURE_LOW_ADDR, LOGICAL_ADDR, mask_sh),\ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ - HWS_SF(, D2VGA_CONTROL, D2VGA_MODE_ENABLE, mask_sh),\ - HWS_SF(, D3VGA_CONTROL, D3VGA_MODE_ENABLE, mask_sh),\ - HWS_SF(, D4VGA_CONTROL, D4VGA_MODE_ENABLE, mask_sh),\ - HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ - HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh) - -#define HWSEQ_DCN2_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN10_PG_CONFIG, DOMAIN10_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN10_PG_CONFIG, DOMAIN10_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN11_PG_CONFIG, DOMAIN11_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN11_PG_CONFIG, DOMAIN11_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN21_PG_CONFIG, DOMAIN21_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN8_PG_STATUS, DOMAIN8_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN9_PG_STATUS, DOMAIN9_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN10_PG_STATUS, DOMAIN10_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN11_PG_STATUS, DOMAIN11_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN19_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN20_PG_STATUS, DOMAIN20_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN21_PG_STATUS, DOMAIN21_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) - -#define HWSEQ_DCN21_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, MMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, PAGE_DIRECTORY_ENTRY_HI32, mask_sh),\ - HWS_SF(, MMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, PAGE_DIRECTORY_ENTRY_LO32, mask_sh),\ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) - -#define HWSEQ_DCN201_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh) - -#define HWSEQ_DCN30_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN2_MASK_SH_LIST(mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) - -#define HWSEQ_DCN301_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, PANEL_PWRSEQ0_CNTL, PANEL_BLON, mask_sh),\ - HWS_SF(, PANEL_PWRSEQ0_CNTL, PANEL_DIGON, mask_sh),\ - HWS_SF(, PANEL_PWRSEQ0_CNTL, PANEL_DIGON_OVRD, mask_sh),\ - HWS_SF(, PANEL_PWRSEQ0_STATE, PANEL_PWRSEQ_TARGET_STATE_R, mask_sh),\ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh) - -#define HWSEQ_DCN302_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN8_PG_STATUS, DOMAIN8_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN9_PG_STATUS, DOMAIN9_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN19_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN20_PG_STATUS, DOMAIN20_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh) - -#define HWSEQ_DCN303_MASK_SH_LIST(mask_sh) \ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh) - -#define HWSEQ_REG_FIELD_LIST(type) \ - type DCFE_CLOCK_ENABLE; \ - type DCFEV_CLOCK_ENABLE; \ - type DC_MEM_GLOBAL_PWR_REQ_DIS; \ - type BLND_DCP_GRPH_V_UPDATE_LOCK; \ - type BLND_SCL_V_UPDATE_LOCK; \ - type BLND_DCP_GRPH_SURF_V_UPDATE_LOCK; \ - type BLND_BLND_V_UPDATE_LOCK; \ - type BLND_V_UPDATE_LOCK_MODE; \ - type BLND_FEEDTHROUGH_EN; \ - type BLND_ALPHA_MODE; \ - type BLND_MODE; \ - type BLND_MULTIPLIED_MODE; \ - type DP_DTO0_ENABLE; \ - type PIXEL_RATE_SOURCE; \ - type PHYPLL_PIXEL_RATE_SOURCE; \ - type PIXEL_RATE_PLL_SOURCE; \ - /* todo: get these from GVM instead of reading registers ourselves */\ - type PAGE_DIRECTORY_ENTRY_HI32;\ - type PAGE_DIRECTORY_ENTRY_LO32;\ - type LOGICAL_PAGE_NUMBER_HI4;\ - type LOGICAL_PAGE_NUMBER_LO32;\ - type PHYSICAL_PAGE_ADDR_HI4;\ - type PHYSICAL_PAGE_ADDR_LO32;\ - type PHYSICAL_PAGE_NUMBER_MSB;\ - type PHYSICAL_PAGE_NUMBER_LSB;\ - type LOGICAL_ADDR; \ - type PF_LFB_REGION;\ - type PF_MAX_REGION;\ - type ENABLE_L1_TLB;\ - type SYSTEM_ACCESS_MODE; - -#define HWSEQ_DCN_REG_FIELD_LIST(type) \ - type HUBP_VTG_SEL; \ - type HUBP_CLOCK_ENABLE; \ - type DPP_CLOCK_ENABLE; \ - type SDPIF_FB_BASE;\ - type SDPIF_FB_OFFSET;\ - type SDPIF_AGP_BASE;\ - type SDPIF_AGP_BOT;\ - type SDPIF_AGP_TOP;\ - type FB_TOP;\ - type FB_BASE;\ - type FB_OFFSET;\ - type AGP_BASE;\ - type AGP_BOT;\ - type AGP_TOP;\ - type DCHUBBUB_GLOBAL_TIMER_ENABLE; \ - type OPP_PIPE_CLOCK_EN;\ - type IP_REQUEST_EN; \ - type DOMAIN0_POWER_FORCEON; \ - type DOMAIN0_POWER_GATE; \ - type DOMAIN1_POWER_FORCEON; \ - type DOMAIN1_POWER_GATE; \ - type DOMAIN2_POWER_FORCEON; \ - type DOMAIN2_POWER_GATE; \ - type DOMAIN3_POWER_FORCEON; \ - type DOMAIN3_POWER_GATE; \ - type DOMAIN4_POWER_FORCEON; \ - type DOMAIN4_POWER_GATE; \ - type DOMAIN5_POWER_FORCEON; \ - type DOMAIN5_POWER_GATE; \ - type DOMAIN6_POWER_FORCEON; \ - type DOMAIN6_POWER_GATE; \ - type DOMAIN7_POWER_FORCEON; \ - type DOMAIN7_POWER_GATE; \ - type DOMAIN8_POWER_FORCEON; \ - type DOMAIN8_POWER_GATE; \ - type DOMAIN9_POWER_FORCEON; \ - type DOMAIN9_POWER_GATE; \ - type DOMAIN10_POWER_FORCEON; \ - type DOMAIN10_POWER_GATE; \ - type DOMAIN11_POWER_FORCEON; \ - type DOMAIN11_POWER_GATE; \ - type DOMAIN16_POWER_FORCEON; \ - type DOMAIN16_POWER_GATE; \ - type DOMAIN17_POWER_FORCEON; \ - type DOMAIN17_POWER_GATE; \ - type DOMAIN18_POWER_FORCEON; \ - type DOMAIN18_POWER_GATE; \ - type DOMAIN19_POWER_FORCEON; \ - type DOMAIN19_POWER_GATE; \ - type DOMAIN20_POWER_FORCEON; \ - type DOMAIN20_POWER_GATE; \ - type DOMAIN21_POWER_FORCEON; \ - type DOMAIN21_POWER_GATE; \ - type DOMAIN0_PGFSM_PWR_STATUS; \ - type DOMAIN1_PGFSM_PWR_STATUS; \ - type DOMAIN2_PGFSM_PWR_STATUS; \ - type DOMAIN3_PGFSM_PWR_STATUS; \ - type DOMAIN4_PGFSM_PWR_STATUS; \ - type DOMAIN5_PGFSM_PWR_STATUS; \ - type DOMAIN6_PGFSM_PWR_STATUS; \ - type DOMAIN7_PGFSM_PWR_STATUS; \ - type DOMAIN8_PGFSM_PWR_STATUS; \ - type DOMAIN9_PGFSM_PWR_STATUS; \ - type DOMAIN10_PGFSM_PWR_STATUS; \ - type DOMAIN11_PGFSM_PWR_STATUS; \ - type DOMAIN16_PGFSM_PWR_STATUS; \ - type DOMAIN17_PGFSM_PWR_STATUS; \ - type DOMAIN18_PGFSM_PWR_STATUS; \ - type DOMAIN19_PGFSM_PWR_STATUS; \ - type DOMAIN20_PGFSM_PWR_STATUS; \ - type DOMAIN21_PGFSM_PWR_STATUS; \ - type DCFCLK_GATE_DIS; \ - type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ - type VGA_TEST_ENABLE; \ - type VGA_TEST_RENDER_START; \ - type D1VGA_MODE_ENABLE; \ - type D2VGA_MODE_ENABLE; \ - type D3VGA_MODE_ENABLE; \ - type D4VGA_MODE_ENABLE; \ - type AZALIA_AUDIO_DTO_MODULE; \ - type ODM_MEM_UNASSIGNED_PWR_MODE; \ - type ODM_MEM_VBLANK_PWR_MODE; \ - type DMCU_ERAM_MEM_PWR_FORCE; \ - type VGA_MEM_PWR_FORCE; - -#define HWSEQ_DCN3_REG_FIELD_LIST(type) \ - type HPO_HDMISTREAMCLK_GATE_DIS; - -#define HWSEQ_DCN301_REG_FIELD_LIST(type) \ - type PANEL_BLON;\ - type PANEL_DIGON;\ - type PANEL_DIGON_OVRD;\ - type PANEL_PWRSEQ_TARGET_STATE_R; - -#define HWSEQ_DCN31_REG_FIELD_LIST(type) \ - type DOMAIN_POWER_FORCEON;\ - type DOMAIN_POWER_GATE;\ - type DOMAIN_PGFSM_PWR_STATUS;\ - type HPO_HDMISTREAMCLK_G_GATE_DIS;\ - type DISABLE_HOSTVM_FORCE_ALLOW_PSTATE;\ - type I2C_LIGHT_SLEEP_FORCE;\ - type HPO_IO_EN; - -#define HWSEQ_DCN35_REG_FIELD_LIST(type) \ - type DISPCLK_R_DMU_GATE_DIS;\ - type DISPCLK_G_RBBMIF_GATE_DIS;\ - type RBBMIF_FGCG_REP_DIS;\ - type IHC_FGCG_REP_DIS;\ - type DPREFCLK_ALLOW_DS_CLKSTOP;\ - type DISPCLK_ALLOW_DS_CLKSTOP;\ - type DPPCLK_ALLOW_DS_CLKSTOP;\ - type DTBCLK_ALLOW_DS_CLKSTOP;\ - type DCFCLK_ALLOW_DS_CLKSTOP;\ - type DPIACLK_ALLOW_DS_CLKSTOP;\ - type LONO_FGCG_REP_DIS;\ - type LONO_DISPCLK_GATE_DISABLE;\ - type LONO_SOCCLK_GATE_DISABLE;\ - type LONO_DMCUBCLK_GATE_DISABLE; - -struct dce_hwseq_shift { - HWSEQ_REG_FIELD_LIST(uint8_t) - HWSEQ_DCN_REG_FIELD_LIST(uint8_t) - HWSEQ_DCN3_REG_FIELD_LIST(uint8_t) - HWSEQ_DCN301_REG_FIELD_LIST(uint8_t) - HWSEQ_DCN31_REG_FIELD_LIST(uint8_t) - HWSEQ_DCN35_REG_FIELD_LIST(uint8_t) -}; - -struct dce_hwseq_mask { - HWSEQ_REG_FIELD_LIST(uint32_t) - HWSEQ_DCN_REG_FIELD_LIST(uint32_t) - HWSEQ_DCN3_REG_FIELD_LIST(uint32_t) - HWSEQ_DCN301_REG_FIELD_LIST(uint32_t) - HWSEQ_DCN31_REG_FIELD_LIST(uint32_t) - HWSEQ_DCN35_REG_FIELD_LIST(uint32_t) -}; - - -enum blnd_mode { - BLND_MODE_CURRENT_PIPE = 0,/* Data from current pipe only */ - BLND_MODE_OTHER_PIPE, /* Data from other pipe only */ - BLND_MODE_BLENDING,/* Alpha blending - blend 'current' and 'other' */ -}; - -struct dce_hwseq; -struct pipe_ctx; -struct clock_source; - -void dce_enable_fe_clock(struct dce_hwseq *hwss, - unsigned int inst, bool enable); - -void dce_pipe_control_lock(struct dc *dc, - struct pipe_ctx *pipe, - bool lock); - -void dce_set_blender_mode(struct dce_hwseq *hws, - unsigned int blnd_inst, enum blnd_mode mode); - -#if defined(CONFIG_DRM_AMD_DC_SI) -void dce60_pipe_control_lock(struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -#endif - -void dce_clock_gating_power_up(struct dce_hwseq *hws, - bool enable); - -void dce_crtc_switch_to_clk_src(struct dce_hwseq *hws, - struct clock_source *clk_src, - unsigned int tg_inst); - -bool dce_use_lut(enum surface_pixel_format format); -#endif /*__DCE_HWSEQ_H__*/ diff --git a/drivers/gpu/drm/amd/display/dc/dce100/Makefile b/drivers/gpu/drm/amd/display/dc/dce100/Makefile index ff20c47f559e..0d2f6bbf7558 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce100/Makefile @@ -25,7 +25,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce100/dce100_resource.o = $(call cc-disable-warning, override-init) -DCE100 = dce100_resource.o dce100_hw_sequencer.o +DCE100 = dce100_resource.o AMD_DAL_DCE100 = $(addprefix $(AMDDALPATH)/dc/dce100/,$(DCE100)) diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c deleted file mode 100644 index 753cb8edd996..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#include "dm_services.h" -#include "dc.h" -#include "core_types.h" -#include "clk_mgr.h" -#include "dce100_hw_sequencer.h" -#include "resource.h" - -#include "dce110/dce110_hw_sequencer.h" - -/* include DCE10 register header files */ -#include "dce/dce_10_0_d.h" -#include "dce/dce_10_0_sh_mask.h" - -struct dce100_hw_seq_reg_offsets { - uint32_t blnd; - uint32_t crtc; -}; - -static const struct dce100_hw_seq_reg_offsets reg_offsets[] = { -{ - .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -} -}; - -#define HW_REG_CRTC(reg, id)\ - (reg + reg_offsets[id].crtc) - -/******************************************************************************* - * Private definitions - ******************************************************************************/ -/***************************PIPE_CONTROL***********************************/ - -bool dce100_enable_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating) -{ - enum bp_result bp_result = BP_RESULT_OK; - enum bp_pipe_control_action cntl; - struct dc_context *ctx = dc->ctx; - - if (power_gating == PIPE_GATING_CONTROL_INIT) - cntl = ASIC_PIPE_INIT; - else if (power_gating == PIPE_GATING_CONTROL_ENABLE) - cntl = ASIC_PIPE_ENABLE; - else - cntl = ASIC_PIPE_DISABLE; - - if (!(power_gating == PIPE_GATING_CONTROL_INIT && controller_id != 0)){ - - bp_result = dcb->funcs->enable_disp_power_gating( - dcb, controller_id + 1, cntl); - - /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 - * by default when command table is called - */ - dm_write_reg(ctx, - HW_REG_CRTC(mmMASTER_UPDATE_MODE, controller_id), - 0); - } - - if (bp_result == BP_RESULT_OK) - return true; - else - return false; -} - -void dce100_prepare_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - false); -} - -void dce100_optimize_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - true); -} - -/**************************************************************************/ - -void dce100_hw_sequencer_construct(struct dc *dc) -{ - dce110_hw_sequencer_construct(dc); - - dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; - dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; - dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h deleted file mode 100644 index 34518da20009..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCE100_H__ -#define __DC_HWSS_DCE100_H__ - -#include "core_types.h" -#include "hw_sequencer_private.h" - -struct dc; -struct dc_state; - -void dce100_hw_sequencer_construct(struct dc *dc); - -void dce100_prepare_bandwidth( - struct dc *dc, - struct dc_state *context); - -void dce100_optimize_bandwidth( - struct dc *dc, - struct dc_state *context); - -bool dce100_enable_display_power_gating(struct dc *dc, uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating); - -#endif /* __DC_HWSS_DCE100_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 899b25b0bad8..53a5f4cb648c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -30,7 +30,7 @@ #include "resource.h" #include "include/irq_service_interface.h" -#include "../virtual/virtual_stream_encoder.h" +#include "virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dce110/dce110_timing_generator.h" #include "irq/dce110/irq_service_dce110.h" @@ -43,7 +43,7 @@ #include "dce/dce_clock_source.h" #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" -#include "dce100/dce100_hw_sequencer.h" +#include "dce100/dce100_hwseq.h" #include "dce/dce_panel_cntl.h" #include "reg_helper.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce110/Makefile b/drivers/gpu/drm/amd/display/dc/dce110/Makefile index 84ab48df0c26..695a50ed5ad2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce110/Makefile @@ -26,7 +26,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce110/dce110_resource.o = $(call cc-disable-warning, override-init) DCE110 = dce110_timing_generator.o \ -dce110_compressor.o dce110_hw_sequencer.o dce110_resource.o \ +dce110_compressor.o dce110_resource.o \ dce110_opp_regamma_v.o dce110_opp_csc_v.o dce110_timing_generator_v.o \ dce110_mem_input_v.o dce110_opp_v.o dce110_transform_v.o diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c deleted file mode 100644 index 5e4e9c1eb4f2..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ /dev/null @@ -1,3200 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dc.h" -#include "dc_bios_types.h" -#include "core_types.h" -#include "core_status.h" -#include "resource.h" -#include "dm_helpers.h" -#include "dce110_timing_generator.h" -#include "dce/dce_hwseq.h" -#include "gpio_service_interface.h" - -#include "dce110_compressor.h" - -#include "bios/bios_parser_helper.h" -#include "timing_generator.h" -#include "mem_input.h" -#include "opp.h" -#include "ipp.h" -#include "transform.h" -#include "stream_encoder.h" -#include "link_encoder.h" -#include "link_enc_cfg.h" -#include "link_hwss.h" -#include "link.h" -#include "dccg.h" -#include "clock_source.h" -#include "clk_mgr.h" -#include "abm.h" -#include "audio.h" -#include "reg_helper.h" -#include "panel_cntl.h" -#include "dpcd_defs.h" -/* include DCE11 register header files */ -#include "dce/dce_11_0_d.h" -#include "dce/dce_11_0_sh_mask.h" -#include "custom_float.h" - -#include "atomfirmware.h" - -#include "dcn10/dcn10_hw_sequencer.h" - -#include "dce110_hw_sequencer.h" - -#define GAMMA_HW_POINTS_NUM 256 - -/* - * All values are in milliseconds; - * For eDP, after power-up/power/down, - * 300/500 msec max. delay from LCDVCC to black video generation - */ -#define PANEL_POWER_UP_TIMEOUT 300 -#define PANEL_POWER_DOWN_TIMEOUT 500 -#define HPD_CHECK_INTERVAL 10 -#define OLED_POST_T7_DELAY 100 -#define OLED_PRE_T11_DELAY 150 - -#define CTX \ - hws->ctx - -#define DC_LOGGER \ - ctx->logger -#define DC_LOGGER_INIT() \ - struct dc_context *ctx = dc->ctx - -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -struct dce110_hw_seq_reg_offsets { - uint32_t crtc; -}; - -static const struct dce110_hw_seq_reg_offsets reg_offsets[] = { -{ - .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTCV_GSL_CONTROL - mmCRTC_GSL_CONTROL), -} -}; - -#define HW_REG_BLND(reg, id)\ - (reg + reg_offsets[id].blnd) - -#define HW_REG_CRTC(reg, id)\ - (reg + reg_offsets[id].crtc) - -#define MAX_WATERMARK 0xFFFF -#define SAFE_NBP_MARK 0x7FFF - -/******************************************************************************* - * Private definitions - ******************************************************************************/ -/***************************PIPE_CONTROL***********************************/ -static void dce110_init_pte(struct dc_context *ctx) -{ - uint32_t addr; - uint32_t value = 0; - uint32_t chunk_int = 0; - uint32_t chunk_mul = 0; - - addr = mmUNP_DVMM_PTE_CONTROL; - value = dm_read_reg(ctx, addr); - - set_reg_field_value( - value, - 0, - DVMM_PTE_CONTROL, - DVMM_USE_SINGLE_PTE); - - set_reg_field_value( - value, - 1, - DVMM_PTE_CONTROL, - DVMM_PTE_BUFFER_MODE0); - - set_reg_field_value( - value, - 1, - DVMM_PTE_CONTROL, - DVMM_PTE_BUFFER_MODE1); - - dm_write_reg(ctx, addr, value); - - addr = mmDVMM_PTE_REQ; - value = dm_read_reg(ctx, addr); - - chunk_int = get_reg_field_value( - value, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_INT); - - chunk_mul = get_reg_field_value( - value, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); - - if (chunk_int != 0x4 || chunk_mul != 0x4) { - - set_reg_field_value( - value, - 255, - DVMM_PTE_REQ, - MAX_PTEREQ_TO_ISSUE); - - set_reg_field_value( - value, - 4, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_INT); - - set_reg_field_value( - value, - 4, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); - - dm_write_reg(ctx, addr, value); - } -} -/**************************************************************************/ - -static void enable_display_pipe_clock_gating( - struct dc_context *ctx, - bool clock_gating) -{ - /*TODO*/ -} - -static bool dce110_enable_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating) -{ - enum bp_result bp_result = BP_RESULT_OK; - enum bp_pipe_control_action cntl; - struct dc_context *ctx = dc->ctx; - unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; - - if (power_gating == PIPE_GATING_CONTROL_INIT) - cntl = ASIC_PIPE_INIT; - else if (power_gating == PIPE_GATING_CONTROL_ENABLE) - cntl = ASIC_PIPE_ENABLE; - else - cntl = ASIC_PIPE_DISABLE; - - if (controller_id == underlay_idx) - controller_id = CONTROLLER_ID_UNDERLAY0 - 1; - - if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0) { - - bp_result = dcb->funcs->enable_disp_power_gating( - dcb, controller_id + 1, cntl); - - /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 - * by default when command table is called - * - * Bios parser accepts controller_id = 6 as indicative of - * underlay pipe in dce110. But we do not support more - * than 3. - */ - if (controller_id < CONTROLLER_ID_MAX - 1) - dm_write_reg(ctx, - HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id), - 0); - } - - if (power_gating != PIPE_GATING_CONTROL_ENABLE) - dce110_init_pte(ctx); - - if (bp_result == BP_RESULT_OK) - return true; - else - return false; -} - -static void build_prescale_params(struct ipp_prescale_params *prescale_params, - const struct dc_plane_state *plane_state) -{ - prescale_params->mode = IPP_PRESCALE_MODE_FIXED_UNSIGNED; - - switch (plane_state->format) { - case SURFACE_PIXEL_FORMAT_GRPH_RGB565: - prescale_params->scale = 0x2082; - break; - case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: - case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: - prescale_params->scale = 0x2020; - break; - case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: - case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: - prescale_params->scale = 0x2008; - break; - case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: - case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: - case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: - prescale_params->scale = 0x2000; - break; - default: - ASSERT(false); - break; - } -} - -static bool -dce110_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) -{ - struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; - const struct dc_transfer_func *tf = NULL; - struct ipp_prescale_params prescale_params = { 0 }; - bool result = true; - - if (ipp == NULL) - return false; - - if (plane_state->in_transfer_func) - tf = plane_state->in_transfer_func; - - build_prescale_params(&prescale_params, plane_state); - ipp->funcs->ipp_program_prescale(ipp, &prescale_params); - - if (plane_state->gamma_correction && - !plane_state->gamma_correction->is_identity && - dce_use_lut(plane_state->format)) - ipp->funcs->ipp_program_input_lut(ipp, plane_state->gamma_correction); - - if (tf == NULL) { - /* Default case if no input transfer function specified */ - ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_sRGB); - } else if (tf->type == TF_TYPE_PREDEFINED) { - switch (tf->tf) { - case TRANSFER_FUNCTION_SRGB: - ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_sRGB); - break; - case TRANSFER_FUNCTION_BT709: - ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_xvYCC); - break; - case TRANSFER_FUNCTION_LINEAR: - ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS); - break; - case TRANSFER_FUNCTION_PQ: - default: - result = false; - break; - } - } else if (tf->type == TF_TYPE_BYPASS) { - ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS); - } else { - /*TF_TYPE_DISTRIBUTED_POINTS - Not supported in DCE 11*/ - result = false; - } - - return result; -} - -static bool convert_to_custom_float(struct pwl_result_data *rgb_resulted, - struct curve_points *arr_points, - uint32_t hw_points_num) -{ - struct custom_float_format fmt; - - struct pwl_result_data *rgb = rgb_resulted; - - uint32_t i = 0; - - fmt.exponenta_bits = 6; - fmt.mantissa_bits = 12; - fmt.sign = true; - - if (!convert_to_custom_float_format(arr_points[0].x, &fmt, - &arr_points[0].custom_float_x)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(arr_points[0].offset, &fmt, - &arr_points[0].custom_float_offset)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(arr_points[0].slope, &fmt, - &arr_points[0].custom_float_slope)) { - BREAK_TO_DEBUGGER(); - return false; - } - - fmt.mantissa_bits = 10; - fmt.sign = false; - - if (!convert_to_custom_float_format(arr_points[1].x, &fmt, - &arr_points[1].custom_float_x)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(arr_points[1].y, &fmt, - &arr_points[1].custom_float_y)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(arr_points[1].slope, &fmt, - &arr_points[1].custom_float_slope)) { - BREAK_TO_DEBUGGER(); - return false; - } - - fmt.mantissa_bits = 12; - fmt.sign = true; - - while (i != hw_points_num) { - if (!convert_to_custom_float_format(rgb->red, &fmt, - &rgb->red_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(rgb->green, &fmt, - &rgb->green_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(rgb->blue, &fmt, - &rgb->blue_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(rgb->delta_red, &fmt, - &rgb->delta_red_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(rgb->delta_green, &fmt, - &rgb->delta_green_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!convert_to_custom_float_format(rgb->delta_blue, &fmt, - &rgb->delta_blue_reg)) { - BREAK_TO_DEBUGGER(); - return false; - } - - ++rgb; - ++i; - } - - return true; -} - -#define MAX_LOW_POINT 25 -#define NUMBER_REGIONS 16 -#define NUMBER_SW_SEGMENTS 16 - -static bool -dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, - struct pwl_params *regamma_params) -{ - struct curve_points *arr_points; - struct pwl_result_data *rgb_resulted; - struct pwl_result_data *rgb; - struct pwl_result_data *rgb_plus_1; - struct fixed31_32 y_r; - struct fixed31_32 y_g; - struct fixed31_32 y_b; - struct fixed31_32 y1_min; - struct fixed31_32 y3_max; - - int32_t region_start, region_end; - uint32_t i, j, k, seg_distr[NUMBER_REGIONS], increment, start_index, hw_points; - - if (output_tf == NULL || regamma_params == NULL || output_tf->type == TF_TYPE_BYPASS) - return false; - - arr_points = regamma_params->arr_points; - rgb_resulted = regamma_params->rgb_resulted; - hw_points = 0; - - memset(regamma_params, 0, sizeof(struct pwl_params)); - - if (output_tf->tf == TRANSFER_FUNCTION_PQ) { - /* 16 segments - * segments are from 2^-11 to 2^5 - */ - region_start = -11; - region_end = region_start + NUMBER_REGIONS; - - for (i = 0; i < NUMBER_REGIONS; i++) - seg_distr[i] = 4; - - } else { - /* 10 segments - * segment is from 2^-10 to 2^1 - * We include an extra segment for range [2^0, 2^1). This is to - * ensure that colors with normalized values of 1 don't miss the - * LUT. - */ - region_start = -10; - region_end = 1; - - seg_distr[0] = 4; - seg_distr[1] = 4; - seg_distr[2] = 4; - seg_distr[3] = 4; - seg_distr[4] = 4; - seg_distr[5] = 4; - seg_distr[6] = 4; - seg_distr[7] = 4; - seg_distr[8] = 4; - seg_distr[9] = 4; - seg_distr[10] = 0; - seg_distr[11] = -1; - seg_distr[12] = -1; - seg_distr[13] = -1; - seg_distr[14] = -1; - seg_distr[15] = -1; - } - - for (k = 0; k < 16; k++) { - if (seg_distr[k] != -1) - hw_points += (1 << seg_distr[k]); - } - - j = 0; - for (k = 0; k < (region_end - region_start); k++) { - increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); - start_index = (region_start + k + MAX_LOW_POINT) * - NUMBER_SW_SEGMENTS; - for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; - i += increment) { - if (j == hw_points - 1) - break; - rgb_resulted[j].red = output_tf->tf_pts.red[i]; - rgb_resulted[j].green = output_tf->tf_pts.green[i]; - rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; - j++; - } - } - - /* last point */ - start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; - rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; - rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; - rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; - - arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2), - dc_fixpt_from_int(region_start)); - arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2), - dc_fixpt_from_int(region_end)); - - y_r = rgb_resulted[0].red; - y_g = rgb_resulted[0].green; - y_b = rgb_resulted[0].blue; - - y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b)); - - arr_points[0].y = y1_min; - arr_points[0].slope = dc_fixpt_div(arr_points[0].y, - arr_points[0].x); - - y_r = rgb_resulted[hw_points - 1].red; - y_g = rgb_resulted[hw_points - 1].green; - y_b = rgb_resulted[hw_points - 1].blue; - - /* see comment above, m_arrPoints[1].y should be the Y value for the - * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) - */ - y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b)); - - arr_points[1].y = y3_max; - - arr_points[1].slope = dc_fixpt_zero; - - if (output_tf->tf == TRANSFER_FUNCTION_PQ) { - /* for PQ, we want to have a straight line from last HW X point, - * and the slope to be such that we hit 1.0 at 10000 nits. - */ - const struct fixed31_32 end_value = dc_fixpt_from_int(125); - - arr_points[1].slope = dc_fixpt_div( - dc_fixpt_sub(dc_fixpt_one, arr_points[1].y), - dc_fixpt_sub(end_value, arr_points[1].x)); - } - - regamma_params->hw_points_num = hw_points; - - k = 0; - for (i = 1; i < 16; i++) { - if (seg_distr[k] != -1) { - regamma_params->arr_curve_points[k].segments_num = seg_distr[k]; - regamma_params->arr_curve_points[i].offset = - regamma_params->arr_curve_points[k].offset + (1 << seg_distr[k]); - } - k++; - } - - if (seg_distr[k] != -1) - regamma_params->arr_curve_points[k].segments_num = seg_distr[k]; - - rgb = rgb_resulted; - rgb_plus_1 = rgb_resulted + 1; - - i = 1; - - while (i != hw_points + 1) { - if (dc_fixpt_lt(rgb_plus_1->red, rgb->red)) - rgb_plus_1->red = rgb->red; - if (dc_fixpt_lt(rgb_plus_1->green, rgb->green)) - rgb_plus_1->green = rgb->green; - if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue)) - rgb_plus_1->blue = rgb->blue; - - rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red); - rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green); - rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue); - - ++rgb_plus_1; - ++rgb; - ++i; - } - - convert_to_custom_float(rgb_resulted, arr_points, hw_points); - - return true; -} - -static bool -dce110_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) -{ - struct transform *xfm = pipe_ctx->plane_res.xfm; - - xfm->funcs->opp_power_on_regamma_lut(xfm, true); - xfm->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; - - if (stream->out_transfer_func && - stream->out_transfer_func->type == TF_TYPE_PREDEFINED && - stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) { - xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_SRGB); - } else if (dce110_translate_regamma_to_hw_format(stream->out_transfer_func, - &xfm->regamma_params)) { - xfm->funcs->opp_program_regamma_pwl(xfm, &xfm->regamma_params); - xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_USER); - } else { - xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_BYPASS); - } - - xfm->funcs->opp_power_on_regamma_lut(xfm, false); - - return true; -} - -void dce110_update_info_frame(struct pipe_ctx *pipe_ctx) -{ - bool is_hdmi_tmds; - bool is_dp; - - ASSERT(pipe_ctx->stream); - - if (pipe_ctx->stream_res.stream_enc == NULL) - return; /* this is not root pipe */ - - is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); - is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); - - if (!is_hdmi_tmds && !is_dp) - return; - - if (is_hdmi_tmds) - pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - else { - if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num) - pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - - pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - } -} - -void dce110_enable_stream(struct pipe_ctx *pipe_ctx) -{ - enum dc_lane_count lane_count = - pipe_ctx->stream->link->cur_link_settings.lane_count; - struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - struct dc_link *link = pipe_ctx->stream->link; - const struct dc *dc = link->dc; - const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); - uint32_t active_total_with_borders; - uint32_t early_control = 0; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - - link_hwss->setup_stream_encoder(pipe_ctx); - - dc->hwss.update_info_frame(pipe_ctx); - - /* enable early control to avoid corruption on DP monitor*/ - active_total_with_borders = - timing->h_addressable - + timing->h_border_left - + timing->h_border_right; - - if (lane_count != 0) - early_control = active_total_with_borders % lane_count; - - if (early_control == 0) - early_control = lane_count; - - tg->funcs->set_early_control(tg, early_control); -} - -static enum bp_result link_transmitter_control( - struct dc_bios *bios, - struct bp_transmitter_control *cntl) -{ - enum bp_result result; - - result = bios->funcs->transmitter_control(bios, cntl); - - return result; -} - -/* - * @brief - * eDP only. - */ -void dce110_edp_wait_for_hpd_ready( - struct dc_link *link, - bool power_up) -{ - struct dc_context *ctx = link->ctx; - struct graphics_object_id connector = link->link_enc->connector; - struct gpio *hpd; - bool edp_hpd_high = false; - uint32_t time_elapsed = 0; - uint32_t timeout = power_up ? - PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT; - - if (dal_graphics_object_id_get_connector_id(connector) - != CONNECTOR_ID_EDP) { - BREAK_TO_DEBUGGER(); - return; - } - - if (!power_up) - /* - * From KV, we will not HPD low after turning off VCC - - * instead, we will check the SW timer in power_up(). - */ - return; - - /* - * When we power on/off the eDP panel, - * we need to wait until SENSE bit is high/low. - */ - - /* obtain HPD */ - /* TODO what to do with this? */ - hpd = ctx->dc->link_srv->get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service); - - if (!hpd) { - BREAK_TO_DEBUGGER(); - return; - } - - if (link != NULL) { - if (link->panel_config.pps.extra_t3_ms > 0) { - int extra_t3_in_ms = link->panel_config.pps.extra_t3_ms; - - msleep(extra_t3_in_ms); - } - } - - dal_gpio_open(hpd, GPIO_MODE_INTERRUPT); - - /* wait until timeout or panel detected */ - - do { - uint32_t detected = 0; - - dal_gpio_get_value(hpd, &detected); - - if (!(detected ^ power_up)) { - edp_hpd_high = true; - break; - } - - msleep(HPD_CHECK_INTERVAL); - - time_elapsed += HPD_CHECK_INTERVAL; - } while (time_elapsed < timeout); - - dal_gpio_close(hpd); - - dal_gpio_destroy_irq(&hpd); - - /* ensure that the panel is detected */ - if (!edp_hpd_high) - DC_LOG_DC("%s: wait timed out!\n", __func__); -} - -void dce110_edp_power_control( - struct dc_link *link, - bool power_up) -{ - struct dc_context *ctx = link->ctx; - struct bp_transmitter_control cntl = { 0 }; - enum bp_result bp_result; - uint8_t panel_instance; - - - if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) - != CONNECTOR_ID_EDP) { - BREAK_TO_DEBUGGER(); - return; - } - - if (!link->panel_cntl) - return; - if (power_up != - link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl)) { - - unsigned long long current_ts = dm_get_timestamp(ctx); - unsigned long long time_since_edp_poweroff_ms = - div64_u64(dm_get_elapse_time_in_ns( - ctx, - current_ts, - ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link)), 1000000); - unsigned long long time_since_edp_poweron_ms = - div64_u64(dm_get_elapse_time_in_ns( - ctx, - current_ts, - ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link)), 1000000); - DC_LOG_HW_RESUME_S3( - "%s: transition: power_up=%d current_ts=%llu edp_poweroff=%llu edp_poweron=%llu time_since_edp_poweroff_ms=%llu time_since_edp_poweron_ms=%llu", - __func__, - power_up, - current_ts, - ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link), - ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link), - time_since_edp_poweroff_ms, - time_since_edp_poweron_ms); - - /* Send VBIOS command to prompt eDP panel power */ - if (power_up) { - /* edp requires a min of 500ms from LCDVDD off to on */ - unsigned long long remaining_min_edp_poweroff_time_ms = 500; - - /* add time defined by a patch, if any (usually patch extra_t12_ms is 0) */ - if (link->local_sink != NULL) - remaining_min_edp_poweroff_time_ms += - link->panel_config.pps.extra_t12_ms; - - /* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */ - if (ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link) != 0) { - if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms) - remaining_min_edp_poweroff_time_ms = - remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms; - else - remaining_min_edp_poweroff_time_ms = 0; - } - - if (remaining_min_edp_poweroff_time_ms) { - DC_LOG_HW_RESUME_S3( - "%s: remaining_min_edp_poweroff_time_ms=%llu: begin wait.\n", - __func__, remaining_min_edp_poweroff_time_ms); - msleep(remaining_min_edp_poweroff_time_ms); - DC_LOG_HW_RESUME_S3( - "%s: remaining_min_edp_poweroff_time_ms=%llu: end wait.\n", - __func__, remaining_min_edp_poweroff_time_ms); - dm_output_to_console("%s: wait %lld ms to power on eDP.\n", - __func__, remaining_min_edp_poweroff_time_ms); - } else { - DC_LOG_HW_RESUME_S3( - "%s: remaining_min_edp_poweroff_time_ms=%llu: no wait required.\n", - __func__, remaining_min_edp_poweroff_time_ms); - } - } - - DC_LOG_HW_RESUME_S3( - "%s: BEGIN: Panel Power action: %s\n", - __func__, (power_up ? "On":"Off")); - - cntl.action = power_up ? - TRANSMITTER_CONTROL_POWER_ON : - TRANSMITTER_CONTROL_POWER_OFF; - cntl.transmitter = link->link_enc->transmitter; - cntl.connector_obj_id = link->link_enc->connector; - cntl.coherent = false; - cntl.lanes_number = LANE_COUNT_FOUR; - cntl.hpd_sel = link->link_enc->hpd_source; - panel_instance = link->panel_cntl->inst; - - if (ctx->dc->ctx->dmub_srv && - ctx->dc->debug.dmub_command_table) { - - if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) { - bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, - LVTMA_CONTROL_POWER_ON, - panel_instance, link->link_powered_externally); - } else { - bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, - LVTMA_CONTROL_POWER_OFF, - panel_instance, link->link_powered_externally); - } - } - - bp_result = link_transmitter_control(ctx->dc_bios, &cntl); - - DC_LOG_HW_RESUME_S3( - "%s: END: Panel Power action: %s bp_result=%u\n", - __func__, (power_up ? "On":"Off"), - bp_result); - - ctx->dc->link_srv->dp_trace_set_edp_power_timestamp(link, power_up); - - DC_LOG_HW_RESUME_S3( - "%s: updated values: edp_poweroff=%llu edp_poweron=%llu\n", - __func__, - ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link), - ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link)); - - if (bp_result != BP_RESULT_OK) - DC_LOG_ERROR( - "%s: Panel Power bp_result: %d\n", - __func__, bp_result); - } else { - DC_LOG_HW_RESUME_S3( - "%s: Skipping Panel Power action: %s\n", - __func__, (power_up ? "On":"Off")); - } -} - -void dce110_edp_wait_for_T12( - struct dc_link *link) -{ - struct dc_context *ctx = link->ctx; - - if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) - != CONNECTOR_ID_EDP) { - BREAK_TO_DEBUGGER(); - return; - } - - if (!link->panel_cntl) - return; - - if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) && - ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link) != 0) { - unsigned int t12_duration = 500; // Default T12 as per spec - unsigned long long current_ts = dm_get_timestamp(ctx); - unsigned long long time_since_edp_poweroff_ms = - div64_u64(dm_get_elapse_time_in_ns( - ctx, - current_ts, - ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link)), 1000000); - - t12_duration += link->panel_config.pps.extra_t12_ms; // Add extra T12 - - if (time_since_edp_poweroff_ms < t12_duration) - msleep(t12_duration - time_since_edp_poweroff_ms); - } -} -/*todo: cloned in stream enc, fix*/ -/* - * @brief - * eDP only. Control the backlight of the eDP panel - */ -void dce110_edp_backlight_control( - struct dc_link *link, - bool enable) -{ - struct dc_context *ctx = link->ctx; - struct bp_transmitter_control cntl = { 0 }; - uint8_t panel_instance; - unsigned int pre_T11_delay = OLED_PRE_T11_DELAY; - unsigned int post_T7_delay = OLED_POST_T7_DELAY; - - if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) - != CONNECTOR_ID_EDP) { - BREAK_TO_DEBUGGER(); - return; - } - - if (link->panel_cntl && !(link->dpcd_sink_ext_caps.bits.oled || - link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 || - link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)) { - bool is_backlight_on = link->panel_cntl->funcs->is_panel_backlight_on(link->panel_cntl); - - if ((enable && is_backlight_on) || (!enable && !is_backlight_on)) { - DC_LOG_HW_RESUME_S3( - "%s: panel already powered up/off. Do nothing.\n", - __func__); - return; - } - } - - /* Send VBIOS command to control eDP panel backlight */ - - DC_LOG_HW_RESUME_S3( - "%s: backlight action: %s\n", - __func__, (enable ? "On":"Off")); - - cntl.action = enable ? - TRANSMITTER_CONTROL_BACKLIGHT_ON : - TRANSMITTER_CONTROL_BACKLIGHT_OFF; - - /*cntl.engine_id = ctx->engine;*/ - cntl.transmitter = link->link_enc->transmitter; - cntl.connector_obj_id = link->link_enc->connector; - /*todo: unhardcode*/ - cntl.lanes_number = LANE_COUNT_FOUR; - cntl.hpd_sel = link->link_enc->hpd_source; - cntl.signal = SIGNAL_TYPE_EDP; - - /* For eDP, the following delays might need to be considered - * after link training completed: - * idle period - min. accounts for required BS-Idle pattern, - * max. allows for source frame synchronization); - * 50 msec max. delay from valid video data from source - * to video on dislpay or backlight enable. - * - * Disable the delay for now. - * Enable it in the future if necessary. - */ - /* dc_service_sleep_in_milliseconds(50); */ - /*edp 1.2*/ - panel_instance = link->panel_cntl->inst; - - if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { - if (!link->dc->config.edp_no_power_sequencing) - /* - * Sometimes, DP receiver chip power-controlled externally by an - * Embedded Controller could be treated and used as eDP, - * if it drives mobile display. In this case, - * we shouldn't be doing power-sequencing, hence we can skip - * waiting for T7-ready. - */ - ctx->dc->link_srv->edp_receiver_ready_T7(link); - else - DC_LOG_DC("edp_receiver_ready_T7 skipped\n"); - } - - /* Setting link_powered_externally will bypass delays in the backlight - * as they are not required if the link is being powered by a different - * source. - */ - if (ctx->dc->ctx->dmub_srv && - ctx->dc->debug.dmub_command_table) { - if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) - ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, - LVTMA_CONTROL_LCD_BLON, - panel_instance, link->link_powered_externally); - else - ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, - LVTMA_CONTROL_LCD_BLOFF, - panel_instance, link->link_powered_externally); - } - - link_transmitter_control(ctx->dc_bios, &cntl); - - if (enable && link->dpcd_sink_ext_caps.bits.oled && - !link->dc->config.edp_no_power_sequencing) { - post_T7_delay += link->panel_config.pps.extra_post_t7_ms; - msleep(post_T7_delay); - } - - if (link->dpcd_sink_ext_caps.bits.oled || - link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 || - link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1) - ctx->dc->link_srv->edp_backlight_enable_aux(link, enable); - - /*edp 1.2*/ - if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) { - if (!link->dc->config.edp_no_power_sequencing) - /* - * Sometimes, DP receiver chip power-controlled externally by an - * Embedded Controller could be treated and used as eDP, - * if it drives mobile display. In this case, - * we shouldn't be doing power-sequencing, hence we can skip - * waiting for T9-ready. - */ - ctx->dc->link_srv->edp_add_delay_for_T9(link); - else - DC_LOG_DC("edp_receiver_ready_T9 skipped\n"); - } - - if (!enable && link->dpcd_sink_ext_caps.bits.oled) { - pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms; - msleep(pre_T11_delay); - } -} - -void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) -{ - /* notify audio driver for audio modes of monitor */ - struct dc *dc; - struct clk_mgr *clk_mgr; - unsigned int i, num_audio = 1; - const struct link_hwss *link_hwss; - - if (!pipe_ctx->stream) - return; - - dc = pipe_ctx->stream->ctx->dc; - clk_mgr = dc->clk_mgr; - link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res); - - if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true) - return; - - if (pipe_ctx->stream_res.audio) { - for (i = 0; i < MAX_PIPES; i++) { - /*current_state not updated yet*/ - if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) - num_audio++; - } - - pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); - - if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) - /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ - clk_mgr->funcs->enable_pme_wa(clk_mgr); - - link_hwss->enable_audio_packet(pipe_ctx); - - if (pipe_ctx->stream_res.audio) - pipe_ctx->stream_res.audio->enabled = true; - } -} - -void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx) -{ - struct dc *dc; - struct clk_mgr *clk_mgr; - const struct link_hwss *link_hwss; - - if (!pipe_ctx || !pipe_ctx->stream) - return; - - dc = pipe_ctx->stream->ctx->dc; - clk_mgr = dc->clk_mgr; - link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res); - - if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false) - return; - - link_hwss->disable_audio_packet(pipe_ctx); - - if (pipe_ctx->stream_res.audio) { - pipe_ctx->stream_res.audio->enabled = false; - - if (clk_mgr->funcs->enable_pme_wa) - /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ - clk_mgr->funcs->enable_pme_wa(clk_mgr); - - /* TODO: notify audio driver for if audio modes list changed - * add audio mode list change flag */ - /* dal_audio_disable_azalia_audio_jack_presence(stream->audio, - * stream->stream_engine_id); - */ - } -} - -void dce110_disable_stream(struct pipe_ctx *pipe_ctx) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dc *dc = pipe_ctx->stream->ctx->dc; - const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); - struct dccg *dccg = dc->res_pool->dccg; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - struct dtbclk_dto_params dto_params = {0}; - int dp_hpo_inst; - struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link); - struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; - - if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) { - pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( - pipe_ctx->stream_res.stream_enc); - pipe_ctx->stream_res.stream_enc->funcs->hdmi_reset_stream_attribute( - pipe_ctx->stream_res.stream_enc); - } - - if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets( - pipe_ctx->stream_res.hpo_dp_stream_enc); - } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets( - pipe_ctx->stream_res.stream_enc); - - dc->hwss.disable_audio_stream(pipe_ctx); - - link_hwss->reset_stream_encoder(pipe_ctx); - - if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) && dccg) { - dto_params.otg_inst = tg->inst; - dto_params.timing = &pipe_ctx->stream->timing; - dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; - - dccg->funcs->set_dtbclk_dto(dccg, &dto_params); - dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); - dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst); - } else if (dccg && dccg->funcs->disable_symclk_se) { - dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst, - link_enc->transmitter - TRANSMITTER_UNIPHY_A); - } - - if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - /* TODO: This looks like a bug to me as we are disabling HPO IO when - * we are just disabling a single HPO stream. Shouldn't we disable HPO - * HW control only when HPOs for all streams are disabled? - */ - if (pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control) - pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control( - pipe_ctx->stream->ctx->dc->hwseq, false); - } -} - -void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings) -{ - struct encoder_unblank_param params = { { 0 } }; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dce_hwseq *hws = link->dc->hwseq; - - /* only 3 items below are used by unblank */ - params.timing = pipe_ctx->stream->timing; - params.link_settings.link_rate = link_settings->link_rate; - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); - - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - hws->funcs.edp_backlight_control(link, true); - } -} - -void dce110_blank_stream(struct pipe_ctx *pipe_ctx) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dce_hwseq *hws = link->dc->hwseq; - - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - if (!link->skip_implict_edp_power_control) - hws->funcs.edp_backlight_control(link, false); - link->dc->hwss.set_abm_immediate_disable(pipe_ctx); - } - - if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank( - pipe_ctx->stream_res.hpo_dp_stream_enc); - } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - pipe_ctx->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc); - - if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) { - /* - * After output is idle pattern some sinks need time to recognize the stream - * has changed or they enter protection state and hang. - */ - msleep(60); - } else if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) { - if (!link->dc->config.edp_no_power_sequencing) { - /* - * Sometimes, DP receiver chip power-controlled externally by an - * Embedded Controller could be treated and used as eDP, - * if it drives mobile display. In this case, - * we shouldn't be doing power-sequencing, hence we can skip - * waiting for T9-ready. - */ - link->dc->link_srv->edp_receiver_ready_T9(link); - } - } - } - -} - - -void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) -{ - if (pipe_ctx != NULL && pipe_ctx->stream_res.stream_enc != NULL) - pipe_ctx->stream_res.stream_enc->funcs->set_avmute(pipe_ctx->stream_res.stream_enc, enable); -} - -static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id) -{ - switch (crtc_id) { - case CONTROLLER_ID_D0: - return DTO_SOURCE_ID0; - case CONTROLLER_ID_D1: - return DTO_SOURCE_ID1; - case CONTROLLER_ID_D2: - return DTO_SOURCE_ID2; - case CONTROLLER_ID_D3: - return DTO_SOURCE_ID3; - case CONTROLLER_ID_D4: - return DTO_SOURCE_ID4; - case CONTROLLER_ID_D5: - return DTO_SOURCE_ID5; - default: - return DTO_SOURCE_UNKNOWN; - } -} - -static void build_audio_output( - struct dc_state *state, - const struct pipe_ctx *pipe_ctx, - struct audio_output *audio_output) -{ - const struct dc_stream_state *stream = pipe_ctx->stream; - audio_output->engine_id = pipe_ctx->stream_res.stream_enc->id; - - audio_output->signal = pipe_ctx->stream->signal; - - /* audio_crtc_info */ - - audio_output->crtc_info.h_total = - stream->timing.h_total; - - /* - * Audio packets are sent during actual CRTC blank physical signal, we - * need to specify actual active signal portion - */ - audio_output->crtc_info.h_active = - stream->timing.h_addressable - + stream->timing.h_border_left - + stream->timing.h_border_right; - - audio_output->crtc_info.v_active = - stream->timing.v_addressable - + stream->timing.v_border_top - + stream->timing.v_border_bottom; - - audio_output->crtc_info.pixel_repetition = 1; - - audio_output->crtc_info.interlaced = - stream->timing.flags.INTERLACE; - - audio_output->crtc_info.refresh_rate = - (stream->timing.pix_clk_100hz*100)/ - (stream->timing.h_total*stream->timing.v_total); - - audio_output->crtc_info.color_depth = - stream->timing.display_color_depth; - - audio_output->crtc_info.requested_pixel_clock_100Hz = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz; - - audio_output->crtc_info.calculated_pixel_clock_100Hz = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz; - -/*for HDMI, audio ACR is with deep color ratio factor*/ - if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) && - audio_output->crtc_info.requested_pixel_clock_100Hz == - (stream->timing.pix_clk_100hz)) { - if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) { - audio_output->crtc_info.requested_pixel_clock_100Hz = - audio_output->crtc_info.requested_pixel_clock_100Hz/2; - audio_output->crtc_info.calculated_pixel_clock_100Hz = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/2; - - } - } - - if (state->clk_mgr && - (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT || - pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)) { - audio_output->pll_info.dp_dto_source_clock_in_khz = - state->clk_mgr->funcs->get_dp_ref_clk_frequency( - state->clk_mgr); - } - - audio_output->pll_info.feed_back_divider = - pipe_ctx->pll_settings.feedback_divider; - - audio_output->pll_info.dto_source = - translate_to_dto_source( - pipe_ctx->stream_res.tg->inst + 1); - - /* TODO hard code to enable for now. Need get from stream */ - audio_output->pll_info.ss_enabled = true; - - audio_output->pll_info.ss_percentage = - pipe_ctx->pll_settings.ss_percentage; -} - -static void program_scaler(const struct dc *dc, - const struct pipe_ctx *pipe_ctx) -{ - struct tg_color color = {0}; - - /* TOFPGA */ - if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL) - return; - - if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) - get_surface_visual_confirm_color(pipe_ctx, &color); - else - color_space_to_black_color(dc, - pipe_ctx->stream->output_color_space, - &color); - - pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth( - pipe_ctx->plane_res.xfm, - pipe_ctx->plane_res.scl_data.lb_params.depth, - &pipe_ctx->stream->bit_depth_params); - - if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) { - /* - * The way 420 is packed, 2 channels carry Y component, 1 channel - * alternate between Cb and Cr, so both channels need the pixel - * value for Y - */ - if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - color.color_r_cr = color.color_g_y; - - pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color( - pipe_ctx->stream_res.tg, - &color); - } - - pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm, - &pipe_ctx->plane_res.scl_data); -} - -static enum dc_status dce110_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx. - pipe_ctx[pipe_ctx->pipe_idx]; - struct tg_color black_color = {0}; - - if (!pipe_ctx_old->stream) { - - /* program blank color */ - color_space_to_black_color(dc, - stream->output_color_space, &black_color); - pipe_ctx->stream_res.tg->funcs->set_blank_color( - pipe_ctx->stream_res.tg, - &black_color); - - /* - * Must blank CRTC after disabling power gating and before any - * programming, otherwise CRTC will be hung in bad state - */ - pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); - - if (false == pipe_ctx->clock_source->funcs->program_pix_clk( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), - &pipe_ctx->pll_settings)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - - if (dc_is_hdmi_tmds_signal(stream->signal)) { - stream->link->phy_state.symclk_ref_cnts.otg = 1; - if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; - else - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; - } - - pipe_ctx->stream_res.tg->funcs->program_timing( - pipe_ctx->stream_res.tg, - &stream->timing, - 0, - 0, - 0, - 0, - pipe_ctx->stream->signal, - true); - } - - if (!pipe_ctx_old->stream) { - if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc( - pipe_ctx->stream_res.tg)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - } - - return DC_OK; -} - -static enum dc_status apply_single_controller_ctx_to_hw( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct drr_params params = {0}; - unsigned int event_triggers = 0; - struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; - struct dce_hwseq *hws = dc->hwseq; - const struct link_hwss *link_hwss = get_link_hwss( - link, &pipe_ctx->link_res); - - - if (hws->funcs.disable_stream_gating) { - hws->funcs.disable_stream_gating(dc, pipe_ctx); - } - - if (pipe_ctx->stream_res.audio != NULL) { - struct audio_output audio_output; - - build_audio_output(context, pipe_ctx, &audio_output); - - link_hwss->setup_audio_output(pipe_ctx, &audio_output, - pipe_ctx->stream_res.audio->inst); - - pipe_ctx->stream_res.audio->funcs->az_configure( - pipe_ctx->stream_res.audio, - pipe_ctx->stream->signal, - &audio_output.crtc_info, - &pipe_ctx->stream->audio_info); - } - - /* make sure no pipes syncd to the pipe being enabled */ - if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic) - check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx); - - pipe_ctx->stream_res.opp->funcs->opp_program_fmt( - pipe_ctx->stream_res.opp, - &stream->bit_depth_params, - &stream->clamping); - - pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion( - pipe_ctx->stream_res.opp, - COLOR_SPACE_YCBCR601, - stream->timing.display_color_depth, - stream->signal); - - while (odm_pipe) { - odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion( - odm_pipe->stream_res.opp, - COLOR_SPACE_YCBCR601, - stream->timing.display_color_depth, - stream->signal); - - odm_pipe->stream_res.opp->funcs->opp_program_fmt( - odm_pipe->stream_res.opp, - &stream->bit_depth_params, - &stream->clamping); - odm_pipe = odm_pipe->next_odm_pipe; - } - - /* DCN3.1 FPGA Workaround - * Need to enable HPO DP Stream Encoder before setting OTG master enable. - * To do so, move calling function enable_stream_timing to only be done AFTER calling - * function core_link_enable_stream - */ - if (!(hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))) - /* */ - /* Do not touch stream timing on seamless boot optimization. */ - if (!pipe_ctx->stream->apply_seamless_boot_optimization) - hws->funcs.enable_stream_timing(pipe_ctx, context, dc); - - if (hws->funcs.setup_vupdate_interrupt) - hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); - - params.vertical_total_min = stream->adjust.v_total_min; - params.vertical_total_max = stream->adjust.v_total_max; - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, ¶ms); - - // DRR should set trigger event to monitor surface update event - if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) - event_triggers = 0x80; - /* Event triggers and num frames initialized for DRR, but can be - * later updated for PSR use. Note DRR trigger events are generated - * regardless of whether num frames met. - */ - if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx->stream_res.tg, event_triggers, 2); - - if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( - pipe_ctx->stream_res.stream_enc, - pipe_ctx->stream_res.tg->inst); - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG); - - if (!stream->dpms_off) - dc->link_srv->set_dpms_on(context, pipe_ctx); - - /* DCN3.1 FPGA Workaround - * Need to enable HPO DP Stream Encoder before setting OTG master enable. - * To do so, move calling function enable_stream_timing to only be done AFTER calling - * function core_link_enable_stream - */ - if (hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - if (!pipe_ctx->stream->apply_seamless_boot_optimization) - hws->funcs.enable_stream_timing(pipe_ctx, context, dc); - } - - pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL; - - /* Phantom and main stream share the same link (because the stream - * is constructed with the same sink). Make sure not to override - * and link programming on the main. - */ - if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { - pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false; - pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false; - } - return DC_OK; -} - -/******************************************************************************/ - -static void power_down_encoders(struct dc *dc) -{ - int i; - - for (i = 0; i < dc->link_count; i++) { - enum signal_type signal = dc->links[i]->connector_signal; - - dc->link_srv->blank_dp_stream(dc->links[i], false); - - if (signal != SIGNAL_TYPE_EDP) - signal = SIGNAL_TYPE_NONE; - - if (dc->links[i]->ep_type == DISPLAY_ENDPOINT_PHY) - dc->links[i]->link_enc->funcs->disable_output( - dc->links[i]->link_enc, signal); - - dc->links[i]->link_status.link_active = false; - memset(&dc->links[i]->cur_link_settings, 0, - sizeof(dc->links[i]->cur_link_settings)); - } -} - -static void power_down_controllers(struct dc *dc) -{ - int i; - - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - dc->res_pool->timing_generators[i]->funcs->disable_crtc( - dc->res_pool->timing_generators[i]); - } -} - -static void power_down_clock_sources(struct dc *dc) -{ - int i; - - if (dc->res_pool->dp_clock_source->funcs->cs_power_down( - dc->res_pool->dp_clock_source) == false) - dm_error("Failed to power down pll! (dp clk src)\n"); - - for (i = 0; i < dc->res_pool->clk_src_count; i++) { - if (dc->res_pool->clock_sources[i]->funcs->cs_power_down( - dc->res_pool->clock_sources[i]) == false) - dm_error("Failed to power down pll! (clk src index=%d)\n", i); - } -} - -static void power_down_all_hw_blocks(struct dc *dc) -{ - power_down_encoders(dc); - - power_down_controllers(dc); - - power_down_clock_sources(dc); - - if (dc->fbc_compressor) - dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); -} - -static void disable_vga_and_power_gate_all_controllers( - struct dc *dc) -{ - int i; - struct timing_generator *tg; - struct dc_context *ctx = dc->ctx; - - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->disable_vga) - tg->funcs->disable_vga(tg); - } - for (i = 0; i < dc->res_pool->pipe_count; i++) { - /* Enable CLOCK gating for each pipe BEFORE controller - * powergating. */ - enable_display_pipe_clock_gating(ctx, - true); - - dc->current_state->res_ctx.pipe_ctx[i].pipe_idx = i; - dc->hwss.disable_plane(dc, - &dc->current_state->res_ctx.pipe_ctx[i]); - } -} - - -static void get_edp_streams(struct dc_state *context, - struct dc_stream_state **edp_streams, - int *edp_stream_num) -{ - int i; - - *edp_stream_num = 0; - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->signal == SIGNAL_TYPE_EDP) { - edp_streams[*edp_stream_num] = context->streams[i]; - if (++(*edp_stream_num) == MAX_NUM_EDP) - return; - } - } -} - -static void get_edp_links_with_sink( - struct dc *dc, - struct dc_link **edp_links_with_sink, - int *edp_with_sink_num) -{ - int i; - - /* check if there is an eDP panel not in use */ - *edp_with_sink_num = 0; - for (i = 0; i < dc->link_count; i++) { - if (dc->links[i]->local_sink && - dc->links[i]->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - edp_links_with_sink[*edp_with_sink_num] = dc->links[i]; - if (++(*edp_with_sink_num) == MAX_NUM_EDP) - return; - } - } -} - -/* - * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need: - * 1. Power down all DC HW blocks - * 2. Disable VGA engine on all controllers - * 3. Enable power gating for controller - * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS) - */ -void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) -{ - struct dc_link *edp_links_with_sink[MAX_NUM_EDP]; - struct dc_link *edp_links[MAX_NUM_EDP]; - struct dc_stream_state *edp_streams[MAX_NUM_EDP]; - struct dc_link *edp_link_with_sink = NULL; - struct dc_link *edp_link = NULL; - struct dce_hwseq *hws = dc->hwseq; - int edp_with_sink_num; - int edp_num; - int edp_stream_num; - int i; - bool can_apply_edp_fast_boot = false; - bool can_apply_seamless_boot = false; - bool keep_edp_vdd_on = false; - DC_LOGGER_INIT(); - - - get_edp_links_with_sink(dc, edp_links_with_sink, &edp_with_sink_num); - dc_get_edp_links(dc, edp_links, &edp_num); - - if (hws->funcs.init_pipes) - hws->funcs.init_pipes(dc, context); - - get_edp_streams(context, edp_streams, &edp_stream_num); - - // Check fastboot support, disable on DCE8 because of blank screens - if (edp_num && edp_stream_num && dc->ctx->dce_version != DCE_VERSION_8_0 && - dc->ctx->dce_version != DCE_VERSION_8_1 && - dc->ctx->dce_version != DCE_VERSION_8_3) { - for (i = 0; i < edp_num; i++) { - edp_link = edp_links[i]; - if (edp_link != edp_streams[0]->link) - continue; - // enable fastboot if backend is enabled on eDP - if (edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - edp_link->link_status.link_active) { - struct dc_stream_state *edp_stream = edp_streams[0]; - - can_apply_edp_fast_boot = dc_validate_boot_timing(dc, - edp_stream->sink, &edp_stream->timing); - edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot; - if (can_apply_edp_fast_boot) - DC_LOG_EVENT_LINK_TRAINING("eDP fast boot disabled to optimize link rate\n"); - - break; - } - } - // We are trying to enable eDP, don't power down VDD - if (can_apply_edp_fast_boot) - keep_edp_vdd_on = true; - } - - // Check seamless boot support - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->apply_seamless_boot_optimization) { - can_apply_seamless_boot = true; - break; - } - } - - /* eDP should not have stream in resume from S4 and so even with VBios post - * it should get turned off - */ - if (edp_with_sink_num) - edp_link_with_sink = edp_links_with_sink[0]; - - if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) { - if (edp_link_with_sink && !keep_edp_vdd_on) { - /*turn off backlight before DP_blank and encoder powered down*/ - hws->funcs.edp_backlight_control(edp_link_with_sink, false); - } - /*resume from S3, no vbios posting, no need to power down again*/ - clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr); - - power_down_all_hw_blocks(dc); - disable_vga_and_power_gate_all_controllers(dc); - if (edp_link_with_sink && !keep_edp_vdd_on) - dc->hwss.edp_power_control(edp_link_with_sink, false); - clk_mgr_optimize_pwr_state(dc, dc->clk_mgr); - } - bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1); -} - -static uint32_t compute_pstate_blackout_duration( - struct bw_fixed blackout_duration, - const struct dc_stream_state *stream) -{ - uint32_t total_dest_line_time_ns; - uint32_t pstate_blackout_duration_ns; - - pstate_blackout_duration_ns = 1000 * blackout_duration.value >> 24; - - total_dest_line_time_ns = 1000000UL * - (stream->timing.h_total * 10) / - stream->timing.pix_clk_100hz + - pstate_blackout_duration_ns; - - return total_dest_line_time_ns; -} - -static void dce110_set_displaymarks( - const struct dc *dc, - struct dc_state *context) -{ - uint8_t i, num_pipes; - unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; - - for (i = 0, num_pipes = 0; i < MAX_PIPES; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - uint32_t total_dest_line_time_ns; - - if (pipe_ctx->stream == NULL) - continue; - - total_dest_line_time_ns = compute_pstate_blackout_duration( - dc->bw_vbios->blackout_duration, pipe_ctx->stream); - pipe_ctx->plane_res.mi->funcs->mem_input_program_display_marks( - pipe_ctx->plane_res.mi, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[num_pipes], - context->bw_ctx.bw.dce.stutter_exit_wm_ns[num_pipes], - context->bw_ctx.bw.dce.stutter_entry_wm_ns[num_pipes], - context->bw_ctx.bw.dce.urgent_wm_ns[num_pipes], - total_dest_line_time_ns); - if (i == underlay_idx) { - num_pipes++; - pipe_ctx->plane_res.mi->funcs->mem_input_program_chroma_display_marks( - pipe_ctx->plane_res.mi, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[num_pipes], - context->bw_ctx.bw.dce.stutter_exit_wm_ns[num_pipes], - context->bw_ctx.bw.dce.urgent_wm_ns[num_pipes], - total_dest_line_time_ns); - } - num_pipes++; - } -} - -void dce110_set_safe_displaymarks( - struct resource_context *res_ctx, - const struct resource_pool *pool) -{ - int i; - int underlay_idx = pool->underlay_pipe_index; - struct dce_watermarks max_marks = { - MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK }; - struct dce_watermarks nbp_marks = { - SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK }; - struct dce_watermarks min_marks = { 0, 0, 0, 0}; - - for (i = 0; i < MAX_PIPES; i++) { - if (res_ctx->pipe_ctx[i].stream == NULL || res_ctx->pipe_ctx[i].plane_res.mi == NULL) - continue; - - res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_display_marks( - res_ctx->pipe_ctx[i].plane_res.mi, - nbp_marks, - max_marks, - min_marks, - max_marks, - MAX_WATERMARK); - - if (i == underlay_idx) - res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_chroma_display_marks( - res_ctx->pipe_ctx[i].plane_res.mi, - nbp_marks, - max_marks, - max_marks, - MAX_WATERMARK); - - } -} - -/******************************************************************************* - * Public functions - ******************************************************************************/ - -static void set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, struct dc_crtc_timing_adjust adjust) -{ - int i = 0; - struct drr_params params = {0}; - // DRR should set trigger event to monitor surface update event - unsigned int event_triggers = 0x80; - // Note DRR trigger events are generated regardless of whether num frames met. - unsigned int num_frames = 2; - - params.vertical_total_max = adjust.v_total_max; - params.vertical_total_min = adjust.v_total_min; - - /* TODO: If multiple pipes are to be supported, you need - * some GSL stuff. Static screen triggers may be programmed differently - * as well. - */ - for (i = 0; i < num_pipes; i++) { - pipe_ctx[i]->stream_res.tg->funcs->set_drr( - pipe_ctx[i]->stream_res.tg, ¶ms); - - if (adjust.v_total_max != 0 && adjust.v_total_min != 0) - pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx[i]->stream_res.tg, - event_triggers, num_frames); - } -} - -static void get_position(struct pipe_ctx **pipe_ctx, - int num_pipes, - struct crtc_position *position) -{ - int i = 0; - - /* TODO: handle pipes > 1 - */ - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); -} - -static void set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params) -{ - unsigned int i; - unsigned int triggers = 0; - - if (params->triggers.overlay_update) - triggers |= 0x100; - if (params->triggers.surface_update) - triggers |= 0x80; - if (params->triggers.cursor_update) - triggers |= 0x2; - if (params->triggers.force_trigger) - triggers |= 0x1; - - if (num_pipes) { - struct dc *dc = pipe_ctx[0]->stream->ctx->dc; - - if (dc->fbc_compressor) - triggers |= 0x84; - } - - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs-> - set_static_screen_control(pipe_ctx[i]->stream_res.tg, - triggers, params->num_frames); -} - -/* - * Check if FBC can be enabled - */ -static bool should_enable_fbc(struct dc *dc, - struct dc_state *context, - uint32_t *pipe_idx) -{ - uint32_t i; - struct pipe_ctx *pipe_ctx = NULL; - struct resource_context *res_ctx = &context->res_ctx; - unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; - - - ASSERT(dc->fbc_compressor); - - /* FBC memory should be allocated */ - if (!dc->ctx->fbc_gpu_addr) - return false; - - /* Only supports single display */ - if (context->stream_count != 1) - return false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (res_ctx->pipe_ctx[i].stream) { - - pipe_ctx = &res_ctx->pipe_ctx[i]; - - /* fbc not applicable on underlay pipe */ - if (pipe_ctx->pipe_idx != underlay_idx) { - *pipe_idx = i; - break; - } - } - } - - if (i == dc->res_pool->pipe_count) - return false; - - if (!pipe_ctx->stream->link) - return false; - - /* Only supports eDP */ - if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP) - return false; - - /* PSR should not be enabled */ - if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled) - return false; - - /* Replay should not be enabled */ - if (pipe_ctx->stream->link->replay_settings.replay_feature_enabled) - return false; - - /* Nothing to compress */ - if (!pipe_ctx->plane_state) - return false; - - /* Only for non-linear tiling */ - if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL) - return false; - - return true; -} - -/* - * Enable FBC - */ -static void enable_fbc( - struct dc *dc, - struct dc_state *context) -{ - uint32_t pipe_idx = 0; - - if (should_enable_fbc(dc, context, &pipe_idx)) { - /* Program GRPH COMPRESSED ADDRESS and PITCH */ - struct compr_addr_and_pitch_params params = {0, 0, 0}; - struct compressor *compr = dc->fbc_compressor; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; - - params.source_view_width = pipe_ctx->stream->timing.h_addressable; - params.source_view_height = pipe_ctx->stream->timing.v_addressable; - params.inst = pipe_ctx->stream_res.tg->inst; - compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr; - - compr->funcs->surface_address_and_pitch(compr, ¶ms); - compr->funcs->set_fbc_invalidation_triggers(compr, 1); - - compr->funcs->enable_fbc(compr, ¶ms); - } -} - -static void dce110_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context) -{ - int i; - - /* Reset old context */ - /* look up the targets that have been removed since last commit */ - for (i = 0; i < MAX_PIPES; i++) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* Note: We need to disable output if clock sources change, - * since bios does optimization and doesn't apply if changing - * PHY when not already disabled. - */ - - /* Skip underlay pipe since it will be handled in commit surface*/ - if (!pipe_ctx_old->stream || pipe_ctx_old->top_pipe) - continue; - - if (!pipe_ctx->stream || - pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { - struct clock_source *old_clk = pipe_ctx_old->clock_source; - - /* Disable if new stream is null. O/w, if stream is - * disabled already, no need to disable again. - */ - if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off) { - dc->link_srv->set_dpms_off(pipe_ctx_old); - - /* free acquired resources*/ - if (pipe_ctx_old->stream_res.audio) { - /*disable az_endpoint*/ - pipe_ctx_old->stream_res.audio->funcs-> - az_disable(pipe_ctx_old->stream_res.audio); - - /*free audio*/ - if (dc->caps.dynamic_audio == true) { - /*we have to dynamic arbitrate the audio endpoints*/ - /*we free the resource, need reset is_audio_acquired*/ - update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, - pipe_ctx_old->stream_res.audio, false); - pipe_ctx_old->stream_res.audio = NULL; - } - } - } - - pipe_ctx_old->stream_res.tg->funcs->set_blank(pipe_ctx_old->stream_res.tg, true); - if (!hwss_wait_for_blank_complete(pipe_ctx_old->stream_res.tg)) { - dm_error("DC: failed to blank crtc!\n"); - BREAK_TO_DEBUGGER(); - } - pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); - pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; - pipe_ctx_old->plane_res.mi->funcs->free_mem_input( - pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); - - if (old_clk && 0 == resource_get_clock_source_reference(&context->res_ctx, - dc->res_pool, - old_clk)) - old_clk->funcs->cs_power_down(old_clk); - - dc->hwss.disable_plane(dc, pipe_ctx_old); - - pipe_ctx_old->stream = NULL; - } - } -} - -static void dce110_setup_audio_dto( - struct dc *dc, - struct dc_state *context) -{ - int i; - - /* program audio wall clock. use HDMI as clock source if HDMI - * audio active. Otherwise, use DP as clock source - * first, loop to find any HDMI audio, if not, loop find DP audio - */ - /* Setup audio rate clock source */ - /* Issue: - * Audio lag happened on DP monitor when unplug a HDMI monitor - * - * Cause: - * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL - * is set to either dto0 or dto1, audio should work fine. - * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1, - * set to dto0 will cause audio lag. - * - * Solution: - * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx, - * find first available pipe with audio, setup audio wall DTO per topology - * instead of per pipe. - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == NULL) - continue; - - if (pipe_ctx->top_pipe) - continue; - if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A) - continue; - if (pipe_ctx->stream_res.audio != NULL) { - struct audio_output audio_output; - - build_audio_output(context, pipe_ctx, &audio_output); - - if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) { - struct dtbclk_dto_params dto_params = {0}; - - dc->res_pool->dccg->funcs->set_audio_dtbclk_dto( - dc->res_pool->dccg, &dto_params); - - pipe_ctx->stream_res.audio->funcs->wall_dto_setup( - pipe_ctx->stream_res.audio, - pipe_ctx->stream->signal, - &audio_output.crtc_info, - &audio_output.pll_info); - } else - pipe_ctx->stream_res.audio->funcs->wall_dto_setup( - pipe_ctx->stream_res.audio, - pipe_ctx->stream->signal, - &audio_output.crtc_info, - &audio_output.pll_info); - break; - } - } - - /* no HDMI audio is found, try DP audio */ - if (i == dc->res_pool->pipe_count) { - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == NULL) - continue; - - if (pipe_ctx->top_pipe) - continue; - - if (!dc_is_dp_signal(pipe_ctx->stream->signal)) - continue; - - if (pipe_ctx->stream_res.audio != NULL) { - struct audio_output audio_output; - - build_audio_output(context, pipe_ctx, &audio_output); - - pipe_ctx->stream_res.audio->funcs->wall_dto_setup( - pipe_ctx->stream_res.audio, - pipe_ctx->stream->signal, - &audio_output.crtc_info, - &audio_output.pll_info); - break; - } - } - } -} - -enum dc_status dce110_apply_ctx_to_hw( - struct dc *dc, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - enum dc_status status; - int i; - - /* reset syncd pipes from disabled pipes */ - if (dc->config.use_pipe_ctx_sync_logic) - reset_syncd_pipes_from_disabled_pipes(dc, context); - - /* Reset old context */ - /* look up the targets that have been removed since last commit */ - hws->funcs.reset_hw_ctx_wrap(dc, context); - - /* Skip applying if no targets */ - if (context->stream_count <= 0) - return DC_OK; - - /* Apply new context */ - dcb->funcs->set_scratch_critical_state(dcb, true); - - /* below is for real asic only */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe) - continue; - - if (pipe_ctx->stream == pipe_ctx_old->stream) { - if (pipe_ctx_old->clock_source != pipe_ctx->clock_source) - dce_crtc_switch_to_clk_src(dc->hwseq, - pipe_ctx->clock_source, i); - continue; - } - - hws->funcs.enable_display_power_gating( - dc, i, dc->ctx->dc_bios, - PIPE_GATING_CONTROL_DISABLE); - } - - if (dc->fbc_compressor) - dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); - - dce110_setup_audio_dto(dc, context); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == NULL) - continue; - - if (pipe_ctx->stream == pipe_ctx_old->stream && - pipe_ctx->stream->link->link_state_valid) { - continue; - } - - if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) - continue; - - if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe) - continue; - - status = apply_single_controller_ctx_to_hw( - pipe_ctx, - context, - dc); - - if (DC_OK != status) - return status; - -#ifdef CONFIG_DRM_AMD_DC_FP - if (hws->funcs.resync_fifo_dccg_dio) - hws->funcs.resync_fifo_dccg_dio(hws, dc, context); -#endif - } - - if (dc->fbc_compressor) - enable_fbc(dc, dc->current_state); - - dcb->funcs->set_scratch_critical_state(dcb, false); - - return DC_OK; -} - -/******************************************************************************* - * Front End programming - ******************************************************************************/ -static void set_default_colors(struct pipe_ctx *pipe_ctx) -{ - struct default_adjustment default_adjust = { 0 }; - - default_adjust.force_hw_default = false; - default_adjust.in_color_space = pipe_ctx->plane_state->color_space; - default_adjust.out_color_space = pipe_ctx->stream->output_color_space; - default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW; - default_adjust.surface_pixel_format = pipe_ctx->plane_res.scl_data.format; - - /* display color depth */ - default_adjust.color_depth = - pipe_ctx->stream->timing.display_color_depth; - - /* Lb color depth */ - default_adjust.lb_color_depth = pipe_ctx->plane_res.scl_data.lb_params.depth; - - pipe_ctx->plane_res.xfm->funcs->opp_set_csc_default( - pipe_ctx->plane_res.xfm, &default_adjust); -} - - -/******************************************************************************* - * In order to turn on/off specific surface we will program - * Blender + CRTC - * - * In case that we have two surfaces and they have a different visibility - * we can't turn off the CRTC since it will turn off the entire display - * - * |----------------------------------------------- | - * |bottom pipe|curr pipe | | | - * |Surface |Surface | Blender | CRCT | - * |visibility |visibility | Configuration| | - * |------------------------------------------------| - * | off | off | CURRENT_PIPE | blank | - * | off | on | CURRENT_PIPE | unblank | - * | on | off | OTHER_PIPE | unblank | - * | on | on | BLENDING | unblank | - * -------------------------------------------------| - * - ******************************************************************************/ -static void program_surface_visibility(const struct dc *dc, - struct pipe_ctx *pipe_ctx) -{ - enum blnd_mode blender_mode = BLND_MODE_CURRENT_PIPE; - bool blank_target = false; - - if (pipe_ctx->bottom_pipe) { - - /* For now we are supporting only two pipes */ - ASSERT(pipe_ctx->bottom_pipe->bottom_pipe == NULL); - - if (pipe_ctx->bottom_pipe->plane_state->visible) { - if (pipe_ctx->plane_state->visible) - blender_mode = BLND_MODE_BLENDING; - else - blender_mode = BLND_MODE_OTHER_PIPE; - - } else if (!pipe_ctx->plane_state->visible) - blank_target = true; - - } else if (!pipe_ctx->plane_state->visible) - blank_target = true; - - dce_set_blender_mode(dc->hwseq, pipe_ctx->stream_res.tg->inst, blender_mode); - pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, blank_target); - -} - -static void program_gamut_remap(struct pipe_ctx *pipe_ctx) -{ - int i = 0; - struct xfm_grph_csc_adjustment adjust; - memset(&adjust, 0, sizeof(adjust)); - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - - - if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - - for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) - adjust.temperature_matrix[i] = - pipe_ctx->stream->gamut_remap_matrix.matrix[i]; - } - - pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); -} -static void update_plane_addr(const struct dc *dc, - struct pipe_ctx *pipe_ctx) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - - if (plane_state == NULL) - return; - - pipe_ctx->plane_res.mi->funcs->mem_input_program_surface_flip_and_addr( - pipe_ctx->plane_res.mi, - &plane_state->address, - plane_state->flip_immediate); - - plane_state->status.requested_address = plane_state->address; -} - -static void dce110_update_pending_status(struct pipe_ctx *pipe_ctx) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - - if (plane_state == NULL) - return; - - plane_state->status.is_flip_pending = - pipe_ctx->plane_res.mi->funcs->mem_input_is_flip_pending( - pipe_ctx->plane_res.mi); - - if (plane_state->status.is_flip_pending && !plane_state->visible) - pipe_ctx->plane_res.mi->current_address = pipe_ctx->plane_res.mi->request_address; - - plane_state->status.current_address = pipe_ctx->plane_res.mi->current_address; - if (pipe_ctx->plane_res.mi->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && - pipe_ctx->stream_res.tg->funcs->is_stereo_left_eye) { - plane_state->status.is_right_eye =\ - !pipe_ctx->stream_res.tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); - } -} - -void dce110_power_down(struct dc *dc) -{ - power_down_all_hw_blocks(dc); - disable_vga_and_power_gate_all_controllers(dc); -} - -static bool wait_for_reset_trigger_to_occur( - struct dc_context *dc_ctx, - struct timing_generator *tg) -{ - struct dc_context *ctx = dc_ctx; - bool rc = false; - - /* To avoid endless loop we wait at most - * frames_to_wait_on_triggered_reset frames for the reset to occur. */ - const uint32_t frames_to_wait_on_triggered_reset = 10; - uint32_t i; - - for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { - - if (!tg->funcs->is_counter_moving(tg)) { - DC_ERROR("TG counter is not moving!\n"); - break; - } - - if (tg->funcs->did_triggered_reset_occur(tg)) { - rc = true; - /* usually occurs at i=1 */ - DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", - i); - break; - } - - /* Wait for one frame. */ - tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); - tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); - } - - if (false == rc) - DC_ERROR("GSL: Timeout on reset trigger!\n"); - - return rc; -} - -/* Enable timing synchronization for a group of Timing Generators. */ -static void dce110_enable_timing_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - struct dcp_gsl_params gsl_params = { 0 }; - int i; - DC_LOGGER_INIT(); - - DC_SYNC_INFO("GSL: Setting-up...\n"); - - /* Designate a single TG in the group as a master. - * Since HW doesn't care which one, we always assign - * the 1st one in the group. */ - gsl_params.gsl_group = 0; - gsl_params.gsl_master = grouped_pipes[0]->stream_res.tg->inst; - - for (i = 0; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock( - grouped_pipes[i]->stream_res.tg, &gsl_params); - - /* Reset slave controllers on master VSync */ - DC_SYNC_INFO("GSL: enabling trigger-reset\n"); - - for (i = 1 /* skip the master */; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( - grouped_pipes[i]->stream_res.tg, - gsl_params.gsl_group); - - for (i = 1 /* skip the master */; i < group_size; i++) { - DC_SYNC_INFO("GSL: waiting for reset to occur.\n"); - wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); - grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( - grouped_pipes[i]->stream_res.tg); - } - - /* GSL Vblank synchronization is a one time sync mechanism, assumption - * is that the sync'ed displays will not drift out of sync over time*/ - DC_SYNC_INFO("GSL: Restoring register states.\n"); - for (i = 0; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->stream_res.tg); - - DC_SYNC_INFO("GSL: Set-up complete.\n"); -} - -static void dce110_enable_per_frame_crtc_position_reset( - struct dc *dc, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - struct dcp_gsl_params gsl_params = { 0 }; - int i; - DC_LOGGER_INIT(); - - gsl_params.gsl_group = 0; - gsl_params.gsl_master = 0; - - for (i = 0; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock( - grouped_pipes[i]->stream_res.tg, &gsl_params); - - DC_SYNC_INFO("GSL: enabling trigger-reset\n"); - - for (i = 1; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( - grouped_pipes[i]->stream_res.tg, - gsl_params.gsl_master, - &grouped_pipes[i]->stream->triggered_crtc_reset); - - DC_SYNC_INFO("GSL: waiting for reset to occur.\n"); - for (i = 1; i < group_size; i++) - wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); - - for (i = 0; i < group_size; i++) - grouped_pipes[i]->stream_res.tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->stream_res.tg); - -} - -static void init_pipes(struct dc *dc, struct dc_state *context) -{ - // Do nothing -} - -static void init_hw(struct dc *dc) -{ - int i; - struct dc_bios *bp; - struct transform *xfm; - struct abm *abm; - struct dmcu *dmcu; - struct dce_hwseq *hws = dc->hwseq; - uint32_t backlight = MAX_BACKLIGHT_LEVEL; - - bp = dc->ctx->dc_bios; - for (i = 0; i < dc->res_pool->pipe_count; i++) { - xfm = dc->res_pool->transforms[i]; - xfm->funcs->transform_reset(xfm); - - hws->funcs.enable_display_power_gating( - dc, i, bp, - PIPE_GATING_CONTROL_INIT); - hws->funcs.enable_display_power_gating( - dc, i, bp, - PIPE_GATING_CONTROL_DISABLE); - hws->funcs.enable_display_pipe_clock_gating( - dc->ctx, - true); - } - - dce_clock_gating_power_up(dc->hwseq, false); - /***************************************/ - - for (i = 0; i < dc->link_count; i++) { - /****************************************/ - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). */ - struct dc_link *link = dc->links[i]; - - link->link_enc->funcs->hw_init(link->link_enc); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - tg->funcs->disable_vga(tg); - - /* Blank controller using driver code instead of - * command table. */ - tg->funcs->set_blank(tg, true); - hwss_wait_for_blank_complete(tg); - } - - for (i = 0; i < dc->res_pool->audio_count; i++) { - struct audio *audio = dc->res_pool->audios[i]; - audio->funcs->hw_init(audio); - } - - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); - } - - abm = dc->res_pool->abm; - if (abm != NULL) - abm->funcs->abm_init(abm, backlight); - - dmcu = dc->res_pool->dmcu; - if (dmcu != NULL && abm != NULL) - abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); - - if (dc->fbc_compressor) - dc->fbc_compressor->funcs->power_up_fbc(dc->fbc_compressor); - -} - - -void dce110_prepare_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct clk_mgr *dccg = dc->clk_mgr; - - dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); - if (dccg) - dccg->funcs->update_clocks( - dccg, - context, - false); -} - -void dce110_optimize_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct clk_mgr *dccg = dc->clk_mgr; - - dce110_set_displaymarks(dc, context); - - if (dccg) - dccg->funcs->update_clocks( - dccg, - context, - true); -} - -static void dce110_program_front_end_for_pipe( - struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct mem_input *mi = pipe_ctx->plane_res.mi; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct xfm_grph_csc_adjustment adjust; - struct out_csc_color_matrix tbl_entry; - unsigned int i; - struct dce_hwseq *hws = dc->hwseq; - - memset(&tbl_entry, 0, sizeof(tbl_entry)); - - memset(&adjust, 0, sizeof(adjust)); - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - - dce_enable_fe_clock(dc->hwseq, mi->inst, true); - - set_default_colors(pipe_ctx); - if (pipe_ctx->stream->csc_color_matrix.enable_adjustment - == true) { - tbl_entry.color_space = - pipe_ctx->stream->output_color_space; - - for (i = 0; i < 12; i++) - tbl_entry.regval[i] = - pipe_ctx->stream->csc_color_matrix.matrix[i]; - - pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment - (pipe_ctx->plane_res.xfm, &tbl_entry); - } - - if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - - for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) - adjust.temperature_matrix[i] = - pipe_ctx->stream->gamut_remap_matrix.matrix[i]; - } - - pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); - - pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL; - - program_scaler(dc, pipe_ctx); - - mi->funcs->mem_input_program_surface_config( - mi, - plane_state->format, - &plane_state->tiling_info, - &plane_state->plane_size, - plane_state->rotation, - NULL, - false); - if (mi->funcs->set_blank) - mi->funcs->set_blank(mi, pipe_ctx->plane_state->visible); - - if (dc->config.gpu_vm_support) - mi->funcs->mem_input_program_pte_vm( - pipe_ctx->plane_res.mi, - plane_state->format, - &plane_state->tiling_info, - plane_state->rotation); - - /* Moved programming gamma from dc to hwss */ - if (pipe_ctx->plane_state->update_flags.bits.full_update || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change) - hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); - - if (pipe_ctx->plane_state->update_flags.bits.full_update) - hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); - - DC_LOG_SURFACE( - "Pipe:%d %p: addr hi:0x%x, " - "addr low:0x%x, " - "src: %d, %d, %d," - " %d; dst: %d, %d, %d, %d;" - "clip: %d, %d, %d, %d\n", - pipe_ctx->pipe_idx, - (void *) pipe_ctx->plane_state, - pipe_ctx->plane_state->address.grph.addr.high_part, - pipe_ctx->plane_state->address.grph.addr.low_part, - pipe_ctx->plane_state->src_rect.x, - pipe_ctx->plane_state->src_rect.y, - pipe_ctx->plane_state->src_rect.width, - pipe_ctx->plane_state->src_rect.height, - pipe_ctx->plane_state->dst_rect.x, - pipe_ctx->plane_state->dst_rect.y, - pipe_ctx->plane_state->dst_rect.width, - pipe_ctx->plane_state->dst_rect.height, - pipe_ctx->plane_state->clip_rect.x, - pipe_ctx->plane_state->clip_rect.y, - pipe_ctx->plane_state->clip_rect.width, - pipe_ctx->plane_state->clip_rect.height); - - DC_LOG_SURFACE( - "Pipe %d: width, height, x, y\n" - "viewport:%d, %d, %d, %d\n" - "recout: %d, %d, %d, %d\n", - pipe_ctx->pipe_idx, - pipe_ctx->plane_res.scl_data.viewport.width, - pipe_ctx->plane_res.scl_data.viewport.height, - pipe_ctx->plane_res.scl_data.viewport.x, - pipe_ctx->plane_res.scl_data.viewport.y, - pipe_ctx->plane_res.scl_data.recout.width, - pipe_ctx->plane_res.scl_data.recout.height, - pipe_ctx->plane_res.scl_data.recout.x, - pipe_ctx->plane_res.scl_data.recout.y); -} - -static void dce110_apply_ctx_for_surface( - struct dc *dc, - const struct dc_stream_state *stream, - int num_planes, - struct dc_state *context) -{ - int i; - - if (num_planes == 0) - return; - - if (dc->fbc_compressor) - dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream != stream) - continue; - - /* Need to allocate mem before program front end for Fiji */ - pipe_ctx->plane_res.mi->funcs->allocate_mem_input( - pipe_ctx->plane_res.mi, - pipe_ctx->stream->timing.h_total, - pipe_ctx->stream->timing.v_total, - pipe_ctx->stream->timing.pix_clk_100hz / 10, - context->stream_count); - - dce110_program_front_end_for_pipe(dc, pipe_ctx); - - dc->hwss.update_plane_addr(dc, pipe_ctx); - - program_surface_visibility(dc, pipe_ctx); - - } - - if (dc->fbc_compressor) - enable_fbc(dc, context); -} - -static void dce110_post_unlock_program_front_end( - struct dc *dc, - struct dc_state *context) -{ -} - -static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - int fe_idx = pipe_ctx->plane_res.mi ? - pipe_ctx->plane_res.mi->inst : pipe_ctx->pipe_idx; - - /* Do not power down fe when stream is active on dce*/ - if (dc->current_state->res_ctx.pipe_ctx[fe_idx].stream) - return; - - hws->funcs.enable_display_power_gating( - dc, fe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE); - - dc->res_pool->transforms[fe_idx]->funcs->transform_reset( - dc->res_pool->transforms[fe_idx]); -} - -static void dce110_wait_for_mpcc_disconnect( - struct dc *dc, - struct resource_pool *res_pool, - struct pipe_ctx *pipe_ctx) -{ - /* do nothing*/ -} - -static void program_output_csc(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id) -{ - int i; - struct out_csc_color_matrix tbl_entry; - - if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { - enum dc_color_space color_space = pipe_ctx->stream->output_color_space; - - for (i = 0; i < 12; i++) - tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i]; - - tbl_entry.color_space = color_space; - - pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment( - pipe_ctx->plane_res.xfm, &tbl_entry); - } -} - -static void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) -{ - struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; - struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; - struct mem_input *mi = pipe_ctx->plane_res.mi; - struct dc_cursor_mi_param param = { - .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, - .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.xtalin_clock_inKhz, - .viewport = pipe_ctx->plane_res.scl_data.viewport, - .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, - .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, - .rotation = pipe_ctx->plane_state->rotation, - .mirror = pipe_ctx->plane_state->horizontal_mirror - }; - - /** - * If the cursor's source viewport is clipped then we need to - * translate the cursor to appear in the correct position on - * the screen. - * - * This translation isn't affected by scaling so it needs to be - * done *after* we adjust the position for the scale factor. - * - * This is only done by opt-in for now since there are still - * some usecases like tiled display that might enable the - * cursor on both streams while expecting dc to clip it. - */ - if (pos_cpy.translate_by_source) { - pos_cpy.x += pipe_ctx->plane_state->src_rect.x; - pos_cpy.y += pipe_ctx->plane_state->src_rect.y; - } - - if (pipe_ctx->plane_state->address.type - == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) - pos_cpy.enable = false; - - if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) - pos_cpy.enable = false; - - if (ipp->funcs->ipp_cursor_set_position) - ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); - if (mi->funcs->set_cursor_position) - mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); -} - -static void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) -{ - struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; - - if (pipe_ctx->plane_res.ipp && - pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) - pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( - pipe_ctx->plane_res.ipp, attributes); - - if (pipe_ctx->plane_res.mi && - pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) - pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( - pipe_ctx->plane_res.mi, attributes); - - if (pipe_ctx->plane_res.xfm && - pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) - pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( - pipe_ctx->plane_res.xfm, attributes); -} - -bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp) -{ - struct dc_link *link = pipe_ctx->stream->link; - struct dc *dc = link->ctx->dc; - struct abm *abm = pipe_ctx->stream_res.abm; - struct panel_cntl *panel_cntl = link->panel_cntl; - struct dmcu *dmcu = dc->res_pool->dmcu; - bool fw_set_brightness = true; - /* DMCU -1 for all controller id values, - * therefore +1 here - */ - uint32_t controller_id = pipe_ctx->stream_res.tg->inst + 1; - - if (abm == NULL || panel_cntl == NULL || (abm->funcs->set_backlight_level_pwm == NULL)) - return false; - - if (dmcu) - fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); - - if (!fw_set_brightness && panel_cntl->funcs->driver_set_backlight) - panel_cntl->funcs->driver_set_backlight(panel_cntl, backlight_pwm_u16_16); - else - abm->funcs->set_backlight_level_pwm( - abm, - backlight_pwm_u16_16, - frame_ramp, - controller_id, - link->panel_cntl->inst); - - return true; -} - -void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) -{ - struct abm *abm = pipe_ctx->stream_res.abm; - struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; - - if (abm) - abm->funcs->set_abm_immediate_disable(abm, - pipe_ctx->stream->link->panel_cntl->inst); - - if (panel_cntl) - panel_cntl->funcs->store_backlight_level(panel_cntl); -} - -void dce110_set_pipe(struct pipe_ctx *pipe_ctx) -{ - struct abm *abm = pipe_ctx->stream_res.abm; - struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; - uint32_t otg_inst = pipe_ctx->stream_res.tg->inst + 1; - - if (abm && panel_cntl) - abm->funcs->set_pipe(abm, otg_inst, panel_cntl->inst); -} - -void dce110_enable_lvds_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum clock_source_id clock_source, - uint32_t pixel_clock) -{ - link->link_enc->funcs->enable_lvds_output( - link->link_enc, - clock_source, - pixel_clock); - link->phy_state.symclk_state = SYMCLK_ON_TX_ON; -} - -void dce110_enable_tmds_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - enum dc_color_depth color_depth, - uint32_t pixel_clock) -{ - link->link_enc->funcs->enable_tmds_output( - link->link_enc, - clock_source, - color_depth, - signal, - pixel_clock); - link->phy_state.symclk_state = SYMCLK_ON_TX_ON; -} - -void dce110_enable_dp_link_output( - struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - const struct dc_link_settings *link_settings) -{ - struct dc *dc = link->ctx->dc; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct pipe_ctx *pipes = - link->dc->current_state->res_ctx.pipe_ctx; - struct clock_source *dp_cs = - link->dc->res_pool->dp_clock_source; - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - unsigned int i; - - /* - * Add the logic to extract BOTH power up and power down sequences - * from enable/disable link output and only call edp panel control - * in enable_link_dp and disable_link_dp once. - */ - if (link->connector_signal == SIGNAL_TYPE_EDP) { - link->dc->hwss.edp_wait_for_hpd_ready(link, true); - } - - /* If the current pixel clock source is not DTO(happens after - * switching from HDMI passive dongle to DP on the same connector), - * switch the pixel clock source to DTO. - */ - - for (i = 0; i < MAX_PIPES; i++) { - if (pipes[i].stream != NULL && - pipes[i].stream->link == link) { - if (pipes[i].clock_source != NULL && - pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) { - pipes[i].clock_source = dp_cs; - pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz = - pipes[i].stream->timing.pix_clk_100hz; - pipes[i].clock_source->funcs->program_pix_clk( - pipes[i].clock_source, - &pipes[i].stream_res.pix_clk_params, - dc->link_srv->dp_get_encoding_format(link_settings), - &pipes[i].pll_settings); - } - } - } - - if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) { - if (dc->clk_mgr->funcs->notify_link_rate_change) - dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); - } - - if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->lock_phy(dmcu); - - if (link_hwss->ext.enable_dp_link_output) - link_hwss->ext.enable_dp_link_output(link, link_res, signal, - clock_source, link_settings); - - link->phy_state.symclk_state = SYMCLK_ON_TX_ON; - - if (dmcu != NULL && dmcu->funcs->unlock_phy) - dmcu->funcs->unlock_phy(dmcu); - - dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY); -} - -void dce110_disable_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal) -{ - struct dc *dc = link->ctx->dc; - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - struct dmcu *dmcu = dc->res_pool->dmcu; - - if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control) - link->dc->hwss.edp_backlight_control(link, false); - else if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->lock_phy(dmcu); - - link_hwss->disable_link_output(link, link_res, signal); - link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; - /* - * Add the logic to extract BOTH power up and power down sequences - * from enable/disable link output and only call edp panel control - * in enable_link_dp and disable_link_dp once. - */ - if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->unlock_phy(dmcu); - dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); -} - -static const struct hw_sequencer_funcs dce110_funcs = { - .program_gamut_remap = program_gamut_remap, - .program_output_csc = program_output_csc, - .init_hw = init_hw, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = dce110_apply_ctx_for_surface, - .post_unlock_program_front_end = dce110_post_unlock_program_front_end, - .update_plane_addr = update_plane_addr, - .update_pending_status = dce110_update_pending_status, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dce110_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dce110_enable_per_frame_crtc_position_reset, - .update_info_frame = dce110_update_info_frame, - .enable_stream = dce110_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dce110_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dce110_power_down_fe, - .pipe_control_lock = dce_pipe_control_lock, - .interdependent_update_lock = NULL, - .cursor_lock = dce_pipe_control_lock, - .prepare_bandwidth = dce110_prepare_bandwidth, - .optimize_bandwidth = dce110_optimize_bandwidth, - .set_drr = set_drr, - .get_position = get_position, - .set_static_screen_control = set_static_screen_control, - .setup_stereo = NULL, - .set_avmute = dce110_set_avmute, - .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dce110_set_cursor_position, - .set_cursor_attribute = dce110_set_cursor_attribute, - .set_backlight_level = dce110_set_backlight_level, - .set_abm_immediate_disable = dce110_set_abm_immediate_disable, - .set_pipe = dce110_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, -}; - -static const struct hwseq_private_funcs dce110_private_funcs = { - .init_pipes = init_pipes, - .update_plane_addr = update_plane_addr, - .set_input_transfer_func = dce110_set_input_transfer_func, - .set_output_transfer_func = dce110_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating, - .enable_display_power_gating = dce110_enable_display_power_gating, - .reset_hw_ctx_wrap = dce110_reset_hw_ctx_wrap, - .enable_stream_timing = dce110_enable_stream_timing, - .disable_stream_gating = NULL, - .enable_stream_gating = NULL, - .edp_backlight_control = dce110_edp_backlight_control, -}; - -void dce110_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dce110_funcs; - dc->hwseq->funcs = dce110_private_funcs; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h deleted file mode 100644 index 08028a1779ae..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -* Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCE110_H__ -#define __DC_HWSS_DCE110_H__ - -#include "core_types.h" -#include "hw_sequencer_private.h" - -struct dc; -struct dc_state; -struct dm_pp_display_configuration; - -void dce110_hw_sequencer_construct(struct dc *dc); - -enum dc_status dce110_apply_ctx_to_hw( - struct dc *dc, - struct dc_state *context); - - -void dce110_enable_stream(struct pipe_ctx *pipe_ctx); - -void dce110_disable_stream(struct pipe_ctx *pipe_ctx); - -void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings); - -void dce110_blank_stream(struct pipe_ctx *pipe_ctx); - -void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); -void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx); - -void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); - -void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); -void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); - -void dce110_power_down(struct dc *dc); - -void dce110_set_safe_displaymarks( - struct resource_context *res_ctx, - const struct resource_pool *pool); - -void dce110_prepare_bandwidth( - struct dc *dc, - struct dc_state *context); - -void dce110_optimize_bandwidth( - struct dc *dc, - struct dc_state *context); - -void dce110_edp_power_control( - struct dc_link *link, - bool power_up); - -void dce110_edp_backlight_control( - struct dc_link *link, - bool enable); - -void dce110_edp_wait_for_hpd_ready( - struct dc_link *link, - bool power_up); - -bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); -void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx); -void dce110_set_pipe(struct pipe_ctx *pipe_ctx); -void dce110_disable_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal); -void dce110_enable_lvds_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum clock_source_id clock_source, - uint32_t pixel_clock); -void dce110_enable_tmds_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - enum dc_color_depth color_depth, - uint32_t pixel_clock); -void dce110_enable_dp_link_output( - struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - const struct dc_link_settings *link_settings); -#endif /* __DC_HWSS_DCE110_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 1289b9418877..fe518fd27b08 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -46,7 +46,7 @@ #include "dce110/dce110_opp_v.h" #include "dce/dce_clock_source.h" #include "dce/dce_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dce/dce_aux.h" #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce112/Makefile b/drivers/gpu/drm/amd/display/dc/dce112/Makefile index 9de6501702d2..e846ef58cab3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce112/Makefile @@ -25,7 +25,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce112/dce112_resource.o = $(call cc-disable-warning, override-init) -DCE112 = dce112_compressor.o dce112_hw_sequencer.o \ +DCE112 = dce112_compressor.o \ dce112_resource.o AMD_DAL_DCE112 = $(addprefix $(AMDDALPATH)/dc/dce112/,$(DCE112)) diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c deleted file mode 100644 index 0ef9ebb3c1e2..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dc.h" -#include "core_types.h" -#include "dce112_hw_sequencer.h" - -#include "dce110/dce110_hw_sequencer.h" - -/* include DCE11.2 register header files */ -#include "dce/dce_11_2_d.h" -#include "dce/dce_11_2_sh_mask.h" - -struct dce112_hw_seq_reg_offsets { - uint32_t crtc; -}; - - -static const struct dce112_hw_seq_reg_offsets reg_offsets[] = { -{ - .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), -} -}; -#define HW_REG_CRTC(reg, id)\ - (reg + reg_offsets[id].crtc) - -/******************************************************************************* - * Private definitions - ******************************************************************************/ - -static void dce112_init_pte(struct dc_context *ctx) -{ - uint32_t addr; - uint32_t value = 0; - uint32_t chunk_int = 0; - uint32_t chunk_mul = 0; - - addr = mmDVMM_PTE_REQ; - value = dm_read_reg(ctx, addr); - - chunk_int = get_reg_field_value( - value, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_INT); - - chunk_mul = get_reg_field_value( - value, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); - - if (chunk_int != 0x4 || chunk_mul != 0x4) { - - set_reg_field_value( - value, - 255, - DVMM_PTE_REQ, - MAX_PTEREQ_TO_ISSUE); - - set_reg_field_value( - value, - 4, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_INT); - - set_reg_field_value( - value, - 4, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); - - dm_write_reg(ctx, addr, value); - } -} - -static bool dce112_enable_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating) -{ - enum bp_result bp_result = BP_RESULT_OK; - enum bp_pipe_control_action cntl; - struct dc_context *ctx = dc->ctx; - - if (power_gating == PIPE_GATING_CONTROL_INIT) - cntl = ASIC_PIPE_INIT; - else if (power_gating == PIPE_GATING_CONTROL_ENABLE) - cntl = ASIC_PIPE_ENABLE; - else - cntl = ASIC_PIPE_DISABLE; - - if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0) { - - bp_result = dcb->funcs->enable_disp_power_gating( - dcb, controller_id + 1, cntl); - - /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 - * by default when command table is called - */ - dm_write_reg(ctx, - HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id), - 0); - } - - if (power_gating != PIPE_GATING_CONTROL_ENABLE) - dce112_init_pte(ctx); - - if (bp_result == BP_RESULT_OK) - return true; - else - return false; -} - -void dce112_hw_sequencer_construct(struct dc *dc) -{ - /* All registers used by dce11.2 match those in dce11 in offset and - * structure - */ - dce110_hw_sequencer_construct(dc); - dc->hwseq->funcs.enable_display_power_gating = dce112_enable_display_power_gating; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h deleted file mode 100644 index 943f1b2c5b2f..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -* Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCE112_H__ -#define __DC_HWSS_DCE112_H__ - -#include "core_types.h" -#include "hw_sequencer_private.h" - -struct dc; - -void dce112_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_HWSS_DCE112_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 2b20180f1a32..d1edac46c9a0 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -44,7 +44,7 @@ #include "dce/dce_clock_source.h" #include "dce/dce_hwseq.h" -#include "dce112/dce112_hw_sequencer.h" +#include "dce112/dce112_hwseq.h" #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce120/Makefile b/drivers/gpu/drm/amd/display/dc/dce120/Makefile index a9cc4b73270b..097cf407a15d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce120/Makefile @@ -27,7 +27,6 @@ CFLAGS_$(AMDDALPATH)/dc/dce120/dce120_resource.o = $(call cc-disable-warning, override-init) DCE120 = dce120_resource.o dce120_timing_generator.o \ -dce120_hw_sequencer.o AMD_DAL_DCE120 = $(addprefix $(AMDDALPATH)/dc/dce120/,$(DCE120)) diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c deleted file mode 100644 index 45e08c4d5861..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dc.h" -#include "core_types.h" -#include "dce120_hw_sequencer.h" -#include "dce/dce_hwseq.h" - -#include "dce110/dce110_hw_sequencer.h" - -#include "dce/dce_12_0_offset.h" -#include "dce/dce_12_0_sh_mask.h" -#include "soc15_hw_ip.h" -#include "vega10_ip_offset.h" -#include "reg_helper.h" - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -struct dce120_hw_seq_reg_offsets { - uint32_t crtc; -}; - -#if 0 -static const struct dce120_hw_seq_reg_offsets reg_offsets[] = { -{ - .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), -}, -{ - .crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), -} -}; - -#define HW_REG_CRTC(reg, id)\ - (reg + reg_offsets[id].crtc) - -#define CNTL_ID(controller_id)\ - controller_id -/******************************************************************************* - * Private definitions - ******************************************************************************/ -static void dce120_init_pte(struct dc_context *ctx, uint8_t controller_id) -{ - uint32_t addr; - uint32_t value = 0; - uint32_t chunk_int = 0; - uint32_t chunk_mul = 0; -/* - addr = mmDCP0_DVMM_PTE_CONTROL + controller_id * - (mmDCP1_DVMM_PTE_CONTROL- mmDCP0_DVMM_PTE_CONTROL); - - value = dm_read_reg(ctx, addr); - - set_reg_field_value( - value, 0, DCP, controller_id, - DVMM_PTE_CONTROL, - DVMM_USE_SINGLE_PTE); - - set_reg_field_value_soc15( - value, 1, DCP, controller_id, - DVMM_PTE_CONTROL, - DVMM_PTE_BUFFER_MODE0); - - set_reg_field_value_soc15( - value, 1, DCP, controller_id, - DVMM_PTE_CONTROL, - DVMM_PTE_BUFFER_MODE1); - - dm_write_reg(ctx, addr, value);*/ - - addr = mmDVMM_PTE_REQ; - value = dm_read_reg(ctx, addr); - - chunk_int = get_reg_field_value( - value, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_INT); - - chunk_mul = get_reg_field_value( - value, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); - - if (chunk_int != 0x4 || chunk_mul != 0x4) { - - set_reg_field_value( - value, - 255, - DVMM_PTE_REQ, - MAX_PTEREQ_TO_ISSUE); - - set_reg_field_value( - value, - 4, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_INT); - - set_reg_field_value( - value, - 4, - DVMM_PTE_REQ, - HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); - - dm_write_reg(ctx, addr, value); - } -} -#endif - -static bool dce120_enable_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating) -{ - /* disable for bringup */ -#if 0 - enum bp_result bp_result = BP_RESULT_OK; - enum bp_pipe_control_action cntl; - struct dc_context *ctx = dc->ctx; - - if (power_gating == PIPE_GATING_CONTROL_INIT) - cntl = ASIC_PIPE_INIT; - else if (power_gating == PIPE_GATING_CONTROL_ENABLE) - cntl = ASIC_PIPE_ENABLE; - else - cntl = ASIC_PIPE_DISABLE; - - if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0) { - - bp_result = dcb->funcs->enable_disp_power_gating( - dcb, controller_id + 1, cntl); - - /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 - * by default when command table is called - */ - dm_write_reg(ctx, - HW_REG_CRTC(mmCRTC0_CRTC_MASTER_UPDATE_MODE, controller_id), - 0); - } - - if (power_gating != PIPE_GATING_CONTROL_ENABLE) - dce120_init_pte(ctx, controller_id); - - if (bp_result == BP_RESULT_OK) - return true; - else - return false; -#endif - return false; -} - -static void dce120_update_dchub( - struct dce_hwseq *hws, - struct dchub_init_data *dh_data) -{ - /* TODO: port code from dal2 */ - switch (dh_data->fb_mode) { - case FRAME_BUFFER_MODE_ZFB_ONLY: - /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ - REG_UPDATE_2(DCHUB_FB_LOCATION, - FB_TOP, 0, - FB_BASE, 0x0FFFF); - - REG_UPDATE(DCHUB_AGP_BASE, - AGP_BASE, dh_data->zfb_phys_addr_base >> 22); - - REG_UPDATE(DCHUB_AGP_BOT, - AGP_BOT, dh_data->zfb_mc_base_addr >> 22); - - REG_UPDATE(DCHUB_AGP_TOP, - AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22); - break; - case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: - /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ - REG_UPDATE(DCHUB_AGP_BASE, - AGP_BASE, dh_data->zfb_phys_addr_base >> 22); - - REG_UPDATE(DCHUB_AGP_BOT, - AGP_BOT, dh_data->zfb_mc_base_addr >> 22); - - REG_UPDATE(DCHUB_AGP_TOP, - AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22); - break; - case FRAME_BUFFER_MODE_LOCAL_ONLY: - /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ - REG_UPDATE(DCHUB_AGP_BASE, - AGP_BASE, 0); - - REG_UPDATE(DCHUB_AGP_BOT, - AGP_BOT, 0x03FFFF); - - REG_UPDATE(DCHUB_AGP_TOP, - AGP_TOP, 0); - break; - default: - break; - } - - dh_data->dchub_initialzied = true; - dh_data->dchub_info_valid = false; -} - -/** - * dce121_xgmi_enabled() - Check if xGMI is enabled - * @hws: DCE hardware sequencer object - * - * Return true if xGMI is enabled. False otherwise. - */ -bool dce121_xgmi_enabled(struct dce_hwseq *hws) -{ - uint32_t pf_max_region; - - REG_GET(MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, &pf_max_region); - /* PF_MAX_REGION == 0 means xgmi is disabled */ - return !!pf_max_region; -} - -void dce120_hw_sequencer_construct(struct dc *dc) -{ - /* All registers used by dce11.2 match those in dce11 in offset and - * structure - */ - dce110_hw_sequencer_construct(dc); - dc->hwseq->funcs.enable_display_power_gating = dce120_enable_display_power_gating; - dc->hwss.update_dchub = dce120_update_dchub; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h deleted file mode 100644 index bc024534732f..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -* Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCE120_H__ -#define __DC_HWSS_DCE120_H__ - -#include "core_types.h" -#include "hw_sequencer_private.h" - -struct dc; - -bool dce121_xgmi_enabled(struct dce_hwseq *hws); -void dce120_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_HWSS_DCE112_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 18c5a86d2d61..962de79be169 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -35,7 +35,7 @@ #include "dce112/dce112_resource.h" #include "dce110/dce110_resource.h" -#include "../virtual/virtual_stream_encoder.h" +#include "virtual/virtual_stream_encoder.h" #include "dce120_timing_generator.h" #include "irq/dce120/irq_service_dce120.h" #include "dce/dce_opp.h" @@ -44,8 +44,8 @@ #include "dce/dce_mem_input.h" #include "dce/dce_panel_cntl.h" -#include "dce110/dce110_hw_sequencer.h" -#include "dce120/dce120_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dce120/dce120_hwseq.h" #include "dce/dce_transform.h" #include "clk_mgr.h" #include "dce/dce_audio.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c index 920c7ae29d53..1fdeef47e4dc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c @@ -29,8 +29,8 @@ #include "dce60_hw_sequencer.h" #include "dce/dce_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" -#include "dce100/dce100_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dce100/dce100_hwseq.h" /* include DCE6 register header files */ #include "dce/dce_6_0_d.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce80/Makefile b/drivers/gpu/drm/amd/display/dc/dce80/Makefile index 0a9d1a350d8b..93dd68c31275 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce80/Makefile @@ -25,7 +25,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce80/dce80_resource.o = $(call cc-disable-warning, override-init) -DCE80 = dce80_timing_generator.o dce80_hw_sequencer.o \ +DCE80 = dce80_timing_generator.o \ dce80_resource.o AMD_DAL_DCE80 = $(addprefix $(AMDDALPATH)/dc/dce80/,$(DCE80)) diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c deleted file mode 100644 index d2ceebdbdf51..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dc.h" -#include "core_types.h" -#include "dce80_hw_sequencer.h" - -#include "dce/dce_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" -#include "dce100/dce100_hw_sequencer.h" - -/* include DCE8 register header files */ -#include "dce/dce_8_0_d.h" -#include "dce/dce_8_0_sh_mask.h" - -/******************************************************************************* - * Private definitions - ******************************************************************************/ - -/***************************PIPE_CONTROL***********************************/ - -void dce80_hw_sequencer_construct(struct dc *dc) -{ - dce110_hw_sequencer_construct(dc); - - dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; - dc->hwss.pipe_control_lock = dce_pipe_control_lock; - dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; - dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.h deleted file mode 100644 index e43af832d00c..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -* Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCE80_H__ -#define __DC_HWSS_DCE80_H__ - -#include "core_types.h" -#include "hw_sequencer_private.h" - -struct dc; - -void dce80_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_HWSS_DCE80_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 061221394ce0..35a2cce0c2b8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -46,7 +46,7 @@ #include "dce/dce_clock_source.h" #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" -#include "dce80/dce80_hw_sequencer.h" +#include "dce80/dce80_hwseq.h" #include "dce100/dce100_resource.h" #include "dce/dce_panel_cntl.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 62ad1a11bff9..2d2007c3e2b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -22,7 +22,7 @@ # # Makefile for DCN. -DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \ +DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o \ dcn10_hw_sequencer_debug.o \ dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ dcn10_hubp.o dcn10_mpc.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c deleted file mode 100644 index 817827fa0a0e..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ /dev/null @@ -1,3898 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include -#include "dm_services.h" -#include "basics/dc_common.h" -#include "core_types.h" -#include "resource.h" -#include "custom_float.h" -#include "dcn10_hw_sequencer.h" -#include "dcn10_hw_sequencer_debug.h" -#include "dce/dce_hwseq.h" -#include "abm.h" -#include "dmcu.h" -#include "dcn10_optc.h" -#include "dcn10_dpp.h" -#include "dcn10_mpc.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "reg_helper.h" -#include "dcn10_hubp.h" -#include "dcn10_hubbub.h" -#include "dcn10_cm_common.h" -#include "dccg.h" -#include "clk_mgr.h" -#include "link_hwss.h" -#include "dpcd_defs.h" -#include "dsc.h" -#include "dce/dmub_psr.h" -#include "dc_dmub_srv.h" -#include "dce/dmub_hw_lock_mgr.h" -#include "dc_trace.h" -#include "dce/dmub_outbox.h" -#include "link.h" - -#define DC_LOGGER \ - dc_logger -#define DC_LOGGER_INIT(logger) \ - struct dal_logger *dc_logger = logger - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -/*print is 17 wide, first two characters are spaces*/ -#define DTN_INFO_MICRO_SEC(ref_cycle) \ - print_microsec(dc_ctx, log_ctx, ref_cycle) - -#define GAMMA_HW_POINTS_NUM 256 - -#define PGFSM_POWER_ON 0 -#define PGFSM_POWER_OFF 2 - -static void print_microsec(struct dc_context *dc_ctx, - struct dc_log_buffer_ctx *log_ctx, - uint32_t ref_cycle) -{ - const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; - static const unsigned int frac = 1000; - uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; - - DTN_INFO(" %11d.%03d", - us_x10 / frac, - us_x10 % frac); -} - -void dcn10_lock_all_pipes(struct dc *dc, - struct dc_state *context, - bool lock) -{ - struct pipe_ctx *pipe_ctx; - struct pipe_ctx *old_pipe_ctx; - struct timing_generator *tg; - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - pipe_ctx = &context->res_ctx.pipe_ctx[i]; - tg = pipe_ctx->stream_res.tg; - - /* - * Only lock the top pipe's tg to prevent redundant - * (un)locking. Also skip if pipe is disabled. - */ - if (pipe_ctx->top_pipe || - !pipe_ctx->stream || - (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) || - !tg->funcs->is_tg_enabled(tg) || - pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - if (lock) - dc->hwss.pipe_control_lock(dc, pipe_ctx, true); - else - dc->hwss.pipe_control_lock(dc, pipe_ctx, false); - } -} - -static void log_mpc_crc(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct dce_hwseq *hws = dc->hwseq; - - if (REG(MPC_CRC_RESULT_GB)) - DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n", - REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR)); - if (REG(DPP_TOP0_DPP_CRC_VAL_B_A)) - DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n", - REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G)); -} - -static void dcn10_log_hubbub_state(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct dcn_hubbub_wm wm; - int i; - - memset(&wm, 0, sizeof(struct dcn_hubbub_wm)); - dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm); - - DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent" - " sr_enter sr_exit dram_clk_change\n"); - - for (i = 0; i < 4; i++) { - struct dcn_hubbub_wm_set *s; - - s = &wm.sets[i]; - DTN_INFO("WM_Set[%d]:", s->wm_set); - DTN_INFO_MICRO_SEC(s->data_urgent); - DTN_INFO_MICRO_SEC(s->pte_meta_urgent); - DTN_INFO_MICRO_SEC(s->sr_enter); - DTN_INFO_MICRO_SEC(s->sr_exit); - DTN_INFO_MICRO_SEC(s->dram_clk_change); - DTN_INFO("\n"); - } - - DTN_INFO("\n"); -} - -static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct resource_pool *pool = dc->res_pool; - int i; - - DTN_INFO( - "HUBP: format addr_hi width height rot mir sw_mode dcc_en blank_en clock_en ttu_dis underflow min_ttu_vblank qos_low_wm qos_high_wm\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct hubp *hubp = pool->hubps[i]; - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); - - hubp->funcs->hubp_read_state(hubp); - - if (!s->blank_en) { - DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh", - hubp->inst, - s->pixel_format, - s->inuse_addr_hi, - s->viewport_width, - s->viewport_height, - s->rotation_angle, - s->h_mirror_en, - s->sw_mode, - s->dcc_en, - s->blank_en, - s->clock_en, - s->ttu_disable, - s->underflow_status); - DTN_INFO_MICRO_SEC(s->min_ttu_vblank); - DTN_INFO_MICRO_SEC(s->qos_level_low_wm); - DTN_INFO_MICRO_SEC(s->qos_level_high_wm); - DTN_INFO("\n"); - } - } - - DTN_INFO("\n=========RQ========\n"); - DTN_INFO("HUBP: drq_exp_m prq_exp_m mrq_exp_m crq_exp_m plane1_ba L:chunk_s min_chu_s meta_ch_s" - " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s" - " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); - struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; - - if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", - pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode, - rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size, - rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size, - rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size, - rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height, - rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size, - rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size, - rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size, - rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear); - } - - DTN_INFO("========DLG========\n"); - DTN_INFO("HUBP: rc_hbe dlg_vbe min_d_y_n rc_per_ht rc_x_a_s " - " dst_y_a_s dst_y_pf dst_y_vvb dst_y_rvb dst_y_vfl dst_y_rfl rf_pix_fq" - " vratio_pf vrat_pf_c rc_pg_vbl rc_pg_vbc rc_mc_vbl rc_mc_vbc rc_pg_fll" - " rc_pg_flc rc_mc_fll rc_mc_flc pr_nom_l pr_nom_c rc_pg_nl rc_pg_nc " - " mr_nom_l mr_nom_c rc_mc_nl rc_mc_nc rc_ld_pl rc_ld_pc rc_ld_l " - " rc_ld_c cha_cur0 ofst_cur1 cha_cur1 vr_af_vc0 ddrq_limt x_rt_dlay" - " x_rp_dlay x_rr_sfl\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); - struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr; - - if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" - " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" - " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", - pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start, - dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler, - dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank, - dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq, - dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l, - dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l, - dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l, - dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l, - dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l, - dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l, - dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l, - dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l, - dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l, - dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l, - dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1, - dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit, - dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay, - dlg_regs->xfc_reg_remote_surface_flip_latency); - } - - DTN_INFO("========TTU========\n"); - DTN_INFO("HUBP: qos_ll_wm qos_lh_wm mn_ttu_vb qos_l_flp rc_rd_p_l rc_rd_l rc_rd_p_c" - " rc_rd_c rc_rd_c0 rc_rd_pc0 rc_rd_c1 rc_rd_pc1 qos_lf_l qos_rds_l" - " qos_lf_c qos_rds_c qos_lf_c0 qos_rds_c0 qos_lf_c1 qos_rds_c1\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); - struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr; - - if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", - pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank, - ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l, - ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0, - ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1, - ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l, - ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0, - ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1); - } - DTN_INFO("\n"); -} - -void dcn10_log_hw_state(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx) -{ - struct dc_context *dc_ctx = dc->ctx; - struct resource_pool *pool = dc->res_pool; - int i; - - DTN_INFO_BEGIN(); - - dcn10_log_hubbub_state(dc, log_ctx); - - dcn10_log_hubp_states(dc, log_ctx); - - DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" - " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 " - "C31 C32 C33 C34\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct dpp *dpp = pool->dpps[i]; - struct dcn_dpp_state s = {0}; - - dpp->funcs->dpp_read_state(dpp, &s); - - if (!s.is_enabled) - continue; - - DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s" - "%8x %08xh %08xh %08xh %08xh %08xh %08xh", - dpp->inst, - s.igam_input_format, - (s.igam_lut_mode == 0) ? "BypassFixed" : - ((s.igam_lut_mode == 1) ? "BypassFloat" : - ((s.igam_lut_mode == 2) ? "RAM" : - ((s.igam_lut_mode == 3) ? "RAM" : - "Unknown"))), - (s.dgam_lut_mode == 0) ? "Bypass" : - ((s.dgam_lut_mode == 1) ? "sRGB" : - ((s.dgam_lut_mode == 2) ? "Ycc" : - ((s.dgam_lut_mode == 3) ? "RAM" : - ((s.dgam_lut_mode == 4) ? "RAM" : - "Unknown")))), - (s.rgam_lut_mode == 0) ? "Bypass" : - ((s.rgam_lut_mode == 1) ? "sRGB" : - ((s.rgam_lut_mode == 2) ? "Ycc" : - ((s.rgam_lut_mode == 3) ? "RAM" : - ((s.rgam_lut_mode == 4) ? "RAM" : - "Unknown")))), - s.gamut_remap_mode, - s.gamut_remap_c11_c12, - s.gamut_remap_c13_c14, - s.gamut_remap_c21_c22, - s.gamut_remap_c23_c24, - s.gamut_remap_c31_c32, - s.gamut_remap_c33_c34); - DTN_INFO("\n"); - } - DTN_INFO("\n"); - - DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE\n"); - for (i = 0; i < pool->pipe_count; i++) { - struct mpcc_state s = {0}; - - pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); - if (s.opp_id != 0xf) - DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d\n", - i, s.opp_id, s.dpp_id, s.bot_mpcc_id, - s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, - s.idle); - } - DTN_INFO("\n"); - - DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel h_bs h_be h_ss h_se hpol htot vtot underflow blank_en\n"); - - for (i = 0; i < pool->timing_generator_count; i++) { - struct timing_generator *tg = pool->timing_generators[i]; - struct dcn_otg_state s = {0}; - /* Read shared OTG state registers for all DCNx */ - optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); - - /* - * For DCN2 and greater, a register on the OPP is used to - * determine if the CRTC is blanked instead of the OTG. So use - * dpg_is_blanked() if exists, otherwise fallback on otg. - * - * TODO: Implement DCN-specific read_otg_state hooks. - */ - if (pool->opps[i]->funcs->dpg_is_blanked) - s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]); - else - s.blank_enabled = tg->funcs->is_blanked(tg); - - //only print if OTG master is enabled - if ((s.otg_enabled & 1) == 0) - continue; - - DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n", - tg->inst, - s.v_blank_start, - s.v_blank_end, - s.v_sync_a_start, - s.v_sync_a_end, - s.v_sync_a_pol, - s.v_total_max, - s.v_total_min, - s.v_total_max_sel, - s.v_total_min_sel, - s.h_blank_start, - s.h_blank_end, - s.h_sync_a_start, - s.h_sync_a_end, - s.h_sync_a_pol, - s.h_total, - s.v_total, - s.underflow_occurred_status, - s.blank_enabled); - - // Clear underflow for debug purposes - // We want to keep underflow sticky bit on for the longevity tests outside of test environment. - // This function is called only from Windows or Diags test environment, hence it's safe to clear - // it from here without affecting the original intent. - tg->funcs->clear_optc_underflow(tg); - } - DTN_INFO("\n"); - - // dcn_dsc_state struct field bytes_per_pixel was renamed to bits_per_pixel - // TODO: Update golden log header to reflect this name change - DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); - for (i = 0; i < pool->res_cap->num_dsc; i++) { - struct display_stream_compressor *dsc = pool->dscs[i]; - struct dcn_dsc_state s = {0}; - - dsc->funcs->dsc_read_state(dsc, &s); - DTN_INFO("[%d]: %-9d %-12d %-10d\n", - dsc->inst, - s.dsc_clock_en, - s.dsc_slice_width, - s.dsc_bits_per_pixel); - DTN_INFO("\n"); - } - DTN_INFO("\n"); - - DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM" - " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n"); - for (i = 0; i < pool->stream_enc_count; i++) { - struct stream_encoder *enc = pool->stream_enc[i]; - struct enc_state s = {0}; - - if (enc->funcs->enc_read_state) { - enc->funcs->enc_read_state(enc, &s); - DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n", - enc->id, - s.dsc_mode, - s.sec_gsp_pps_line_num, - s.vbid6_line_reference, - s.vbid6_line_num, - s.sec_gsp_pps_enable, - s.sec_stream_enable); - DTN_INFO("\n"); - } - } - DTN_INFO("\n"); - - DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n"); - for (i = 0; i < dc->link_count; i++) { - struct link_encoder *lenc = dc->links[i]->link_enc; - - struct link_enc_state s = {0}; - - if (lenc && lenc->funcs->read_state) { - lenc->funcs->read_state(lenc, &s); - DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n", - i, - s.dphy_fec_en, - s.dphy_fec_ready_shadow, - s.dphy_fec_active_status, - s.dp_link_training_complete); - DTN_INFO("\n"); - } - } - DTN_INFO("\n"); - - DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" - "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", - dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz, - dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz, - dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz); - - log_mpc_crc(dc, log_ctx); - - { - if (pool->hpo_dp_stream_enc_count > 0) { - DTN_INFO("DP HPO S_ENC: Enabled OTG Format Depth Vid SDP Compressed Link\n"); - for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { - struct hpo_dp_stream_encoder_state hpo_dp_se_state = {0}; - struct hpo_dp_stream_encoder *hpo_dp_stream_enc = pool->hpo_dp_stream_enc[i]; - - if (hpo_dp_stream_enc && hpo_dp_stream_enc->funcs->read_state) { - hpo_dp_stream_enc->funcs->read_state(hpo_dp_stream_enc, &hpo_dp_se_state); - - DTN_INFO("[%d]: %d %d %6s %d %d %d %d %d\n", - hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0, - hpo_dp_se_state.stream_enc_enabled, - hpo_dp_se_state.otg_inst, - (hpo_dp_se_state.pixel_encoding == 0) ? "4:4:4" : - ((hpo_dp_se_state.pixel_encoding == 1) ? "4:2:2" : - (hpo_dp_se_state.pixel_encoding == 2) ? "4:2:0" : "Y-Only"), - (hpo_dp_se_state.component_depth == 0) ? 6 : - ((hpo_dp_se_state.component_depth == 1) ? 8 : - (hpo_dp_se_state.component_depth == 2) ? 10 : 12), - hpo_dp_se_state.vid_stream_enabled, - hpo_dp_se_state.sdp_enabled, - hpo_dp_se_state.compressed_format, - hpo_dp_se_state.mapped_to_link_enc); - } - } - - DTN_INFO("\n"); - } - - /* log DP HPO L_ENC section if any hpo_dp_link_enc exists */ - if (pool->hpo_dp_link_enc_count) { - DTN_INFO("DP HPO L_ENC: Enabled Mode Lanes Stream Slots VC Rate X VC Rate Y\n"); - - for (i = 0; i < pool->hpo_dp_link_enc_count; i++) { - struct hpo_dp_link_encoder *hpo_dp_link_enc = pool->hpo_dp_link_enc[i]; - struct hpo_dp_link_enc_state hpo_dp_le_state = {0}; - - if (hpo_dp_link_enc->funcs->read_state) { - hpo_dp_link_enc->funcs->read_state(hpo_dp_link_enc, &hpo_dp_le_state); - DTN_INFO("[%d]: %d %6s %d %d %d %d %d\n", - hpo_dp_link_enc->inst, - hpo_dp_le_state.link_enc_enabled, - (hpo_dp_le_state.link_mode == 0) ? "TPS1" : - (hpo_dp_le_state.link_mode == 1) ? "TPS2" : - (hpo_dp_le_state.link_mode == 2) ? "ACTIVE" : "TEST", - hpo_dp_le_state.lane_count, - hpo_dp_le_state.stream_src[0], - hpo_dp_le_state.slot_count[0], - hpo_dp_le_state.vc_rate_x[0], - hpo_dp_le_state.vc_rate_y[0]); - DTN_INFO("\n"); - } - } - - DTN_INFO("\n"); - } - } - - DTN_INFO_END(); -} - -bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - - if (tg->funcs->is_optc_underflow_occurred(tg)) { - tg->funcs->clear_optc_underflow(tg); - return true; - } - - if (hubp->funcs->hubp_get_underflow_status(hubp)) { - hubp->funcs->hubp_clear_underflow(hubp); - return true; - } - return false; -} - -void dcn10_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable) -{ - bool force_on = true; /* disable power gating */ - - if (enable) - force_on = false; - - /* DCHUBP0/1/2/3 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); - - /* DPP0/1/2/3 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); -} - -void dcn10_disable_vga( - struct dce_hwseq *hws) -{ - unsigned int in_vga1_mode = 0; - unsigned int in_vga2_mode = 0; - unsigned int in_vga3_mode = 0; - unsigned int in_vga4_mode = 0; - - REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); - REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); - REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); - REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); - - if (in_vga1_mode == 0 && in_vga2_mode == 0 && - in_vga3_mode == 0 && in_vga4_mode == 0) - return; - - REG_WRITE(D1VGA_CONTROL, 0); - REG_WRITE(D2VGA_CONTROL, 0); - REG_WRITE(D3VGA_CONTROL, 0); - REG_WRITE(D4VGA_CONTROL, 0); - - /* HW Engineer's Notes: - * During switch from vga->extended, if we set the VGA_TEST_ENABLE and - * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. - * - * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset - * VGA_TEST_ENABLE, to leave it in the same state as before. - */ - REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); - REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); -} - -/** - * dcn10_dpp_pg_control - DPP power gate control. - * - * @hws: dce_hwseq reference. - * @dpp_inst: DPP instance reference. - * @power_on: true if we want to enable power gate, false otherwise. - * - * Enable or disable power gate in the specific DPP instance. - */ -void dcn10_dpp_pg_control( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; - - if (hws->ctx->dc->debug.disable_dpp_power_gate) - return; - if (REG(DOMAIN1_PG_CONFIG) == 0) - return; - - switch (dpp_inst) { - case 0: /* DPP0 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, - DOMAIN1_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN1_PG_STATUS, - DOMAIN1_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DPP1 */ - REG_UPDATE(DOMAIN3_PG_CONFIG, - DOMAIN3_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN3_PG_STATUS, - DOMAIN3_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DPP2 */ - REG_UPDATE(DOMAIN5_PG_CONFIG, - DOMAIN5_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN5_PG_STATUS, - DOMAIN5_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DPP3 */ - REG_UPDATE(DOMAIN7_PG_CONFIG, - DOMAIN7_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN7_PG_STATUS, - DOMAIN7_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -/** - * dcn10_hubp_pg_control - HUBP power gate control. - * - * @hws: dce_hwseq reference. - * @hubp_inst: DPP instance reference. - * @power_on: true if we want to enable power gate, false otherwise. - * - * Enable or disable power gate in the specific HUBP instance. - */ -void dcn10_hubp_pg_control( - struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; - - if (hws->ctx->dc->debug.disable_hubp_power_gate) - return; - if (REG(DOMAIN0_PG_CONFIG) == 0) - return; - - switch (hubp_inst) { - case 0: /* DCHUBP0 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, - DOMAIN0_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN0_PG_STATUS, - DOMAIN0_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DCHUBP1 */ - REG_UPDATE(DOMAIN2_PG_CONFIG, - DOMAIN2_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN2_PG_STATUS, - DOMAIN2_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DCHUBP2 */ - REG_UPDATE(DOMAIN4_PG_CONFIG, - DOMAIN4_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN4_PG_STATUS, - DOMAIN4_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DCHUBP3 */ - REG_UPDATE(DOMAIN6_PG_CONFIG, - DOMAIN6_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN6_PG_STATUS, - DOMAIN6_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -static void power_on_plane_resources( - struct dce_hwseq *hws, - int plane_id) -{ - DC_LOGGER_INIT(hws->ctx->logger); - - if (hws->funcs.dpp_root_clock_control) - hws->funcs.dpp_root_clock_control(hws, plane_id, true); - - if (REG(DC_IP_REQUEST_CNTL)) { - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - if (hws->funcs.dpp_pg_control) - hws->funcs.dpp_pg_control(hws, plane_id, true); - - if (hws->funcs.hubp_pg_control) - hws->funcs.hubp_pg_control(hws, plane_id, true); - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - DC_LOG_DEBUG( - "Un-gated front end for pipe %d\n", plane_id); - } -} - -static void undo_DEGVIDCN10_253_wa(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = dc->res_pool->hubps[0]; - - if (!hws->wa_state.DEGVIDCN10_253_applied) - return; - - hubp->funcs->set_blank(hubp, true); - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - hws->funcs.hubp_pg_control(hws, 0, false); - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - - hws->wa_state.DEGVIDCN10_253_applied = false; -} - -static void apply_DEGVIDCN10_253_wa(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = dc->res_pool->hubps[0]; - int i; - - if (dc->debug.disable_stutter) - return; - - if (!hws->wa.DEGVIDCN10_253) - return; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (!dc->res_pool->hubps[i]->power_gated) - return; - } - - /* all pipe power gated, apply work around to enable stutter. */ - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - hws->funcs.hubp_pg_control(hws, 0, true); - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - - hubp->funcs->set_hubp_blank_en(hubp, false); - hws->wa_state.DEGVIDCN10_253_applied = true; -} - -void dcn10_bios_golden_init(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *bp = dc->ctx->dc_bios; - int i; - bool allow_self_fresh_force_enable = true; - - if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc)) - return; - - if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) - allow_self_fresh_force_enable = - dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); - - - /* WA for making DF sleep when idle after resume from S0i3. - * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by - * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 - * before calling command table and it changed to 1 after, - * it should be set back to 0. - */ - - /* initialize dcn global */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0, ASIC_PIPE_INIT); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - /* initialize dcn per pipe */ - bp->funcs->enable_disp_power_gating(bp, - CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); - } - - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - if (allow_self_fresh_force_enable == false && - dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub)) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - -} - -static void false_optc_underflow_wa( - struct dc *dc, - const struct dc_stream_state *stream, - struct timing_generator *tg) -{ - int i; - bool underflow; - - if (!dc->hwseq->wa.false_optc_underflow) - return; - - underflow = tg->funcs->is_optc_underflow_occurred(tg); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (old_pipe_ctx->stream != stream) - continue; - - dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); - } - - if (tg->funcs->set_blank_data_double_buffer) - tg->funcs->set_blank_data_double_buffer(tg, true); - - if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) - tg->funcs->clear_optc_underflow(tg); -} - -static int calculate_vready_offset_for_group(struct pipe_ctx *pipe) -{ - struct pipe_ctx *other_pipe; - int vready_offset = pipe->pipe_dlg_param.vready_offset; - - /* Always use the largest vready_offset of all connected pipes */ - for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - - return vready_offset; -} - -enum dc_status dcn10_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - enum dc_color_space color_space; - struct tg_color black_color = {0}; - - /* by upper caller loop, pipe0 is parent pipe and be called first. - * back end is set up by for pipe0. Other children pipe share back end - * with pipe 0. No program is needed. - */ - if (pipe_ctx->top_pipe != NULL) - return DC_OK; - - /* TODO check if timing_changed, disable stream if timing changed */ - - /* HW program guide assume display already disable - * by unplug sequence. OTG assume stop. - */ - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); - - if (false == pipe_ctx->clock_source->funcs->program_pix_clk( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), - &pipe_ctx->pll_settings)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - - if (dc_is_hdmi_tmds_signal(stream->signal)) { - stream->link->phy_state.symclk_ref_cnts.otg = 1; - if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; - else - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; - } - - pipe_ctx->stream_res.tg->funcs->program_timing( - pipe_ctx->stream_res.tg, - &stream->timing, - calculate_vready_offset_for_group(pipe_ctx), - pipe_ctx->pipe_dlg_param.vstartup_start, - pipe_ctx->pipe_dlg_param.vupdate_offset, - pipe_ctx->pipe_dlg_param.vupdate_width, - pipe_ctx->stream->signal, - true); - -#if 0 /* move to after enable_crtc */ - /* TODO: OPP FMT, ABM. etc. should be done here. */ - /* or FPGA now. instance 0 only. TODO: move to opp.c */ - - inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt; - - pipe_ctx->stream_res.opp->funcs->opp_program_fmt( - pipe_ctx->stream_res.opp, - &stream->bit_depth_params, - &stream->clamping); -#endif - /* program otg blank color */ - color_space = stream->output_color_space; - color_space_to_black_color(dc, color_space, &black_color); - - /* - * The way 420 is packed, 2 channels carry Y component, 1 channel - * alternate between Cb and Cr, so both channels need the pixel - * value for Y - */ - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - black_color.color_r_cr = black_color.color_g_y; - - if (pipe_ctx->stream_res.tg->funcs->set_blank_color) - pipe_ctx->stream_res.tg->funcs->set_blank_color( - pipe_ctx->stream_res.tg, - &black_color); - - if (pipe_ctx->stream_res.tg->funcs->is_blanked && - !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) { - pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); - hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); - false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg); - } - - /* VTG is within DCHUB command block. DCFCLK is always on */ - if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - - /* TODO program crtc source select for non-virtual signal*/ - /* TODO program FMT */ - /* TODO setup link_enc */ - /* TODO set stream attributes */ - /* TODO program audio */ - /* TODO enable stream if timing changed */ - /* TODO unblank stream if DP */ - - return DC_OK; -} - -static void dcn10_reset_back_end_for_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - int i; - struct dc_link *link; - DC_LOGGER_INIT(dc->ctx->logger); - if (pipe_ctx->stream_res.stream_enc == NULL) { - pipe_ctx->stream = NULL; - return; - } - - link = pipe_ctx->stream->link; - /* DPMS may already disable or */ - /* dpms_off status is incorrect due to fastboot - * feature. When system resume from S4 with second - * screen only, the dpms_off would be true but - * VBIOS lit up eDP, so check link status too. - */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) - dc->link_srv->set_dpms_off(pipe_ctx); - else if (pipe_ctx->stream_res.audio) - dc->hwss.disable_audio_stream(pipe_ctx); - - if (pipe_ctx->stream_res.audio) { - /*disable az_endpoint*/ - pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); - - /*free audio*/ - if (dc->caps.dynamic_audio == true) { - /*we have to dynamic arbitrate the audio endpoints*/ - /*we free the resource, need reset is_audio_acquired*/ - update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, - pipe_ctx->stream_res.audio, false); - pipe_ctx->stream_res.audio = NULL; - } - } - - /* by upper caller loop, parent pipe: pipe0, will be reset last. - * back end share by all pipes and will be disable only when disable - * parent pipe. - */ - if (pipe_ctx->top_pipe == NULL) { - - if (pipe_ctx->stream_res.abm) - dc->hwss.set_abm_immediate_disable(pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); - - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, NULL); - pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) - break; - - if (i == dc->res_pool->pipe_count) - return; - - pipe_ctx->stream = NULL; - DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", - pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); -} - -static bool dcn10_hw_wa_force_recovery(struct dc *dc) -{ - struct hubp *hubp ; - unsigned int i; - bool need_recover = true; - - if (!dc->debug.recovery_enabled) - return false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) { - if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) { - /* one pipe underflow, we will reset all the pipes*/ - need_recover = true; - } - } - } - } - if (!need_recover) - return false; - /* - DCHUBP_CNTL:HUBP_BLANK_EN=1 - DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1 - DCHUBP_CNTL:HUBP_DISABLE=1 - DCHUBP_CNTL:HUBP_DISABLE=0 - DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0 - DCSURF_PRIMARY_SURFACE_ADDRESS - DCHUBP_CNTL:HUBP_BLANK_EN=0 - */ - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/ - if (hubp != NULL && hubp->funcs->set_hubp_blank_en) - hubp->funcs->set_hubp_blank_en(hubp, true); - } - } - /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/ - hubbub1_soft_reset(dc->res_pool->hubbub, true); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_DISABLE=1*/ - if (hubp != NULL && hubp->funcs->hubp_disable_control) - hubp->funcs->hubp_disable_control(hubp, true); - } - } - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_DISABLE=0*/ - if (hubp != NULL && hubp->funcs->hubp_disable_control) - hubp->funcs->hubp_disable_control(hubp, true); - } - } - /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/ - hubbub1_soft_reset(dc->res_pool->hubbub, false); - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx != NULL) { - hubp = pipe_ctx->plane_res.hubp; - /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/ - if (hubp != NULL && hubp->funcs->set_hubp_blank_en) - hubp->funcs->set_hubp_blank_en(hubp, true); - } - } - return true; - -} - -void dcn10_verify_allow_pstate_change_high(struct dc *dc) -{ - struct hubbub *hubbub = dc->res_pool->hubbub; - static bool should_log_hw_state; /* prevent hw state log by default */ - - if (!hubbub->funcs->verify_allow_pstate_change_high) - return; - - if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) { - int i = 0; - - if (should_log_hw_state) - dcn10_log_hw_state(dc, NULL); - - TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES); - BREAK_TO_DEBUGGER(); - if (dcn10_hw_wa_force_recovery(dc)) { - /*check again*/ - if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) - BREAK_TO_DEBUGGER(); - } - } -} - -/* trigger HW to start disconnect plane from stream on the next vsync */ -void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - int dpp_id = pipe_ctx->plane_res.dpp->inst; - struct mpc *mpc = dc->res_pool->mpc; - struct mpc_tree *mpc_tree_params; - struct mpcc *mpcc_to_remove = NULL; - struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; - - mpc_tree_params = &(opp->mpc_tree_params); - mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); - - /*Already reset*/ - if (mpcc_to_remove == NULL) - return; - - mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - // Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle, - // so don't wait for MPCC_IDLE in the programming sequence - if (opp != NULL && !pipe_ctx->plane_state->is_phantom) - opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - - dc->optimized_required = true; - - if (hubp->funcs->hubp_disconnect) - hubp->funcs->hubp_disconnect(hubp); - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -/** - * dcn10_plane_atomic_power_down - Power down plane components. - * - * @dc: dc struct reference. used for grab hwseq. - * @dpp: dpp struct reference. - * @hubp: hubp struct reference. - * - * Keep in mind that this operation requires a power gate configuration; - * however, requests for switch power gate are precisely controlled to avoid - * problems. For this reason, power gate request is usually disabled. This - * function first needs to enable the power gate request before disabling DPP - * and HUBP. Finally, it disables the power gate request again. - */ -void dcn10_plane_atomic_power_down(struct dc *dc, - struct dpp *dpp, - struct hubp *hubp) -{ - struct dce_hwseq *hws = dc->hwseq; - DC_LOGGER_INIT(dc->ctx->logger); - - if (REG(DC_IP_REQUEST_CNTL)) { - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - if (hws->funcs.dpp_pg_control) - hws->funcs.dpp_pg_control(hws, dpp->inst, false); - - if (hws->funcs.hubp_pg_control) - hws->funcs.hubp_pg_control(hws, hubp->inst, false); - - dpp->funcs->dpp_reset(dpp); - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - DC_LOG_DEBUG( - "Power gated front end %d\n", hubp->inst); - } - - if (hws->funcs.dpp_root_clock_control) - hws->funcs.dpp_root_clock_control(hws, dpp->inst, false); -} - -/* disable HW used by plane. - * note: cannot disable until disconnect is complete - */ -void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - int opp_id = hubp->opp_id; - - dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); - - hubp->funcs->hubp_clk_cntl(hubp, false); - - dpp->funcs->dpp_dppclk_control(dpp, false, false); - - if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL) - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( - pipe_ctx->stream_res.opp, - false); - - hubp->power_gated = true; - dc->optimized_required = false; /* We're powering off, no need to optimize */ - - hws->funcs.plane_atomic_power_down(dc, - pipe_ctx->plane_res.dpp, - pipe_ctx->plane_res.hubp); - - pipe_ctx->stream = NULL; - memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); - memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); - pipe_ctx->top_pipe = NULL; - pipe_ctx->bottom_pipe = NULL; - pipe_ctx->plane_state = NULL; -} - -void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - DC_LOGGER_INIT(dc->ctx->logger); - - if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) - return; - - hws->funcs.plane_atomic_disable(dc, pipe_ctx); - - apply_DEGVIDCN10_253_wa(dc); - - DC_LOG_DC("Power down front end %d\n", - pipe_ctx->pipe_idx); -} - -void dcn10_init_pipes(struct dc *dc, struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - struct hubbub *hubbub = dc->res_pool->hubbub; - bool can_apply_seamless_boot = false; - - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->apply_seamless_boot_optimization) { - can_apply_seamless_boot = true; - break; - } - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* There is assumption that pipe_ctx is not mapping irregularly - * to non-preferred front end. If pipe_ctx->stream is not NULL, - * we will use the pipe, so don't disable - */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - /* Blank controller using driver code instead of - * command table. - */ - if (tg->funcs->is_tg_enabled(tg)) { - if (hws->funcs.init_blank != NULL) { - hws->funcs.init_blank(dc, tg); - tg->funcs->lock(tg); - } else { - tg->funcs->lock(tg); - tg->funcs->set_blank(tg, true); - hwss_wait_for_blank_complete(tg); - } - } - } - - /* Reset det size */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - - /* Do not need to reset for seamless boot */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - if (hubbub && hubp) { - if (hubbub->funcs->program_det_size) - hubbub->funcs->program_det_size(hubbub, hubp->inst, 0); - } - } - - /* num_opp will be equal to number of mpcc */ - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* Cannot reset the MPC mux if seamless boot */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - dc->res_pool->mpc->funcs->mpc_init_single_inst( - dc->res_pool->mpc, i); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - struct dpp *dpp = dc->res_pool->dpps[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* There is assumption that pipe_ctx is not mapping irregularly - * to non-preferred front end. If pipe_ctx->stream is not NULL, - * we will use the pipe, so don't disable - */ - if (can_apply_seamless_boot && - pipe_ctx->stream != NULL && - pipe_ctx->stream_res.tg->funcs->is_tg_enabled( - pipe_ctx->stream_res.tg)) { - // Enable double buffering for OTG_BLANK no matter if - // seamless boot is enabled or not to suppress global sync - // signals when OTG blanked. This is to prevent pipe from - // requesting data while in PSR. - tg->funcs->tg_init(tg); - hubp->power_gated = true; - continue; - } - - /* Disable on the current state so the new one isn't cleared. */ - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - dpp->funcs->dpp_reset(dpp); - - pipe_ctx->stream_res.tg = tg; - pipe_ctx->pipe_idx = i; - - pipe_ctx->plane_res.hubp = hubp; - pipe_ctx->plane_res.dpp = dpp; - pipe_ctx->plane_res.mpcc_inst = dpp->inst; - hubp->mpcc_id = dpp->inst; - hubp->opp_id = OPP_ID_INVALID; - hubp->power_gated = false; - - dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; - dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->unlock(tg); - - dc->hwss.disable_plane(dc, pipe_ctx); - - pipe_ctx->stream_res.tg = NULL; - pipe_ctx->plane_res.hubp = NULL; - - if (tg->funcs->is_tg_enabled(tg)) { - if (tg->funcs->init_odm) - tg->funcs->init_odm(tg); - } - - tg->funcs->tg_init(tg); - } - - /* Power gate DSCs */ - if (hws->funcs.dsc_pg_control != NULL) { - uint32_t num_opps = 0; - uint32_t opp_id_src0 = OPP_ID_INVALID; - uint32_t opp_id_src1 = OPP_ID_INVALID; - - // Step 1: To find out which OPTC is running & OPTC DSC is ON - // We can't use res_pool->res_cap->num_timing_generator to check - // Because it records display pipes default setting built in driver, - // not display pipes of the current chip. - // Some ASICs would be fused display pipes less than the default setting. - // In dcnxx_resource_construct function, driver would obatin real information. - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - uint32_t optc_dsc_state = 0; - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) { - if (tg->funcs->get_dsc_status) - tg->funcs->get_dsc_status(tg, &optc_dsc_state); - // Only one OPTC with DSC is ON, so if we got one result, we would exit this block. - // non-zero value is DSC enabled - if (optc_dsc_state != 0) { - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - break; - } - } - } - - // Step 2: To power down DSC but skip DSC of running OPTC - for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { - struct dcn_dsc_state s = {0}; - - dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); - - if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && - s.dsc_clock_en && s.dsc_fw_en) - continue; - - hws->funcs.dsc_pg_control(hws, dc->res_pool->dscs[i]->inst, false); - } - } -} - -void dcn10_init_hw(struct dc *dc) -{ - int i; - struct abm *abm = dc->res_pool->abm; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - uint32_t backlight = MAX_BACKLIGHT_LEVEL; - bool is_optimized_init_done = false; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - /* Align bw context with hw config when system resume. */ - if (dc->clk_mgr->clks.dispclk_khz != 0 && dc->clk_mgr->clks.dppclk_khz != 0) { - dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz = dc->clk_mgr->clks.dispclk_khz; - dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz = dc->clk_mgr->clks.dppclk_khz; - } - - // Initialize the dccg - if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) - dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - if (!dcb->funcs->is_accelerated_mode(dcb)) - hws->funcs.disable_vga(dc->hwseq); - - if (!dc_dmub_srv_optimized_init_done(dc->ctx->dmub_srv)) - hws->funcs.bios_golden_init(dc); - - - if (dc->ctx->dc_bios->fw_info_valid) { - res_pool->ref_clocks.xtalin_clock_inKhz = - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - - if (res_pool->dccg && res_pool->hubbub) { - - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - if (!is_optimized_init_done) - link->link_enc->funcs->hw_init(link->link_enc); - - /* Check for enabled DIG to identify enabled display */ - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc)) { - link->link_status.link_active = true; - if (link->link_enc->funcs->fec_is_active && - link->link_enc->funcs->fec_is_active(link->link_enc)) - link->fec_state = dc_link_fec_enabled; - } - } - - /* we want to turn off all dp displays before doing detection */ - dc->link_srv->blank_all_dp_displays(dc); - - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); - - /* If taking control over from VBIOS, we may want to optimize our first - * mode set, so we need to skip powering down pipes until we know which - * pipes we want to use. - * Otherwise, if taking control is not possible, we need to power - * everything down. - */ - if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { - if (!is_optimized_init_done) { - hws->funcs.init_pipes(dc, dc->current_state); - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - } - } - - if (!is_optimized_init_done) { - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); - } - - if (abm != NULL) - abm->funcs->abm_init(abm, backlight); - - if (dmcu != NULL && !dmcu->auto_load_dmcu) - dmcu->funcs->dmcu_init(dmcu); - } - - if (abm != NULL && dmcu != NULL) - abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - if (!is_optimized_init_done) - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - if (dc->clk_mgr->funcs->notify_wm_ranges) - dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); -} - -/* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on - */ -void dcn10_power_down_on_boot(struct dc *dc) -{ - struct dc_link *edp_links[MAX_NUM_EDP]; - struct dc_link *edp_link = NULL; - int edp_num; - int i = 0; - - dc_get_edp_links(dc, edp_links, &edp_num); - if (edp_num) - edp_link = edp_links[0]; - - if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwseq->funcs.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwseq->funcs.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - } else { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->link_enc && link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } - } - - /* - * Call update_clocks with empty context - * to send DISPLAY_OFF - * Otherwise DISPLAY_OFF may not be asserted - */ - if (dc->clk_mgr->funcs->set_low_power_state) - dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr); -} - -void dcn10_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - - /* Reset Back End*/ - for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx_old->stream) - continue; - - if (pipe_ctx_old->top_pipe) - continue; - - if (!pipe_ctx->stream || - pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { - struct clock_source *old_clk = pipe_ctx_old->clock_source; - - dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); - if (hws->funcs.enable_stream_gating) - hws->funcs.enable_stream_gating(dc, pipe_ctx_old); - if (old_clk) - old_clk->funcs->cs_power_down(old_clk); - } - } -} - -static bool patch_address_for_sbs_tb_stereo( - struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - bool sec_split = pipe_ctx->top_pipe && - pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; - if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && - (pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_SIDE_BY_SIDE || - pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { - *addr = plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.left_addr = - plane_state->address.grph_stereo.right_addr; - return true; - } else { - if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && - plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { - plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; - plane_state->address.grph_stereo.right_addr = - plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.right_meta_addr = - plane_state->address.grph_stereo.left_meta_addr; - } - } - return false; -} - -void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - bool addr_patched = false; - PHYSICAL_ADDRESS_LOC addr; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - - if (plane_state == NULL) - return; - - addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); - - pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( - pipe_ctx->plane_res.hubp, - &plane_state->address, - plane_state->flip_immediate); - - plane_state->status.requested_address = plane_state->address; - - if (plane_state->flip_immediate) - plane_state->status.current_address = plane_state->address; - - if (addr_patched) - pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; -} - -bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - const struct dc_transfer_func *tf = NULL; - bool result = true; - - if (dpp_base == NULL) - return false; - - if (plane_state->in_transfer_func) - tf = plane_state->in_transfer_func; - - if (plane_state->gamma_correction && - !dpp_base->ctx->dc->debug.always_use_regamma - && !plane_state->gamma_correction->is_identity - && dce_use_lut(plane_state->format)) - dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); - - if (tf == NULL) - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); - else if (tf->type == TF_TYPE_PREDEFINED) { - switch (tf->tf) { - case TRANSFER_FUNCTION_SRGB: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB); - break; - case TRANSFER_FUNCTION_BT709: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC); - break; - case TRANSFER_FUNCTION_LINEAR: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); - break; - case TRANSFER_FUNCTION_PQ: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); - cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); - dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); - result = true; - break; - default: - result = false; - break; - } - } else if (tf->type == TF_TYPE_BYPASS) { - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); - } else { - cm_helper_translate_curve_to_degamma_hw_format(tf, - &dpp_base->degamma_params); - dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, - &dpp_base->degamma_params); - result = true; - } - - return result; -} - -#define MAX_NUM_HW_POINTS 0x200 - -static void log_tf(struct dc_context *ctx, - struct dc_transfer_func *tf, uint32_t hw_points_num) -{ - // DC_LOG_GAMMA is default logging of all hw points - // DC_LOG_ALL_GAMMA logs all points, not only hw points - // DC_LOG_ALL_TF_POINTS logs all channels of the tf - int i = 0; - - DC_LOG_GAMMA("Gamma Correction TF"); - DC_LOG_ALL_GAMMA("Logging all tf points..."); - DC_LOG_ALL_TF_CHANNELS("Logging all channels..."); - - for (i = 0; i < hw_points_num; i++) { - DC_LOG_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); - DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); - DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); - } - - for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) { - DC_LOG_ALL_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); - DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); - DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); - } -} - -bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) -{ - struct dpp *dpp = pipe_ctx->plane_res.dpp; - - if (dpp == NULL) - return false; - - dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; - - if (stream->out_transfer_func && - stream->out_transfer_func->type == TF_TYPE_PREDEFINED && - stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) - dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB); - - /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full - * update. - */ - else if (cm_helper_translate_curve_to_hw_format(dc->ctx, - stream->out_transfer_func, - &dpp->regamma_params, false)) { - dpp->funcs->dpp_program_regamma_pwl( - dpp, - &dpp->regamma_params, OPP_REGAMMA_USER); - } else - dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); - - if (stream != NULL && stream->ctx != NULL && - stream->out_transfer_func != NULL) { - log_tf(stream->ctx, - stream->out_transfer_func, - dpp->regamma_params.hw_points_num); - } - - return true; -} - -void dcn10_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock) -{ - struct dce_hwseq *hws = dc->hwseq; - - /* use TG master update lock to lock everything on the TG - * therefore only top pipe need to lock - */ - if (!pipe || pipe->top_pipe) - return; - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); - - if (lock) - pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); - else - pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -/** - * delay_cursor_until_vupdate() - Delay cursor update if too close to VUPDATE. - * - * Software keepout workaround to prevent cursor update locking from stalling - * out cursor updates indefinitely or from old values from being retained in - * the case where the viewport changes in the same frame as the cursor. - * - * The idea is to calculate the remaining time from VPOS to VUPDATE. If it's - * too close to VUPDATE, then stall out until VUPDATE finishes. - * - * TODO: Optimize cursor programming to be once per frame before VUPDATE - * to avoid the need for this workaround. - * - * @dc: Current DC state - * @pipe_ctx: Pipe_ctx pointer for delayed cursor update - * - * Return: void - */ -static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct crtc_position position; - uint32_t vupdate_start, vupdate_end; - unsigned int lines_to_vupdate, us_to_vupdate, vpos; - unsigned int us_per_line, us_vupdate; - - if (!dc->hwss.calc_vupdate_position || !dc->hwss.get_position) - return; - - if (!pipe_ctx->stream_res.stream_enc || !pipe_ctx->stream_res.tg) - return; - - dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start, - &vupdate_end); - - dc->hwss.get_position(&pipe_ctx, 1, &position); - vpos = position.vertical_count; - - /* Avoid wraparound calculation issues */ - vupdate_start += stream->timing.v_total; - vupdate_end += stream->timing.v_total; - vpos += stream->timing.v_total; - - if (vpos <= vupdate_start) { - /* VPOS is in VACTIVE or back porch. */ - lines_to_vupdate = vupdate_start - vpos; - } else if (vpos > vupdate_end) { - /* VPOS is in the front porch. */ - return; - } else { - /* VPOS is in VUPDATE. */ - lines_to_vupdate = 0; - } - - /* Calculate time until VUPDATE in microseconds. */ - us_per_line = - stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; - us_to_vupdate = lines_to_vupdate * us_per_line; - - /* 70 us is a conservative estimate of cursor update time*/ - if (us_to_vupdate > 70) - return; - - /* Stall out until the cursor update completes. */ - if (vupdate_end < vupdate_start) - vupdate_end += stream->timing.v_total; - us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; - udelay(us_to_vupdate + us_vupdate); -} - -void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock) -{ - /* cursor lock is per MPCC tree, so only need to lock one pipe per stream */ - if (!pipe || pipe->top_pipe) - return; - - /* Prevent cursor lock from stalling out cursor updates. */ - if (lock) - delay_cursor_until_vupdate(dc, pipe); - - if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) { - union dmub_hw_lock_flags hw_locks = { 0 }; - struct dmub_hw_lock_inst_flags inst_flags = { 0 }; - - hw_locks.bits.lock_cursor = 1; - inst_flags.opp_inst = pipe->stream_res.opp->inst; - - dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, - lock, - &hw_locks, - &inst_flags); - } else - dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc, - pipe->stream_res.opp->inst, lock); -} - -static bool wait_for_reset_trigger_to_occur( - struct dc_context *dc_ctx, - struct timing_generator *tg) -{ - bool rc = false; - - DC_LOGGER_INIT(dc_ctx->logger); - - /* To avoid endless loop we wait at most - * frames_to_wait_on_triggered_reset frames for the reset to occur. */ - const uint32_t frames_to_wait_on_triggered_reset = 10; - int i; - - for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { - - if (!tg->funcs->is_counter_moving(tg)) { - DC_ERROR("TG counter is not moving!\n"); - break; - } - - if (tg->funcs->did_triggered_reset_occur(tg)) { - rc = true; - /* usually occurs at i=1 */ - DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", - i); - break; - } - - /* Wait for one frame. */ - tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); - tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); - } - - if (false == rc) - DC_ERROR("GSL: Timeout on reset trigger!\n"); - - return rc; -} - -static uint64_t reduceSizeAndFraction(uint64_t *numerator, - uint64_t *denominator, - bool checkUint32Bounary) -{ - int i; - bool ret = checkUint32Bounary == false; - uint64_t max_int32 = 0xffffffff; - uint64_t num, denom; - static const uint16_t prime_numbers[] = { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, - 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, - 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, - 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, - 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, - 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, - 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, - 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, - 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, - 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, - 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, - 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, - 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, - 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, - 941, 947, 953, 967, 971, 977, 983, 991, 997}; - int count = ARRAY_SIZE(prime_numbers); - - num = *numerator; - denom = *denominator; - for (i = 0; i < count; i++) { - uint32_t num_remainder, denom_remainder; - uint64_t num_result, denom_result; - if (checkUint32Bounary && - num <= max_int32 && denom <= max_int32) { - ret = true; - break; - } - do { - num_result = div_u64_rem(num, prime_numbers[i], &num_remainder); - denom_result = div_u64_rem(denom, prime_numbers[i], &denom_remainder); - if (num_remainder == 0 && denom_remainder == 0) { - num = num_result; - denom = denom_result; - } - } while (num_remainder == 0 && denom_remainder == 0); - } - *numerator = num; - *denominator = denom; - return ret; -} - -static bool is_low_refresh_rate(struct pipe_ctx *pipe) -{ - uint32_t master_pipe_refresh_rate = - pipe->stream->timing.pix_clk_100hz * 100 / - pipe->stream->timing.h_total / - pipe->stream->timing.v_total; - return master_pipe_refresh_rate <= 30; -} - -static uint8_t get_clock_divider(struct pipe_ctx *pipe, - bool account_low_refresh_rate) -{ - uint32_t clock_divider = 1; - uint32_t numpipes = 1; - - if (account_low_refresh_rate && is_low_refresh_rate(pipe)) - clock_divider *= 2; - - if (pipe->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) - clock_divider *= 2; - - while (pipe->next_odm_pipe) { - pipe = pipe->next_odm_pipe; - numpipes++; - } - clock_divider *= numpipes; - - return clock_divider; -} - -static int dcn10_align_pixel_clocks(struct dc *dc, int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - int i, master = -1, embedded = -1; - struct dc_crtc_timing *hw_crtc_timing; - uint64_t phase[MAX_PIPES]; - uint64_t modulo[MAX_PIPES]; - unsigned int pclk; - - uint32_t embedded_pix_clk_100hz; - uint16_t embedded_h_total; - uint16_t embedded_v_total; - uint32_t dp_ref_clk_100hz = - dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10; - - DC_LOGGER_INIT(dc_ctx->logger); - - hw_crtc_timing = kcalloc(MAX_PIPES, sizeof(*hw_crtc_timing), GFP_KERNEL); - if (!hw_crtc_timing) - return master; - - if (dc->config.vblank_alignment_dto_params && - dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) { - embedded_h_total = - (dc->config.vblank_alignment_dto_params >> 32) & 0x7FFF; - embedded_v_total = - (dc->config.vblank_alignment_dto_params >> 48) & 0x7FFF; - embedded_pix_clk_100hz = - dc->config.vblank_alignment_dto_params & 0xFFFFFFFF; - - for (i = 0; i < group_size; i++) { - grouped_pipes[i]->stream_res.tg->funcs->get_hw_timing( - grouped_pipes[i]->stream_res.tg, - &hw_crtc_timing[i]); - dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( - dc->res_pool->dp_clock_source, - grouped_pipes[i]->stream_res.tg->inst, - &pclk); - hw_crtc_timing[i].pix_clk_100hz = pclk; - if (dc_is_embedded_signal( - grouped_pipes[i]->stream->signal)) { - embedded = i; - master = i; - phase[i] = embedded_pix_clk_100hz*100; - modulo[i] = dp_ref_clk_100hz*100; - } else { - - phase[i] = (uint64_t)embedded_pix_clk_100hz* - hw_crtc_timing[i].h_total* - hw_crtc_timing[i].v_total; - phase[i] = div_u64(phase[i], get_clock_divider(grouped_pipes[i], true)); - modulo[i] = (uint64_t)dp_ref_clk_100hz* - embedded_h_total* - embedded_v_total; - - if (reduceSizeAndFraction(&phase[i], - &modulo[i], true) == false) { - /* - * this will help to stop reporting - * this timing synchronizable - */ - DC_SYNC_INFO("Failed to reduce DTO parameters\n"); - grouped_pipes[i]->stream->has_non_synchronizable_pclk = true; - } - } - } - - for (i = 0; i < group_size; i++) { - if (i != embedded && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) { - dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk( - dc->res_pool->dp_clock_source, - grouped_pipes[i]->stream_res.tg->inst, - phase[i], modulo[i]); - dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( - dc->res_pool->dp_clock_source, - grouped_pipes[i]->stream_res.tg->inst, &pclk); - grouped_pipes[i]->stream->timing.pix_clk_100hz = - pclk*get_clock_divider(grouped_pipes[i], false); - if (master == -1) - master = i; - } - } - - } - - kfree(hw_crtc_timing); - return master; -} - -void dcn10_enable_vblanks_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - struct output_pixel_processor *opp; - struct timing_generator *tg; - int i, width, height, master; - - DC_LOGGER_INIT(dc_ctx->logger); - - for (i = 1; i < group_size; i++) { - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - - if (!tg->funcs->is_tg_enabled(tg)) { - DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); - return; - } - - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); - } - - for (i = 0; i < group_size; i++) { - if (grouped_pipes[i]->stream == NULL) - continue; - grouped_pipes[i]->stream->vblank_synchronized = false; - grouped_pipes[i]->stream->has_non_synchronizable_pclk = false; - } - - DC_SYNC_INFO("Aligning DP DTOs\n"); - - master = dcn10_align_pixel_clocks(dc, group_size, grouped_pipes); - - DC_SYNC_INFO("Synchronizing VBlanks\n"); - - if (master >= 0) { - for (i = 0; i < group_size; i++) { - if (i != master && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) - grouped_pipes[i]->stream_res.tg->funcs->align_vblanks( - grouped_pipes[master]->stream_res.tg, - grouped_pipes[i]->stream_res.tg, - grouped_pipes[master]->stream->timing.pix_clk_100hz, - grouped_pipes[i]->stream->timing.pix_clk_100hz, - get_clock_divider(grouped_pipes[master], false), - get_clock_divider(grouped_pipes[i], false)); - grouped_pipes[i]->stream->vblank_synchronized = true; - } - grouped_pipes[master]->stream->vblank_synchronized = true; - DC_SYNC_INFO("Sync complete\n"); - } - - for (i = 1; i < group_size; i++) { - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, height); - } -} - -void dcn10_enable_timing_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - struct output_pixel_processor *opp; - struct timing_generator *tg; - int i, width, height; - - DC_LOGGER_INIT(dc_ctx->logger); - - DC_SYNC_INFO("Setting up OTG reset trigger\n"); - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - - if (!tg->funcs->is_tg_enabled(tg)) { - DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); - return; - } - - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); - } - - for (i = 0; i < group_size; i++) { - if (grouped_pipes[i]->stream == NULL) - continue; - - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - grouped_pipes[i]->stream->vblank_synchronized = false; - } - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( - grouped_pipes[i]->stream_res.tg, - grouped_pipes[0]->stream_res.tg->inst); - } - - DC_SYNC_INFO("Waiting for trigger\n"); - - /* Need to get only check 1 pipe for having reset as all the others are - * synchronized. Look at last pipe programmed to reset. - */ - - if (grouped_pipes[1]->stream && grouped_pipes[1]->stream->mall_stream_config.type != SUBVP_PHANTOM) - wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg); - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( - grouped_pipes[i]->stream_res.tg); - } - - for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) - continue; - - opp = grouped_pipes[i]->stream_res.opp; - tg = grouped_pipes[i]->stream_res.tg; - tg->funcs->get_otg_active_size(tg, &width, &height); - if (opp->funcs->opp_program_dpg_dimensions) - opp->funcs->opp_program_dpg_dimensions(opp, width, height); - } - - DC_SYNC_INFO("Sync complete\n"); -} - -void dcn10_enable_per_frame_crtc_position_reset( - struct dc *dc, - int group_size, - struct pipe_ctx *grouped_pipes[]) -{ - struct dc_context *dc_ctx = dc->ctx; - int i; - - DC_LOGGER_INIT(dc_ctx->logger); - - DC_SYNC_INFO("Setting up\n"); - for (i = 0; i < group_size; i++) - if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) - grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( - grouped_pipes[i]->stream_res.tg, - 0, - &grouped_pipes[i]->stream->triggered_crtc_reset); - - DC_SYNC_INFO("Waiting for trigger\n"); - - for (i = 0; i < group_size; i++) - wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); - - DC_SYNC_INFO("Multi-display sync is complete\n"); -} - -static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1, - struct vm_system_aperture_param *apt, - struct dce_hwseq *hws) -{ - PHYSICAL_ADDRESS_LOC physical_page_number; - uint32_t logical_addr_low; - uint32_t logical_addr_high; - - REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, - PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part); - REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, - PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part); - - REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR, - LOGICAL_ADDR, &logical_addr_low); - - REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, - LOGICAL_ADDR, &logical_addr_high); - - apt->sys_default.quad_part = physical_page_number.quad_part << 12; - apt->sys_low.quad_part = (int64_t)logical_addr_low << 18; - apt->sys_high.quad_part = (int64_t)logical_addr_high << 18; -} - -/* Temporary read settings, future will get values from kmd directly */ -static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, - struct vm_context0_param *vm0, - struct dce_hwseq *hws) -{ - PHYSICAL_ADDRESS_LOC fb_base; - PHYSICAL_ADDRESS_LOC fb_offset; - uint32_t fb_base_value; - uint32_t fb_offset_value; - - REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value); - REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value); - - REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, - PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part); - REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, - PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part); - - REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, - LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part); - REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, - LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part); - - REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, - LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part); - REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, - LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part); - - REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, - PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part); - REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, - PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part); - - /* - * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space. - * Therefore we need to do - * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR - * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE - */ - fb_base.quad_part = (uint64_t)fb_base_value << 24; - fb_offset.quad_part = (uint64_t)fb_offset_value << 24; - vm0->pte_base.quad_part += fb_base.quad_part; - vm0->pte_base.quad_part -= fb_offset.quad_part; -} - - -static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) -{ - struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); - struct vm_system_aperture_param apt = {0}; - struct vm_context0_param vm0 = {0}; - - mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws); - mmhub_read_vm_context0_settings(hubp1, &vm0, hws); - - hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt); - hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0); -} - -static void dcn10_enable_plane( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - - undo_DEGVIDCN10_253_wa(dc); - - power_on_plane_resources(dc->hwseq, - pipe_ctx->plane_res.hubp->inst); - - /* enable DCFCLK current DCHUB */ - pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); - - /* make sure OPP_PIPE_CLOCK_EN = 1 */ - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( - pipe_ctx->stream_res.opp, - true); - - if (dc->config.gpu_vm_support) - dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - - if (!pipe_ctx->top_pipe - && pipe_ctx->plane_state - && pipe_ctx->plane_state->flip_int_enabled - && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) - pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); - -} - -void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) -{ - int i = 0; - struct dpp_grph_csc_adjustment adjust; - memset(&adjust, 0, sizeof(adjust)); - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - - - if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) - adjust.temperature_matrix[i] = - pipe_ctx->stream->gamut_remap_matrix.matrix[i]; - } else if (pipe_ctx->plane_state && - pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { - adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) - adjust.temperature_matrix[i] = - pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; - } - - pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); -} - - -static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace) -{ - if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) { - if (pipe_ctx->top_pipe) { - struct pipe_ctx *top = pipe_ctx->top_pipe; - - while (top->top_pipe) - top = top->top_pipe; // Traverse to top pipe_ctx - if (top->plane_state && top->plane_state->layer_index == 0) - return true; // Front MPO plane not hidden - } - } - return false; -} - -static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix) -{ - // Override rear plane RGB bias to fix MPO brightness - uint16_t rgb_bias = matrix[3]; - - matrix[3] = 0; - matrix[7] = 0; - matrix[11] = 0; - pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); - matrix[3] = rgb_bias; - matrix[7] = rgb_bias; - matrix[11] = rgb_bias; -} - -void dcn10_program_output_csc(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id) -{ - if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { - if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) { - - /* MPO is broken with RGB colorspaces when OCSC matrix - * brightness offset >= 0 on DCN1 due to OCSC before MPC - * Blending adds offsets from front + rear to rear plane - * - * Fix is to set RGB bias to 0 on rear plane, top plane - * black value pixels add offset instead of rear + front - */ - - int16_t rgb_bias = matrix[3]; - // matrix[3/7/11] are all the same offset value - - if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) { - dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix); - } else { - pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); - } - } - } else { - if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) - pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); - } -} - -static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) -{ - struct dc_bias_and_scale bns_params = {0}; - - // program the input csc - dpp->funcs->dpp_setup(dpp, - plane_state->format, - EXPANSION_MODE_ZERO, - plane_state->input_csc_color_matrix, - plane_state->color_space, - NULL); - - //set scale and bias registers - build_prescale_params(&bns_params, plane_state); - if (dpp->funcs->dpp_program_bias_and_scale) - dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); -} - -void dcn10_update_visual_confirm_color(struct dc *dc, - struct pipe_ctx *pipe_ctx, - int mpcc_id) -{ - struct mpc *mpc = dc->res_pool->mpc; - - if (mpc->funcs->set_bg_color) { - memcpy(&pipe_ctx->plane_state->visual_confirm_color, &(pipe_ctx->visual_confirm_color), sizeof(struct tg_color)); - mpc->funcs->set_bg_color(mpc, &(pipe_ctx->visual_confirm_color), mpcc_id); - } -} - -void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct mpcc_blnd_cfg blnd_cfg = {0}; - bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; - int mpcc_id; - struct mpcc *new_mpcc; - struct mpc *mpc = dc->res_pool->mpc; - struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); - - blnd_cfg.overlap_only = false; - blnd_cfg.global_gain = 0xff; - - if (per_pixel_alpha) { - /* DCN1.0 has output CM before MPC which seems to screw with - * pre-multiplied alpha. - */ - blnd_cfg.pre_multiplied_alpha = (is_rgb_cspace( - pipe_ctx->stream->output_color_space) - && pipe_ctx->plane_state->pre_multiplied_alpha); - if (pipe_ctx->plane_state->global_alpha) { - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; - blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; - } else { - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; - } - } else { - blnd_cfg.pre_multiplied_alpha = false; - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; - } - - if (pipe_ctx->plane_state->global_alpha) - blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; - else - blnd_cfg.global_alpha = 0xff; - - /* - * TODO: remove hack - * Note: currently there is a bug in init_hw such that - * on resume from hibernate, BIOS sets up MPCC0, and - * we do mpcc_remove but the mpcc cannot go to idle - * after remove. This cause us to pick mpcc1 here, - * which causes a pstate hang for yet unknown reason. - */ - mpcc_id = hubp->inst; - - /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update) { - mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - return; - } - - /* check if this MPCC is already being used */ - new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); - /* remove MPCC if being used */ - if (new_mpcc != NULL) - mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); - else - if (dc->debug.sanity_checks) - mpc->funcs->assert_mpcc_idle_before_connect( - dc->res_pool->mpc, mpcc_id); - - /* Call MPC to insert new plane */ - new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, - mpc_tree_params, - &blnd_cfg, - NULL, - NULL, - hubp->inst, - mpcc_id); - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - - ASSERT(new_mpcc != NULL); - hubp->opp_id = pipe_ctx->stream_res.opp->inst; - hubp->mpcc_id = mpcc_id; -} - -static void update_scaler(struct pipe_ctx *pipe_ctx) -{ - bool per_pixel_alpha = - pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; - - pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; - pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; - /* scaler configuration */ - pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( - pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); -} - -static void dcn10_update_dchubp_dpp( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct plane_size size = plane_state->plane_size; - unsigned int compat_level = 0; - bool should_divided_by_2 = false; - - /* depends on DML calculation, DPP clock value may change dynamically */ - /* If request max dpp clk is lower than current dispclk, no need to - * divided by 2 - */ - if (plane_state->update_flags.bits.full_update) { - - /* new calculated dispclk, dppclk are stored in - * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current - * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz. - * dcn10_validate_bandwidth compute new dispclk, dppclk. - * dispclk will put in use after optimize_bandwidth when - * ramp_up_dispclk_with_dpp is called. - * there are two places for dppclk be put in use. One location - * is the same as the location as dispclk. Another is within - * update_dchubp_dpp which happens between pre_bandwidth and - * optimize_bandwidth. - * dppclk updated within update_dchubp_dpp will cause new - * clock values of dispclk and dppclk not be in use at the same - * time. when clocks are decreased, this may cause dppclk is - * lower than previous configuration and let pipe stuck. - * for example, eDP + external dp, change resolution of DP from - * 1920x1080x144hz to 1280x960x60hz. - * before change: dispclk = 337889 dppclk = 337889 - * change mode, dcn10_validate_bandwidth calculate - * dispclk = 143122 dppclk = 143122 - * update_dchubp_dpp be executed before dispclk be updated, - * dispclk = 337889, but dppclk use new value dispclk /2 = - * 168944. this will cause pipe pstate warning issue. - * solution: between pre_bandwidth and optimize_bandwidth, while - * dispclk is going to be decreased, keep dppclk = dispclk - **/ - if (context->bw_ctx.bw.dcn.clk.dispclk_khz < - dc->clk_mgr->clks.dispclk_khz) - should_divided_by_2 = false; - else - should_divided_by_2 = - context->bw_ctx.bw.dcn.clk.dppclk_khz <= - dc->clk_mgr->clks.dispclk_khz / 2; - - dpp->funcs->dpp_dppclk_control( - dpp, - should_divided_by_2, - true); - - if (dc->res_pool->dccg) - dc->res_pool->dccg->funcs->update_dpp_dto( - dc->res_pool->dccg, - dpp->inst, - pipe_ctx->plane_res.bw.dppclk_khz); - else - dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? - dc->clk_mgr->clks.dispclk_khz / 2 : - dc->clk_mgr->clks.dispclk_khz; - } - - /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG - * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. - * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG - */ - if (plane_state->update_flags.bits.full_update) { - hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); - - hubp->funcs->hubp_setup( - hubp, - &pipe_ctx->dlg_regs, - &pipe_ctx->ttu_regs, - &pipe_ctx->rq_regs, - &pipe_ctx->pipe_dlg_param); - hubp->funcs->hubp_setup_interdependent( - hubp, - &pipe_ctx->dlg_regs, - &pipe_ctx->ttu_regs); - } - - size.surface_size = pipe_ctx->plane_res.scl_data.viewport; - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.bpp_change) - dcn10_update_dpp(dpp, plane_state); - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.per_pixel_alpha_change || - plane_state->update_flags.bits.global_alpha_change) - hws->funcs.update_mpcc(dc, pipe_ctx); - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.per_pixel_alpha_change || - plane_state->update_flags.bits.global_alpha_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change) { - update_scaler(pipe_ctx); - } - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change) { - hubp->funcs->mem_program_viewport( - hubp, - &pipe_ctx->plane_res.scl_data.viewport, - &pipe_ctx->plane_res.scl_data.viewport_c); - } - - if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { - dc->hwss.set_cursor_position(pipe_ctx); - dc->hwss.set_cursor_attribute(pipe_ctx); - - if (dc->hwss.set_cursor_sdr_white_level) - dc->hwss.set_cursor_sdr_white_level(pipe_ctx); - } - - if (plane_state->update_flags.bits.full_update) { - /*gamut remap*/ - dc->hwss.program_gamut_remap(pipe_ctx); - - dc->hwss.program_output_csc(dc, - pipe_ctx, - pipe_ctx->stream->output_color_space, - pipe_ctx->stream->csc_color_matrix.matrix, - pipe_ctx->stream_res.opp->inst); - } - - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.pixel_format_change || - plane_state->update_flags.bits.horizontal_mirror_change || - plane_state->update_flags.bits.rotation_change || - plane_state->update_flags.bits.swizzle_change || - plane_state->update_flags.bits.dcc_change || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.plane_size_change) { - hubp->funcs->hubp_program_surface_config( - hubp, - plane_state->format, - &plane_state->tiling_info, - &size, - plane_state->rotation, - &plane_state->dcc, - plane_state->horizontal_mirror, - compat_level); - } - - hubp->power_gated = false; - - hws->funcs.update_plane_addr(dc, pipe_ctx); - - if (is_pipe_tree_visible(pipe_ctx)) - hubp->funcs->set_blank(hubp, false); -} - -void dcn10_blank_pixel_data( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank) -{ - enum dc_color_space color_space; - struct tg_color black_color = {0}; - struct stream_resource *stream_res = &pipe_ctx->stream_res; - struct dc_stream_state *stream = pipe_ctx->stream; - - /* program otg blank color */ - color_space = stream->output_color_space; - color_space_to_black_color(dc, color_space, &black_color); - - /* - * The way 420 is packed, 2 channels carry Y component, 1 channel - * alternate between Cb and Cr, so both channels need the pixel - * value for Y - */ - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - black_color.color_r_cr = black_color.color_g_y; - - - if (stream_res->tg->funcs->set_blank_color) - stream_res->tg->funcs->set_blank_color( - stream_res->tg, - &black_color); - - if (!blank) { - if (stream_res->tg->funcs->set_blank) - stream_res->tg->funcs->set_blank(stream_res->tg, blank); - if (stream_res->abm) { - dc->hwss.set_pipe(pipe_ctx); - stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); - } - } else { - dc->hwss.set_abm_immediate_disable(pipe_ctx); - if (stream_res->tg->funcs->set_blank) { - stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK); - stream_res->tg->funcs->set_blank(stream_res->tg, blank); - } - } -} - -void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx) -{ - struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; - uint32_t hw_mult = 0x1f000; // 1.0 default multiplier - struct custom_float_format fmt; - - fmt.exponenta_bits = 6; - fmt.mantissa_bits = 12; - fmt.sign = true; - - - if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 - convert_to_custom_float_format(multiplier, &fmt, &hw_mult); - - pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( - pipe_ctx->plane_res.dpp, hw_mult); -} - -void dcn10_program_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - - if (pipe_ctx->top_pipe == NULL) { - bool blank = !is_pipe_tree_visible(pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->program_global_sync( - pipe_ctx->stream_res.tg, - calculate_vready_offset_for_group(pipe_ctx), - pipe_ctx->pipe_dlg_param.vstartup_start, - pipe_ctx->pipe_dlg_param.vupdate_offset, - pipe_ctx->pipe_dlg_param.vupdate_width); - - pipe_ctx->stream_res.tg->funcs->set_vtg_params( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); - - if (hws->funcs.setup_vupdate_interrupt) - hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); - - hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); - } - - if (pipe_ctx->plane_state->update_flags.bits.full_update) - dcn10_enable_plane(dc, pipe_ctx, context); - - dcn10_update_dchubp_dpp(dc, pipe_ctx, context); - - hws->funcs.set_hdr_multiplier(pipe_ctx); - - if (pipe_ctx->plane_state->update_flags.bits.full_update || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change) - hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); - - /* dcn10_translate_regamma_to_hw_format takes 750us to finish - * only do gamma programming for full update. - * TODO: This can be further optimized/cleaned up - * Always call this for now since it does memcmp inside before - * doing heavy calculation and programming - */ - if (pipe_ctx->plane_state->update_flags.bits.full_update) - hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); -} - -void dcn10_wait_for_pending_cleared(struct dc *dc, - struct dc_state *context) -{ - struct pipe_ctx *pipe_ctx; - struct timing_generator *tg; - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe_ctx = &context->res_ctx.pipe_ctx[i]; - tg = pipe_ctx->stream_res.tg; - - /* - * Only wait for top pipe's tg penindg bit - * Also skip if pipe is disabled. - */ - if (pipe_ctx->top_pipe || - !pipe_ctx->stream || !pipe_ctx->plane_state || - !tg->funcs->is_tg_enabled(tg)) - continue; - - /* - * Wait for VBLANK then VACTIVE to ensure we get VUPDATE. - * For some reason waiting for OTG_UPDATE_PENDING cleared - * seems to not trigger the update right away, and if we - * lock again before VUPDATE then we don't get a separated - * operation. - */ - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); - } -} - -void dcn10_post_unlock_program_front_end( - struct dc *dc, - struct dc_state *context) -{ - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->top_pipe && - !pipe_ctx->prev_odm_pipe && - pipe_ctx->stream) { - struct timing_generator *tg = pipe_ctx->stream_res.tg; - - if (context->stream_status[i].plane_count == 0) - false_optc_underflow_wa(dc, pipe_ctx->stream, tg); - } - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) - dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) { - dc->hwss.optimize_bandwidth(dc, context); - break; - } - - if (dc->hwseq->wa.DEGVIDCN10_254) - hubbub1_wm_change_req_wa(dc->res_pool->hubbub); -} - -static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context) -{ - uint8_t i; - - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->timing.timing_3d_format - == TIMING_3D_FORMAT_HW_FRAME_PACKING) { - /* - * Disable stutter - */ - hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false); - break; - } - } -} - -void dcn10_prepare_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubbub *hubbub = dc->res_pool->hubbub; - int min_fclk_khz, min_dcfclk_khz, socclk_khz; - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); - - if (context->stream_count == 0) - context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - false); - - dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub, - &context->bw_ctx.bw.dcn.watermarks, - dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, - true); - dcn10_stereo_hw_frame_pack_wa(dc, context); - - if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { - DC_FP_START(); - dcn_get_soc_clks( - dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); - DC_FP_END(); - dcn_bw_notify_pplib_of_wm_ranges( - dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); - } - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -void dcn10_optimize_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubbub *hubbub = dc->res_pool->hubbub; - int min_fclk_khz, min_dcfclk_khz, socclk_khz; - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); - - if (context->stream_count == 0) - context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - true); - - hubbub->funcs->program_watermarks(hubbub, - &context->bw_ctx.bw.dcn.watermarks, - dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, - true); - - dcn10_stereo_hw_frame_pack_wa(dc, context); - - if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { - DC_FP_START(); - dcn_get_soc_clks( - dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); - DC_FP_END(); - dcn_bw_notify_pplib_of_wm_ranges( - dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); - } - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -void dcn10_set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, struct dc_crtc_timing_adjust adjust) -{ - int i = 0; - struct drr_params params = {0}; - // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow - unsigned int event_triggers = 0x800; - // Note DRR trigger events are generated regardless of whether num frames met. - unsigned int num_frames = 2; - - params.vertical_total_max = adjust.v_total_max; - params.vertical_total_min = adjust.v_total_min; - params.vertical_total_mid = adjust.v_total_mid; - params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num; - /* TODO: If multiple pipes are to be supported, you need - * some GSL stuff. Static screen triggers may be programmed differently - * as well. - */ - for (i = 0; i < num_pipes; i++) { - if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) { - if (pipe_ctx[i]->stream_res.tg->funcs->set_drr) - pipe_ctx[i]->stream_res.tg->funcs->set_drr( - pipe_ctx[i]->stream_res.tg, ¶ms); - if (adjust.v_total_max != 0 && adjust.v_total_min != 0) - if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx[i]->stream_res.tg, - event_triggers, num_frames); - } - } -} - -void dcn10_get_position(struct pipe_ctx **pipe_ctx, - int num_pipes, - struct crtc_position *position) -{ - int i = 0; - - /* TODO: handle pipes > 1 - */ - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); -} - -void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params) -{ - unsigned int i; - unsigned int triggers = 0; - - if (params->triggers.surface_update) - triggers |= 0x80; - if (params->triggers.cursor_update) - triggers |= 0x2; - if (params->triggers.force_trigger) - triggers |= 0x1; - - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs-> - set_static_screen_control(pipe_ctx[i]->stream_res.tg, - triggers, params->num_frames); -} - -static void dcn10_config_stereo_parameters( - struct dc_stream_state *stream, struct crtc_stereo_flags *flags) -{ - enum view_3d_format view_format = stream->view_format; - enum dc_timing_3d_format timing_3d_format =\ - stream->timing.timing_3d_format; - bool non_stereo_timing = false; - - if (timing_3d_format == TIMING_3D_FORMAT_NONE || - timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE || - timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM) - non_stereo_timing = true; - - if (non_stereo_timing == false && - view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) { - - flags->PROGRAM_STEREO = 1; - flags->PROGRAM_POLARITY = 1; - if (timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE || - timing_3d_format == TIMING_3D_FORMAT_INBAND_FA || - timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || - timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { - - if (stream->link && stream->link->ddc) { - enum display_dongle_type dongle = \ - stream->link->ddc->dongle_type; - - if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || - dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || - dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) - flags->DISABLE_STEREO_DP_SYNC = 1; - } - } - flags->RIGHT_EYE_POLARITY =\ - stream->timing.flags.RIGHT_EYE_3D_POLARITY; - if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - flags->FRAME_PACKED = 1; - } - - return; -} - -void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) -{ - struct crtc_stereo_flags flags = { 0 }; - struct dc_stream_state *stream = pipe_ctx->stream; - - dcn10_config_stereo_parameters(stream, &flags); - - if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { - if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service)) - dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); - } else { - dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); - } - - pipe_ctx->stream_res.opp->funcs->opp_program_stereo( - pipe_ctx->stream_res.opp, - flags.PROGRAM_STEREO == 1, - &stream->timing); - - pipe_ctx->stream_res.tg->funcs->program_stereo( - pipe_ctx->stream_res.tg, - &stream->timing, - &flags); - - return; -} - -static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) -{ - int i; - - for (i = 0; i < res_pool->pipe_count; i++) { - if (res_pool->hubps[i]->inst == mpcc_inst) - return res_pool->hubps[i]; - } - ASSERT(false); - return NULL; -} - -void dcn10_wait_for_mpcc_disconnect( - struct dc *dc, - struct resource_pool *res_pool, - struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - int mpcc_inst; - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - - if (!pipe_ctx->stream_res.opp) - return; - - for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { - if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { - struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); - - if (pipe_ctx->stream_res.tg && - pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) - res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); - pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; - hubp->funcs->set_blank(hubp, true); - } - } - - if (dc->debug.sanity_checks) { - hws->funcs.verify_allow_pstate_change_high(dc); - } - -} - -bool dcn10_dummy_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating) -{ - return true; -} - -void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - bool flip_pending; - struct dc *dc = pipe_ctx->stream->ctx->dc; - - if (plane_state == NULL) - return; - - flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( - pipe_ctx->plane_res.hubp); - - plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending; - - if (!flip_pending) - plane_state->status.current_address = plane_state->status.requested_address; - - if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && - tg->funcs->is_stereo_left_eye) { - plane_state->status.is_right_eye = - !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); - } - - if (dc->hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied) { - struct dce_hwseq *hwseq = dc->hwseq; - struct timing_generator *tg = dc->res_pool->timing_generators[0]; - unsigned int cur_frame = tg->funcs->get_frame_count(tg); - - if (cur_frame != hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame) { - struct hubbub *hubbub = dc->res_pool->hubbub; - - hubbub->funcs->allow_self_refresh_control(hubbub, !dc->debug.disable_stutter); - hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = false; - } - } -} - -void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) -{ - struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; - - /* In DCN, this programming sequence is owned by the hubbub */ - hubbub->funcs->update_dchub(hubbub, dh_data); -} - -static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *test_pipe, *split_pipe; - const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data; - struct rect r1 = scl_data->recout, r2, r2_half; - int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b; - int cur_layer = pipe_ctx->plane_state->layer_index; - - /** - * Disable the cursor if there's another pipe above this with a - * plane that contains this pipe's viewport to prevent double cursor - * and incorrect scaling artifacts. - */ - for (test_pipe = pipe_ctx->top_pipe; test_pipe; - test_pipe = test_pipe->top_pipe) { - // Skip invisible layer and pipe-split plane on same layer - if (!test_pipe->plane_state || - !test_pipe->plane_state->visible || - test_pipe->plane_state->layer_index == cur_layer) - continue; - - r2 = test_pipe->plane_res.scl_data.recout; - r2_r = r2.x + r2.width; - r2_b = r2.y + r2.height; - split_pipe = test_pipe; - - /** - * There is another half plane on same layer because of - * pipe-split, merge together per same height. - */ - for (split_pipe = pipe_ctx->top_pipe; split_pipe; - split_pipe = split_pipe->top_pipe) - if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) { - r2_half = split_pipe->plane_res.scl_data.recout; - r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x; - r2.width = r2.width + r2_half.width; - r2_r = r2.x + r2.width; - break; - } - - if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b) - return true; - } - - return false; -} - -void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) -{ - struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_cursor_mi_param param = { - .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, - .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, - .viewport = pipe_ctx->plane_res.scl_data.viewport, - .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, - .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, - .rotation = pipe_ctx->plane_state->rotation, - .mirror = pipe_ctx->plane_state->horizontal_mirror - }; - bool pipe_split_on = false; - bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) || - (pipe_ctx->prev_odm_pipe != NULL); - - int x_plane = pipe_ctx->plane_state->dst_rect.x; - int y_plane = pipe_ctx->plane_state->dst_rect.y; - int x_pos = pos_cpy.x; - int y_pos = pos_cpy.y; - - if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { - if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) || - (pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) { - pipe_split_on = true; - } - } - - /** - * DC cursor is stream space, HW cursor is plane space and drawn - * as part of the framebuffer. - * - * Cursor position can't be negative, but hotspot can be used to - * shift cursor out of the plane bounds. Hotspot must be smaller - * than the cursor size. - */ - - /** - * Translate cursor from stream space to plane space. - * - * If the cursor is scaled then we need to scale the position - * to be in the approximately correct place. We can't do anything - * about the actual size being incorrect, that's a limitation of - * the hardware. - */ - if (param.rotation == ROTATION_ANGLE_90 || param.rotation == ROTATION_ANGLE_270) { - x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.height / - pipe_ctx->plane_state->dst_rect.width; - y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.width / - pipe_ctx->plane_state->dst_rect.height; - } else { - x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / - pipe_ctx->plane_state->dst_rect.width; - y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / - pipe_ctx->plane_state->dst_rect.height; - } - - /** - * If the cursor's source viewport is clipped then we need to - * translate the cursor to appear in the correct position on - * the screen. - * - * This translation isn't affected by scaling so it needs to be - * done *after* we adjust the position for the scale factor. - * - * This is only done by opt-in for now since there are still - * some usecases like tiled display that might enable the - * cursor on both streams while expecting dc to clip it. - */ - if (pos_cpy.translate_by_source) { - x_pos += pipe_ctx->plane_state->src_rect.x; - y_pos += pipe_ctx->plane_state->src_rect.y; - } - - /** - * If the position is negative then we need to add to the hotspot - * to shift the cursor outside the plane. - */ - - if (x_pos < 0) { - pos_cpy.x_hotspot -= x_pos; - x_pos = 0; - } - - if (y_pos < 0) { - pos_cpy.y_hotspot -= y_pos; - y_pos = 0; - } - - pos_cpy.x = (uint32_t)x_pos; - pos_cpy.y = (uint32_t)y_pos; - - if (pipe_ctx->plane_state->address.type - == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) - pos_cpy.enable = false; - - if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx)) - pos_cpy.enable = false; - - - if (param.rotation == ROTATION_ANGLE_0) { - int viewport_width = - pipe_ctx->plane_res.scl_data.viewport.width; - int viewport_x = - pipe_ctx->plane_res.scl_data.viewport.x; - - if (param.mirror) { - if (pipe_split_on || odm_combine_on) { - if (pos_cpy.x >= viewport_width + viewport_x) { - pos_cpy.x = 2 * viewport_width - - pos_cpy.x + 2 * viewport_x; - } else { - uint32_t temp_x = pos_cpy.x; - - pos_cpy.x = 2 * viewport_x - pos_cpy.x; - if (temp_x >= viewport_x + - (int)hubp->curs_attr.width || pos_cpy.x - <= (int)hubp->curs_attr.width + - pipe_ctx->plane_state->src_rect.x) { - pos_cpy.x = temp_x + viewport_width; - } - } - } else { - pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; - } - } - } - // Swap axis and mirror horizontally - else if (param.rotation == ROTATION_ANGLE_90) { - uint32_t temp_x = pos_cpy.x; - - pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width - - (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x; - pos_cpy.y = temp_x; - } - // Swap axis and mirror vertically - else if (param.rotation == ROTATION_ANGLE_270) { - uint32_t temp_y = pos_cpy.y; - int viewport_height = - pipe_ctx->plane_res.scl_data.viewport.height; - int viewport_y = - pipe_ctx->plane_res.scl_data.viewport.y; - - /** - * Display groups that are 1xnY, have pos_cpy.x > 2 * viewport.height - * For pipe split cases: - * - apply offset of viewport.y to normalize pos_cpy.x - * - calculate the pos_cpy.y as before - * - shift pos_cpy.y back by same offset to get final value - * - since we iterate through both pipes, use the lower - * viewport.y for offset - * For non pipe split cases, use the same calculation for - * pos_cpy.y as the 180 degree rotation case below, - * but use pos_cpy.x as our input because we are rotating - * 270 degrees - */ - if (pipe_split_on || odm_combine_on) { - int pos_cpy_x_offset; - int other_pipe_viewport_y; - - if (pipe_split_on) { - if (pipe_ctx->bottom_pipe) { - other_pipe_viewport_y = - pipe_ctx->bottom_pipe->plane_res.scl_data.viewport.y; - } else { - other_pipe_viewport_y = - pipe_ctx->top_pipe->plane_res.scl_data.viewport.y; - } - } else { - if (pipe_ctx->next_odm_pipe) { - other_pipe_viewport_y = - pipe_ctx->next_odm_pipe->plane_res.scl_data.viewport.y; - } else { - other_pipe_viewport_y = - pipe_ctx->prev_odm_pipe->plane_res.scl_data.viewport.y; - } - } - pos_cpy_x_offset = (viewport_y > other_pipe_viewport_y) ? - other_pipe_viewport_y : viewport_y; - pos_cpy.x -= pos_cpy_x_offset; - if (pos_cpy.x > viewport_height) { - pos_cpy.x = pos_cpy.x - viewport_height; - pos_cpy.y = viewport_height - pos_cpy.x; - } else { - pos_cpy.y = 2 * viewport_height - pos_cpy.x; - } - pos_cpy.y += pos_cpy_x_offset; - } else { - pos_cpy.y = (2 * viewport_y) + viewport_height - pos_cpy.x; - } - pos_cpy.x = temp_y; - } - // Mirror horizontally and vertically - else if (param.rotation == ROTATION_ANGLE_180) { - int viewport_width = - pipe_ctx->plane_res.scl_data.viewport.width; - int viewport_x = - pipe_ctx->plane_res.scl_data.viewport.x; - - if (!param.mirror) { - if (pipe_split_on || odm_combine_on) { - if (pos_cpy.x >= viewport_width + viewport_x) { - pos_cpy.x = 2 * viewport_width - - pos_cpy.x + 2 * viewport_x; - } else { - uint32_t temp_x = pos_cpy.x; - - pos_cpy.x = 2 * viewport_x - pos_cpy.x; - if (temp_x >= viewport_x + - (int)hubp->curs_attr.width || pos_cpy.x - <= (int)hubp->curs_attr.width + - pipe_ctx->plane_state->src_rect.x) { - pos_cpy.x = 2 * viewport_width - temp_x; - } - } - } else { - pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; - } - } - - /** - * Display groups that are 1xnY, have pos_cpy.y > viewport.height - * Calculation: - * delta_from_bottom = viewport.y + viewport.height - pos_cpy.y - * pos_cpy.y_new = viewport.y + delta_from_bottom - * Simplify it as: - * pos_cpy.y = viewport.y * 2 + viewport.height - pos_cpy.y - */ - pos_cpy.y = (2 * pipe_ctx->plane_res.scl_data.viewport.y) + - pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; - } - - hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); - dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); -} - -void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) -{ - struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; - - pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.hubp, attributes); - pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.dpp, attributes); -} - -void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) -{ - uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; - struct fixed31_32 multiplier; - struct dpp_cursor_attributes opt_attr = { 0 }; - uint32_t hw_scale = 0x3c00; // 1.0 default multiplier - struct custom_float_format fmt; - - if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes) - return; - - fmt.exponenta_bits = 5; - fmt.mantissa_bits = 10; - fmt.sign = true; - - if (sdr_white_level > 80) { - multiplier = dc_fixpt_from_fraction(sdr_white_level, 80); - convert_to_custom_float_format(multiplier, &fmt, &hw_scale); - } - - opt_attr.scale = hw_scale; - opt_attr.bias = 0; - - pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes( - pipe_ctx->plane_res.dpp, &opt_attr); -} - -/* - * apply_front_porch_workaround TODO FPGA still need? - * - * This is a workaround for a bug that has existed since R5xx and has not been - * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. - */ -static void apply_front_porch_workaround( - struct dc_crtc_timing *timing) -{ - if (timing->flags.INTERLACE == 1) { - if (timing->v_front_porch < 2) - timing->v_front_porch = 2; - } else { - if (timing->v_front_porch < 1) - timing->v_front_porch = 1; - } -} - -int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) -{ - const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; - struct dc_crtc_timing patched_crtc_timing; - int vesa_sync_start; - int asic_blank_end; - int interlace_factor; - - patched_crtc_timing = *dc_crtc_timing; - apply_front_porch_workaround(&patched_crtc_timing); - - interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; - - vesa_sync_start = patched_crtc_timing.v_addressable + - patched_crtc_timing.v_border_bottom + - patched_crtc_timing.v_front_porch; - - asic_blank_end = (patched_crtc_timing.v_total - - vesa_sync_start - - patched_crtc_timing.v_border_top) - * interlace_factor; - - return asic_blank_end - - pipe_ctx->pipe_dlg_param.vstartup_start + 1; -} - -void dcn10_calc_vupdate_position( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - uint32_t *start_line, - uint32_t *end_line) -{ - const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - int vupdate_pos = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); - - if (vupdate_pos >= 0) - *start_line = vupdate_pos - ((vupdate_pos / timing->v_total) * timing->v_total); - else - *start_line = vupdate_pos + ((-vupdate_pos / timing->v_total) + 1) * timing->v_total - 1; - *end_line = (*start_line + 2) % timing->v_total; -} - -static void dcn10_cal_vline_position( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - uint32_t *start_line, - uint32_t *end_line) -{ - const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - int vline_pos = pipe_ctx->stream->periodic_interrupt.lines_offset; - - if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_UPDATE) { - if (vline_pos > 0) - vline_pos--; - else if (vline_pos < 0) - vline_pos++; - - vline_pos += dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); - if (vline_pos >= 0) - *start_line = vline_pos - ((vline_pos / timing->v_total) * timing->v_total); - else - *start_line = vline_pos + ((-vline_pos / timing->v_total) + 1) * timing->v_total - 1; - *end_line = (*start_line + 2) % timing->v_total; - } else if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_SYNC) { - // vsync is line 0 so start_line is just the requested line offset - *start_line = vline_pos; - *end_line = (*start_line + 2) % timing->v_total; - } else - ASSERT(0); -} - -void dcn10_setup_periodic_interrupt( - struct dc *dc, - struct pipe_ctx *pipe_ctx) -{ - struct timing_generator *tg = pipe_ctx->stream_res.tg; - uint32_t start_line = 0; - uint32_t end_line = 0; - - dcn10_cal_vline_position(dc, pipe_ctx, &start_line, &end_line); - - tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); -} - -void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct timing_generator *tg = pipe_ctx->stream_res.tg; - int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); - - if (start_line < 0) { - ASSERT(0); - start_line = 0; - } - - if (tg->funcs->setup_vertical_interrupt2) - tg->funcs->setup_vertical_interrupt2(tg, start_line); -} - -void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings) -{ - struct encoder_unblank_param params = {0}; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dce_hwseq *hws = link->dc->hwseq; - - /* only 3 items below are used by unblank */ - params.timing = pipe_ctx->stream->timing; - - params.link_settings.link_rate = link_settings->link_rate; - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - params.timing.pix_clk_100hz /= 2; - pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); - } - - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - hws->funcs.edp_backlight_control(link, true); - } -} - -void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, - const uint8_t *custom_sdp_message, - unsigned int sdp_message_size) -{ - if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message( - pipe_ctx->stream_res.stream_enc, - custom_sdp_message, - sdp_message_size); - } -} -enum dc_status dcn10_set_clock(struct dc *dc, - enum dc_clock_type clock_type, - uint32_t clk_khz, - uint32_t stepping) -{ - struct dc_state *context = dc->current_state; - struct dc_clock_config clock_cfg = {0}; - struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk; - - if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock) - return DC_FAIL_UNSUPPORTED_1; - - dc->clk_mgr->funcs->get_clock(dc->clk_mgr, - context, clock_type, &clock_cfg); - - if (clk_khz > clock_cfg.max_clock_khz) - return DC_FAIL_CLK_EXCEED_MAX; - - if (clk_khz < clock_cfg.min_clock_khz) - return DC_FAIL_CLK_BELOW_MIN; - - if (clk_khz < clock_cfg.bw_requirequired_clock_khz) - return DC_FAIL_CLK_BELOW_CFG_REQUIRED; - - /*update internal request clock for update clock use*/ - if (clock_type == DC_CLOCK_TYPE_DISPCLK) - current_clocks->dispclk_khz = clk_khz; - else if (clock_type == DC_CLOCK_TYPE_DPPCLK) - current_clocks->dppclk_khz = clk_khz; - else - return DC_ERROR_UNEXPECTED; - - if (dc->clk_mgr->funcs->update_clocks) - dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, - context, true); - return DC_OK; - -} - -void dcn10_get_clock(struct dc *dc, - enum dc_clock_type clock_type, - struct dc_clock_config *clock_cfg) -{ - struct dc_state *context = dc->current_state; - - if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock) - dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); - -} - -void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits) -{ - struct resource_pool *pool = dc->res_pool; - int i; - - for (i = 0; i < pool->pipe_count; i++) { - struct hubp *hubp = pool->hubps[i]; - struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); - - hubp->funcs->hubp_read_state(hubp); - - if (!s->blank_en) - dcc_en_bits[i] = s->dcc_en ? 1 : 0; - } -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h deleted file mode 100644 index ef6d56da417c..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ /dev/null @@ -1,207 +0,0 @@ -/* -* Copyright 2016-2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN10_H__ -#define __DC_HWSS_DCN10_H__ - -#include "core_types.h" -#include "hw_sequencer_private.h" - -struct dc; - -void dcn10_hw_sequencer_construct(struct dc *dc); - -int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx); -void dcn10_calc_vupdate_position( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - uint32_t *start_line, - uint32_t *end_line); -void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); -enum dc_status dcn10_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc); -void dcn10_optimize_bandwidth( - struct dc *dc, - struct dc_state *context); -void dcn10_prepare_bandwidth( - struct dc *dc, - struct dc_state *context); -void dcn10_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock); -void dcn10_blank_pixel_data( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank); -void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings); -void dcn10_program_output_csc(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id); -bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); -bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); -void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context); -void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_lock_all_pipes( - struct dc *dc, - struct dc_state *context, - bool lock); -void dcn10_post_unlock_program_front_end( - struct dc *dc, - struct dc_state *context); -void dcn10_hubp_pg_control( - struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on); -void dcn10_dpp_pg_control( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on); -void dcn10_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable); -void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_disable_vga( - struct dce_hwseq *hws); -void dcn10_program_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context); -void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx); -void dcn10_init_hw(struct dc *dc); -void dcn10_init_pipes(struct dc *dc, struct dc_state *context); -void dcn10_power_down_on_boot(struct dc *dc); -enum dc_status dce110_apply_ctx_to_hw( - struct dc *dc, - struct dc_state *context); -void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data); -void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx); -void dce110_power_down(struct dc *dc); -void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); -void dcn10_enable_timing_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]); -void dcn10_enable_vblanks_synchronization( - struct dc *dc, - int group_index, - int group_size, - struct pipe_ctx *grouped_pipes[]); -void dcn10_enable_per_frame_crtc_position_reset( - struct dc *dc, - int group_size, - struct pipe_ctx *grouped_pipes[]); -void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); -void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, - const uint8_t *custom_sdp_message, - unsigned int sdp_message_size); -void dce110_blank_stream(struct pipe_ctx *pipe_ctx); -void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); -void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx); -bool dcn10_dummy_display_power_gating( - struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating); -void dcn10_set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, struct dc_crtc_timing_adjust adjust); -void dcn10_get_position(struct pipe_ctx **pipe_ctx, - int num_pipes, - struct crtc_position *position); -void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params); -void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc); -void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); -void dcn10_log_hw_state(struct dc *dc, - struct dc_log_buffer_ctx *log_ctx); -void dcn10_get_hw_state(struct dc *dc, - char *pBuf, - unsigned int bufSize, - unsigned int mask); -void dcn10_clear_status_bits(struct dc *dc, unsigned int mask); -void dcn10_wait_for_mpcc_disconnect( - struct dc *dc, - struct resource_pool *res_pool, - struct pipe_ctx *pipe_ctx); -void dce110_edp_backlight_control( - struct dc_link *link, - bool enable); -void dce110_edp_wait_for_T12( - struct dc_link *link); -void dce110_edp_power_control( - struct dc_link *link, - bool power_up); -void dce110_edp_wait_for_hpd_ready( - struct dc_link *link, - bool power_up); -void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx); -void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx); -void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx); -void dcn10_setup_periodic_interrupt( - struct dc *dc, - struct pipe_ctx *pipe_ctx); -enum dc_status dcn10_set_clock(struct dc *dc, - enum dc_clock_type clock_type, - uint32_t clk_khz, - uint32_t stepping); -void dcn10_get_clock(struct dc *dc, - enum dc_clock_type clock_type, - struct dc_clock_config *clock_cfg); -bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn10_bios_golden_init(struct dc *dc); -void dcn10_plane_atomic_power_down(struct dc *dc, - struct dpp *dpp, - struct hubp *hubp); -bool dcn10_disconnect_pipes( - struct dc *dc, - struct dc_state *context); - -void dcn10_wait_for_pending_cleared(struct dc *dc, - struct dc_state *context); -void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx); -void dcn10_verify_allow_pstate_change_high(struct dc *dc); - -void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits); - -void dcn10_update_visual_confirm_color( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - int mpcc_id); - -#endif /* __DC_HWSS_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 46a2ebcabd1a..92fdab731f4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -27,8 +27,8 @@ #include "core_types.h" #include "resource.h" #include "custom_float.h" -#include "dcn10_hw_sequencer.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hwseq.h" +#include "dce110/dce110_hwseq.h" #include "dce/dce_hwseq.h" #include "abm.h" #include "dmcu.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index f2371c948822..a5bdac79a744 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -24,8 +24,8 @@ */ #include "hw_sequencer_private.h" -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" static const struct hw_sequencer_funcs dcn10_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 9f9145742f14..d1d8e904346e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -36,8 +36,8 @@ #include "irq/dcn10/irq_service_dcn10.h" #include "dcn10_dpp.h" #include "dcn10_optc.h" -#include "dcn10_hw_sequencer.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hwseq.h" +#include "dce110/dce110_hwseq.h" #include "dcn10_opp.h" #include "dcn10_link_encoder.h" #include "dcn10_stream_encoder.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index abaed2121feb..d7dc9696a8c8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -2,7 +2,7 @@ # # Makefile for DCN. -DCN20 = dcn20_resource.o dcn20_init.o dcn20_hwseq.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ +DCN20 = dcn20_resource.o dcn20_init.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_optc.o dcn20_mmhubbub.o \ dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \ dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c deleted file mode 100644 index f5a7002302f8..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ /dev/null @@ -1,2941 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#include - -#include "dm_services.h" -#include "basics/dc_common.h" -#include "dm_helpers.h" -#include "core_types.h" -#include "resource.h" -#include "dcn20_resource.h" -#include "dcn20_hwseq.h" -#include "dce/dce_hwseq.h" -#include "dcn20_dsc.h" -#include "dcn20_optc.h" -#include "abm.h" -#include "clk_mgr.h" -#include "dmcu.h" -#include "hubp.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "mcif_wb.h" -#include "dchubbub.h" -#include "reg_helper.h" -#include "dcn10/dcn10_cm_common.h" -#include "vm_helper.h" -#include "dccg.h" -#include "dc_dmub_srv.h" -#include "dce/dmub_hw_lock_mgr.h" -#include "hw_sequencer.h" -#include "dpcd_defs.h" -#include "inc/link_enc_cfg.h" -#include "link_hwss.h" -#include "link.h" - -#define DC_LOGGER \ - dc_logger -#define DC_LOGGER_INIT(logger) \ - struct dal_logger *dc_logger = logger - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -static int find_free_gsl_group(const struct dc *dc) -{ - if (dc->res_pool->gsl_groups.gsl_0 == 0) - return 1; - if (dc->res_pool->gsl_groups.gsl_1 == 0) - return 2; - if (dc->res_pool->gsl_groups.gsl_2 == 0) - return 3; - - return 0; -} - -/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock) - * This is only used to lock pipes in pipe splitting case with immediate flip - * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate, - * so we get tearing with freesync since we cannot flip multiple pipes - * atomically. - * We use GSL for this: - * - immediate flip: find first available GSL group if not already assigned - * program gsl with that group, set current OTG as master - * and always us 0x4 = AND of flip_ready from all pipes - * - vsync flip: disable GSL if used - * - * Groups in stream_res are stored as +1 from HW registers, i.e. - * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1 - * Using a magic value like -1 would require tracking all inits/resets - */ - void dcn20_setup_gsl_group_as_lock( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enable) -{ - struct gsl_params gsl; - int group_idx; - - memset(&gsl, 0, sizeof(struct gsl_params)); - - if (enable) { - /* return if group already assigned since GSL was set up - * for vsync flip, we would unassign so it can't be "left over" - */ - if (pipe_ctx->stream_res.gsl_group > 0) - return; - - group_idx = find_free_gsl_group(dc); - ASSERT(group_idx != 0); - pipe_ctx->stream_res.gsl_group = group_idx; - - /* set gsl group reg field and mark resource used */ - switch (group_idx) { - case 1: - gsl.gsl0_en = 1; - dc->res_pool->gsl_groups.gsl_0 = 1; - break; - case 2: - gsl.gsl1_en = 1; - dc->res_pool->gsl_groups.gsl_1 = 1; - break; - case 3: - gsl.gsl2_en = 1; - dc->res_pool->gsl_groups.gsl_2 = 1; - break; - default: - BREAK_TO_DEBUGGER(); - return; // invalid case - } - gsl.gsl_master_en = 1; - } else { - group_idx = pipe_ctx->stream_res.gsl_group; - if (group_idx == 0) - return; // if not in use, just return - - pipe_ctx->stream_res.gsl_group = 0; - - /* unset gsl group reg field and mark resource free */ - switch (group_idx) { - case 1: - gsl.gsl0_en = 0; - dc->res_pool->gsl_groups.gsl_0 = 0; - break; - case 2: - gsl.gsl1_en = 0; - dc->res_pool->gsl_groups.gsl_1 = 0; - break; - case 3: - gsl.gsl2_en = 0; - dc->res_pool->gsl_groups.gsl_2 = 0; - break; - default: - BREAK_TO_DEBUGGER(); - return; - } - gsl.gsl_master_en = 0; - } - - /* at this point we want to program whether it's to enable or disable */ - if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL && - pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) { - pipe_ctx->stream_res.tg->funcs->set_gsl( - pipe_ctx->stream_res.tg, - &gsl); - - pipe_ctx->stream_res.tg->funcs->set_gsl_source_select( - pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0); - } else - BREAK_TO_DEBUGGER(); -} - -void dcn20_set_flip_control_gsl( - struct pipe_ctx *pipe_ctx, - bool flip_immediate) -{ - if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl) - pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl( - pipe_ctx->plane_res.hubp, flip_immediate); - -} - -void dcn20_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable) -{ - bool force_on = true; /* disable power gating */ - uint32_t org_ip_request_cntl = 0; - - if (enable) - force_on = false; - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - /* DCHUBP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); - if (REG(DOMAIN8_PG_CONFIG)) - REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); - if (REG(DOMAIN10_PG_CONFIG)) - REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); - - /* DPP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); - if (REG(DOMAIN9_PG_CONFIG)) - REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); - if (REG(DOMAIN11_PG_CONFIG)) - REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); - - /* DCS0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on); - if (REG(DOMAIN19_PG_CONFIG)) - REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on); - if (REG(DOMAIN20_PG_CONFIG)) - REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on); - if (REG(DOMAIN21_PG_CONFIG)) - REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on); - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - -} - -void dcn20_dccg_init(struct dce_hwseq *hws) -{ - /* - * set MICROSECOND_TIME_BASE_DIV - * 100Mhz refclk -> 0x120264 - * 27Mhz refclk -> 0x12021b - * 48Mhz refclk -> 0x120230 - * - */ - REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264); - - /* - * set MILLISECOND_TIME_BASE_DIV - * 100Mhz refclk -> 0x1186a0 - * 27Mhz refclk -> 0x106978 - * 48Mhz refclk -> 0x10bb80 - * - */ - REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0); - - /* This value is dependent on the hardware pipeline delay so set once per SOC */ - REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c); -} - -void dcn20_disable_vga( - struct dce_hwseq *hws) -{ - REG_WRITE(D1VGA_CONTROL, 0); - REG_WRITE(D2VGA_CONTROL, 0); - REG_WRITE(D3VGA_CONTROL, 0); - REG_WRITE(D4VGA_CONTROL, 0); - REG_WRITE(D5VGA_CONTROL, 0); - REG_WRITE(D6VGA_CONTROL, 0); -} - -void dcn20_program_triple_buffer( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enable_triple_buffer) -{ - if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) { - pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer( - pipe_ctx->plane_res.hubp, - enable_triple_buffer); - } -} - -/* Blank pixel data during initialization */ -void dcn20_init_blank( - struct dc *dc, - struct timing_generator *tg) -{ - struct dce_hwseq *hws = dc->hwseq; - enum dc_color_space color_space; - struct tg_color black_color = {0}; - struct output_pixel_processor *opp = NULL; - struct output_pixel_processor *bottom_opp = NULL; - uint32_t num_opps, opp_id_src0, opp_id_src1; - uint32_t otg_active_width, otg_active_height; - - /* program opp dpg blank color */ - color_space = COLOR_SPACE_SRGB; - color_space_to_black_color(dc, color_space, &black_color); - - /* get the OTG active size */ - tg->funcs->get_otg_active_size(tg, - &otg_active_width, - &otg_active_height); - - /* get the OPTC source */ - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - - if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) { - ASSERT(false); - return; - } - opp = dc->res_pool->opps[opp_id_src0]; - - /* don't override the blank pattern if already enabled with the correct one. */ - if (opp->funcs->dpg_is_blanked && opp->funcs->dpg_is_blanked(opp)) - return; - - if (num_opps == 2) { - otg_active_width = otg_active_width / 2; - - if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) { - ASSERT(false); - return; - } - bottom_opp = dc->res_pool->opps[opp_id_src1]; - } - - opp->funcs->opp_set_disp_pattern_generator( - opp, - CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - COLOR_DEPTH_UNDEFINED, - &black_color, - otg_active_width, - otg_active_height, - 0); - - if (num_opps == 2) { - bottom_opp->funcs->opp_set_disp_pattern_generator( - bottom_opp, - CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - COLOR_DEPTH_UNDEFINED, - &black_color, - otg_active_width, - otg_active_height, - 0); - } - - hws->funcs.wait_for_blank_complete(opp); -} - -void dcn20_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - uint32_t org_ip_request_cntl = 0; - - if (hws->ctx->dc->debug.disable_dsc_power_gate) - return; - - if (REG(DOMAIN16_PG_CONFIG) == 0) - return; - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - switch (dsc_inst) { - case 0: /* DSC0 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, - DOMAIN16_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN16_PG_STATUS, - DOMAIN16_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DSC1 */ - REG_UPDATE(DOMAIN17_PG_CONFIG, - DOMAIN17_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN17_PG_STATUS, - DOMAIN17_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DSC2 */ - REG_UPDATE(DOMAIN18_PG_CONFIG, - DOMAIN18_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN18_PG_STATUS, - DOMAIN18_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DSC3 */ - REG_UPDATE(DOMAIN19_PG_CONFIG, - DOMAIN19_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN19_PG_STATUS, - DOMAIN19_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 4: /* DSC4 */ - REG_UPDATE(DOMAIN20_PG_CONFIG, - DOMAIN20_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN20_PG_STATUS, - DOMAIN20_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 5: /* DSC5 */ - REG_UPDATE(DOMAIN21_PG_CONFIG, - DOMAIN21_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN21_PG_STATUS, - DOMAIN21_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} - -void dcn20_dpp_pg_control( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - - if (hws->ctx->dc->debug.disable_dpp_power_gate) - return; - if (REG(DOMAIN1_PG_CONFIG) == 0) - return; - - switch (dpp_inst) { - case 0: /* DPP0 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, - DOMAIN1_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN1_PG_STATUS, - DOMAIN1_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DPP1 */ - REG_UPDATE(DOMAIN3_PG_CONFIG, - DOMAIN3_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN3_PG_STATUS, - DOMAIN3_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DPP2 */ - REG_UPDATE(DOMAIN5_PG_CONFIG, - DOMAIN5_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN5_PG_STATUS, - DOMAIN5_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DPP3 */ - REG_UPDATE(DOMAIN7_PG_CONFIG, - DOMAIN7_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN7_PG_STATUS, - DOMAIN7_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 4: /* DPP4 */ - REG_UPDATE(DOMAIN9_PG_CONFIG, - DOMAIN9_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN9_PG_STATUS, - DOMAIN9_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 5: /* DPP5 */ - /* - * Do not power gate DPP5, should be left at HW default, power on permanently. - * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard - * reset. - * REG_UPDATE(DOMAIN11_PG_CONFIG, - * DOMAIN11_POWER_GATE, power_gate); - * - * REG_WAIT(DOMAIN11_PG_STATUS, - * DOMAIN11_PGFSM_PWR_STATUS, pwr_status, - * 1, 1000); - */ - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - - -void dcn20_hubp_pg_control( - struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - - if (hws->ctx->dc->debug.disable_hubp_power_gate) - return; - if (REG(DOMAIN0_PG_CONFIG) == 0) - return; - - switch (hubp_inst) { - case 0: /* DCHUBP0 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, - DOMAIN0_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN0_PG_STATUS, - DOMAIN0_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DCHUBP1 */ - REG_UPDATE(DOMAIN2_PG_CONFIG, - DOMAIN2_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN2_PG_STATUS, - DOMAIN2_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DCHUBP2 */ - REG_UPDATE(DOMAIN4_PG_CONFIG, - DOMAIN4_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN4_PG_STATUS, - DOMAIN4_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DCHUBP3 */ - REG_UPDATE(DOMAIN6_PG_CONFIG, - DOMAIN6_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN6_PG_STATUS, - DOMAIN6_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 4: /* DCHUBP4 */ - REG_UPDATE(DOMAIN8_PG_CONFIG, - DOMAIN8_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN8_PG_STATUS, - DOMAIN8_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 5: /* DCHUBP5 */ - /* - * Do not power gate DCHUB5, should be left at HW default, power on permanently. - * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard - * reset. - * REG_UPDATE(DOMAIN10_PG_CONFIG, - * DOMAIN10_POWER_GATE, power_gate); - * - * REG_WAIT(DOMAIN10_PG_STATUS, - * DOMAIN10_PGFSM_PWR_STATUS, pwr_status, - * 1, 1000); - */ - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - - -/* disable HW used by plane. - * note: cannot disable until disconnect is complete - */ -void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - - dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); - - /* In flip immediate with pipe splitting case GSL is used for - * synchronization so we must disable it when the plane is disabled. - */ - if (pipe_ctx->stream_res.gsl_group != 0) - dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false); - - if (hubp->funcs->hubp_update_mall_sel) - hubp->funcs->hubp_update_mall_sel(hubp, 0, false); - - dc->hwss.set_flip_control_gsl(pipe_ctx, false); - - hubp->funcs->hubp_clk_cntl(hubp, false); - - dpp->funcs->dpp_dppclk_control(dpp, false, false); - - hubp->power_gated = true; - - hws->funcs.plane_atomic_power_down(dc, - pipe_ctx->plane_res.dpp, - pipe_ctx->plane_res.hubp); - - pipe_ctx->stream = NULL; - memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); - memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); - pipe_ctx->top_pipe = NULL; - pipe_ctx->bottom_pipe = NULL; - pipe_ctx->prev_odm_pipe = NULL; - pipe_ctx->next_odm_pipe = NULL; - pipe_ctx->plane_state = NULL; -} - - -void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom; - struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) - return; - - dcn20_plane_atomic_disable(dc, pipe_ctx); - - /* Turn back off the phantom OTG after the phantom plane is fully disabled - */ - if (is_phantom) - if (tg && tg->funcs->disable_phantom_crtc) - tg->funcs->disable_phantom_crtc(tg); - - DC_LOG_DC("Power down front end %d\n", - pipe_ctx->pipe_idx); -} - -void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank) -{ - dcn20_blank_pixel_data(dc, pipe_ctx, blank); -} - -static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, - int opp_cnt) -{ - bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); - int flow_ctrl_cnt; - - if (opp_cnt >= 2) - hblank_halved = true; - - flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - - stream->timing.h_border_left - - stream->timing.h_border_right; - - if (hblank_halved) - flow_ctrl_cnt /= 2; - - /* ODM combine 4:1 case */ - if (opp_cnt == 4) - flow_ctrl_cnt /= 2; - - return flow_ctrl_cnt; -} - -static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link) -{ - switch (link->link_enc->transmitter) { - case TRANSMITTER_UNIPHY_A: - return PHYD32CLKA; - case TRANSMITTER_UNIPHY_B: - return PHYD32CLKB; - case TRANSMITTER_UNIPHY_C: - return PHYD32CLKC; - case TRANSMITTER_UNIPHY_D: - return PHYD32CLKD; - case TRANSMITTER_UNIPHY_E: - return PHYD32CLKE; - default: - return PHYD32CLKA; - } -} - -static int get_odm_segment_count(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; - int count = 1; - - while (odm_pipe != NULL) { - count++; - odm_pipe = odm_pipe->next_odm_pipe; - } - - return count; -} - -enum dc_status dcn20_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dc_stream_state *stream = pipe_ctx->stream; - struct drr_params params = {0}; - unsigned int event_triggers = 0; - struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; - bool interlace = stream->timing.flags.INTERLACE; - int i; - struct mpc_dwb_flow_control flow_control; - struct mpc *mpc = dc->res_pool->mpc; - bool rate_control_2x_pclk = (interlace || optc2_is_two_pixels_per_containter(&stream->timing)); - unsigned int k1_div = PIXEL_RATE_DIV_NA; - unsigned int k2_div = PIXEL_RATE_DIV_NA; - - if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { - hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); - - dc->res_pool->dccg->funcs->set_pixel_rate_div( - dc->res_pool->dccg, - pipe_ctx->stream_res.tg->inst, - k1_div, k2_div); - } - /* by upper caller loop, pipe0 is parent pipe and be called first. - * back end is set up by for pipe0. Other children pipe share back end - * with pipe 0. No program is needed. - */ - if (pipe_ctx->top_pipe != NULL) - return DC_OK; - - /* TODO check if timing_changed, disable stream if timing changed */ - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; - opp_cnt++; - } - - if (opp_cnt > 1) - pipe_ctx->stream_res.tg->funcs->set_odm_combine( - pipe_ctx->stream_res.tg, - opp_inst, opp_cnt, - &pipe_ctx->stream->timing); - - /* HW program guide assume display already disable - * by unplug sequence. OTG assume stop. - */ - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); - - if (false == pipe_ctx->clock_source->funcs->program_pix_clk( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), - &pipe_ctx->pll_settings)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - - if (dc_is_hdmi_tmds_signal(stream->signal)) { - stream->link->phy_state.symclk_ref_cnts.otg = 1; - if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; - else - stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; - } - - if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal))) - dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->program_timing( - pipe_ctx->stream_res.tg, - &stream->timing, - pipe_ctx->pipe_dlg_param.vready_offset, - pipe_ctx->pipe_dlg_param.vstartup_start, - pipe_ctx->pipe_dlg_param.vupdate_offset, - pipe_ctx->pipe_dlg_param.vupdate_width, - pipe_ctx->stream->signal, - true); - - rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; - flow_control.flow_ctrl_mode = 0; - flow_control.flow_ctrl_cnt0 = 0x80; - flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt); - if (mpc->funcs->set_out_rate_control) { - for (i = 0; i < opp_cnt; ++i) { - mpc->funcs->set_out_rate_control( - mpc, opp_inst[i], - true, - rate_control_2x_pclk, - &flow_control); - } - } - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( - odm_pipe->stream_res.opp, - true); - - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( - pipe_ctx->stream_res.opp, - true); - - hws->funcs.blank_pixel_data(dc, pipe_ctx, true); - - /* VTG is within DCHUB command block. DCFCLK is always on */ - if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } - - hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp); - - params.vertical_total_min = stream->adjust.v_total_min; - params.vertical_total_max = stream->adjust.v_total_max; - params.vertical_total_mid = stream->adjust.v_total_mid; - params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num; - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, ¶ms); - - // DRR should set trigger event to monitor surface update event - if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) - event_triggers = 0x80; - /* Event triggers and num frames initialized for DRR, but can be - * later updated for PSR use. Note DRR trigger events are generated - * regardless of whether num frames met. - */ - if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx->stream_res.tg, event_triggers, 2); - - /* TODO program crtc source select for non-virtual signal*/ - /* TODO program FMT */ - /* TODO setup link_enc */ - /* TODO set stream attributes */ - /* TODO program audio */ - /* TODO enable stream if timing changed */ - /* TODO unblank stream if DP */ - - if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) { - if (pipe_ctx->stream_res.tg && pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable) - pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg); - } - - if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - struct dccg *dccg = dc->res_pool->dccg; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - struct dtbclk_dto_params dto_params = {0}; - - if (dccg->funcs->set_dtbclk_p_src) - dccg->funcs->set_dtbclk_p_src(dccg, DTBCLK0, tg->inst); - - dto_params.otg_inst = tg->inst; - dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; - dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); - dto_params.timing = &pipe_ctx->stream->timing; - dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); - dccg->funcs->set_dtbclk_dto(dccg, &dto_params); - } - - return DC_OK; -} - -void dcn20_program_output_csc(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id) -{ - struct mpc *mpc = dc->res_pool->mpc; - enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - - if (mpc->funcs->power_on_mpc_mem_pwr) - mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); - - if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { - if (mpc->funcs->set_output_csc != NULL) - mpc->funcs->set_output_csc(mpc, - opp_id, - matrix, - ocsc_mode); - } else { - if (mpc->funcs->set_ocsc_default != NULL) - mpc->funcs->set_ocsc_default(mpc, - opp_id, - colorspace, - ocsc_mode); - } -} - -bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) -{ - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; - struct pwl_params *params = NULL; - /* - * program OGAM only for the top pipe - * if there is a pipe split then fix diagnostic is required: - * how to pass OGAM parameter for stream. - * if programming for all pipes is required then remove condition - * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic. - */ - if (mpc->funcs->power_on_mpc_mem_pwr) - mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); - if (pipe_ctx->top_pipe == NULL - && mpc->funcs->set_output_gamma && stream->out_transfer_func) { - if (stream->out_transfer_func->type == TF_TYPE_HWPWL) - params = &stream->out_transfer_func->pwl; - else if (pipe_ctx->stream->out_transfer_func->type == - TF_TYPE_DISTRIBUTED_POINTS && - cm_helper_translate_curve_to_hw_format(dc->ctx, - stream->out_transfer_func, - &mpc->blender_params, false)) - params = &mpc->blender_params; - /* - * there is no ROM - */ - if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) - BREAK_TO_DEBUGGER(); - } - /* - * if above if is not executed then 'params' equal to 0 and set in bypass - */ - mpc->funcs->set_output_gamma(mpc, mpcc_id, params); - - return true; -} - -bool dcn20_set_blend_lut( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - bool result = true; - struct pwl_params *blend_lut = NULL; - - if (plane_state->blend_tf) { - if (plane_state->blend_tf->type == TF_TYPE_HWPWL) - blend_lut = &plane_state->blend_tf->pwl; - else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm_helper_translate_curve_to_hw_format(plane_state->ctx, - plane_state->blend_tf, - &dpp_base->regamma_params, false); - blend_lut = &dpp_base->regamma_params; - } - } - result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut); - - return result; -} - -bool dcn20_set_shaper_3dlut( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - bool result = true; - struct pwl_params *shaper_lut = NULL; - - if (plane_state->in_shaper_func) { - if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL) - shaper_lut = &plane_state->in_shaper_func->pwl; - else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm_helper_translate_curve_to_hw_format(plane_state->ctx, - plane_state->in_shaper_func, - &dpp_base->shaper_params, true); - shaper_lut = &dpp_base->shaper_params; - } - } - - result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); - if (plane_state->lut3d_func && - plane_state->lut3d_func->state.bits.initialized == 1) - result = dpp_base->funcs->dpp_program_3dlut(dpp_base, - &plane_state->lut3d_func->lut_3d); - else - result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL); - - return result; -} - -bool dcn20_set_input_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - const struct dc_transfer_func *tf = NULL; - bool result = true; - bool use_degamma_ram = false; - - if (dpp_base == NULL || plane_state == NULL) - return false; - - hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state); - hws->funcs.set_blend_lut(pipe_ctx, plane_state); - - if (plane_state->in_transfer_func) - tf = plane_state->in_transfer_func; - - - if (tf == NULL) { - dpp_base->funcs->dpp_set_degamma(dpp_base, - IPP_DEGAMMA_MODE_BYPASS); - return true; - } - - if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS) - use_degamma_ram = true; - - if (use_degamma_ram == true) { - if (tf->type == TF_TYPE_HWPWL) - dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, - &tf->pwl); - else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm_helper_translate_curve_to_degamma_hw_format(tf, - &dpp_base->degamma_params); - dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, - &dpp_base->degamma_params); - } - return true; - } - /* handle here the optimized cases when de-gamma ROM could be used. - * - */ - if (tf->type == TF_TYPE_PREDEFINED) { - switch (tf->tf) { - case TRANSFER_FUNCTION_SRGB: - dpp_base->funcs->dpp_set_degamma(dpp_base, - IPP_DEGAMMA_MODE_HW_sRGB); - break; - case TRANSFER_FUNCTION_BT709: - dpp_base->funcs->dpp_set_degamma(dpp_base, - IPP_DEGAMMA_MODE_HW_xvYCC); - break; - case TRANSFER_FUNCTION_LINEAR: - dpp_base->funcs->dpp_set_degamma(dpp_base, - IPP_DEGAMMA_MODE_BYPASS); - break; - case TRANSFER_FUNCTION_PQ: - dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); - cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); - dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); - result = true; - break; - default: - result = false; - break; - } - } else if (tf->type == TF_TYPE_BYPASS) - dpp_base->funcs->dpp_set_degamma(dpp_base, - IPP_DEGAMMA_MODE_BYPASS); - else { - /* - * if we are here, we did not handle correctly. - * fix is required for this use case - */ - BREAK_TO_DEBUGGER(); - dpp_base->funcs->dpp_set_degamma(dpp_base, - IPP_DEGAMMA_MODE_BYPASS); - } - - return result; -} - -void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; - opp_cnt++; - } - - if (opp_cnt > 1) - pipe_ctx->stream_res.tg->funcs->set_odm_combine( - pipe_ctx->stream_res.tg, - opp_inst, opp_cnt, - &pipe_ctx->stream->timing); - else - pipe_ctx->stream_res.tg->funcs->set_odm_bypass( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); -} - -void dcn20_blank_pixel_data( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank) -{ - struct tg_color black_color = {0}; - struct stream_resource *stream_res = &pipe_ctx->stream_res; - struct dc_stream_state *stream = pipe_ctx->stream; - enum dc_color_space color_space = stream->output_color_space; - enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; - enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; - struct pipe_ctx *odm_pipe; - int odm_cnt = 1; - int h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; - int v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; - int odm_slice_width, last_odm_slice_width, offset = 0; - - if (stream->link->test_pattern_enabled) - return; - - /* get opp dpg blank color */ - color_space_to_black_color(dc, color_space, &black_color); - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - odm_cnt++; - odm_slice_width = h_active / odm_cnt; - last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1); - - if (blank) { - dc->hwss.set_abm_immediate_disable(pipe_ctx); - - if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { - test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; - test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; - } - } else { - test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; - } - - odm_pipe = pipe_ctx; - - while (odm_pipe->next_odm_pipe) { - dc->hwss.set_disp_pattern_generator(dc, - odm_pipe, - test_pattern, - test_pattern_color_space, - stream->timing.display_color_depth, - &black_color, - odm_slice_width, - v_active, - offset); - offset += odm_slice_width; - odm_pipe = odm_pipe->next_odm_pipe; - } - - dc->hwss.set_disp_pattern_generator(dc, - odm_pipe, - test_pattern, - test_pattern_color_space, - stream->timing.display_color_depth, - &black_color, - last_odm_slice_width, - v_active, - offset); - - if (!blank) - if (stream_res->abm) { - dc->hwss.set_pipe(pipe_ctx); - stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); - } -} - - -static void dcn20_power_on_plane_resources( - struct dce_hwseq *hws, - struct pipe_ctx *pipe_ctx) -{ - DC_LOGGER_INIT(hws->ctx->logger); - - if (hws->funcs.dpp_root_clock_control) - hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true); - - if (REG(DC_IP_REQUEST_CNTL)) { - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 1); - - if (hws->funcs.dpp_pg_control) - hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true); - - if (hws->funcs.hubp_pg_control) - hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true); - - REG_SET(DC_IP_REQUEST_CNTL, 0, - IP_REQUEST_EN, 0); - DC_LOG_DEBUG( - "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst); - } -} - -static void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - //if (dc->debug.sanity_checks) { - // dcn10_verify_allow_pstate_change_high(dc); - //} - dcn20_power_on_plane_resources(dc->hwseq, pipe_ctx); - - /* enable DCFCLK current DCHUB */ - pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); - - /* initialize HUBP on power up */ - pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp); - - /* make sure OPP_PIPE_CLOCK_EN = 1 */ - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( - pipe_ctx->stream_res.opp, - true); - -/* TODO: enable/disable in dm as per update type. - if (plane_state) { - DC_LOG_DC(dc->ctx->logger, - "Pipe:%d 0x%x: addr hi:0x%x, " - "addr low:0x%x, " - "src: %d, %d, %d," - " %d; dst: %d, %d, %d, %d;\n", - pipe_ctx->pipe_idx, - plane_state, - plane_state->address.grph.addr.high_part, - plane_state->address.grph.addr.low_part, - plane_state->src_rect.x, - plane_state->src_rect.y, - plane_state->src_rect.width, - plane_state->src_rect.height, - plane_state->dst_rect.x, - plane_state->dst_rect.y, - plane_state->dst_rect.width, - plane_state->dst_rect.height); - - DC_LOG_DC(dc->ctx->logger, - "Pipe %d: width, height, x, y format:%d\n" - "viewport:%d, %d, %d, %d\n" - "recout: %d, %d, %d, %d\n", - pipe_ctx->pipe_idx, - plane_state->format, - pipe_ctx->plane_res.scl_data.viewport.width, - pipe_ctx->plane_res.scl_data.viewport.height, - pipe_ctx->plane_res.scl_data.viewport.x, - pipe_ctx->plane_res.scl_data.viewport.y, - pipe_ctx->plane_res.scl_data.recout.width, - pipe_ctx->plane_res.scl_data.recout.height, - pipe_ctx->plane_res.scl_data.recout.x, - pipe_ctx->plane_res.scl_data.recout.y); - print_rq_dlg_ttu(dc, pipe_ctx); - } -*/ - if (dc->vm_pa_config.valid) { - struct vm_system_aperture_param apt; - - apt.sys_default.quad_part = 0; - - apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr; - apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr; - - // Program system aperture settings - pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); - } - - if (!pipe_ctx->top_pipe - && pipe_ctx->plane_state - && pipe_ctx->plane_state->flip_int_enabled - && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) - pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); - -// if (dc->debug.sanity_checks) { -// dcn10_verify_allow_pstate_change_high(dc); -// } -} - -void dcn20_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock) -{ - struct pipe_ctx *temp_pipe; - bool flip_immediate = false; - - /* use TG master update lock to lock everything on the TG - * therefore only top pipe need to lock - */ - if (!pipe || pipe->top_pipe) - return; - - if (pipe->plane_state != NULL) - flip_immediate = pipe->plane_state->flip_immediate; - - if (pipe->stream_res.gsl_group > 0) { - temp_pipe = pipe->bottom_pipe; - while (!flip_immediate && temp_pipe) { - if (temp_pipe->plane_state != NULL) - flip_immediate = temp_pipe->plane_state->flip_immediate; - temp_pipe = temp_pipe->bottom_pipe; - } - } - - if (flip_immediate && lock) { - const int TIMEOUT_FOR_FLIP_PENDING_US = 100000; - unsigned int polling_interval_us = 1; - int i; - - temp_pipe = pipe; - while (temp_pipe) { - if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) { - for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING_US / polling_interval_us; ++i) { - if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp)) - break; - udelay(polling_interval_us); - } - - /* no reason it should take this long for immediate flips */ - ASSERT(i != TIMEOUT_FOR_FLIP_PENDING_US); - } - temp_pipe = temp_pipe->bottom_pipe; - } - } - - /* In flip immediate and pipe splitting case, we need to use GSL - * for synchronization. Only do setup on locking and on flip type change. - */ - if (lock && (pipe->bottom_pipe != NULL || !flip_immediate)) - if ((flip_immediate && pipe->stream_res.gsl_group == 0) || - (!flip_immediate && pipe->stream_res.gsl_group > 0)) - dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate); - - if (pipe->plane_state != NULL) - flip_immediate = pipe->plane_state->flip_immediate; - - temp_pipe = pipe->bottom_pipe; - while (flip_immediate && temp_pipe) { - if (temp_pipe->plane_state != NULL) - flip_immediate = temp_pipe->plane_state->flip_immediate; - temp_pipe = temp_pipe->bottom_pipe; - } - - if (!lock && pipe->stream_res.gsl_group > 0 && pipe->plane_state && - !flip_immediate) - dcn20_setup_gsl_group_as_lock(dc, pipe, false); - - if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) { - union dmub_hw_lock_flags hw_locks = { 0 }; - struct dmub_hw_lock_inst_flags inst_flags = { 0 }; - - hw_locks.bits.lock_pipe = 1; - inst_flags.otg_inst = pipe->stream_res.tg->inst; - - if (pipe->plane_state != NULL) - hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips; - - dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, - lock, - &hw_locks, - &inst_flags); - } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { - if (lock) - pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); - else - pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg); - } else { - if (lock) - pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); - else - pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); - } -} - -static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx *new_pipe) -{ - new_pipe->update_flags.raw = 0; - - /* If non-phantom pipe is being transitioned to a phantom pipe, - * set disable and return immediately. This is because the pipe - * that was previously in use must be fully disabled before we - * can "enable" it as a phantom pipe (since the OTG will certainly - * be different). The post_unlock sequence will set the correct - * update flags to enable the phantom pipe. - */ - if (old_pipe->plane_state && !old_pipe->plane_state->is_phantom && - new_pipe->plane_state && new_pipe->plane_state->is_phantom) { - new_pipe->update_flags.bits.disable = 1; - return; - } - - /* Exit on unchanged, unused pipe */ - if (!old_pipe->plane_state && !new_pipe->plane_state) - return; - /* Detect pipe enable/disable */ - if (!old_pipe->plane_state && new_pipe->plane_state) { - new_pipe->update_flags.bits.enable = 1; - new_pipe->update_flags.bits.mpcc = 1; - new_pipe->update_flags.bits.dppclk = 1; - new_pipe->update_flags.bits.hubp_interdependent = 1; - new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; - new_pipe->update_flags.bits.unbounded_req = 1; - new_pipe->update_flags.bits.gamut_remap = 1; - new_pipe->update_flags.bits.scaler = 1; - new_pipe->update_flags.bits.viewport = 1; - new_pipe->update_flags.bits.det_size = 1; - if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) { - new_pipe->update_flags.bits.odm = 1; - new_pipe->update_flags.bits.global_sync = 1; - } - return; - } - - /* For SubVP we need to unconditionally enable because any phantom pipes are - * always removed then newly added for every full updates whenever SubVP is in use. - * The remove-add sequence of the phantom pipe always results in the pipe - * being blanked in enable_stream_timing (DPG). - */ - if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) - new_pipe->update_flags.bits.enable = 1; - - /* Phantom pipes are effectively disabled, if the pipe was previously phantom - * we have to enable - */ - if (old_pipe->plane_state && old_pipe->plane_state->is_phantom && - new_pipe->plane_state && !new_pipe->plane_state->is_phantom) - new_pipe->update_flags.bits.enable = 1; - - if (old_pipe->plane_state && !new_pipe->plane_state) { - new_pipe->update_flags.bits.disable = 1; - return; - } - - /* Detect plane change */ - if (old_pipe->plane_state != new_pipe->plane_state) { - new_pipe->update_flags.bits.plane_changed = true; - } - - /* Detect top pipe only changes */ - if (resource_is_pipe_type(new_pipe, OTG_MASTER)) { - /* Detect odm changes */ - if (resource_is_odm_topology_changed(new_pipe, old_pipe)) - new_pipe->update_flags.bits.odm = 1; - - /* Detect global sync changes */ - if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset - || old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start - || old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset - || old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width) - new_pipe->update_flags.bits.global_sync = 1; - } - - if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb) - new_pipe->update_flags.bits.det_size = 1; - - /* - * Detect opp / tg change, only set on change, not on enable - * Assume mpcc inst = pipe index, if not this code needs to be updated - * since mpcc is what is affected by these. In fact all of our sequence - * makes this assumption at the moment with how hubp reset is matched to - * same index mpcc reset. - */ - if (old_pipe->stream_res.opp != new_pipe->stream_res.opp) - new_pipe->update_flags.bits.opp_changed = 1; - if (old_pipe->stream_res.tg != new_pipe->stream_res.tg) - new_pipe->update_flags.bits.tg_changed = 1; - - /* - * Detect mpcc blending changes, only dpp inst and opp matter here, - * mpccs getting removed/inserted update connected ones during their own - * programming - */ - if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp - || old_pipe->stream_res.opp != new_pipe->stream_res.opp) - new_pipe->update_flags.bits.mpcc = 1; - - /* Detect dppclk change */ - if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz) - new_pipe->update_flags.bits.dppclk = 1; - - /* Check for scl update */ - if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data))) - new_pipe->update_flags.bits.scaler = 1; - /* Check for vp update */ - if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect)) - || memcmp(&old_pipe->plane_res.scl_data.viewport_c, - &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect))) - new_pipe->update_flags.bits.viewport = 1; - - /* Detect dlg/ttu/rq updates */ - { - struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs; - struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs; - struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs; - struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs; - - /* Detect pipe interdependent updates */ - if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch || - old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch || - old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c || - old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank || - old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank || - old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip || - old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip || - old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l || - old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c || - old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l || - old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l || - old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c || - old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l || - old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c || - old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 || - old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 || - old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank || - old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) { - old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch; - old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch; - old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c; - old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank; - old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank; - old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip; - old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip; - old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l; - old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c; - old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l; - old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l; - old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c; - old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l; - old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c; - old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0; - old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1; - old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank; - old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip; - new_pipe->update_flags.bits.hubp_interdependent = 1; - } - /* Detect any other updates to ttu/rq/dlg */ - if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) || - memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) || - memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs))) - new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; - } - - if (old_pipe->unbounded_req != new_pipe->unbounded_req) - new_pipe->update_flags.bits.unbounded_req = 1; -} - -static void dcn20_update_dchubp_dpp( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct dccg *dccg = dc->res_pool->dccg; - bool viewport_changed = false; - - if (pipe_ctx->update_flags.bits.dppclk) - dpp->funcs->dpp_dppclk_control(dpp, false, true); - - if (pipe_ctx->update_flags.bits.enable) - dccg->funcs->update_dpp_dto(dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz); - - /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG - * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. - * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG - */ - if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) { - hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); - - hubp->funcs->hubp_setup( - hubp, - &pipe_ctx->dlg_regs, - &pipe_ctx->ttu_regs, - &pipe_ctx->rq_regs, - &pipe_ctx->pipe_dlg_param); - } - - if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting) - hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req); - - if (pipe_ctx->update_flags.bits.hubp_interdependent) - hubp->funcs->hubp_setup_interdependent( - hubp, - &pipe_ctx->dlg_regs, - &pipe_ctx->ttu_regs); - - if (pipe_ctx->update_flags.bits.enable || - pipe_ctx->update_flags.bits.plane_changed || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.input_csc_change || - plane_state->update_flags.bits.color_space_change || - plane_state->update_flags.bits.coeff_reduction_change) { - struct dc_bias_and_scale bns_params = {0}; - - // program the input csc - dpp->funcs->dpp_setup(dpp, - plane_state->format, - EXPANSION_MODE_ZERO, - plane_state->input_csc_color_matrix, - plane_state->color_space, - NULL); - - if (dpp->funcs->dpp_program_bias_and_scale) { - //TODO :for CNVC set scale and bias registers if necessary - build_prescale_params(&bns_params, plane_state); - dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); - } - } - - if (pipe_ctx->update_flags.bits.mpcc - || pipe_ctx->update_flags.bits.plane_changed - || plane_state->update_flags.bits.global_alpha_change - || plane_state->update_flags.bits.per_pixel_alpha_change) { - // MPCC inst is equal to pipe index in practice - hws->funcs.update_mpcc(dc, pipe_ctx); - } - - if (pipe_ctx->update_flags.bits.scaler || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change || - plane_state->update_flags.bits.per_pixel_alpha_change || - pipe_ctx->stream->update_flags.bits.scaling) { - pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; - ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP); - /* scaler configuration */ - pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( - pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); - } - - if (pipe_ctx->update_flags.bits.viewport || - (context == dc->current_state && plane_state->update_flags.bits.position_change) || - (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || - (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { - - hubp->funcs->mem_program_viewport( - hubp, - &pipe_ctx->plane_res.scl_data.viewport, - &pipe_ctx->plane_res.scl_data.viewport_c); - viewport_changed = true; - } - - /* Any updates are handled in dc interface, just need to apply existing for plane enable */ - if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || - pipe_ctx->update_flags.bits.scaler || viewport_changed == true) && - pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { - dc->hwss.set_cursor_position(pipe_ctx); - dc->hwss.set_cursor_attribute(pipe_ctx); - - if (dc->hwss.set_cursor_sdr_white_level) - dc->hwss.set_cursor_sdr_white_level(pipe_ctx); - } - - /* Any updates are handled in dc interface, just need - * to apply existing for plane enable / opp change */ - if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed - || pipe_ctx->update_flags.bits.plane_changed - || pipe_ctx->stream->update_flags.bits.gamut_remap - || plane_state->update_flags.bits.gamut_remap_change - || pipe_ctx->stream->update_flags.bits.out_csc) { - /* dpp/cm gamut remap*/ - dc->hwss.program_gamut_remap(pipe_ctx); - - /*call the dcn2 method which uses mpc csc*/ - dc->hwss.program_output_csc(dc, - pipe_ctx, - pipe_ctx->stream->output_color_space, - pipe_ctx->stream->csc_color_matrix.matrix, - hubp->opp_id); - } - - if (pipe_ctx->update_flags.bits.enable || - pipe_ctx->update_flags.bits.plane_changed || - pipe_ctx->update_flags.bits.opp_changed || - plane_state->update_flags.bits.pixel_format_change || - plane_state->update_flags.bits.horizontal_mirror_change || - plane_state->update_flags.bits.rotation_change || - plane_state->update_flags.bits.swizzle_change || - plane_state->update_flags.bits.dcc_change || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.plane_size_change) { - struct plane_size size = plane_state->plane_size; - - size.surface_size = pipe_ctx->plane_res.scl_data.viewport; - hubp->funcs->hubp_program_surface_config( - hubp, - plane_state->format, - &plane_state->tiling_info, - &size, - plane_state->rotation, - &plane_state->dcc, - plane_state->horizontal_mirror, - 0); - hubp->power_gated = false; - } - - if (pipe_ctx->update_flags.bits.enable || - pipe_ctx->update_flags.bits.plane_changed || - plane_state->update_flags.bits.addr_update) { - if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && - pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { - union block_sequence_params params; - - params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv; - params.subvp_save_surf_addr.addr = &pipe_ctx->plane_state->address; - params.subvp_save_surf_addr.subvp_index = pipe_ctx->subvp_index; - hwss_subvp_save_surf_addr(¶ms); - } - hws->funcs.update_plane_addr(dc, pipe_ctx); - } - - if (pipe_ctx->update_flags.bits.enable) - hubp->funcs->set_blank(hubp, false); - /* If the stream paired with this plane is phantom, the plane is also phantom */ - if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM - && hubp->funcs->phantom_hubp_post_enable) - hubp->funcs->phantom_hubp_post_enable(hubp); -} - -static int calculate_vready_offset_for_group(struct pipe_ctx *pipe) -{ - struct pipe_ctx *other_pipe; - int vready_offset = pipe->pipe_dlg_param.vready_offset; - - /* Always use the largest vready_offset of all connected pipes */ - for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) { - if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) - vready_offset = other_pipe->pipe_dlg_param.vready_offset; - } - - return vready_offset; -} - -static void dcn20_program_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dce_hwseq *hws = dc->hwseq; - - /* Only need to unblank on top pipe */ - if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) { - if (pipe_ctx->update_flags.bits.enable || - pipe_ctx->update_flags.bits.odm || - pipe_ctx->stream->update_flags.bits.abm_level) - hws->funcs.blank_pixel_data(dc, pipe_ctx, - !pipe_ctx->plane_state || - !pipe_ctx->plane_state->visible); - } - - /* Only update TG on top pipe */ - if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe - && !pipe_ctx->prev_odm_pipe) { - pipe_ctx->stream_res.tg->funcs->program_global_sync( - pipe_ctx->stream_res.tg, - calculate_vready_offset_for_group(pipe_ctx), - pipe_ctx->pipe_dlg_param.vstartup_start, - pipe_ctx->pipe_dlg_param.vupdate_offset, - pipe_ctx->pipe_dlg_param.vupdate_width); - - if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); - - pipe_ctx->stream_res.tg->funcs->set_vtg_params( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); - - if (hws->funcs.setup_vupdate_interrupt) - hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); - } - - if (pipe_ctx->update_flags.bits.odm) - hws->funcs.update_odm(dc, context, pipe_ctx); - - if (pipe_ctx->update_flags.bits.enable) { - if (hws->funcs.enable_plane) - hws->funcs.enable_plane(dc, pipe_ctx, context); - else - dcn20_enable_plane(dc, pipe_ctx, context); - - if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes) - dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub); - } - - if (dc->res_pool->hubbub->funcs->program_det_size && pipe_ctx->update_flags.bits.det_size) - dc->res_pool->hubbub->funcs->program_det_size( - dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb); - - if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw) - dcn20_update_dchubp_dpp(dc, pipe_ctx, context); - - if (pipe_ctx->update_flags.bits.enable - || pipe_ctx->plane_state->update_flags.bits.hdr_mult) - hws->funcs.set_hdr_multiplier(pipe_ctx); - - if (pipe_ctx->update_flags.bits.enable || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change || - pipe_ctx->plane_state->update_flags.bits.lut_3d) - hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); - - /* dcn10_translate_regamma_to_hw_format takes 750us to finish - * only do gamma programming for powering on, internal memcmp to avoid - * updating on slave planes - */ - if (pipe_ctx->update_flags.bits.enable || - pipe_ctx->update_flags.bits.plane_changed || - pipe_ctx->stream->update_flags.bits.out_tf || - pipe_ctx->plane_state->update_flags.bits.output_tf_change) - hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); - - /* If the pipe has been enabled or has a different opp, we - * should reprogram the fmt. This deals with cases where - * interation between mpc and odm combine on different streams - * causes a different pipe to be chosen to odm combine with. - */ - if (pipe_ctx->update_flags.bits.enable - || pipe_ctx->update_flags.bits.opp_changed) { - - pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion( - pipe_ctx->stream_res.opp, - COLOR_SPACE_YCBCR601, - pipe_ctx->stream->timing.display_color_depth, - pipe_ctx->stream->signal); - - pipe_ctx->stream_res.opp->funcs->opp_program_fmt( - pipe_ctx->stream_res.opp, - &pipe_ctx->stream->bit_depth_params, - &pipe_ctx->stream->clamping); - } - - /* Set ABM pipe after other pipe configurations done */ - if (pipe_ctx->plane_state->visible) { - if (pipe_ctx->stream_res.abm) { - dc->hwss.set_pipe(pipe_ctx); - pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm, - pipe_ctx->stream->abm_level); - } - } -} - -void dcn20_program_front_end_for_ctx( - struct dc *dc, - struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - DC_LOGGER_INIT(dc->ctx->logger); - - if (resource_is_pipe_topology_changed(dc->current_state, context)) - resource_log_pipe_topology_update(dc, context); - - if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->plane_state) { - ASSERT(!pipe_ctx->plane_state->triplebuffer_flips); - /*turn off triple buffer for full update*/ - dc->hwss.program_triplebuffer( - dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); - } - } - } - - /* Set pipe update flags and lock pipes */ - for (i = 0; i < dc->res_pool->pipe_count; i++) - dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i], - &context->res_ctx.pipe_ctx[i]); - - /* When disabling phantom pipes, turn on phantom OTG first (so we can get double - * buffer updates properly) - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream; - - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream && - dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { - struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; - - if (tg->funcs->enable_crtc) { - if (dc->hwss.blank_phantom) { - int main_pipe_width, main_pipe_height; - - main_pipe_width = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.width; - main_pipe_height = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.height; - dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); - } - tg->funcs->enable_crtc(tg); - } - } - } - /* OTG blank before disabling all front ends */ - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable - && !context->res_ctx.pipe_ctx[i].top_pipe - && !context->res_ctx.pipe_ctx[i].prev_odm_pipe - && context->res_ctx.pipe_ctx[i].stream) - hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); - - - /* Disconnect mpcc */ - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable - || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { - struct hubbub *hubbub = dc->res_pool->hubbub; - - /* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom - * then we want to do the programming here (effectively it's being disabled). If we do - * the programming later the DET won't be updated until the OTG for the phantom pipe is - * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with - * DET allocation. - */ - if (hubbub->funcs->program_det_size && (context->res_ctx.pipe_ctx[i].update_flags.bits.disable || - (context->res_ctx.pipe_ctx[i].plane_state && context->res_ctx.pipe_ctx[i].plane_state->is_phantom))) - hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); - hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); - DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); - } - - /* - * Program all updated pipes, order matters for mpcc setup. Start with - * top pipe and program all pipes that follow in order - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - if (pipe->plane_state && !pipe->top_pipe) { - while (pipe) { - if (hws->funcs.program_pipe) - hws->funcs.program_pipe(dc, pipe, context); - else { - /* Don't program phantom pipes in the regular front end programming sequence. - * There is an MPO transition case where a pipe being used by a video plane is - * transitioned directly to be a phantom pipe when closing the MPO video. However - * the phantom pipe will program a new HUBP_VTG_SEL (update takes place right away), - * but the MPO still exists until the double buffered update of the main pipe so we - * will get a frame of underflow if the phantom pipe is programmed here. - */ - if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) - dcn20_program_pipe(dc, pipe, context); - } - - pipe = pipe->bottom_pipe; - } - } - /* Program secondary blending tree and writeback pipes */ - pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->top_pipe && !pipe->prev_odm_pipe - && pipe->stream && pipe->stream->num_wb_info > 0 - && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw) - || pipe->stream->update_flags.raw) - && hws->funcs.program_all_writeback_pipes_in_tree) - hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); - - /* Avoid underflow by check of pipe line read when adding 2nd plane. */ - if (hws->wa.wait_hubpret_read_start_during_mpo_transition && - !pipe->top_pipe && - pipe->stream && - pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start && - dc->current_state->stream_status[0].plane_count == 1 && - context->stream_status[0].plane_count > 1) { - pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp); - } - - /* when dynamic ODM is active, pipes must be reconfigured when all planes are - * disabled, as some transitions will leave software and hardware state - * mismatched. - */ - if (dc->debug.enable_single_display_2to1_odm_policy && - pipe->stream && - pipe->update_flags.bits.disable && - !pipe->prev_odm_pipe && - hws->funcs.update_odm) - hws->funcs.update_odm(dc, context, pipe); - } -} - -void dcn20_post_unlock_program_front_end( - struct dc *dc, - struct dc_state *context) -{ - int i; - const unsigned int TIMEOUT_FOR_PIPE_ENABLE_US = 100000; - unsigned int polling_interval_us = 1; - struct dce_hwseq *hwseq = dc->hwseq; - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) - dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); - - /* - * If we are enabling a pipe, we need to wait for pending clear as this is a critical - * part of the enable operation otherwise, DM may request an immediate flip which - * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which - * is unsupported on DCN. - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - // Don't check flip pending on phantom pipes - if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable && - pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { - struct hubp *hubp = pipe->plane_res.hubp; - int j = 0; - for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_US / polling_interval_us - && hubp->funcs->hubp_is_flip_pending(hubp); j++) - udelay(polling_interval_us); - } - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - if (pipe->plane_state && !pipe->top_pipe) { - /* Program phantom pipe here to prevent a frame of underflow in the MPO transition - * case (if a pipe being used for a video plane transitions to a phantom pipe, it - * can underflow due to HUBP_VTG_SEL programming if done in the regular front end - * programming sequence). - */ - while (pipe) { - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - /* When turning on the phantom pipe we want to run through the - * entire enable sequence, so apply all the "enable" flags. - */ - if (dc->hwss.apply_update_flags_for_phantom) - dc->hwss.apply_update_flags_for_phantom(pipe); - if (dc->hwss.update_phantom_vp_position) - dc->hwss.update_phantom_vp_position(dc, context, pipe); - dcn20_program_pipe(dc, pipe, context); - } - pipe = pipe->bottom_pipe; - } - } - } - - /* P-State support transitions: - * Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe - * FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally) - * Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe - * FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe - * FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes - */ - if (hwseq && hwseq->funcs.update_force_pstate) - dc->hwseq->funcs.update_force_pstate(dc, context); - - /* Only program the MALL registers after all the main and phantom pipes - * are done programming. - */ - if (hwseq->funcs.program_mall_pipe_config) - hwseq->funcs.program_mall_pipe_config(dc, context); - - /* WA to apply WM setting*/ - if (hwseq->wa.DEGVIDCN21) - dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub); - - - /* WA for stutter underflow during MPO transitions when adding 2nd plane */ - if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) { - - if (dc->current_state->stream_status[0].plane_count == 1 && - context->stream_status[0].plane_count > 1) { - - struct timing_generator *tg = dc->res_pool->timing_generators[0]; - - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false); - - hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true; - hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame = tg->funcs->get_frame_count(tg); - } - } -} - -void dcn20_prepare_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct hubbub *hubbub = dc->res_pool->hubbub; - unsigned int compbuf_size_kb = 0; - unsigned int cache_wm_a = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns; - unsigned int i; - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - false); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - // At optimize don't restore the original watermark value - if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { - context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; - break; - } - } - - /* program dchubbub watermarks: - * For assigning wm_optimized_required, use |= operator since we don't want - * to clear the value if the optimize has not happened yet - */ - dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub, - &context->bw_ctx.bw.dcn.watermarks, - dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, - false); - - // Restore the real watermark so we can commit the value to DMCUB - // DMCUB uses the "original" watermark value in SubVP MCLK switch - context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = cache_wm_a; - - /* decrease compbuf size */ - if (hubbub->funcs->program_compbuf_size) { - if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes) { - compbuf_size_kb = context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes; - dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.dml.ip.min_comp_buffer_size_kbytes); - } else { - compbuf_size_kb = context->bw_ctx.bw.dcn.compbuf_size_kb; - dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.bw.dcn.compbuf_size_kb); - } - - hubbub->funcs->program_compbuf_size(hubbub, compbuf_size_kb, false); - } -} - -void dcn20_optimize_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct hubbub *hubbub = dc->res_pool->hubbub; - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - // At optimize don't need to restore the original watermark value - if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { - context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; - break; - } - } - - /* program dchubbub watermarks */ - hubbub->funcs->program_watermarks(hubbub, - &context->bw_ctx.bw.dcn.watermarks, - dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, - true); - - if (dc->clk_mgr->dc_mode_softmax_enabled) - if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && - context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) - dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk); - - /* increase compbuf size */ - if (hubbub->funcs->program_compbuf_size) - hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true); - - if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { - dc_dmub_srv_p_state_delegate(dc, - true, context); - context->bw_ctx.bw.dcn.clk.p_state_change_support = true; - dc->clk_mgr->clks.fw_based_mclk_switching = true; - } else { - dc->clk_mgr->clks.fw_based_mclk_switching = false; - } - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - true); - if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) { - for (i = 0; i < dc->res_pool->pipe_count; ++i) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank - && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max - && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total) - pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp, - pipe_ctx->dlg_regs.min_dst_y_next_start); - } - } -} - -bool dcn20_update_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - - /* recalculate DML parameters */ - if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) - return false; - - /* apply updated bandwidth parameters */ - dc->hwss.prepare_bandwidth(dc, context); - - /* update hubp configs for all pipes */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->plane_state == NULL) - continue; - - if (pipe_ctx->top_pipe == NULL) { - bool blank = !is_pipe_tree_visible(pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->program_global_sync( - pipe_ctx->stream_res.tg, - calculate_vready_offset_for_group(pipe_ctx), - pipe_ctx->pipe_dlg_param.vstartup_start, - pipe_ctx->pipe_dlg_param.vupdate_offset, - pipe_ctx->pipe_dlg_param.vupdate_width); - - pipe_ctx->stream_res.tg->funcs->set_vtg_params( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false); - - if (pipe_ctx->prev_odm_pipe == NULL) - hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); - - if (hws->funcs.setup_vupdate_interrupt) - hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); - } - - pipe_ctx->plane_res.hubp->funcs->hubp_setup( - pipe_ctx->plane_res.hubp, - &pipe_ctx->dlg_regs, - &pipe_ctx->ttu_regs, - &pipe_ctx->rq_regs, - &pipe_ctx->pipe_dlg_param); - } - - return true; -} - -void dcn20_enable_writeback( - struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context) -{ - struct dwbc *dwb; - struct mcif_wb *mcif_wb; - struct timing_generator *optc; - - ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES); - ASSERT(wb_info->wb_enabled); - dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; - mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; - - /* set the OPTC source mux */ - optc = dc->res_pool->timing_generators[dwb->otg_inst]; - optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst); - /* set MCIF_WB buffer and arbitration configuration */ - mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height); - mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); - /* Enable MCIF_WB */ - mcif_wb->funcs->enable_mcif(mcif_wb); - /* Enable DWB */ - dwb->funcs->enable(dwb, &wb_info->dwb_params); - /* TODO: add sequence to enable/disable warmup */ -} - -void dcn20_disable_writeback( - struct dc *dc, - unsigned int dwb_pipe_inst) -{ - struct dwbc *dwb; - struct mcif_wb *mcif_wb; - - ASSERT(dwb_pipe_inst < MAX_DWB_PIPES); - dwb = dc->res_pool->dwbc[dwb_pipe_inst]; - mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst]; - - dwb->funcs->disable(dwb); - mcif_wb->funcs->disable_mcif(mcif_wb); -} - -bool dcn20_wait_for_blank_complete( - struct output_pixel_processor *opp) -{ - int counter; - - for (counter = 0; counter < 1000; counter++) { - if (opp->funcs->dpg_is_blanked(opp)) - break; - - udelay(100); - } - - if (counter == 1000) { - dm_error("DC: failed to blank crtc!\n"); - return false; - } - - return true; -} - -bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - - if (!hubp) - return false; - return hubp->funcs->dmdata_status_done(hubp); -} - -void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - - if (pipe_ctx->stream_res.dsc) { - struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; - - hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true); - while (odm_pipe) { - hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true); - odm_pipe = odm_pipe->next_odm_pipe; - } - } -} - -void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - - if (pipe_ctx->stream_res.dsc) { - struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; - - hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false); - while (odm_pipe) { - hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false); - odm_pipe = odm_pipe->next_odm_pipe; - } - } -} - -void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) -{ - struct dc_dmdata_attributes attr = { 0 }; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - - attr.dmdata_mode = DMDATA_HW_MODE; - attr.dmdata_size = - dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36; - attr.address.quad_part = - pipe_ctx->stream->dmdata_address.quad_part; - attr.dmdata_dl_delta = 0; - attr.dmdata_qos_mode = 0; - attr.dmdata_qos_level = 0; - attr.dmdata_repeat = 1; /* always repeat */ - attr.dmdata_updated = 1; - attr.dmdata_sw_data = NULL; - - hubp->funcs->dmdata_set_attributes(hubp, &attr); -} - -void dcn20_init_vm_ctx( - struct dce_hwseq *hws, - struct dc *dc, - struct dc_virtual_addr_space_config *va_config, - int vmid) -{ - struct dcn_hubbub_virt_addr_config config; - - if (vmid == 0) { - ASSERT(0); /* VMID cannot be 0 for vm context */ - return; - } - - config.page_table_start_addr = va_config->page_table_start_addr; - config.page_table_end_addr = va_config->page_table_end_addr; - config.page_table_block_size = va_config->page_table_block_size_in_bytes; - config.page_table_depth = va_config->page_table_depth; - config.page_table_base_addr = va_config->page_table_base_addr; - - dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid); -} - -int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) -{ - struct dcn_hubbub_phys_addr_config config; - - config.system_aperture.fb_top = pa_config->system_aperture.fb_top; - config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; - config.system_aperture.fb_base = pa_config->system_aperture.fb_base; - config.system_aperture.agp_top = pa_config->system_aperture.agp_top; - config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; - config.system_aperture.agp_base = pa_config->system_aperture.agp_base; - config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; - config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; - config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; - config.page_table_default_page_addr = pa_config->page_table_default_page_addr; - - return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); -} - -static bool patch_address_for_sbs_tb_stereo( - struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - bool sec_split = pipe_ctx->top_pipe && - pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; - if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && - (pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_SIDE_BY_SIDE || - pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { - *addr = plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.left_addr = - plane_state->address.grph_stereo.right_addr; - return true; - } - - if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && - plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { - plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; - plane_state->address.grph_stereo.right_addr = - plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.right_meta_addr = - plane_state->address.grph_stereo.left_meta_addr; - } - return false; -} - -void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - bool addr_patched = false; - PHYSICAL_ADDRESS_LOC addr; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - - if (plane_state == NULL) - return; - - addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); - - // Call Helper to track VMID use - vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst); - - pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( - pipe_ctx->plane_res.hubp, - &plane_state->address, - plane_state->flip_immediate); - - plane_state->status.requested_address = plane_state->address; - - if (plane_state->flip_immediate) - plane_state->status.current_address = plane_state->address; - - if (addr_patched) - pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; -} - -void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings) -{ - struct encoder_unblank_param params = {0}; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dce_hwseq *hws = link->dc->hwseq; - struct pipe_ctx *odm_pipe; - - params.opp_cnt = 1; - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - params.opp_cnt++; - } - /* only 3 items below are used by unblank */ - params.timing = pipe_ctx->stream->timing; - - params.link_settings.link_rate = link_settings->link_rate; - - if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( - pipe_ctx->stream_res.hpo_dp_stream_enc, - pipe_ctx->stream_res.tg->inst); - } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1) - params.timing.pix_clk_100hz /= 2; - pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( - pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1); - pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); - } - - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - hws->funcs.edp_backlight_control(link, true); - } -} - -void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct timing_generator *tg = pipe_ctx->stream_res.tg; - int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); - - if (start_line < 0) - start_line = 0; - - if (tg->funcs->setup_vertical_interrupt2) - tg->funcs->setup_vertical_interrupt2(tg, start_line); -} - -static void dcn20_reset_back_end_for_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - int i; - struct dc_link *link = pipe_ctx->stream->link; - const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); - - DC_LOGGER_INIT(dc->ctx->logger); - if (pipe_ctx->stream_res.stream_enc == NULL) { - pipe_ctx->stream = NULL; - return; - } - - /* DPMS may already disable or */ - /* dpms_off status is incorrect due to fastboot - * feature. When system resume from S4 with second - * screen only, the dpms_off would be true but - * VBIOS lit up eDP, so check link status too. - */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) - dc->link_srv->set_dpms_off(pipe_ctx); - else if (pipe_ctx->stream_res.audio) - dc->hwss.disable_audio_stream(pipe_ctx); - - /* free acquired resources */ - if (pipe_ctx->stream_res.audio) { - /*disable az_endpoint*/ - pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); - - /*free audio*/ - if (dc->caps.dynamic_audio == true) { - /*we have to dynamic arbitrate the audio endpoints*/ - /*we free the resource, need reset is_audio_acquired*/ - update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, - pipe_ctx->stream_res.audio, false); - pipe_ctx->stream_res.audio = NULL; - } - } - - /* by upper caller loop, parent pipe: pipe0, will be reset last. - * back end share by all pipes and will be disable only when disable - * parent pipe. - */ - if (pipe_ctx->top_pipe == NULL) { - - dc->hwss.set_abm_immediate_disable(pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); - - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); - if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) - pipe_ctx->stream_res.tg->funcs->set_odm_bypass( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, NULL); - /* TODO - convert symclk_ref_cnts for otg to a bit map to solve - * the case where the same symclk is shared across multiple otg - * instances - */ - link->phy_state.symclk_ref_cnts.otg = 0; - if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { - link_hwss->disable_link_output(link, - &pipe_ctx->link_res, pipe_ctx->stream->signal); - link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; - } - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) - break; - - if (i == dc->res_pool->pipe_count) - return; - - pipe_ctx->stream = NULL; - DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", - pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); -} - -void dcn20_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - - /* Reset Back End*/ - for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx_old->stream) - continue; - - if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) - continue; - - if (!pipe_ctx->stream || - pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { - struct clock_source *old_clk = pipe_ctx_old->clock_source; - - dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); - if (hws->funcs.enable_stream_gating) - hws->funcs.enable_stream_gating(dc, pipe_ctx_old); - if (old_clk) - old_clk->funcs->cs_power_down(old_clk); - } - } -} - -void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct mpcc_blnd_cfg blnd_cfg = {0}; - bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; - int mpcc_id; - struct mpcc *new_mpcc; - struct mpc *mpc = dc->res_pool->mpc; - struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); - - blnd_cfg.overlap_only = false; - blnd_cfg.global_gain = 0xff; - - if (per_pixel_alpha) { - blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha; - if (pipe_ctx->plane_state->global_alpha) { - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; - blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; - } else { - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; - } - } else { - blnd_cfg.pre_multiplied_alpha = false; - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; - } - - if (pipe_ctx->plane_state->global_alpha) - blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; - else - blnd_cfg.global_alpha = 0xff; - - blnd_cfg.background_color_bpc = 4; - blnd_cfg.bottom_gain_mode = 0; - blnd_cfg.top_gain = 0x1f000; - blnd_cfg.bottom_inside_gain = 0x1f000; - blnd_cfg.bottom_outside_gain = 0x1f000; - - if (pipe_ctx->plane_state->format - == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA) - blnd_cfg.pre_multiplied_alpha = false; - - /* - * TODO: remove hack - * Note: currently there is a bug in init_hw such that - * on resume from hibernate, BIOS sets up MPCC0, and - * we do mpcc_remove but the mpcc cannot go to idle - * after remove. This cause us to pick mpcc1 here, - * which causes a pstate hang for yet unknown reason. - */ - mpcc_id = hubp->inst; - - /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update && - !pipe_ctx->update_flags.bits.mpcc) { - mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - return; - } - - /* check if this MPCC is already being used */ - new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); - /* remove MPCC if being used */ - if (new_mpcc != NULL) - mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); - else - if (dc->debug.sanity_checks) - mpc->funcs->assert_mpcc_idle_before_connect( - dc->res_pool->mpc, mpcc_id); - - /* Call MPC to insert new plane */ - new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, - mpc_tree_params, - &blnd_cfg, - NULL, - NULL, - hubp->inst, - mpcc_id); - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - - ASSERT(new_mpcc != NULL); - hubp->opp_id = pipe_ctx->stream_res.opp->inst; - hubp->mpcc_id = mpcc_id; -} - -void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) -{ - enum dc_lane_count lane_count = - pipe_ctx->stream->link->cur_link_settings.lane_count; - - struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - struct dc_link *link = pipe_ctx->stream->link; - - uint32_t active_total_with_borders; - uint32_t early_control = 0; - struct timing_generator *tg = pipe_ctx->stream_res.tg; - const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); - struct dc *dc = pipe_ctx->stream->ctx->dc; - struct dtbclk_dto_params dto_params = {0}; - struct dccg *dccg = dc->res_pool->dccg; - enum phyd32clk_clock_source phyd32clk; - int dp_hpo_inst; - struct dce_hwseq *hws = dc->hwseq; - unsigned int k1_div = PIXEL_RATE_DIV_NA; - unsigned int k2_div = PIXEL_RATE_DIV_NA; - - if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - if (dc->hwseq->funcs.setup_hpo_hw_control) - dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, true); - } - - if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; - dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst); - - phyd32clk = get_phyd32clk_src(link); - dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); - - dto_params.otg_inst = tg->inst; - dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; - dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); - dto_params.timing = &pipe_ctx->stream->timing; - dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); - dccg->funcs->set_dtbclk_dto(dccg, &dto_params); - } - if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { - hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); - - dc->res_pool->dccg->funcs->set_pixel_rate_div( - dc->res_pool->dccg, - pipe_ctx->stream_res.tg->inst, - k1_div, k2_div); - } - - link_hwss->setup_stream_encoder(pipe_ctx); - - if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) { - if (dc->hwss.program_dmdata_engine) - dc->hwss.program_dmdata_engine(pipe_ctx); - } - - dc->hwss.update_info_frame(pipe_ctx); - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME); - - /* enable early control to avoid corruption on DP monitor*/ - active_total_with_borders = - timing->h_addressable - + timing->h_border_left - + timing->h_border_right; - - if (lane_count != 0) - early_control = active_total_with_borders % lane_count; - - if (early_control == 0) - early_control = lane_count; - - tg->funcs->set_early_control(tg, early_control); - - if (dc->hwseq->funcs.set_pixels_per_cycle) - dc->hwseq->funcs.set_pixels_per_cycle(pipe_ctx); -} - -void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - bool enable = false; - struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; - enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) - ? dmdata_dp - : dmdata_hdmi; - - /* if using dynamic meta, don't set up generic infopackets */ - if (pipe_ctx->stream->dmdata_address.quad_part != 0) { - pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; - enable = true; - } - - if (!hubp) - return; - - if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) - return; - - stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, - hubp->inst, mode); -} - -void dcn20_fpga_init_hw(struct dc *dc) -{ - int i, j; - struct dce_hwseq *hws = dc->hwseq; - struct resource_pool *res_pool = dc->res_pool; - struct dc_state *context = dc->current_state; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - //Enable ability to power gate / don't force power on permanently - hws->funcs.enable_power_gating_plane(hws, true); - - // Specific to FPGA dccg and registers - REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); - REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); - - hws->funcs.dccg_init(hws); - - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); - if (REG(REFCLK_CNTL)) - REG_WRITE(REFCLK_CNTL, 0); - // - - - /* Blank pixel data with OPP DPG */ - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) - dcn20_init_blank(dc, tg); - } - - for (i = 0; i < res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->lock(tg); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct dpp *dpp = res_pool->dpps[i]; - - dpp->funcs->dpp_reset(dpp); - } - - /* Reset all MPCC muxes */ - res_pool->mpc->funcs->mpc_init(res_pool->mpc); - - /* initialize OPP mpc_tree parameter */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; - res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - for (j = 0; j < MAX_PIPES; j++) - res_pool->opps[i]->mpcc_disconnect_pending[j] = false; - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - struct dpp *dpp = dc->res_pool->dpps[i]; - - pipe_ctx->stream_res.tg = tg; - pipe_ctx->pipe_idx = i; - - pipe_ctx->plane_res.hubp = hubp; - pipe_ctx->plane_res.dpp = dpp; - pipe_ctx->plane_res.mpcc_inst = dpp->inst; - hubp->mpcc_id = dpp->inst; - hubp->opp_id = OPP_ID_INVALID; - hubp->power_gated = false; - pipe_ctx->stream_res.opp = NULL; - - hubp->funcs->hubp_init(hubp); - - //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; - //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - /*to do*/ - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); - } - - /* initialize DWB pointer to MCIF_WB */ - for (i = 0; i < res_pool->res_cap->num_dwb; i++) - res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; - - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->unlock(tg); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - dc->hwss.disable_plane(dc, pipe_ctx); - - pipe_ctx->stream_res.tg = NULL; - pipe_ctx->plane_res.hubp = NULL; - } - - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - tg->funcs->tg_init(tg); - } - - if (dc->res_pool->hubbub->funcs->init_crb) - dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); -} - -void dcn20_set_disp_pattern_generator(const struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum controller_dp_test_pattern test_pattern, - enum controller_dp_color_space color_space, - enum dc_color_depth color_depth, - const struct tg_color *solid_color, - int width, int height, int offset) -{ - pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern, - color_space, color_depth, solid_color, width, height, offset); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h deleted file mode 100644 index ab02e4e9c8c2..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h +++ /dev/null @@ -1,153 +0,0 @@ -/* -* Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN20_H__ -#define __DC_HWSS_DCN20_H__ - -#include "hw_sequencer_private.h" - -bool dcn20_set_blend_lut( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); -bool dcn20_set_shaper_3dlut( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); -void dcn20_program_front_end_for_ctx( - struct dc *dc, - struct dc_state *context); -void dcn20_post_unlock_program_front_end( - struct dc *dc, - struct dc_state *context); -void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); -bool dcn20_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); -bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); -void dcn20_program_output_csc(struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, - int opp_id); -void dcn20_enable_stream(struct pipe_ctx *pipe_ctx); -void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings); -void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_disable_pixel_data( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank); -void dcn20_blank_pixel_data( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank); -void dcn20_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -void dcn20_prepare_bandwidth( - struct dc *dc, - struct dc_state *context); -void dcn20_optimize_bandwidth( - struct dc *dc, - struct dc_state *context); -bool dcn20_update_bandwidth( - struct dc *dc, - struct dc_state *context); -void dcn20_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context); -enum dc_status dcn20_enable_stream_timing( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc); -void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_init_blank( - struct dc *dc, - struct timing_generator *tg); -void dcn20_disable_vga( - struct dce_hwseq *hws); -void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn20_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable); -void dcn20_dpp_pg_control( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on); -void dcn20_hubp_pg_control( - struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on); -void dcn20_program_triple_buffer( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enable_triple_buffer); -void dcn20_enable_writeback( - struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context); -void dcn20_disable_writeback( - struct dc *dc, - unsigned int dwb_pipe_inst); -void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); -bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx); -void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx); -void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx); -void dcn20_init_vm_ctx( - struct dce_hwseq *hws, - struct dc *dc, - struct dc_virtual_addr_space_config *va_config, - int vmid); -void dcn20_set_flip_control_gsl( - struct pipe_ctx *pipe_ctx, - bool flip_immediate); -void dcn20_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on); -void dcn20_fpga_init_hw(struct dc *dc); -bool dcn20_wait_for_blank_complete( - struct output_pixel_processor *opp); -void dcn20_dccg_init(struct dce_hwseq *hws); -int dcn20_init_sys_ctx(struct dce_hwseq *hws, - struct dc *dc, - struct dc_phy_addr_space_config *pa_config); - -void dcn20_set_disp_pattern_generator(const struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum controller_dp_test_pattern test_pattern, - enum controller_dp_color_space color_space, - enum dc_color_depth color_depth, - const struct tg_color *solid_color, - int width, int height, int offset); - -void dcn20_setup_gsl_group_as_lock( - const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool enable); - -#endif /* __DC_HWSS_DCN20_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c index 15b66ed66ad6..884e3e323338 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c @@ -23,9 +23,9 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" -#include "dcn20_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" #include "dcn20_init.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 768fef798cf1..7eda4bbcd8ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -45,8 +45,8 @@ #include "irq/dcn20/irq_service_dcn20.h" #include "dcn20_dpp.h" #include "dcn20_optc.h" -#include "dcn20_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn20/dcn20_hwseq.h" +#include "dce110/dce110_hwseq.h" #include "dcn10/dcn10_resource.h" #include "dcn20_opp.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile index 5c9ce2cebb0f..3a41a97b0729 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT # # Makefile for DCN. -DCN201 = dcn201_init.o dcn201_resource.o dcn201_hwseq.o \ +DCN201 = dcn201_init.o dcn201_resource.o \ dcn201_hubbub.o\ dcn201_mpc.o dcn201_hubp.o dcn201_opp.o dcn201_optc.o dcn201_dpp.o \ dcn201_dccg.o dcn201_link_encoder.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c deleted file mode 100644 index 9e027db6d752..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "basics/dc_common.h" -#include "core_types.h" -#include "resource.h" -#include "dcn201_hwseq.h" -#include "dcn201_optc.h" -#include "dce/dce_hwseq.h" -#include "hubp.h" -#include "dchubbub.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "dccg.h" -#include "clk_mgr.h" -#include "reg_helper.h" - -#define CTX \ - hws->ctx - -#define REG(reg)\ - hws->regs->reg - -#define DC_LOGGER \ - dc->ctx->logger - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -static bool patch_address_for_sbs_tb_stereo( - struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) -{ - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - bool sec_split = pipe_ctx->top_pipe && - pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; - - if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && - (pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_SIDE_BY_SIDE || - pipe_ctx->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { - *addr = plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.left_addr = - plane_state->address.grph_stereo.right_addr; - return true; - } else { - if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && - plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { - plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; - plane_state->address.grph_stereo.right_addr = - plane_state->address.grph_stereo.left_addr; - plane_state->address.grph_stereo.right_meta_addr = - plane_state->address.grph_stereo.left_meta_addr; - } - } - return false; -} - -static bool gpu_addr_to_uma(struct dce_hwseq *hwseq, - PHYSICAL_ADDRESS_LOC *addr) -{ - bool is_in_uma; - - if (hwseq->fb_base.quad_part <= addr->quad_part && - addr->quad_part < hwseq->fb_top.quad_part) { - addr->quad_part -= hwseq->fb_base.quad_part; - addr->quad_part += hwseq->fb_offset.quad_part; - is_in_uma = true; - } else if (hwseq->fb_offset.quad_part <= addr->quad_part && - addr->quad_part <= hwseq->uma_top.quad_part) { - is_in_uma = true; - } else { - is_in_uma = false; - } - return is_in_uma; -} - -static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq, - struct dc_plane_address *addr) -{ - switch (addr->type) { - case PLN_ADDR_TYPE_GRAPHICS: - gpu_addr_to_uma(hwseq, &addr->grph.addr); - gpu_addr_to_uma(hwseq, &addr->grph.meta_addr); - break; - case PLN_ADDR_TYPE_GRPH_STEREO: - gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr); - gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr); - gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr); - gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr); - break; - case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE: - gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr); - gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr); - gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr); - gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - bool addr_patched = false; - PHYSICAL_ADDRESS_LOC addr; - struct dc_plane_state *plane_state = pipe_ctx->plane_state; - struct dce_hwseq *hws = dc->hwseq; - struct dc_plane_address uma; - - if (plane_state == NULL) - return; - - uma = plane_state->address; - addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); - - plane_address_in_gpu_space_to_uma(hws, &uma); - - pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( - pipe_ctx->plane_res.hubp, - &uma, - plane_state->flip_immediate); - - plane_state->status.requested_address = plane_state->address; - - if (plane_state->flip_immediate) - plane_state->status.current_address = plane_state->address; - - if (addr_patched) - pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; -} - -/* Blank pixel data during initialization */ -void dcn201_init_blank( - struct dc *dc, - struct timing_generator *tg) -{ - struct dce_hwseq *hws = dc->hwseq; - enum dc_color_space color_space; - struct tg_color black_color = {0}; - struct output_pixel_processor *opp = NULL; - uint32_t num_opps, opp_id_src0, opp_id_src1; - uint32_t otg_active_width, otg_active_height; - - /* program opp dpg blank color */ - color_space = COLOR_SPACE_SRGB; - color_space_to_black_color(dc, color_space, &black_color); - - /* get the OTG active size */ - tg->funcs->get_otg_active_size(tg, - &otg_active_width, - &otg_active_height); - - /* get the OPTC source */ - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); - opp = dc->res_pool->opps[opp_id_src0]; - - opp->funcs->opp_set_disp_pattern_generator( - opp, - CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - COLOR_DEPTH_UNDEFINED, - &black_color, - otg_active_width, - otg_active_height, - 0); - - hws->funcs.wait_for_blank_complete(opp); -} - -static void read_mmhub_vm_setup(struct dce_hwseq *hws) -{ - uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE); - uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP); - uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET); - - /* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */ - fb_top++; - - /* bit 23:0 in register map to bit 47:24 in address */ - hws->fb_base.low_part = fb_base; - hws->fb_base.quad_part <<= 24; - - hws->fb_top.low_part = fb_top; - hws->fb_top.quad_part <<= 24; - hws->fb_offset.low_part = fb_offset; - hws->fb_offset.quad_part <<= 24; - - hws->uma_top.quad_part = hws->fb_top.quad_part - - hws->fb_base.quad_part + hws->fb_offset.quad_part; -} - -void dcn201_init_hw(struct dc *dc) -{ - int i, j; - struct dce_hwseq *hws = dc->hwseq; - struct resource_pool *res_pool = dc->res_pool; - struct dc_state *context = dc->current_state; - - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - hws->funcs.bios_golden_init(dc); - - if (dc->ctx->dc_bios->fw_info_valid) { - res_pool->ref_clocks.xtalin_clock_inKhz = - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - - if (res_pool->dccg && res_pool->hubbub) { - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - link->link_enc->funcs->hw_init(link->link_enc); - } - if (hws->fb_offset.quad_part == 0) - read_mmhub_vm_setup(hws); - - /* Blank pixel data with OPP DPG */ - for (i = 0; i < res_pool->timing_generator_count; i++) { - struct timing_generator *tg = res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) { - dcn201_init_blank(dc, tg); - } - } - - for (i = 0; i < res_pool->timing_generator_count; i++) { - struct timing_generator *tg = res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->lock(tg); - } - - for (i = 0; i < res_pool->pipe_count; i++) { - struct dpp *dpp = res_pool->dpps[i]; - - dpp->funcs->dpp_reset(dpp); - } - - /* Reset all MPCC muxes */ - res_pool->mpc->funcs->mpc_init(res_pool->mpc); - - /* initialize OPP mpc_tree parameter */ - for (i = 0; i < res_pool->res_cap->num_opp; i++) { - res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; - res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - for (j = 0; j < MAX_PIPES; j++) - res_pool->opps[i]->mpcc_disconnect_pending[j] = false; - } - - for (i = 0; i < res_pool->timing_generator_count; i++) { - struct timing_generator *tg = res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = res_pool->hubps[i]; - struct dpp *dpp = res_pool->dpps[i]; - - pipe_ctx->stream_res.tg = tg; - pipe_ctx->pipe_idx = i; - - pipe_ctx->plane_res.hubp = hubp; - pipe_ctx->plane_res.dpp = dpp; - pipe_ctx->plane_res.mpcc_inst = dpp->inst; - hubp->mpcc_id = dpp->inst; - hubp->opp_id = OPP_ID_INVALID; - hubp->power_gated = false; - pipe_ctx->stream_res.opp = NULL; - - hubp->funcs->hubp_init(hubp); - - res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - pipe_ctx->stream_res.opp = res_pool->opps[i]; - /*To do: number of MPCC != number of opp*/ - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); - } - - /* initialize DWB pointer to MCIF_WB */ - for (i = 0; i < res_pool->res_cap->num_dwb; i++) - res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; - - for (i = 0; i < res_pool->timing_generator_count; i++) { - struct timing_generator *tg = res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->unlock(tg); - } - - for (i = 0; i < res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - dc->hwss.disable_plane(dc, pipe_ctx); - - pipe_ctx->stream_res.tg = NULL; - pipe_ctx->plane_res.hubp = NULL; - } - - for (i = 0; i < res_pool->timing_generator_count; i++) { - struct timing_generator *tg = res_pool->timing_generators[i]; - - tg->funcs->tg_init(tg); - } - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } -} - -/* trigger HW to start disconnect plane from stream on the next vsync */ -void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - int dpp_id = pipe_ctx->plane_res.dpp->inst; - struct mpc *mpc = dc->res_pool->mpc; - struct mpc_tree *mpc_tree_params; - struct mpcc *mpcc_to_remove = NULL; - struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; - bool mpcc_removed = false; - - mpc_tree_params = &(opp->mpc_tree_params); - - /* check if this plane is being used by an MPCC in the secondary blending chain */ - if (mpc->funcs->get_mpcc_for_dpp_from_secondary) - mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id); - - /* remove MPCC from secondary if being used */ - if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) { - mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove); - mpcc_removed = true; - } - - /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */ - mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); - if (mpcc_to_remove != NULL) { - mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - mpcc_removed = true; - } - - /*Already reset*/ - if (mpcc_removed == false) - return; - - if (opp != NULL) - opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - - dc->optimized_required = true; - - if (hubp->funcs->hubp_disconnect) - hubp->funcs->hubp_disconnect(hubp); - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct mpcc_blnd_cfg blnd_cfg; - bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; - int mpcc_id, dpp_id; - struct mpcc *new_mpcc; - struct mpcc *remove_mpcc = NULL; - struct mpc *mpc = dc->res_pool->mpc; - struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); - - if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { - get_hdr_visual_confirm_color( - pipe_ctx, &blnd_cfg.black_color); - } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { - get_surface_visual_confirm_color( - pipe_ctx, &blnd_cfg.black_color); - } else { - color_space_to_black_color( - dc, pipe_ctx->stream->output_color_space, - &blnd_cfg.black_color); - } - - if (per_pixel_alpha) - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; - else - blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; - - blnd_cfg.overlap_only = false; - - if (pipe_ctx->plane_state->global_alpha_value) - blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; - else - blnd_cfg.global_alpha = 0xff; - - blnd_cfg.global_gain = 0xff; - blnd_cfg.background_color_bpc = 4; - blnd_cfg.bottom_gain_mode = 0; - blnd_cfg.top_gain = 0x1f000; - blnd_cfg.bottom_inside_gain = 0x1f000; - blnd_cfg.bottom_outside_gain = 0x1f000; - /*the input to MPCC is RGB*/ - blnd_cfg.black_color.color_b_cb = 0; - blnd_cfg.black_color.color_g_y = 0; - blnd_cfg.black_color.color_r_cr = 0; - - /* DCN1.0 has output CM before MPC which seems to screw with - * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2. - */ - blnd_cfg.pre_multiplied_alpha = per_pixel_alpha; - - /* - * TODO: remove hack - * Note: currently there is a bug in init_hw such that - * on resume from hibernate, BIOS sets up MPCC0, and - * we do mpcc_remove but the mpcc cannot go to idle - * after remove. This cause us to pick mpcc1 here, - * which causes a pstate hang for yet unknown reason. - */ - dpp_id = hubp->inst; - mpcc_id = dpp_id; - - /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update) { - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); - return; - } - - /* check if this plane is being used by an MPCC in the secondary blending chain */ - if (mpc->funcs->get_mpcc_for_dpp_from_secondary) - remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id); - - /* remove MPCC from secondary if being used */ - if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary) - mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc); - - /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */ - remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); - /* remove MPCC if being used */ - - if (remove_mpcc != NULL) - mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc); - else - if (dc->debug.sanity_checks) - mpc->funcs->assert_mpcc_idle_before_connect( - dc->res_pool->mpc, mpcc_id); - - /* Call MPC to insert new plane */ - dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); - new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, - mpc_tree_params, - &blnd_cfg, - NULL, - NULL, - dpp_id, - mpcc_id); - - ASSERT(new_mpcc != NULL); - hubp->opp_id = pipe_ctx->stream_res.opp->inst; - hubp->mpcc_id = mpcc_id; -} - -void dcn201_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock) -{ - struct dce_hwseq *hws = dc->hwseq; - /* use TG master update lock to lock everything on the TG - * therefore only top pipe need to lock - */ - if (pipe->top_pipe) - return; - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); - - if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { - if (lock) - pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); - else - pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg); - } else { - if (lock) - pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); - else - pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); - } - - if (dc->debug.sanity_checks) - hws->funcs.verify_allow_pstate_change_high(dc); -} - -void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx) -{ - struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; - - gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address); - - pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.hubp, attributes); - pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.dpp, attributes); -} - -void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) -{ - struct dc_dmdata_attributes attr = { 0 }; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - - gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, - &pipe_ctx->stream->dmdata_address); - - attr.dmdata_mode = DMDATA_HW_MODE; - attr.dmdata_size = - dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36; - attr.address.quad_part = - pipe_ctx->stream->dmdata_address.quad_part; - attr.dmdata_dl_delta = 0; - attr.dmdata_qos_mode = 0; - attr.dmdata_qos_level = 0; - attr.dmdata_repeat = 1; /* always repeat */ - attr.dmdata_updated = 1; - attr.dmdata_sw_data = NULL; - - hubp->funcs->dmdata_set_attributes(hubp, &attr); -} - -void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings) -{ - struct encoder_unblank_param params = { { 0 } }; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dce_hwseq *hws = link->dc->hwseq; - - /* only 3 items below are used by unblank */ - params.timing = pipe_ctx->stream->timing; - - params.link_settings.link_rate = link_settings->link_rate; - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - /*check whether it is half the rate*/ - if (optc201_is_two_pixels_per_containter(&stream->timing)) - params.timing.pix_clk_100hz /= 2; - - pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); - } - - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { - hws->funcs.edp_backlight_control(link, true); - } -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.h deleted file mode 100644 index 26cd62be6418..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2021 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN201_H__ -#define __DC_HWSS_DCN201_H__ - -#include "hw_sequencer_private.h" - -void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx); -void dcn201_init_hw(struct dc *dc); -void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings); -void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx); -void dcn201_pipe_control_lock( - struct dc *dc, - struct pipe_ctx *pipe, - bool lock); -void dcn201_init_blank( - struct dc *dc, - struct timing_generator *tg); -#endif /* __DC_HWSS_DCN201_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c index 92dd4cddbab8..a13bf6c9386e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c @@ -23,10 +23,10 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" -#include "dcn201_hwseq.h" +#include "dcn201/dcn201_hwseq.h" #include "dcn201_init.h" static const struct hw_sequencer_funcs dcn201_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c index 9389bd8df42b..a11b2f6afe4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c @@ -43,8 +43,8 @@ #include "dcn201/dcn201_hubbub.h" #include "dcn201_dccg.h" #include "dcn201_optc.h" -#include "dcn201_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dcn201/dcn201_hwseq.h" +#include "dce110/dce110_hwseq.h" #include "dcn201_opp.h" #include "dcn201/dcn201_link_encoder.h" #include "dcn20/dcn20_stream_encoder.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile index 0dc06e428999..ce1be0afae4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile @@ -3,7 +3,7 @@ # Makefile for DCN21. DCN21 = dcn21_init.o dcn21_hubp.o dcn21_hubbub.o dcn21_resource.o \ - dcn21_hwseq.o dcn21_link_encoder.o dcn21_dccg.o + dcn21_link_encoder.o dcn21_dccg.o AMD_DAL_DCN21 = $(addprefix $(AMDDALPATH)/dc/dcn21/,$(DCN21)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c deleted file mode 100644 index 43463d08f21b..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dm_helpers.h" -#include "core_types.h" -#include "resource.h" -#include "dce/dce_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" -#include "dcn21_hwseq.h" -#include "vmid.h" -#include "reg_helper.h" -#include "hw/clk_mgr.h" -#include "dc_dmub_srv.h" -#include "abm.h" -#include "link.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -/* Temporary read settings, future will get values from kmd directly */ -static void mmhub_update_page_table_config(struct dcn_hubbub_phys_addr_config *config, - struct dce_hwseq *hws) -{ - uint32_t page_table_base_hi; - uint32_t page_table_base_lo; - - REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, - PAGE_DIRECTORY_ENTRY_HI32, &page_table_base_hi); - REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, - PAGE_DIRECTORY_ENTRY_LO32, &page_table_base_lo); - - config->gart_config.page_table_base_addr = ((uint64_t)page_table_base_hi << 32) | page_table_base_lo; - -} - -int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) -{ - struct dcn_hubbub_phys_addr_config config; - - config.system_aperture.fb_top = pa_config->system_aperture.fb_top; - config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; - config.system_aperture.fb_base = pa_config->system_aperture.fb_base; - config.system_aperture.agp_top = pa_config->system_aperture.agp_top; - config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; - config.system_aperture.agp_base = pa_config->system_aperture.agp_base; - config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; - config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; - config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; - - mmhub_update_page_table_config(&config, hws); - - return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); -} - -// work around for Renoir s0i3, if register is programmed, bypass golden init. - -bool dcn21_s0i3_golden_init_wa(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - uint32_t value = 0; - - value = REG_READ(MICROSECOND_TIME_BASE_DIV); - - return value != 0x00120464; -} - -void dcn21_exit_optimized_pwr_state( - const struct dc *dc, - struct dc_state *context) -{ - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - false); -} - -void dcn21_optimize_pwr_state( - const struct dc *dc, - struct dc_state *context) -{ - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - context, - true); -} - -/* If user hotplug a HDMI monitor while in monitor off, - * OS will do a mode set (with output timing) but keep output off. - * In this case DAL will ask vbios to power up the pll in the PHY. - * If user unplug the monitor (while we are on monitor off) or - * system attempt to enter modern standby (which we will disable PLL), - * PHY will hang on the next mode set attempt. - * if enable PLL follow by disable PLL (without executing lane enable/disable), - * RDPCS_PHY_DP_MPLLB_STATE remains 1, - * which indicate that PLL disable attempt actually didn't go through. - * As a workaround, insert PHY lane enable/disable before PLL disable. - */ -void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx) -{ - if (!pipe_ctx->stream->dpms_off) - return; - - pipe_ctx->stream->dpms_off = false; - pipe_ctx->stream->ctx->dc->link_srv->set_dpms_on(context, pipe_ctx); - pipe_ctx->stream->ctx->dc->link_srv->set_dpms_off(pipe_ctx); - pipe_ctx->stream->dpms_off = true; -} - -static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) -{ - union dmub_rb_cmd cmd; - struct dc_context *dc = abm->ctx; - uint32_t ramping_boundary = 0xFFFF; - - memset(&cmd, 0, sizeof(cmd)); - cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; - cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; - cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; - cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; - cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; - cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; - cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data); - - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - - return true; -} - -static void dmub_abm_set_backlight(struct dc_context *dc, uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp, uint32_t panel_inst) -{ - union dmub_rb_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.abm_set_backlight.header.type = DMUB_CMD__ABM; - cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT; - cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp; - cmd.abm_set_backlight.abm_set_backlight_data.backlight_user_level = backlight_pwm_u16_16; - cmd.abm_set_backlight.abm_set_backlight_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1; - cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst); - cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); - - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); -} - -void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) -{ - struct abm *abm = pipe_ctx->stream_res.abm; - uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; - struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; - - struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; - - if (dmcu) { - dce110_set_abm_immediate_disable(pipe_ctx); - return; - } - - if (abm && panel_cntl) { - if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, - panel_cntl->inst); - } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, panel_cntl->inst); - } - panel_cntl->funcs->store_backlight_level(panel_cntl); - } -} - -void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) -{ - struct abm *abm = pipe_ctx->stream_res.abm; - uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; - struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; - struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; - - if (dmcu) { - dce110_set_pipe(pipe_ctx); - return; - } - - if (abm && panel_cntl) { - if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); - } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); - } - } -} - -bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp) -{ - struct dc_context *dc = pipe_ctx->stream->ctx; - struct abm *abm = pipe_ctx->stream_res.abm; - struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; - - if (dc->dc->res_pool->dmcu) { - dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp); - return true; - } - - if (abm != NULL) { - uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; - - if (abm && panel_cntl) { - if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); - } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); - } - } - } - - if (abm && abm->funcs && abm->funcs->set_backlight_level_pwm) - abm->funcs->set_backlight_level_pwm(abm, backlight_pwm_u16_16, - frame_ramp, 0, panel_cntl->inst); - else - dmub_abm_set_backlight(dc, backlight_pwm_u16_16, frame_ramp, panel_cntl->inst); - - return true; -} - -bool dcn21_is_abm_supported(struct dc *dc, - struct dc_state *context, struct dc_stream_state *stream) -{ - int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == stream && - (pipe_ctx->prev_odm_pipe == NULL && pipe_ctx->next_odm_pipe == NULL)) - return true; - } - return false; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.h deleted file mode 100644 index 9cee9bdb8de9..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -* Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN21_H__ -#define __DC_HWSS_DCN21_H__ - -#include "hw_sequencer_private.h" - -struct dc; - -int dcn21_init_sys_ctx(struct dce_hwseq *hws, - struct dc *dc, - struct dc_phy_addr_space_config *pa_config); - -bool dcn21_s0i3_golden_init_wa(struct dc *dc); - -void dcn21_exit_optimized_pwr_state( - const struct dc *dc, - struct dc_state *context); - -void dcn21_optimize_pwr_state( - const struct dc *dc, - struct dc_state *context); - -void dcn21_PLAT_58856_wa(struct dc_state *context, - struct pipe_ctx *pipe_ctx); - -void dcn21_set_pipe(struct pipe_ctx *pipe_ctx); -void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx); -bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); -bool dcn21_is_abm_supported(struct dc *dc, - struct dc_state *context, struct dc_stream_state *stream); - -#endif /* __DC_HWSS_DCN21_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c index 647e666f692a..18249c6b6d81 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c @@ -23,10 +23,10 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" -#include "dcn21_hwseq.h" +#include "dcn21/dcn21_hwseq.h" #include "dcn21_init.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index d8d77dd8a6dd..58a0d37e9523 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -49,7 +49,7 @@ #include "dcn20/dcn20_dpp.h" #include "dcn20/dcn20_optc.h" #include "dcn21/dcn21_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn20/dcn20_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn21/dcn21_link_encoder.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile index 4a3e9e47b6b6..af4d2065d2c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile @@ -30,7 +30,6 @@ DCN30 := \ dcn30_dpp.o \ dcn30_optc.o \ dcn30_dccg.o \ - dcn30_hwseq.o \ dcn30_mpc.o dcn30_vpg.o \ dcn30_afmt.o \ dcn30_dio_stream_encoder.o \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c deleted file mode 100644 index af9a9fc7db48..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * Copyright 2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - - -#include "dm_services.h" -#include "dm_helpers.h" -#include "core_types.h" -#include "resource.h" -#include "dcn30_hwseq.h" -#include "dccg.h" -#include "dce/dce_hwseq.h" -#include "dcn30_mpc.h" -#include "dcn30_dpp.h" -#include "dcn10/dcn10_cm_common.h" -#include "dcn30_cm_common.h" -#include "reg_helper.h" -#include "abm.h" -#include "clk_mgr.h" -#include "hubp.h" -#include "dchubbub.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "mcif_wb.h" -#include "dc_dmub_srv.h" -#include "link_hwss.h" -#include "dpcd_defs.h" -#include "../dcn20/dcn20_hwseq.h" -#include "dcn30_resource.h" -#include "link.h" - - - - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg -#define DC_LOGGER \ - dc->ctx->logger - - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -bool dcn30_set_blend_lut( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - bool result = true; - struct pwl_params *blend_lut = NULL; - - if (plane_state->blend_tf) { - if (plane_state->blend_tf->type == TF_TYPE_HWPWL) - blend_lut = &plane_state->blend_tf->pwl; - else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm3_helper_translate_curve_to_hw_format( - plane_state->blend_tf, &dpp_base->regamma_params, false); - blend_lut = &dpp_base->regamma_params; - } - } - result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut); - - return result; -} - -static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; - bool result = false; - int acquired_rmu = 0; - int mpcc_id_projected = 0; - - const struct pwl_params *shaper_lut = NULL; - //get the shaper lut params - if (stream->func_shaper) { - if (stream->func_shaper->type == TF_TYPE_HWPWL) { - shaper_lut = &stream->func_shaper->pwl; - } else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm_helper_translate_curve_to_hw_format(stream->ctx, stream->func_shaper, - &dpp_base->shaper_params, true); - shaper_lut = &dpp_base->shaper_params; - } - } - - if (stream->lut3d_func && - stream->lut3d_func->state.bits.initialized == 1 && - stream->lut3d_func->state.bits.rmu_idx_valid == 1) { - if (stream->lut3d_func->state.bits.rmu_mux_num == 0) - mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux; - else if (stream->lut3d_func->state.bits.rmu_mux_num == 1) - mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu1_mux; - else if (stream->lut3d_func->state.bits.rmu_mux_num == 2) - mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux; - if (mpcc_id_projected != mpcc_id) - BREAK_TO_DEBUGGER(); - /* find the reason why logical layer assigned a different - * mpcc_id into acquire_post_bldn_3dlut - */ - acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id, - stream->lut3d_func->state.bits.rmu_mux_num); - if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num) - BREAK_TO_DEBUGGER(); - - result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d, - stream->lut3d_func->state.bits.rmu_mux_num); - result = mpc->funcs->program_shaper(mpc, shaper_lut, - stream->lut3d_func->state.bits.rmu_mux_num); - } else { - // loop through the available mux and release the requested mpcc_id - mpc->funcs->release_rmu(mpc, mpcc_id); - } - - return result; -} - -bool dcn30_set_input_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) -{ - struct dce_hwseq *hws = dc->hwseq; - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - enum dc_transfer_func_predefined tf; - bool result = true; - struct pwl_params *params = NULL; - - if (dpp_base == NULL || plane_state == NULL) - return false; - - tf = TRANSFER_FUNCTION_UNITY; - - if (plane_state->in_transfer_func && - plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED) - tf = plane_state->in_transfer_func->tf; - - dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf); - - if (plane_state->in_transfer_func) { - if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL) - params = &plane_state->in_transfer_func->pwl; - else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func, - &dpp_base->degamma_params, false)) - params = &dpp_base->degamma_params; - } - - result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); - - if (pipe_ctx->stream_res.opp && pipe_ctx->stream_res.opp->ctx) { - if (dpp_base->funcs->dpp_program_blnd_lut) - hws->funcs.set_blend_lut(pipe_ctx, plane_state); - if (dpp_base->funcs->dpp_program_shaper_lut && - dpp_base->funcs->dpp_program_3dlut) - hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state); - } - - return result; -} - -void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx) -{ - int i = 0; - struct dpp_grph_csc_adjustment dpp_adjust; - struct mpc_grph_gamut_adjustment mpc_adjust; - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; - - memset(&dpp_adjust, 0, sizeof(dpp_adjust)); - dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - - if (pipe_ctx->plane_state && - pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { - dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) - dpp_adjust.temperature_matrix[i] = - pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; - } - - pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, - &dpp_adjust); - - memset(&mpc_adjust, 0, sizeof(mpc_adjust)); - mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - - if (pipe_ctx->top_pipe == NULL) { - if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { - mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; - for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) - mpc_adjust.temperature_matrix[i] = - pipe_ctx->stream->gamut_remap_matrix.matrix[i]; - } - } - - mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust); -} - -bool dcn30_set_output_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) -{ - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; - struct pwl_params *params = NULL; - bool ret = false; - - /* program OGAM or 3DLUT only for the top pipe*/ - if (pipe_ctx->top_pipe == NULL) { - /*program rmu shaper and 3dlut in MPC*/ - ret = dcn30_set_mpc_shaper_3dlut(pipe_ctx, stream); - if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) { - if (stream->out_transfer_func->type == TF_TYPE_HWPWL) - params = &stream->out_transfer_func->pwl; - else if (pipe_ctx->stream->out_transfer_func->type == - TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format( - stream->out_transfer_func, - &mpc->blender_params, false)) - params = &mpc->blender_params; - /* there are no ROM LUTs in OUTGAM */ - if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) - BREAK_TO_DEBUGGER(); - } - } - - mpc->funcs->set_output_gamma(mpc, mpcc_id, params); - return ret; -} - -static void dcn30_set_writeback( - struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context) -{ - struct mcif_wb *mcif_wb; - struct mcif_buf_params *mcif_buf_params; - - ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES); - ASSERT(wb_info->wb_enabled); - ASSERT(wb_info->mpcc_inst >= 0); - ASSERT(wb_info->mpcc_inst < dc->res_pool->mpcc_count); - mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; - mcif_buf_params = &wb_info->mcif_buf_params; - - /* set DWB MPC mux */ - dc->res_pool->mpc->funcs->set_dwb_mux(dc->res_pool->mpc, - wb_info->dwb_pipe_inst, wb_info->mpcc_inst); - /* set MCIF_WB buffer and arbitration configuration */ - mcif_wb->funcs->config_mcif_buf(mcif_wb, mcif_buf_params, wb_info->dwb_params.dest_height); - mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); -} - -void dcn30_update_writeback( - struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context) -{ - struct dwbc *dwb; - dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; - DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ - __func__, wb_info->dwb_pipe_inst,\ - wb_info->mpcc_inst); - - dcn30_set_writeback(dc, wb_info, context); - - /* update DWB */ - dwb->funcs->update(dwb, &wb_info->dwb_params); -} - -bool dcn30_mmhubbub_warmup( - struct dc *dc, - unsigned int num_dwb, - struct dc_writeback_info *wb_info) -{ - struct dwbc *dwb; - struct mcif_wb *mcif_wb; - struct mcif_warmup_params warmup_params = {0}; - unsigned int i, i_buf; - /*make sure there is no active DWB eanbled */ - for (i = 0; i < num_dwb; i++) { - dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst]; - if (dwb->dwb_is_efc_transition || dwb->dwb_is_drc) { - /*can not do warmup while any dwb enabled*/ - return false; - } - } - - if (wb_info->mcif_warmup_params.p_vmid == 0) - return false; - - /*check whether this is new interface: warmup big buffer once*/ - if (wb_info->mcif_warmup_params.start_address.quad_part != 0 && - wb_info->mcif_warmup_params.region_size != 0) { - /*mmhubbub is shared, so it does not matter which MCIF*/ - mcif_wb = dc->res_pool->mcif_wb[0]; - /*warmup a big chunk of VM buffer at once*/ - warmup_params.start_address.quad_part = wb_info->mcif_warmup_params.start_address.quad_part; - warmup_params.address_increment = wb_info->mcif_warmup_params.region_size; - warmup_params.region_size = wb_info->mcif_warmup_params.region_size; - warmup_params.p_vmid = wb_info->mcif_warmup_params.p_vmid; - - if (warmup_params.address_increment == 0) - warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes; - - mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params); - return true; - } - /*following is the original: warmup each DWB's mcif buffer*/ - for (i = 0; i < num_dwb; i++) { - dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst]; - mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst]; - /*warmup is for VM mode only*/ - if (wb_info[i].mcif_buf_params.p_vmid == 0) - return false; - - /* Warmup MCIF_WB */ - for (i_buf = 0; i_buf < MCIF_BUF_COUNT; i_buf++) { - warmup_params.start_address.quad_part = wb_info[i].mcif_buf_params.luma_address[i_buf]; - warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes; - warmup_params.region_size = wb_info[i].mcif_buf_params.luma_pitch * wb_info[i].dwb_params.dest_height; - warmup_params.p_vmid = wb_info[i].mcif_buf_params.p_vmid; - mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params); - } - } - return true; -} - -void dcn30_enable_writeback( - struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context) -{ - struct dwbc *dwb; - struct mcif_wb *mcif_wb; - - dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; - mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; - - DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ - __func__, wb_info->dwb_pipe_inst,\ - wb_info->mpcc_inst); - - /* Warmup interface */ - dcn30_mmhubbub_warmup(dc, 1, wb_info); - - /* Update writeback pipe */ - dcn30_set_writeback(dc, wb_info, context); - - /* Enable MCIF_WB */ - mcif_wb->funcs->enable_mcif(mcif_wb); - /* Enable DWB */ - dwb->funcs->enable(dwb, &wb_info->dwb_params); -} - -void dcn30_disable_writeback( - struct dc *dc, - unsigned int dwb_pipe_inst) -{ - struct dwbc *dwb; - struct mcif_wb *mcif_wb; - - ASSERT(dwb_pipe_inst < MAX_DWB_PIPES); - dwb = dc->res_pool->dwbc[dwb_pipe_inst]; - mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst]; - DC_LOG_DWB("%s dwb_pipe_inst = %d",\ - __func__, dwb_pipe_inst); - - /* disable DWB */ - dwb->funcs->disable(dwb); - /* disable MCIF */ - mcif_wb->funcs->disable_mcif(mcif_wb); - /* disable MPC DWB mux */ - dc->res_pool->mpc->funcs->disable_dwb_mux(dc->res_pool->mpc, dwb_pipe_inst); -} - -void dcn30_program_all_writeback_pipes_in_tree( - struct dc *dc, - const struct dc_stream_state *stream, - struct dc_state *context) -{ - struct dc_writeback_info wb_info; - struct dwbc *dwb; - struct dc_stream_status *stream_status = NULL; - int i_wb, i_pipe, i_stream; - DC_LOG_DWB("%s", __func__); - - ASSERT(stream); - for (i_stream = 0; i_stream < context->stream_count; i_stream++) { - if (context->streams[i_stream] == stream) { - stream_status = &context->stream_status[i_stream]; - break; - } - } - ASSERT(stream_status); - - ASSERT(stream->num_wb_info <= dc->res_pool->res_cap->num_dwb); - /* For each writeback pipe */ - for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) { - - /* copy writeback info to local non-const so mpcc_inst can be set */ - wb_info = stream->writeback_info[i_wb]; - if (wb_info.wb_enabled) { - - /* get the MPCC instance for writeback_source_plane */ - wb_info.mpcc_inst = -1; - for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe]; - - if (!pipe_ctx->plane_state) - continue; - - if (pipe_ctx->plane_state == wb_info.writeback_source_plane) { - wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst; - break; - } - } - - if (wb_info.mpcc_inst == -1) { - /* Disable writeback pipe and disconnect from MPCC - * if source plane has been removed - */ - dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst); - continue; - } - - ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb); - dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst]; - if (dwb->funcs->is_enabled(dwb)) { - /* writeback pipe already enabled, only need to update */ - dc->hwss.update_writeback(dc, &wb_info, context); - } else { - /* Enable writeback pipe and connect to MPCC */ - dc->hwss.enable_writeback(dc, &wb_info, context); - } - } else { - /* Disable writeback pipe and disconnect from MPCC */ - dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst); - } - } -} - -void dcn30_init_hw(struct dc *dc) -{ - struct abm **abms = dc->res_pool->multiple_abms; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - int i; - int edp_num; - uint32_t backlight = MAX_BACKLIGHT_LEVEL; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - if (!dcb->funcs->is_accelerated_mode(dcb)) { - hws->funcs.bios_golden_init(dc); - hws->funcs.disable_vga(dc->hwseq); - } - - if (dc->debug.enable_mem_low_power.bits.dmcu) { - // Force ERAM to shutdown if DMCU is not enabled - if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { - REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); - } - } - - // Set default OPTC memory power states - if (dc->debug.enable_mem_low_power.bits.optc) { - // Shutdown when unassigned and light sleep in VBLANK - REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); - } - - if (dc->debug.enable_mem_low_power.bits.vga) { - // Power down VGA memory - REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); - } - - if (dc->ctx->dc_bios->fw_info_valid) { - res_pool->ref_clocks.xtalin_clock_inKhz = - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - - if (res_pool->dccg && res_pool->hubbub) { - - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - link->link_enc->funcs->hw_init(link->link_enc); - - /* Check for enabled DIG to identify enabled display */ - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc)) { - link->link_status.link_active = true; - if (link->link_enc->funcs->fec_is_active && - link->link_enc->funcs->fec_is_active(link->link_enc)) - link->fec_state = dc_link_fec_enabled; - } - } - - /* we want to turn off all dp displays before doing detection */ - dc->link_srv->blank_all_dp_displays(dc); - - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); - - /* If taking control over from VBIOS, we may want to optimize our first - * mode set, so we need to skip powering down pipes until we know which - * pipes we want to use. - * Otherwise, if taking control is not possible, we need to power - * everything down. - */ - if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { - hws->funcs.init_pipes(dc, dc->current_state); - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - } - - /* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on and seamless boot not enabled - */ - if (!dc->config.seamless_boot_edp_requested) { - struct dc_link *edp_links[MAX_NUM_EDP]; - struct dc_link *edp_link = NULL; - - dc_get_edp_links(dc, edp_links, &edp_num); - if (edp_num) - edp_link = edp_links[0]; - if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwss.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwss.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - } else { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } - } - } - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (abms[i] != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); - } - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) - dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); - - if (dc->clk_mgr->funcs->notify_wm_ranges) - dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); - - //if softmax is enabled then hardmax will be set by a different call - if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) - dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); - - if (dc->res_pool->hubbub->funcs->force_pstate_change_control) - dc->res_pool->hubbub->funcs->force_pstate_change_control( - dc->res_pool->hubbub, false, false); - if (dc->res_pool->hubbub->funcs->init_crb) - dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); - - // Get DMCUB capabilities - dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); - dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; - dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; -} - -void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) -{ - if (pipe_ctx == NULL) - return; - - if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) - pipe_ctx->stream_res.stream_enc->funcs->set_avmute( - pipe_ctx->stream_res.stream_enc, - enable); -} - -void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx) -{ - bool is_hdmi_tmds; - bool is_dp; - - ASSERT(pipe_ctx->stream); - - if (pipe_ctx->stream_res.stream_enc == NULL) - return; /* this is not root pipe */ - - is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); - is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); - - if (!is_hdmi_tmds && !is_dp) - return; - - if (is_hdmi_tmds) - pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - else { - if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num) - pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - - pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - } -} - -void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - struct hubp *hubp = pipe_ctx->plane_res.hubp; - bool enable = false; - struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; - enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) - ? dmdata_dp - : dmdata_hdmi; - - /* if using dynamic meta, don't set up generic infopackets */ - if (pipe_ctx->stream->dmdata_address.quad_part != 0) { - pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; - enable = true; - } - - if (!hubp) - return; - - if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) - return; - - stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, - hubp->inst, mode); -} - -bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable) -{ - union dmub_rb_cmd cmd; - uint32_t tmr_delay = 0, tmr_scale = 0; - struct dc_cursor_attributes cursor_attr; - bool cursor_cache_enable = false; - struct dc_stream_state *stream = NULL; - struct dc_plane_state *plane = NULL; - - if (!dc->ctx->dmub_srv) - return false; - - if (enable) { - if (dc->current_state) { - int i; - - /* First, check no-memory-requests case */ - for (i = 0; i < dc->current_state->stream_count; i++) { - if (dc->current_state->stream_status[i].plane_count) - /* Fail eligibility on a visible stream */ - break; - } - - if (i == dc->current_state->stream_count) { - /* Enable no-memory-requests case */ - memset(&cmd, 0, sizeof(cmd)); - cmd.mall.header.type = DMUB_CMD__MALL; - cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ; - cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); - - return true; - } - - stream = dc->current_state->streams[0]; - plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL); - - if (stream && plane) { - cursor_cache_enable = stream->cursor_position.enable && - plane->address.grph.cursor_cache_addr.quad_part; - cursor_attr = stream->cursor_attributes; - } - - /* - * Second, check MALL eligibility - * - * single display only, single surface only, 8 and 16 bit formats only, no VM, - * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW - * - * TODO: When we implement multi-display, PSR displays will be allowed if there is - * a non-PSR display present, since in that case we can't do D0i3.2 - */ - if (dc->current_state->stream_count == 1 && - stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && - dc->current_state->stream_status[0].plane_count == 1 && - plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F && - plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 && - plane->address.page_table_base.quad_part == 0 && - dc->hwss.does_plane_fit_in_mall && - dc->hwss.does_plane_fit_in_mall(dc, plane, - cursor_cache_enable ? &cursor_attr : NULL)) { - unsigned int v_total = stream->adjust.v_total_max ? - stream->adjust.v_total_max : stream->timing.v_total; - unsigned int refresh_hz = div_u64((unsigned long long) stream->timing.pix_clk_100hz * - 100LL, (v_total * stream->timing.h_total)); - - /* - * one frame time in microsec: - * Delay_Us = 1000000 / refresh - * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period - * - * one frame time modified by 'additional timer percent' (p): - * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100 - * = dynamic_delay_us * (1 + p / 100) - * = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100 - * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) - * - * formula for timer duration based on parameters, from regspec: - * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale - * - * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale - * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly - * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64 - * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64 - * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64 - * - * need to round up the result of the division before the subtraction - */ - unsigned int denom = refresh_hz * 6528; - unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us; - - tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) * - (100LL + dc->debug.mall_additional_timer_percent) + denom - 1), - denom) - 64LL; - - /* In some cases the stutter period is really big (tiny modes) in these - * cases MALL cant be enabled, So skip these cases to avoid a ASSERT() - * - * We can check if stutter_period is more than 1/10th the frame time to - * consider if we can actually meet the range of hysteresis timer - */ - if (stutter_period > 100000/refresh_hz) - return false; - - /* scale should be increased until it fits into 6 bits */ - while (tmr_delay & ~0x3F) { - tmr_scale++; - - if (tmr_scale > 3) { - /* Delay exceeds range of hysteresis timer */ - ASSERT(false); - return false; - } - - denom *= 2; - tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) * - (100LL + dc->debug.mall_additional_timer_percent) + denom - 1), - denom) - 64LL; - } - - /* Copy HW cursor */ - if (cursor_cache_enable) { - memset(&cmd, 0, sizeof(cmd)); - cmd.mall.header.type = DMUB_CMD__MALL; - cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR; - cmd.mall.header.payload_bytes = - sizeof(cmd.mall) - sizeof(cmd.mall.header); - - switch (cursor_attr.color_format) { - case CURSOR_MODE_MONO: - cmd.mall.cursor_bpp = 2; - break; - case CURSOR_MODE_COLOR_1BIT_AND: - case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: - case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: - cmd.mall.cursor_bpp = 32; - break; - - case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: - case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: - cmd.mall.cursor_bpp = 64; - break; - } - - cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part; - cmd.mall.cursor_copy_dst.quad_part = - (plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047; - cmd.mall.cursor_width = cursor_attr.width; - cmd.mall.cursor_height = cursor_attr.height; - cmd.mall.cursor_pitch = cursor_attr.pitch; - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - - /* Use copied cursor, and it's okay to not switch back */ - cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part; - dc_stream_set_cursor_attributes(stream, &cursor_attr); - } - - /* Enable MALL */ - memset(&cmd, 0, sizeof(cmd)); - cmd.mall.header.type = DMUB_CMD__MALL; - cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW; - cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); - cmd.mall.tmr_delay = tmr_delay; - cmd.mall.tmr_scale = tmr_scale; - cmd.mall.debug_bits = dc->debug.mall_error_as_fatal; - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); - - return true; - } - } - - /* No applicable optimizations */ - return false; - } - - /* Disable MALL */ - memset(&cmd, 0, sizeof(cmd)); - cmd.mall.header.type = DMUB_CMD__MALL; - cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW; - cmd.mall.header.payload_bytes = - sizeof(cmd.mall) - sizeof(cmd.mall.header); - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - - return true; -} - -bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, struct dc_cursor_attributes *cursor_attr) -{ - // add meta size? - unsigned int surface_size = plane->plane_size.surface_pitch * plane->plane_size.surface_size.height * - (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4); - unsigned int mall_size = dc->caps.mall_size_total; - unsigned int cursor_size = 0; - - if (dc->debug.mall_size_override) - mall_size = 1024 * 1024 * dc->debug.mall_size_override; - - if (cursor_attr) { - cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size; - - switch (cursor_attr->color_format) { - case CURSOR_MODE_MONO: - cursor_size /= 2; - break; - case CURSOR_MODE_COLOR_1BIT_AND: - case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: - case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: - cursor_size *= 4; - break; - - case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: - case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: - cursor_size *= 8; - break; - } - } - - return (surface_size + cursor_size) < mall_size; -} - -void dcn30_hardware_release(struct dc *dc) -{ - bool subvp_in_use = false; - uint32_t i; - - dc_dmub_srv_p_state_delegate(dc, false, NULL); - dc_dmub_setup_subvp_dmub_command(dc, dc->current_state, false); - - /* SubVP treated the same way as FPO. If driver disable and - * we are using a SubVP config, disable and force on DCN side - * to prevent P-State hang on driver enable. - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (!pipe->stream) - continue; - - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - subvp_in_use = true; - break; - } - } - /* If pstate unsupported, or still supported - * by firmware, force it supported by dcn - */ - if (dc->current_state) - if ((!dc->clk_mgr->clks.p_state_change_support || subvp_in_use || - dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) && - dc->res_pool->hubbub->funcs->force_pstate_change_control) - dc->res_pool->hubbub->funcs->force_pstate_change_control( - dc->res_pool->hubbub, true, true); -} - -void dcn30_set_disp_pattern_generator(const struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum controller_dp_test_pattern test_pattern, - enum controller_dp_color_space color_space, - enum dc_color_depth color_depth, - const struct tg_color *solid_color, - int width, int height, int offset) -{ - pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern, - color_space, color_depth, solid_color, width, height, offset); -} - -void dcn30_prepare_bandwidth(struct dc *dc, - struct dc_state *context) -{ - bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support; - /* Any transition into an FPO config should disable MCLK switching first to avoid - * driver and FW P-State synchronization issues. - */ - if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) { - dc->optimized_required = true; - context->bw_ctx.bw.dcn.clk.p_state_change_support = false; - } - - if (dc->clk_mgr->dc_mode_softmax_enabled) - if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && - context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) - 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); - - dcn20_prepare_bandwidth(dc, context); - /* - * enabled -> enabled: do not disable - * enabled -> disabled: disable - * disabled -> enabled: don't care - * disabled -> disabled: don't care - */ - if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) - dc_dmub_srv_p_state_delegate(dc, false, context); - - if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) { - /* After disabling P-State, restore the original value to ensure we get the correct P-State - * on the next optimize. */ - context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support; - } -} - -void dcn30_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params) -{ - unsigned int i; - unsigned int triggers = 0; - - if (params->triggers.surface_update) - triggers |= 0x100; - if (params->triggers.cursor_update) - triggers |= 0x8; - if (params->triggers.force_trigger) - triggers |= 0x1; - - for (i = 0; i < num_pipes; i++) - pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(pipe_ctx[i]->stream_res.tg, - triggers, params->num_frames); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h deleted file mode 100644 index e557e2b98618..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -* Copyright 2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN30_H__ -#define __DC_HWSS_DCN30_H__ - -#include "hw_sequencer_private.h" -#include "dcn20/dcn20_hwseq.h" -struct dc; - -void dcn30_init_hw(struct dc *dc); -void dcn30_program_all_writeback_pipes_in_tree( - struct dc *dc, - const struct dc_stream_state *stream, - struct dc_state *context); -void dcn30_update_writeback( - struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context); -void dcn30_enable_writeback( - struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context); -void dcn30_disable_writeback( - struct dc *dc, - unsigned int dwb_pipe_inst); - -bool dcn30_mmhubbub_warmup( - struct dc *dc, - unsigned int num_dwb, - struct dc_writeback_info *wb_info); - -bool dcn30_set_blend_lut(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - -bool dcn30_set_input_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - -void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx); - -bool dcn30_set_output_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); -void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); -void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx); -void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx); - -bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, - struct dc_cursor_attributes *cursor_attr); - -bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable); - -void dcn30_hardware_release(struct dc *dc); - -void dcn30_set_disp_pattern_generator(const struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum controller_dp_test_pattern test_pattern, - enum controller_dp_color_space color_space, - enum dc_color_depth color_depth, - const struct tg_color *solid_color, - int width, int height, int offset); - -void dcn30_set_hubp_blank(const struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank_enable); - -void dcn30_prepare_bandwidth(struct dc *dc, - struct dc_state *context); - -void dcn30_set_static_screen_control(struct pipe_ctx **pipe_ctx, - int num_pipes, const struct dc_static_screen_params *params); - -#endif /* __DC_HWSS_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c index e56fca60a1ed..9894caedffed 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c @@ -23,11 +23,11 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" #include "dcn21/dcn21_hwseq.h" -#include "dcn30_hwseq.h" +#include "dcn30/dcn30_hwseq.h" #include "dcn30_init.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 9f3c8626c0b2..473581cff06b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -44,7 +44,7 @@ #include "dcn30/dcn30_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile index 9002cb10a6ae..30fbc5e06dca 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile @@ -11,7 +11,7 @@ # Makefile for dcn30. DCN301 = dcn301_init.o dcn301_resource.o dcn301_dccg.o \ - dcn301_dio_link_encoder.o dcn301_hwseq.o dcn301_panel_cntl.o dcn301_hubbub.o \ + dcn301_dio_link_encoder.o dcn301_panel_cntl.o dcn301_hubbub.o \ dcn301_optc.o AMD_DAL_DCN301 = $(addprefix $(AMDDALPATH)/dc/dcn301/,$(DCN301)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hwseq.c deleted file mode 100644 index 10bedb2ea62a..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hwseq.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "core_types.h" -#include "dce/dce_hwseq.h" -#include "dcn301_hwseq.h" -#include "reg_helper.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - - diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hwseq.h deleted file mode 100644 index aa3df3f77108..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hwseq.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* Copyright 2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN301_H__ -#define __DC_HWSS_DCN301_H__ - -#include "hw_sequencer_private.h" - - -#endif /* __DC_HWSS_DCN301_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c index fdbe3d42cd7b..6477009ce065 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c @@ -23,12 +23,12 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" #include "dcn21/dcn21_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dcn301_hwseq.h" +#include "dcn301/dcn301_hwseq.h" #include "dcn301_init.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c index 6d2f99c1fcd5..b4b3b52990b9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c @@ -45,7 +45,7 @@ #include "dcn301/dcn301_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile b/drivers/gpu/drm/amd/display/dc/dcn302/Makefile index ebd01cb467b7..95b66baf39e9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn302/Makefile @@ -5,7 +5,7 @@ # # Makefile for dcn302. -DCN3_02 = dcn302_init.o dcn302_hwseq.o dcn302_resource.o +DCN3_02 = dcn302_init.o dcn302_resource.o AMD_DAL_DCN3_02 = $(addprefix $(AMDDALPATH)/dc/dcn302/,$(DCN3_02)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.c deleted file mode 100644 index 0a6d58dd8f6d..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dcn302_hwseq.h" - -#include "dce/dce_hwseq.h" - -#include "reg_helper.h" -#include "dc.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - - -void dcn302_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - - if (hws->ctx->dc->debug.disable_dpp_power_gate) - return; - if (REG(DOMAIN1_PG_CONFIG) == 0) - return; - - switch (dpp_inst) { - case 0: /* DPP0 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, - DOMAIN1_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN1_PG_STATUS, - DOMAIN1_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DPP1 */ - REG_UPDATE(DOMAIN3_PG_CONFIG, - DOMAIN3_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN3_PG_STATUS, - DOMAIN3_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DPP2 */ - REG_UPDATE(DOMAIN5_PG_CONFIG, - DOMAIN5_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN5_PG_STATUS, - DOMAIN5_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DPP3 */ - REG_UPDATE(DOMAIN7_PG_CONFIG, - DOMAIN7_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN7_PG_STATUS, - DOMAIN7_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 4: /* DPP4 */ - REG_UPDATE(DOMAIN9_PG_CONFIG, - DOMAIN9_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN9_PG_STATUS, - DOMAIN9_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -void dcn302_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - - if (hws->ctx->dc->debug.disable_hubp_power_gate) - return; - if (REG(DOMAIN0_PG_CONFIG) == 0) - return; - - switch (hubp_inst) { - case 0: /* DCHUBP0 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, - DOMAIN0_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN0_PG_STATUS, - DOMAIN0_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DCHUBP1 */ - REG_UPDATE(DOMAIN2_PG_CONFIG, - DOMAIN2_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN2_PG_STATUS, - DOMAIN2_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DCHUBP2 */ - REG_UPDATE(DOMAIN4_PG_CONFIG, - DOMAIN4_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN4_PG_STATUS, - DOMAIN4_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DCHUBP3 */ - REG_UPDATE(DOMAIN6_PG_CONFIG, - DOMAIN6_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN6_PG_STATUS, - DOMAIN6_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 4: /* DCHUBP4 */ - REG_UPDATE(DOMAIN8_PG_CONFIG, - DOMAIN8_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN8_PG_STATUS, - DOMAIN8_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -void dcn302_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - uint32_t org_ip_request_cntl = 0; - - if (hws->ctx->dc->debug.disable_dsc_power_gate) - return; - - if (REG(DOMAIN16_PG_CONFIG) == 0) - return; - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - switch (dsc_inst) { - case 0: /* DSC0 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, - DOMAIN16_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN16_PG_STATUS, - DOMAIN16_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DSC1 */ - REG_UPDATE(DOMAIN17_PG_CONFIG, - DOMAIN17_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN17_PG_STATUS, - DOMAIN17_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DSC2 */ - REG_UPDATE(DOMAIN18_PG_CONFIG, - DOMAIN18_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN18_PG_STATUS, - DOMAIN18_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DSC3 */ - REG_UPDATE(DOMAIN19_PG_CONFIG, - DOMAIN19_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN19_PG_STATUS, - DOMAIN19_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 4: /* DSC4 */ - REG_UPDATE(DOMAIN20_PG_CONFIG, - DOMAIN20_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN20_PG_STATUS, - DOMAIN20_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.h deleted file mode 100644 index 1e5126a0e695..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_hwseq.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN302_H__ -#define __DC_HWSS_DCN302_H__ - -#include "hw_sequencer_private.h" - -void dcn302_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on); -void dcn302_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); -void dcn302_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); - -#endif /* __DC_HWSS_DCN302_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.c index eb375f30f5bc..637f9514d37b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.c @@ -23,7 +23,7 @@ * */ -#include "dcn302_hwseq.h" +#include "dcn302/dcn302_hwseq.h" #include "dcn30/dcn30_init.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile index 8702e0b7fda3..d7b3ad780e5d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile @@ -6,7 +6,7 @@ # # Makefile for dcn303. -DCN3_03 = dcn303_init.o dcn303_hwseq.o dcn303_resource.o +DCN3_03 = dcn303_init.o dcn303_resource.o AMD_DAL_DCN3_03 = $(addprefix $(AMDDALPATH)/dc/dcn303/,$(DCN3_03)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.c deleted file mode 100644 index b48b732aa647..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.c +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright (C) 2021 Advanced Micro Devices, Inc. - * - * Authors: AMD - */ - -#include "dcn303_hwseq.h" - -#include "dce/dce_hwseq.h" - -#include "reg_helper.h" -#include "dc.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - - -void dcn303_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) -{ - /*DCN303 removes PG registers*/ -} - -void dcn303_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) -{ - /*DCN303 removes PG registers*/ -} - -void dcn303_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on) -{ - /*DCN303 removes PG registers*/ -} - -void dcn303_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) -{ - /*DCN303 removes PG registers*/ -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.h deleted file mode 100644 index 8b69a3b76c11..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_hwseq.h +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright (C) 2021 Advanced Micro Devices, Inc. - * - * Authors: AMD - */ - -#ifndef __DC_HWSS_DCN303_H__ -#define __DC_HWSS_DCN303_H__ - -#include "hw_sequencer_private.h" - -void dcn303_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on); -void dcn303_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); -void dcn303_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); -void dcn303_enable_power_gating_plane(struct dce_hwseq *hws, bool enable); - -#endif /* __DC_HWSS_DCN303_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c index f499f8ab5e47..39cf7a50bd26 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c @@ -5,7 +5,7 @@ * Authors: AMD */ -#include "dcn303_hwseq.h" +#include "dcn303/dcn303_hwseq.h" #include "dcn30/dcn30_init.h" #include "dc.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile index ec041e3cda30..996d8c1e9d2a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn31. -DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_hwseq.o dcn31_init.o dcn31_hubp.o \ +DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_init.o dcn31_hubp.o \ dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \ dcn31_apg.o dcn31_hpo_dp_stream_encoder.o dcn31_hpo_dp_link_encoder.o \ dcn31_afmt.o dcn31_vpg.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c deleted file mode 100644 index 65e8504e6063..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - - -#include "dm_services.h" -#include "dm_helpers.h" -#include "core_types.h" -#include "resource.h" -#include "dccg.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "reg_helper.h" -#include "abm.h" -#include "hubp.h" -#include "dchubbub.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "mcif_wb.h" -#include "dc_dmub_srv.h" -#include "dcn31_hwseq.h" -#include "link_hwss.h" -#include "dpcd_defs.h" -#include "dce/dmub_outbox.h" -#include "link.h" -#include "dcn10/dcn10_hw_sequencer.h" -#include "inc/link_enc_cfg.h" -#include "dcn30/dcn30_vpg.h" -#include "dce/dce_i2c_hw.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg -#define DC_LOGGER \ - dc->ctx->logger - - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -static void enable_memory_low_power(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - int i; - - if (dc->debug.enable_mem_low_power.bits.dmcu) { - // Force ERAM to shutdown if DMCU is not enabled - if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { - REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); - } - } - - // Set default OPTC memory power states - if (dc->debug.enable_mem_low_power.bits.optc) { - // Shutdown when unassigned and light sleep in VBLANK - REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); - } - - if (dc->debug.enable_mem_low_power.bits.vga) { - // Power down VGA memory - REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); - } - - if (dc->debug.enable_mem_low_power.bits.mpc && - dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode) - dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc); - - - if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) { - // Power down VPGs - for (i = 0; i < dc->res_pool->stream_enc_count; i++) - if (dc->res_pool->stream_enc[i]->vpg) - dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); -#if defined(CONFIG_DRM_AMD_DC_FP) - for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) - dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); -#endif - } - -} - -void dcn31_init_hw(struct dc *dc) -{ - struct abm **abms = dc->res_pool->multiple_abms; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - uint32_t backlight = MAX_BACKLIGHT_LEVEL; - int i; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - if (!dcb->funcs->is_accelerated_mode(dcb)) { - hws->funcs.bios_golden_init(dc); - if (hws->funcs.disable_vga) - hws->funcs.disable_vga(dc->hwseq); - } - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - enable_memory_low_power(dc); - - if (dc->ctx->dc_bios->fw_info_valid) { - res_pool->ref_clocks.xtalin_clock_inKhz = - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - - if (res_pool->dccg && res_pool->hubbub) { - - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - if (link->ep_type != DISPLAY_ENDPOINT_PHY) - continue; - - link->link_enc->funcs->hw_init(link->link_enc); - - /* Check for enabled DIG to identify enabled display */ - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc)) { - link->link_status.link_active = true; - if (link->link_enc->funcs->fec_is_active && - link->link_enc->funcs->fec_is_active(link->link_enc)) - link->fec_state = dc_link_fec_enabled; - } - } - - /* we want to turn off all dp displays before doing detection */ - dc->link_srv->blank_all_dp_displays(dc); - - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); - - /* If taking control over from VBIOS, we may want to optimize our first - * mode set, so we need to skip powering down pipes until we know which - * pipes we want to use. - * Otherwise, if taking control is not possible, we need to power - * everything down. - */ - if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { - - // we want to turn off edp displays if odm is enabled and no seamless boot - if (!dc->caps.seamless_odm) { - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - uint32_t num_opps, opp_id_src0, opp_id_src1; - - num_opps = 1; - if (tg) { - if (tg->funcs->is_tg_enabled(tg) && tg->funcs->get_optc_source) { - tg->funcs->get_optc_source(tg, &num_opps, - &opp_id_src0, &opp_id_src1); - } - } - - if (num_opps > 1) { - dc->link_srv->blank_all_edp_displays(dc); - break; - } - } - } - - hws->funcs.init_pipes(dc, dc->current_state); - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - } - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (abms[i] != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); - } - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - // Set i2c to light sleep until engine is setup - if (dc->debug.enable_mem_low_power.bits.i2c) - REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1); - - if (hws->funcs.setup_hpo_hw_control) - hws->funcs.setup_hpo_hw_control(hws, false); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) - dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); - - if (dc->clk_mgr->funcs->notify_wm_ranges) - dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); - - if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) - dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); - - if (dc->res_pool->hubbub->funcs->force_pstate_change_control) - dc->res_pool->hubbub->funcs->force_pstate_change_control( - dc->res_pool->hubbub, false, false); -#if defined(CONFIG_DRM_AMD_DC_FP) - if (dc->res_pool->hubbub->funcs->init_crb) - dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); -#endif - - // Get DMCUB capabilities - dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); - dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; - dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; -} - -void dcn31_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - uint32_t org_ip_request_cntl = 0; - - if (hws->ctx->dc->debug.disable_dsc_power_gate) - return; - - if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc && - hws->ctx->dc->res_pool->dccg->funcs->enable_dsc && - power_on) - hws->ctx->dc->res_pool->dccg->funcs->enable_dsc( - hws->ctx->dc->res_pool->dccg, dsc_inst); - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - switch (dsc_inst) { - case 0: /* DSC0 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN16_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DSC1 */ - REG_UPDATE(DOMAIN17_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN17_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DSC2 */ - REG_UPDATE(DOMAIN18_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN18_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - - if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc) { - if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) - hws->ctx->dc->res_pool->dccg->funcs->disable_dsc( - hws->ctx->dc->res_pool->dccg, dsc_inst); - } - -} - - -void dcn31_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable) -{ - bool force_on = true; /* disable power gating */ - uint32_t org_ip_request_cntl = 0; - - if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate) - force_on = false; - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - /* DCHUBP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - /* DPP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - force_on = true; /* disable power gating */ - if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) - force_on = false; - - /* DCS0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} - -void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx) -{ - bool is_hdmi_tmds; - bool is_dp; - - ASSERT(pipe_ctx->stream); - - if (pipe_ctx->stream_res.stream_enc == NULL) - return; /* this is not root pipe */ - - is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); - is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); - - if (!is_hdmi_tmds && !is_dp) - return; - - if (is_hdmi_tmds) - pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - else if (pipe_ctx->stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets( - pipe_ctx->stream_res.hpo_dp_stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - return; - } else { - if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num) - pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - - pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( - pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream_res.encoder_info_frame); - } -} -void dcn31_z10_save_init(struct dc *dc) -{ - union dmub_rb_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; - cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT; - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); -} - -void dcn31_z10_restore(const struct dc *dc) -{ - union dmub_rb_cmd cmd; - - /* - * DMUB notifies whether restore is required. - * Optimization to avoid sending commands when not required. - */ - if (!dc_dmub_srv_is_restore_required(dc->ctx->dmub_srv)) - return; - - memset(&cmd, 0, sizeof(cmd)); - cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; - cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_RESTORE; - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); -} - -void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - uint32_t org_ip_request_cntl; - if (hws->ctx->dc->debug.disable_hubp_power_gate) - return; - - if (REG(DOMAIN0_PG_CONFIG) == 0) - return; - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - switch (hubp_inst) { - case 0: - REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - case 1: - REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - case 2: - REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - case 3: - REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} - -int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) -{ - struct dcn_hubbub_phys_addr_config config; - - config.system_aperture.fb_top = pa_config->system_aperture.fb_top; - config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; - config.system_aperture.fb_base = pa_config->system_aperture.fb_base; - config.system_aperture.agp_top = pa_config->system_aperture.agp_top; - config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; - config.system_aperture.agp_base = pa_config->system_aperture.agp_base; - config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; - config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; - - if (pa_config->gart_config.base_addr_is_mc_addr) { - /* Convert from MC address to offset into FB */ - config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr - - pa_config->system_aperture.fb_base + - pa_config->system_aperture.fb_offset; - } else - config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; - - return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); -} - -static void dcn31_reset_back_end_for_pipe( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - struct dc_link *link; - - DC_LOGGER_INIT(dc->ctx->logger); - if (pipe_ctx->stream_res.stream_enc == NULL) { - pipe_ctx->stream = NULL; - return; - } - ASSERT(!pipe_ctx->top_pipe); - - dc->hwss.set_abm_immediate_disable(pipe_ctx); - - pipe_ctx->stream_res.tg->funcs->set_dsc_config( - pipe_ctx->stream_res.tg, - OPTC_DSC_DISABLED, 0, 0); - pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); - pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); - if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) - pipe_ctx->stream_res.tg->funcs->set_odm_bypass( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; - - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, NULL); - - link = pipe_ctx->stream->link; - /* DPMS may already disable or */ - /* dpms_off status is incorrect due to fastboot - * feature. When system resume from S4 with second - * screen only, the dpms_off would be true but - * VBIOS lit up eDP, so check link status too. - */ - if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) - dc->link_srv->set_dpms_off(pipe_ctx); - else if (pipe_ctx->stream_res.audio) - dc->hwss.disable_audio_stream(pipe_ctx); - - /* free acquired resources */ - if (pipe_ctx->stream_res.audio) { - /*disable az_endpoint*/ - pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); - - /*free audio*/ - if (dc->caps.dynamic_audio == true) { - /*we have to dynamic arbitrate the audio endpoints*/ - /*we free the resource, need reset is_audio_acquired*/ - update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, - pipe_ctx->stream_res.audio, false); - pipe_ctx->stream_res.audio = NULL; - } - } - - pipe_ctx->stream = NULL; - DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", - pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); -} - -void dcn31_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - - /* Reset Back End*/ - for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { - struct pipe_ctx *pipe_ctx_old = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx_old->stream) - continue; - - if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) - continue; - - if (!pipe_ctx->stream || - pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { - struct clock_source *old_clk = pipe_ctx_old->clock_source; - - dcn31_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); - if (hws->funcs.enable_stream_gating) - hws->funcs.enable_stream_gating(dc, pipe_ctx_old); - if (old_clk) - old_clk->funcs->cs_power_down(old_clk); - } - } - - /* New dc_state in the process of being applied to hardware. */ - link_enc_cfg_set_transient_mode(dc, dc->current_state, context); -} - -void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) -{ - if (hws->ctx->dc->debug.hpo_optimization) - REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h deleted file mode 100644 index edfc01d6ad73..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -* Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN31_H__ -#define __DC_HWSS_DCN31_H__ - -#include "hw_sequencer_private.h" - -struct dc; - -void dcn31_init_hw(struct dc *dc); - -void dcn31_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on); - -void dcn31_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable); - -void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx); - -void dcn31_z10_restore(const struct dc *dc); -void dcn31_z10_save_init(struct dc *dc); - -void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); -int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config); -void dcn31_reset_hw_ctx_wrap( - struct dc *dc, - struct dc_state *context); -bool dcn31_is_abm_supported(struct dc *dc, - struct dc_state *context, struct dc_stream_state *stream); -void dcn31_init_pipes(struct dc *dc, struct dc_state *context); -void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); - -#endif /* __DC_HWSS_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c index 084861519e28..669f524bd064 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c @@ -23,8 +23,8 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" #include "dcn21/dcn21_hwseq.h" #include "dcn30/dcn30_hwseq.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 239d7ce8e533..cdf005f91869 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -48,7 +48,7 @@ #include "dcn31/dcn31_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile index 702c28c2560e..72456debb99f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn314. -DCN314 = dcn314_resource.o dcn314_hwseq.o dcn314_init.o \ +DCN314 = dcn314_resource.o dcn314_init.o \ dcn314_dio_stream_encoder.o dcn314_dccg.o dcn314_optc.o AMD_DAL_DCN314 = $(addprefix $(AMDDALPATH)/dc/dcn314/,$(DCN314)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c deleted file mode 100644 index 5b197807080e..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c +++ /dev/null @@ -1,497 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright 2022 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - - -#include "dm_services.h" -#include "dm_helpers.h" -#include "core_types.h" -#include "resource.h" -#include "dccg.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "reg_helper.h" -#include "abm.h" -#include "hubp.h" -#include "dchubbub.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "mcif_wb.h" -#include "dc_dmub_srv.h" -#include "dcn314_hwseq.h" -#include "link_hwss.h" -#include "dpcd_defs.h" -#include "dce/dmub_outbox.h" -#include "link.h" -#include "dcn10/dcn10_hw_sequencer.h" -#include "inc/link_enc_cfg.h" -#include "dcn30/dcn30_vpg.h" -#include "dce/dce_i2c_hw.h" -#include "dsc.h" -#include "dcn20/dcn20_optc.h" -#include "dcn30/dcn30_cm_common.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg -#define DC_LOGGER \ - stream->ctx->logger - - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, - int opp_cnt) -{ - bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); - int flow_ctrl_cnt; - - if (opp_cnt >= 2) - hblank_halved = true; - - flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - - stream->timing.h_border_left - - stream->timing.h_border_right; - - if (hblank_halved) - flow_ctrl_cnt /= 2; - - /* ODM combine 4:1 case */ - if (opp_cnt == 4) - flow_ctrl_cnt /= 2; - - return flow_ctrl_cnt; -} - -static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) -{ - struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; - struct dc_stream_state *stream = pipe_ctx->stream; - struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - - ASSERT(dsc); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - opp_cnt++; - - if (enable) { - struct dsc_config dsc_cfg; - struct dsc_optc_config dsc_optc_cfg; - enum optc_dsc_mode optc_dsc_mode; - - /* Enable DSC hw block */ - dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; - dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; - dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; - dsc_cfg.color_depth = stream->timing.display_color_depth; - dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; - dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; - ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); - dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; - - dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); - dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; - - ASSERT(odm_dsc); - odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); - odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); - } - dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; - dsc_cfg.pic_width *= opp_cnt; - - optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; - - /* Enable DSC in OPTC */ - DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); - pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, - optc_dsc_mode, - dsc_optc_cfg.bytes_per_pixel, - dsc_optc_cfg.slice_width); - } else { - /* disable DSC in OPTC */ - pipe_ctx->stream_res.tg->funcs->set_dsc_config( - pipe_ctx->stream_res.tg, - OPTC_DSC_DISABLED, 0, 0); - - /* disable DSC block */ - dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - ASSERT(odm_pipe->stream_res.dsc); - odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); - } - } -} - -// Given any pipe_ctx, return the total ODM combine factor, and optionally return -// the OPPids which are used -static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) -{ - unsigned int opp_count = 1; - struct pipe_ctx *odm_pipe; - - // First get to the top pipe - for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) - ; - - // First pipe is always used - if (opp_instances) - opp_instances[0] = odm_pipe->stream_res.opp->inst; - - // Find and count odm pipes, if any - for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - if (opp_instances) - opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; - opp_count++; - } - - return opp_count; -} - -void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *odm_pipe; - int opp_cnt = 0; - int opp_inst[MAX_PIPES] = {0}; - bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); - struct mpc_dwb_flow_control flow_control; - struct mpc *mpc = dc->res_pool->mpc; - int i; - - opp_cnt = get_odm_config(pipe_ctx, opp_inst); - - if (opp_cnt > 1) - pipe_ctx->stream_res.tg->funcs->set_odm_combine( - pipe_ctx->stream_res.tg, - opp_inst, opp_cnt, - &pipe_ctx->stream->timing); - else - pipe_ctx->stream_res.tg->funcs->set_odm_bypass( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - - rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; - flow_control.flow_ctrl_mode = 0; - flow_control.flow_ctrl_cnt0 = 0x80; - flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt); - if (mpc->funcs->set_out_rate_control) { - for (i = 0; i < opp_cnt; ++i) { - mpc->funcs->set_out_rate_control( - mpc, opp_inst[i], - true, - rate_control_2x_pclk, - &flow_control); - } - } - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( - odm_pipe->stream_res.opp, - true); - } - - if (pipe_ctx->stream_res.dsc) { - struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; - - update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); - - /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ - if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && - current_pipe_ctx->next_odm_pipe->stream_res.dsc) { - struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; - /* disconnect DSC block from stream */ - dsc->funcs->dsc_disconnect(dsc); - } - } -} - -void dcn314_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - uint32_t org_ip_request_cntl = 0; - - if (hws->ctx->dc->debug.disable_dsc_power_gate) - return; - - if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc && - hws->ctx->dc->res_pool->dccg->funcs->enable_dsc && - power_on) - hws->ctx->dc->res_pool->dccg->funcs->enable_dsc( - hws->ctx->dc->res_pool->dccg, dsc_inst); - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - switch (dsc_inst) { - case 0: /* DSC0 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN16_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DSC1 */ - REG_UPDATE(DOMAIN17_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN17_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DSC2 */ - REG_UPDATE(DOMAIN18_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN18_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DSC3 */ - REG_UPDATE(DOMAIN19_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN19_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); - - if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc) { - if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) - hws->ctx->dc->res_pool->dccg->funcs->disable_dsc( - hws->ctx->dc->res_pool->dccg, dsc_inst); - } - -} - -void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) -{ - bool force_on = true; /* disable power gating */ - uint32_t org_ip_request_cntl = 0; - - if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate) - force_on = false; - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - /* DCHUBP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - /* DPP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - force_on = true; /* disable power gating */ - if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) - force_on = false; - - /* DCS0/1/2/3/4 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} - -unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - unsigned int odm_combine_factor = 0; - bool two_pix_per_container = false; - - two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); - odm_combine_factor = get_odm_config(pipe_ctx, NULL); - - if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - *k1_div = PIXEL_RATE_DIV_BY_1; - *k2_div = PIXEL_RATE_DIV_BY_1; - } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) { - *k1_div = PIXEL_RATE_DIV_BY_1; - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - *k2_div = PIXEL_RATE_DIV_BY_2; - else - *k2_div = PIXEL_RATE_DIV_BY_4; - } else if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) { - if (two_pix_per_container) { - *k1_div = PIXEL_RATE_DIV_BY_1; - *k2_div = PIXEL_RATE_DIV_BY_2; - } else { - *k1_div = PIXEL_RATE_DIV_BY_1; - *k2_div = PIXEL_RATE_DIV_BY_4; - if (odm_combine_factor == 2) - *k2_div = PIXEL_RATE_DIV_BY_2; - } - } - - if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA)) - ASSERT(false); - - return odm_combine_factor; -} - -void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) -{ - uint32_t pix_per_cycle = 1; - uint32_t odm_combine_factor = 1; - - if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc) - return; - - odm_combine_factor = get_odm_config(pipe_ctx, NULL); - if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1) - pix_per_cycle = 2; - - if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) - pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, - pix_per_cycle); -} - -void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context) -{ - unsigned int i; - struct pipe_ctx *pipe = NULL; - bool otg_disabled[MAX_PIPES] = {false}; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (pipe->top_pipe || pipe->prev_odm_pipe) - continue; - - if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { - pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg); - reset_sync_context_for_pipe(dc, context, i); - otg_disabled[i] = true; - } - } - - hws->ctx->dc->res_pool->dccg->funcs->trigger_dio_fifo_resync(hws->ctx->dc->res_pool->dccg); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (otg_disabled[i]) - pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); - } -} - -void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on) -{ - if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp) - return; - - if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control) - hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control( - hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on); -} - -static void apply_symclk_on_tx_off_wa(struct dc_link *link) -{ - /* There are use cases where SYMCLK is referenced by OTG. For instance - * for TMDS signal, OTG relies SYMCLK even if TX video output is off. - * However current link interface will power off PHY when disabling link - * output. This will turn off SYMCLK generated by PHY. The workaround is - * to identify such case where SYMCLK is still in use by OTG when we - * power off PHY. When this is detected, we will temporarily power PHY - * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling - * program_pix_clk interface. When OTG is disabled, we will then power - * off PHY by calling disable link output again. - * - * In future dcn generations, we plan to rework transmitter control - * interface so that we could have an option to set SYMCLK ON TX OFF - * state in one step without this workaround - */ - - struct dc *dc = link->ctx->dc; - struct pipe_ctx *pipe_ctx = NULL; - uint8_t i; - - if (link->phy_state.symclk_ref_cnts.otg > 0) { - for (i = 0; i < MAX_PIPES; i++) { - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { - pipe_ctx->clock_source->funcs->program_pix_clk( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - dc->link_srv->dp_get_encoding_format( - &pipe_ctx->link_config.dp_link_settings), - &pipe_ctx->pll_settings); - link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; - break; - } - } - } -} - -void dcn314_disable_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal) -{ - struct dc *dc = link->ctx->dc; - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - struct dmcu *dmcu = dc->res_pool->dmcu; - - if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control && - !link->skip_implict_edp_power_control) - link->dc->hwss.edp_backlight_control(link, false); - else if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->lock_phy(dmcu); - - link_hwss->disable_link_output(link, link_res, signal); - link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; - /* - * Add the logic to extract BOTH power up and power down sequences - * from enable/disable link output and only call edp panel control - * in enable_link_dp and disable_link_dp once. - */ - if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->unlock_phy(dmcu); - dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); - - apply_symclk_on_tx_off_wa(link); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h deleted file mode 100644 index eafcc4ea6d24..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright 2022 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN314_H__ -#define __DC_HWSS_DCN314_H__ - -#include "hw_sequencer_private.h" - -struct dc; - -void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); - -void dcn314_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); - -void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable); - -unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div); - -void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx); - -void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context); - -void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on); - -void dcn314_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); - -#endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c index 163dd563b209..ccb7e317e86a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c @@ -24,8 +24,8 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" #include "dcn21/dcn21_hwseq.h" #include "dcn30/dcn30_hwseq.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 64a2692fd4f6..2d7436f2ea82 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -50,7 +50,7 @@ #include "dcn314/dcn314_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c index ed804439fb7e..c11dbb1f4033 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c @@ -47,7 +47,7 @@ #include "dcn31/dcn31_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c index 9133a1ea4ca0..4220fe4cae4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c @@ -47,7 +47,7 @@ #include "dcn31/dcn31_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile index e943b643ab6b..8bb251307247 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn32. -DCN32 = dcn32_resource.o dcn32_hubbub.o dcn32_hwseq.o dcn32_init.o \ +DCN32 = dcn32_resource.o dcn32_hubbub.o dcn32_init.o dcn32_dccg.o \ dcn32_dccg.o dcn32_optc.o dcn32_mmhubbub.o dcn32_hubp.o dcn32_dpp.o \ dcn32_dio_stream_encoder.o dcn32_dio_link_encoder.o dcn32_hpo_dp_link_encoder.o \ dcn32_resource_helpers.o dcn32_mpc.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c deleted file mode 100644 index 45b557d8e089..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c +++ /dev/null @@ -1,1678 +0,0 @@ -/* - * Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - - -#include "dm_services.h" -#include "dm_helpers.h" -#include "core_types.h" -#include "resource.h" -#include "dccg.h" -#include "dce/dce_hwseq.h" -#include "dcn30/dcn30_cm_common.h" -#include "reg_helper.h" -#include "abm.h" -#include "hubp.h" -#include "dchubbub.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "mcif_wb.h" -#include "dc_dmub_srv.h" -#include "link_hwss.h" -#include "dpcd_defs.h" -#include "dcn32_hwseq.h" -#include "clk_mgr.h" -#include "dsc.h" -#include "dcn20/dcn20_optc.h" -#include "dce/dmub_hw_lock_mgr.h" -#include "dcn32_resource.h" -#include "link.h" - -#define DC_LOGGER_INIT(logger) - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg -#define DC_LOGGER \ - stream->ctx->logger - - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name - -void dcn32_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - uint32_t org_ip_request_cntl = 0; - - if (hws->ctx->dc->debug.disable_dsc_power_gate) - return; - - if (!hws->ctx->dc->debug.enable_double_buffered_dsc_pg_support) - return; - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - switch (dsc_inst) { - case 0: /* DSC0 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN16_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DSC1 */ - REG_UPDATE(DOMAIN17_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN17_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DSC2 */ - REG_UPDATE(DOMAIN18_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN18_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DSC3 */ - REG_UPDATE(DOMAIN19_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN19_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} - - -void dcn32_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable) -{ - bool force_on = true; /* disable power gating */ - uint32_t org_ip_request_cntl = 0; - - if (enable) - force_on = false; - - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - /* DCHUBP0/1/2/3 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - /* DCS0/1/2/3 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} - -void dcn32_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - - if (hws->ctx->dc->debug.disable_hubp_power_gate) - return; - - if (REG(DOMAIN0_PG_CONFIG) == 0) - return; - - switch (hubp_inst) { - case 0: - REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - case 1: - REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - case 2: - REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - case 3: - REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); - REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } -} - -static bool dcn32_check_no_memory_request_for_cab(struct dc *dc) -{ - int i; - - /* First, check no-memory-request case */ - for (i = 0; i < dc->current_state->stream_count; i++) { - if ((dc->current_state->stream_status[i].plane_count) && - (dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)) - /* Fail eligibility on a visible stream */ - break; - } - - if (i == dc->current_state->stream_count) - return true; - - return false; -} - - -/* This function loops through every surface that needs to be cached in CAB for SS, - * and calculates the total number of ways required to store all surfaces (primary, - * meta, cursor). - */ -static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx) -{ - int i; - uint8_t num_ways = 0; - uint32_t mall_ss_size_bytes = 0; - - mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes; - // TODO add additional logic for PSR active stream exclusion optimization - // mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes; - - // Include cursor size for CAB allocation - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i]; - - if (!pipe->stream || !pipe->plane_state) - continue; - - mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false); - } - - // Convert number of cache lines required to number of ways - if (dc->debug.force_mall_ss_num_ways > 0) { - num_ways = dc->debug.force_mall_ss_num_ways; - } else { - num_ways = dcn32_helper_mall_bytes_to_ways(dc, mall_ss_size_bytes); - } - - return num_ways; -} - -bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) -{ - union dmub_rb_cmd cmd; - uint8_t ways, i; - int j; - bool mall_ss_unsupported = false; - struct dc_plane_state *plane = NULL; - - if (!dc->ctx->dmub_srv) - return false; - - for (i = 0; i < dc->current_state->stream_count; i++) { - /* MALL SS messaging is not supported with PSR at this time */ - if (dc->current_state->streams[i] != NULL && - dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) - return false; - } - - if (enable) { - if (dc->current_state) { - - /* 1. Check no memory request case for CAB. - * If no memory request case, send CAB_ACTION NO_DF_REQ DMUB message - */ - if (dcn32_check_no_memory_request_for_cab(dc)) { - /* Enable no-memory-requests case */ - memset(&cmd, 0, sizeof(cmd)); - cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; - cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ; - cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); - - return true; - } - - /* 2. Check if all surfaces can fit in CAB. - * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message - * and configure HUBP's to fetch from MALL - */ - ways = dcn32_calculate_cab_allocation(dc, dc->current_state); - - /* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo, - * or TMZ surface, don't try to enter MALL. - */ - for (i = 0; i < dc->current_state->stream_count; i++) { - for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) { - plane = dc->current_state->stream_status[i].plane_states[j]; - - if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO || - plane->address.tmz_surface) { - mall_ss_unsupported = true; - break; - } - } - if (mall_ss_unsupported) - break; - } - if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) { - memset(&cmd, 0, sizeof(cmd)); - cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; - cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB; - cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); - cmd.cab.cab_alloc_ways = ways; - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); - - return true; - } - - } - return false; - } - - /* Disable CAB */ - memset(&cmd, 0, sizeof(cmd)); - cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; - cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION; - cmd.cab.header.payload_bytes = - sizeof(cmd.cab) - sizeof(cmd.cab.header); - - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); - - return true; -} - -/* Send DMCUB message with SubVP pipe info - * - For each pipe in context, populate payload with required SubVP information - * if the pipe is using SubVP for MCLK switch - * - This function must be called while the DMUB HW lock is acquired by driver - */ -void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context) -{ - int i; - bool enable_subvp = false; - - if (!dc->ctx || !dc->ctx->dmub_srv) - return; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.paired_stream && - pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { - // There is at least 1 SubVP pipe, so enable SubVP - enable_subvp = true; - break; - } - } - dc_dmub_setup_subvp_dmub_command(dc, context, enable_subvp); -} - -/* Sub-Viewport DMUB lock needs to be acquired by driver whenever SubVP is active and: - * 1. Any full update for any SubVP main pipe - * 2. Any immediate flip for any SubVP pipe - * 3. Any flip for DRR pipe - * 4. If SubVP was previously in use (i.e. in old context) - */ -void dcn32_subvp_pipe_control_lock(struct dc *dc, - struct dc_state *context, - bool lock, - bool should_lock_all_pipes, - struct pipe_ctx *top_pipe_to_program, - bool subvp_prev_use) -{ - unsigned int i = 0; - bool subvp_immediate_flip = false; - bool subvp_in_use = false; - struct pipe_ctx *pipe; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &context->res_ctx.pipe_ctx[i]; - - if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - subvp_in_use = true; - break; - } - } - - if (top_pipe_to_program && top_pipe_to_program->stream && top_pipe_to_program->plane_state) { - if (top_pipe_to_program->stream->mall_stream_config.type == SUBVP_MAIN && - top_pipe_to_program->plane_state->flip_immediate) - subvp_immediate_flip = true; - } - - // Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared. - if ((subvp_in_use && (should_lock_all_pipes || subvp_immediate_flip)) || (!subvp_in_use && subvp_prev_use)) { - union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; - - if (!lock) { - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &context->res_ctx.pipe_ctx[i]; - if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN && - should_lock_all_pipes) - pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK); - } - } - - hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; - hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; - hw_lock_cmd.bits.lock = lock; - hw_lock_cmd.bits.should_release = !lock; - dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); - } -} - -void dcn32_subvp_pipe_control_lock_fast(union block_sequence_params *params) -{ - struct dc *dc = params->subvp_pipe_control_lock_fast_params.dc; - bool lock = params->subvp_pipe_control_lock_fast_params.lock; - struct pipe_ctx *pipe_ctx = params->subvp_pipe_control_lock_fast_params.pipe_ctx; - bool subvp_immediate_flip = false; - - if (pipe_ctx && pipe_ctx->stream && pipe_ctx->plane_state) { - if (pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN && - pipe_ctx->plane_state->flip_immediate) - subvp_immediate_flip = true; - } - - // Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared. - if (subvp_immediate_flip) { - union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; - - hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; - hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; - hw_lock_cmd.bits.lock = lock; - hw_lock_cmd.bits.should_release = !lock; - dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); - } -} - -bool dcn32_set_mpc_shaper_3dlut( - struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; - bool result = false; - - const struct pwl_params *shaper_lut = NULL; - //get the shaper lut params - if (stream->func_shaper) { - if (stream->func_shaper->type == TF_TYPE_HWPWL) - shaper_lut = &stream->func_shaper->pwl; - else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm_helper_translate_curve_to_hw_format(stream->ctx, - stream->func_shaper, - &dpp_base->shaper_params, true); - shaper_lut = &dpp_base->shaper_params; - } - } - - if (stream->lut3d_func && - stream->lut3d_func->state.bits.initialized == 1) { - - result = mpc->funcs->program_3dlut(mpc, - &stream->lut3d_func->lut_3d, - mpcc_id); - - result = mpc->funcs->program_shaper(mpc, - shaper_lut, - mpcc_id); - } - - return result; -} - -bool dcn32_set_mcm_luts( - struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) -{ - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; - bool result = true; - struct pwl_params *lut_params = NULL; - - // 1D LUT - if (plane_state->blend_tf) { - if (plane_state->blend_tf->type == TF_TYPE_HWPWL) - lut_params = &plane_state->blend_tf->pwl; - else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { - cm_helper_translate_curve_to_hw_format(plane_state->ctx, - plane_state->blend_tf, - &dpp_base->regamma_params, false); - lut_params = &dpp_base->regamma_params; - } - } - result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id); - - // Shaper - if (plane_state->in_shaper_func) { - if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL) - lut_params = &plane_state->in_shaper_func->pwl; - else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { - // TODO: dpp_base replace - ASSERT(false); - cm_helper_translate_curve_to_hw_format(plane_state->ctx, - plane_state->in_shaper_func, - &dpp_base->shaper_params, true); - lut_params = &dpp_base->shaper_params; - } - } - - result = mpc->funcs->program_shaper(mpc, lut_params, mpcc_id); - - // 3D - if (plane_state->lut3d_func && plane_state->lut3d_func->state.bits.initialized == 1) - result = mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func->lut_3d, mpcc_id); - else - result = mpc->funcs->program_3dlut(mpc, NULL, mpcc_id); - - return result; -} - -bool dcn32_set_input_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state) -{ - struct dce_hwseq *hws = dc->hwseq; - struct mpc *mpc = dc->res_pool->mpc; - struct dpp *dpp_base = pipe_ctx->plane_res.dpp; - - enum dc_transfer_func_predefined tf; - bool result = true; - struct pwl_params *params = NULL; - - if (mpc == NULL || plane_state == NULL) - return false; - - tf = TRANSFER_FUNCTION_UNITY; - - if (plane_state->in_transfer_func && - plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED) - tf = plane_state->in_transfer_func->tf; - - dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf); - - if (plane_state->in_transfer_func) { - if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL) - params = &plane_state->in_transfer_func->pwl; - else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func, - &dpp_base->degamma_params, false)) - params = &dpp_base->degamma_params; - } - - dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); - - if (pipe_ctx->stream_res.opp && - pipe_ctx->stream_res.opp->ctx && - hws->funcs.set_mcm_luts) - result = hws->funcs.set_mcm_luts(pipe_ctx, plane_state); - - return result; -} - -bool dcn32_set_output_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream) -{ - int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; - struct pwl_params *params = NULL; - bool ret = false; - - /* program OGAM or 3DLUT only for the top pipe*/ - if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) { - /*program shaper and 3dlut in MPC*/ - ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream); - if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) { - if (stream->out_transfer_func->type == TF_TYPE_HWPWL) - params = &stream->out_transfer_func->pwl; - else if (pipe_ctx->stream->out_transfer_func->type == - TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format( - stream->out_transfer_func, - &mpc->blender_params, false)) - params = &mpc->blender_params; - /* there are no ROM LUTs in OUTGAM */ - if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) - BREAK_TO_DEBUGGER(); - } - } - - mpc->funcs->set_output_gamma(mpc, mpcc_id, params); - return ret; -} - -/* Program P-State force value according to if pipe is using SubVP / FPO or not: - * 1. Reset P-State force on all pipes first - * 2. For each main pipe, force P-State disallow (P-State allow moderated by DMUB) - */ -void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context) -{ - int i; - - /* Unforce p-state for each pipe if it is not FPO or SubVP. - * For FPO and SubVP, if it's already forced disallow, leave - * it as disallow. - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = pipe->plane_res.hubp; - - if (!pipe->stream || !(pipe->stream->mall_stream_config.type == SUBVP_MAIN || - pipe->stream->fpo_in_use)) { - if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) - hubp->funcs->hubp_update_force_pstate_disallow(hubp, false); - } - - /* Today only FPO uses cursor P-State force. Only clear cursor P-State force - * if it's not FPO. - */ - if (!pipe->stream || !pipe->stream->fpo_in_use) { - if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow) - hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, false); - } - } - - /* Loop through each pipe -- for each subvp main pipe force p-state allow equal to false. - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = pipe->plane_res.hubp; - - if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) - hubp->funcs->hubp_update_force_pstate_disallow(hubp, true); - } - - if (pipe->stream && pipe->stream->fpo_in_use) { - if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) - hubp->funcs->hubp_update_force_pstate_disallow(hubp, true); - /* For now only force cursor p-state disallow for FPO - * Needs to be added for subvp once FW side gets updated - */ - if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow) - hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, true); - } - } -} - -/* Update MALL_SEL register based on if pipe / plane - * is a phantom pipe, main pipe, and if using MALL - * for SS. - */ -void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context) -{ - int i; - unsigned int num_ways = dcn32_calculate_cab_allocation(dc, context); - bool cache_cursor = false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = pipe->plane_res.hubp; - - if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) { - int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; - - switch (hubp->curs_attr.color_format) { - case CURSOR_MODE_MONO: - cursor_size /= 2; - break; - case CURSOR_MODE_COLOR_1BIT_AND: - case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: - case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: - cursor_size *= 4; - break; - - case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: - case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: - default: - cursor_size *= 8; - break; - } - - if (cursor_size > 16384) - cache_cursor = true; - - if (pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - hubp->funcs->hubp_update_mall_sel(hubp, 1, false); - } else { - // MALL not supported with Stereo3D - hubp->funcs->hubp_update_mall_sel(hubp, - num_ways <= dc->caps.cache_num_ways && - pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && - pipe->plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO && - !pipe->plane_state->address.tmz_surface ? 2 : 0, - cache_cursor); - } - } - } -} - -/* Program the sub-viewport pipe configuration after the main / phantom pipes - * have been programmed in hardware. - * 1. Update force P-State for all the main pipes (disallow P-state) - * 2. Update MALL_SEL register - * 3. Program FORCE_ONE_ROW_FOR_FRAME for main subvp pipes - */ -void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - - // Don't force p-state disallow -- can't block dummy p-state - - // Update MALL_SEL register for each pipe - if (hws && hws->funcs.update_mall_sel) - hws->funcs.update_mall_sel(dc, context); - - // Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = pipe->plane_res.hubp; - - if (pipe->stream && hubp && hubp->funcs->hubp_prepare_subvp_buffering) { - /* TODO - remove setting CURSOR_REQ_MODE to 0 for legacy cases - * - need to investigate single pipe MPO + SubVP case to - * see if CURSOR_REQ_MODE will be back to 1 for SubVP - * when it should be 0 for MPO - */ - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - hubp->funcs->hubp_prepare_subvp_buffering(hubp, true); - } - } - } -} - -static void dcn32_initialize_min_clocks(struct dc *dc) -{ - struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk; - - clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ; - clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000; - clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000; - clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000; - clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000; - clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; - clocks->fclk_p_state_change_support = true; - clocks->p_state_change_support = true; - if (dc->debug.disable_boot_optimizations) { - clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000; - } else { - /* Even though DPG_EN = 1 for the connected display, it still requires the - * correct timing so we cannot set DISPCLK to min freq or it could cause - * audio corruption. Read current DISPCLK from DENTIST and request the same - * freq to ensure that the timing is valid and unchanged. - */ - clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr); - } - - dc->clk_mgr->funcs->update_clocks( - dc->clk_mgr, - dc->current_state, - true); -} - -void dcn32_init_hw(struct dc *dc) -{ - struct abm **abms = dc->res_pool->multiple_abms; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - int i; - int edp_num; - uint32_t backlight = MAX_BACKLIGHT_LEVEL; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - if (!dcb->funcs->is_accelerated_mode(dcb)) { - hws->funcs.bios_golden_init(dc); - hws->funcs.disable_vga(dc->hwseq); - } - - // Set default OPTC memory power states - if (dc->debug.enable_mem_low_power.bits.optc) { - // Shutdown when unassigned and light sleep in VBLANK - REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); - } - - if (dc->debug.enable_mem_low_power.bits.vga) { - // Power down VGA memory - REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); - } - - if (dc->ctx->dc_bios->fw_info_valid) { - res_pool->ref_clocks.xtalin_clock_inKhz = - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - - if (res_pool->dccg && res_pool->hubbub) { - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - link->link_enc->funcs->hw_init(link->link_enc); - - /* Check for enabled DIG to identify enabled display */ - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc)) { - link->link_status.link_active = true; - link->phy_state.symclk_state = SYMCLK_ON_TX_ON; - if (link->link_enc->funcs->fec_is_active && - link->link_enc->funcs->fec_is_active(link->link_enc)) - link->fec_state = dc_link_fec_enabled; - } - } - - /* enable_power_gating_plane before dsc_pg_control because - * FORCEON = 1 with hw default value on bootup, resume from s3 - */ - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); - - /* we want to turn off all dp displays before doing detection */ - dc->link_srv->blank_all_dp_displays(dc); - - /* If taking control over from VBIOS, we may want to optimize our first - * mode set, so we need to skip powering down pipes until we know which - * pipes we want to use. - * Otherwise, if taking control is not possible, we need to power - * everything down. - */ - if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { - /* Disable boot optimizations means power down everything including PHY, DIG, - * and OTG (i.e. the boot is not optimized because we do a full power down). - */ - if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations) - dc->hwss.enable_accelerated_mode(dc, dc->current_state); - else - hws->funcs.init_pipes(dc, dc->current_state); - - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - - dcn32_initialize_min_clocks(dc); - - /* On HW init, allow idle optimizations after pipes have been turned off. - * - * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state - * is reset (i.e. not in idle at the time hw init is called), but software state - * still has idle_optimizations = true, so we must disable idle optimizations first - * (i.e. set false), then re-enable (set true). - */ - dc_allow_idle_optimizations(dc, false); - dc_allow_idle_optimizations(dc, true); - } - - /* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on and seamless boot not enabled - */ - if (!dc->config.seamless_boot_edp_requested) { - struct dc_link *edp_links[MAX_NUM_EDP]; - struct dc_link *edp_link; - - dc_get_edp_links(dc, edp_links, &edp_num); - if (edp_num) { - for (i = 0; i < edp_num; i++) { - edp_link = edp_links[i]; - if (edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwss.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwss.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - } - } - } else { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } - } - } - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (abms[i] != NULL && abms[i]->funcs != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); - } - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) - dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); - - if (dc->clk_mgr->funcs->notify_wm_ranges) - dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); - - if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) - dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); - - if (dc->res_pool->hubbub->funcs->force_pstate_change_control) - dc->res_pool->hubbub->funcs->force_pstate_change_control( - dc->res_pool->hubbub, false, false); - - if (dc->res_pool->hubbub->funcs->init_crb) - dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); - - if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0) - 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); - - // Get DMCUB capabilities - if (dc->ctx->dmub_srv) { - dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); - dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; - dc->caps.dmub_caps.subvp_psr = dc->ctx->dmub_srv->dmub->feature_caps.subvp_psr_support; - dc->caps.dmub_caps.gecc_enable = dc->ctx->dmub_srv->dmub->feature_caps.gecc_enable; - dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; - } -} - -static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, - int opp_cnt) -{ - bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); - int flow_ctrl_cnt; - - if (opp_cnt >= 2) - hblank_halved = true; - - flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - - stream->timing.h_border_left - - stream->timing.h_border_right; - - if (hblank_halved) - flow_ctrl_cnt /= 2; - - /* ODM combine 4:1 case */ - if (opp_cnt == 4) - flow_ctrl_cnt /= 2; - - return flow_ctrl_cnt; -} - -static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) -{ - struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; - struct dc_stream_state *stream = pipe_ctx->stream; - struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - - ASSERT(dsc); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - opp_cnt++; - - if (enable) { - struct dsc_config dsc_cfg; - struct dsc_optc_config dsc_optc_cfg; - enum optc_dsc_mode optc_dsc_mode; - - /* Enable DSC hw block */ - dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; - dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; - dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; - dsc_cfg.color_depth = stream->timing.display_color_depth; - dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; - dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; - ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); - dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; - - dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); - dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; - - ASSERT(odm_dsc); - odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); - odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); - } - dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; - dsc_cfg.pic_width *= opp_cnt; - - optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; - - /* Enable DSC in OPTC */ - DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); - pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, - optc_dsc_mode, - dsc_optc_cfg.bytes_per_pixel, - dsc_optc_cfg.slice_width); - } else { - /* disable DSC in OPTC */ - pipe_ctx->stream_res.tg->funcs->set_dsc_config( - pipe_ctx->stream_res.tg, - OPTC_DSC_DISABLED, 0, 0); - - /* disable DSC block */ - dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - ASSERT(odm_pipe->stream_res.dsc); - odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); - } - } -} - -/* -* Given any pipe_ctx, return the total ODM combine factor, and optionally return -* the OPPids which are used -* */ -static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) -{ - unsigned int opp_count = 1; - struct pipe_ctx *odm_pipe; - - /* First get to the top pipe */ - for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) - ; - - /* First pipe is always used */ - if (opp_instances) - opp_instances[0] = odm_pipe->stream_res.opp->inst; - - /* Find and count odm pipes, if any */ - for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - if (opp_instances) - opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; - opp_count++; - } - - return opp_count; -} - -void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *odm_pipe; - int opp_cnt = 0; - int opp_inst[MAX_PIPES] = {0}; - bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); - struct mpc_dwb_flow_control flow_control; - struct mpc *mpc = dc->res_pool->mpc; - int i; - - opp_cnt = get_odm_config(pipe_ctx, opp_inst); - - if (opp_cnt > 1) - pipe_ctx->stream_res.tg->funcs->set_odm_combine( - pipe_ctx->stream_res.tg, - opp_inst, opp_cnt, - &pipe_ctx->stream->timing); - else - pipe_ctx->stream_res.tg->funcs->set_odm_bypass( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - - rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; - flow_control.flow_ctrl_mode = 0; - flow_control.flow_ctrl_cnt0 = 0x80; - flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt); - if (mpc->funcs->set_out_rate_control) { - for (i = 0; i < opp_cnt; ++i) { - mpc->funcs->set_out_rate_control( - mpc, opp_inst[i], - true, - rate_control_2x_pclk, - &flow_control); - } - } - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( - odm_pipe->stream_res.opp, - true); - } - - if (pipe_ctx->stream_res.dsc) { - struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; - - update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); - - /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ - if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && - current_pipe_ctx->next_odm_pipe->stream_res.dsc) { - struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; - /* disconnect DSC block from stream */ - dsc->funcs->dsc_disconnect(dsc); - } - } -} - -unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div) -{ - struct dc_stream_state *stream = pipe_ctx->stream; - unsigned int odm_combine_factor = 0; - bool two_pix_per_container = false; - - two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); - odm_combine_factor = get_odm_config(pipe_ctx, NULL); - - if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - *k1_div = PIXEL_RATE_DIV_BY_1; - *k2_div = PIXEL_RATE_DIV_BY_1; - } else if (dc_is_hdmi_tmds_signal(stream->signal) || dc_is_dvi_signal(stream->signal)) { - *k1_div = PIXEL_RATE_DIV_BY_1; - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - *k2_div = PIXEL_RATE_DIV_BY_2; - else - *k2_div = PIXEL_RATE_DIV_BY_4; - } else if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) { - if (two_pix_per_container) { - *k1_div = PIXEL_RATE_DIV_BY_1; - *k2_div = PIXEL_RATE_DIV_BY_2; - } else { - *k1_div = PIXEL_RATE_DIV_BY_1; - *k2_div = PIXEL_RATE_DIV_BY_4; - if ((odm_combine_factor == 2) || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) - *k2_div = PIXEL_RATE_DIV_BY_2; - } - } - - if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA)) - ASSERT(false); - - return odm_combine_factor; -} - -void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) -{ - uint32_t pix_per_cycle = 1; - uint32_t odm_combine_factor = 1; - - if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc) - return; - - odm_combine_factor = get_odm_config(pipe_ctx, NULL); - if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1 - || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) - pix_per_cycle = 2; - - if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) - pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, - pix_per_cycle); -} - -void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context) -{ - unsigned int i; - struct pipe_ctx *pipe = NULL; - bool otg_disabled[MAX_PIPES] = {false}; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (!resource_is_pipe_type(pipe, OTG_MASTER)) - continue; - - if ((pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal)) - && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { - pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg); - reset_sync_context_for_pipe(dc, context, i); - otg_disabled[i] = true; - } - } - - hws->ctx->dc->res_pool->dccg->funcs->trigger_dio_fifo_resync(hws->ctx->dc->res_pool->dccg); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (otg_disabled[i]) - pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); - } -} - -void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings) -{ - struct encoder_unblank_param params = {0}; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->link; - struct dce_hwseq *hws = link->dc->hwseq; - struct pipe_ctx *odm_pipe; - uint32_t pix_per_cycle = 1; - - params.opp_cnt = 1; - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - params.opp_cnt++; - - /* only 3 items below are used by unblank */ - params.timing = pipe_ctx->stream->timing; - - params.link_settings.link_rate = link_settings->link_rate; - - if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { - /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ - pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( - pipe_ctx->stream_res.hpo_dp_stream_enc, - pipe_ctx->stream_res.tg->inst); - } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { - if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1 - || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) { - params.timing.pix_clk_100hz /= 2; - pix_per_cycle = 2; - } - pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( - pipe_ctx->stream_res.stream_enc, pix_per_cycle > 1); - pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); - } - - if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) - hws->funcs.edp_backlight_control(link, true); -} - -bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx) -{ - struct dc *dc = pipe_ctx->stream->ctx->dc; - - if (!is_h_timing_divisible_by_2(pipe_ctx->stream)) - return false; - - if (dc_is_dp_signal(pipe_ctx->stream->signal) && !dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) && - dc->debug.enable_dp_dig_pixel_rate_div_policy) - return true; - return false; -} - -static void apply_symclk_on_tx_off_wa(struct dc_link *link) -{ - /* There are use cases where SYMCLK is referenced by OTG. For instance - * for TMDS signal, OTG relies SYMCLK even if TX video output is off. - * However current link interface will power off PHY when disabling link - * output. This will turn off SYMCLK generated by PHY. The workaround is - * to identify such case where SYMCLK is still in use by OTG when we - * power off PHY. When this is detected, we will temporarily power PHY - * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling - * program_pix_clk interface. When OTG is disabled, we will then power - * off PHY by calling disable link output again. - * - * In future dcn generations, we plan to rework transmitter control - * interface so that we could have an option to set SYMCLK ON TX OFF - * state in one step without this workaround - */ - - struct dc *dc = link->ctx->dc; - struct pipe_ctx *pipe_ctx = NULL; - uint8_t i; - - if (link->phy_state.symclk_ref_cnts.otg > 0) { - for (i = 0; i < MAX_PIPES; i++) { - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) && pipe_ctx->stream->link == link) { - pipe_ctx->clock_source->funcs->program_pix_clk( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - dc->link_srv->dp_get_encoding_format( - &pipe_ctx->link_config.dp_link_settings), - &pipe_ctx->pll_settings); - link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; - break; - } - } - } -} - -void dcn32_disable_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal) -{ - struct dc *dc = link->ctx->dc; - const struct link_hwss *link_hwss = get_link_hwss(link, link_res); - struct dmcu *dmcu = dc->res_pool->dmcu; - - if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control && - !link->skip_implict_edp_power_control) - link->dc->hwss.edp_backlight_control(link, false); - else if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->lock_phy(dmcu); - - link_hwss->disable_link_output(link, link_res, signal); - link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; - - if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control && - !link->skip_implict_edp_power_control) - link->dc->hwss.edp_power_control(link, false); - else if (dmcu != NULL && dmcu->funcs->lock_phy) - dmcu->funcs->unlock_phy(dmcu); - - dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); - - apply_symclk_on_tx_off_wa(link); -} - -/* For SubVP the main pipe can have a viewport position change - * without a full update. In this case we must also update the - * viewport positions for the phantom pipe accordingly. - */ -void dcn32_update_phantom_vp_position(struct dc *dc, - struct dc_state *context, - struct pipe_ctx *phantom_pipe) -{ - uint32_t i; - struct dc_plane_state *phantom_plane = phantom_pipe->plane_state; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN && - pipe->stream->mall_stream_config.paired_stream == phantom_pipe->stream) { - if (pipe->plane_state && pipe->plane_state->update_flags.bits.position_change) { - - phantom_plane->src_rect.x = pipe->plane_state->src_rect.x; - phantom_plane->src_rect.y = pipe->plane_state->src_rect.y; - phantom_plane->clip_rect.x = pipe->plane_state->clip_rect.x; - phantom_plane->dst_rect.x = pipe->plane_state->dst_rect.x; - phantom_plane->dst_rect.y = pipe->plane_state->dst_rect.y; - - phantom_pipe->plane_state->update_flags.bits.position_change = 1; - resource_build_scaling_params(phantom_pipe); - return; - } - } - } -} - -/* Treat the phantom pipe as if it needs to be fully enabled. - * If the pipe was previously in use but not phantom, it would - * have been disabled earlier in the sequence so we need to run - * the full enable sequence. - */ -void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe) -{ - phantom_pipe->update_flags.raw = 0; - if (phantom_pipe->stream && phantom_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) { - phantom_pipe->update_flags.bits.enable = 1; - phantom_pipe->update_flags.bits.mpcc = 1; - phantom_pipe->update_flags.bits.dppclk = 1; - phantom_pipe->update_flags.bits.hubp_interdependent = 1; - phantom_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; - phantom_pipe->update_flags.bits.gamut_remap = 1; - phantom_pipe->update_flags.bits.scaler = 1; - phantom_pipe->update_flags.bits.viewport = 1; - phantom_pipe->update_flags.bits.det_size = 1; - if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) { - phantom_pipe->update_flags.bits.odm = 1; - phantom_pipe->update_flags.bits.global_sync = 1; - } - } - } -} - -bool dcn32_dsc_pg_status( - struct dce_hwseq *hws, - unsigned int dsc_inst) -{ - uint32_t pwr_status = 0; - - switch (dsc_inst) { - case 0: /* DSC0 */ - REG_GET(DOMAIN16_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, &pwr_status); - break; - case 1: /* DSC1 */ - - REG_GET(DOMAIN17_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, &pwr_status); - break; - case 2: /* DSC2 */ - REG_GET(DOMAIN18_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, &pwr_status); - break; - case 3: /* DSC3 */ - REG_GET(DOMAIN19_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, &pwr_status); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - return pwr_status == 0; -} - -void dcn32_update_dsc_pg(struct dc *dc, - struct dc_state *context, - bool safe_to_disable) -{ - struct dce_hwseq *hws = dc->hwseq; - int i; - - for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { - struct display_stream_compressor *dsc = dc->res_pool->dscs[i]; - bool is_dsc_ungated = hws->funcs.dsc_pg_status(hws, dsc->inst); - - if (context->res_ctx.is_dsc_acquired[i]) { - if (!is_dsc_ungated) { - hws->funcs.dsc_pg_control(hws, dsc->inst, true); - } - } else if (safe_to_disable) { - if (is_dsc_ungated) { - hws->funcs.dsc_pg_control(hws, dsc->inst, false); - } - } - } -} - -void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context) -{ - unsigned int i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - - /* If an active, non-phantom pipe is being transitioned into a phantom - * pipe, wait for the double buffer update to complete first before we do - * ANY phantom pipe programming. - */ - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM && - old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { - old_pipe->stream_res.tg->funcs->wait_for_state( - old_pipe->stream_res.tg, - CRTC_STATE_VBLANK); - old_pipe->stream_res.tg->funcs->wait_for_state( - old_pipe->stream_res.tg, - CRTC_STATE_VACTIVE); - } - } - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; - - if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - // If old context or new context has phantom pipes, apply - // the phantom timings now. We can't change the phantom - // pipe configuration safely without driver acquiring - // the DMCUB lock first. - dc->hwss.apply_ctx_to_hw(dc, context); - break; - } - } -} - -/* Blank pixel data during initialization */ -void dcn32_init_blank( - struct dc *dc, - struct timing_generator *tg) -{ - struct dce_hwseq *hws = dc->hwseq; - enum dc_color_space color_space; - struct tg_color black_color = {0}; - struct output_pixel_processor *opp = NULL; - struct output_pixel_processor *bottom_opp = NULL; - uint32_t num_opps, opp_id_src0, opp_id_src1; - uint32_t otg_active_width, otg_active_height; - uint32_t i; - - /* program opp dpg blank color */ - color_space = COLOR_SPACE_SRGB; - color_space_to_black_color(dc, color_space, &black_color); - - /* get the OTG active size */ - tg->funcs->get_otg_active_size(tg, - &otg_active_width, - &otg_active_height); - - /* get the OPTC source */ - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - - if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) { - ASSERT(false); - return; - } - - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) { - opp = dc->res_pool->opps[i]; - break; - } - } - - if (num_opps == 2) { - otg_active_width = otg_active_width / 2; - - if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) { - ASSERT(false); - return; - } - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src1) { - bottom_opp = dc->res_pool->opps[i]; - break; - } - } - } - - if (opp && opp->funcs->opp_set_disp_pattern_generator) - opp->funcs->opp_set_disp_pattern_generator( - opp, - CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - COLOR_DEPTH_UNDEFINED, - &black_color, - otg_active_width, - otg_active_height, - 0); - - if (num_opps == 2) { - if (bottom_opp && bottom_opp->funcs->opp_set_disp_pattern_generator) { - bottom_opp->funcs->opp_set_disp_pattern_generator( - bottom_opp, - CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - COLOR_DEPTH_UNDEFINED, - &black_color, - otg_active_width, - otg_active_height, - 0); - hws->funcs.wait_for_blank_complete(bottom_opp); - } - } - - if (opp) - hws->funcs.wait_for_blank_complete(opp); -} - -void dcn32_blank_phantom(struct dc *dc, - struct timing_generator *tg, - int width, - int height) -{ - struct dce_hwseq *hws = dc->hwseq; - enum dc_color_space color_space; - struct tg_color black_color = {0}; - struct output_pixel_processor *opp = NULL; - uint32_t num_opps, opp_id_src0, opp_id_src1; - uint32_t otg_active_width, otg_active_height; - uint32_t i; - - /* program opp dpg blank color */ - color_space = COLOR_SPACE_SRGB; - color_space_to_black_color(dc, color_space, &black_color); - - otg_active_width = width; - otg_active_height = height; - - /* get the OPTC source */ - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); - - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) { - opp = dc->res_pool->opps[i]; - break; - } - } - - if (opp && opp->funcs->opp_set_disp_pattern_generator) - opp->funcs->opp_set_disp_pattern_generator( - opp, - CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - COLOR_DEPTH_UNDEFINED, - &black_color, - otg_active_width, - otg_active_height, - 0); - - if (tg->funcs->is_tg_enabled(tg)) - hws->funcs.wait_for_blank_complete(opp); -} - -bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc, - const struct dc_state *cur_ctx, - const struct dc_state *new_ctx) -{ - int i; - const struct pipe_ctx *cur_pipe, *new_pipe; - bool is_seamless = true; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - cur_pipe = &cur_ctx->res_ctx.pipe_ctx[i]; - new_pipe = &new_ctx->res_ctx.pipe_ctx[i]; - - if (resource_is_pipe_type(cur_pipe, FREE_PIPE) || - resource_is_pipe_type(new_pipe, FREE_PIPE)) - /* adding or removing free pipes is always seamless */ - continue; - else if (resource_is_pipe_type(cur_pipe, OTG_MASTER)) { - if (resource_is_pipe_type(new_pipe, OTG_MASTER)) - if (cur_pipe->stream->stream_id == new_pipe->stream->stream_id) - /* OTG master with the same stream is seamless */ - continue; - } else if (resource_is_pipe_type(cur_pipe, OPP_HEAD)) { - if (resource_is_pipe_type(new_pipe, OPP_HEAD)) { - if (cur_pipe->stream_res.tg == new_pipe->stream_res.tg) - /* - * OPP heads sharing the same timing - * generator is seamless - */ - continue; - } - } else if (resource_is_pipe_type(cur_pipe, DPP_PIPE)) { - if (resource_is_pipe_type(new_pipe, DPP_PIPE)) { - if (cur_pipe->stream_res.opp == new_pipe->stream_res.opp) - /* - * DPP pipes sharing the same OPP head is - * seamless - */ - continue; - } - } - - /* - * This pipe's transition doesn't fall under any seamless - * conditions - */ - is_seamless = false; - break; - } - - return is_seamless; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h deleted file mode 100644 index 9992e40acd21..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -* Copyright 2016 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HWSS_DCN32_H__ -#define __DC_HWSS_DCN32_H__ - -#include "hw_sequencer_private.h" - -struct dc; - -void dcn32_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on); - -void dcn32_enable_power_gating_plane( - struct dce_hwseq *hws, - bool enable); - -void dcn32_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); - -bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable); - -void dcn32_cab_for_ss_control(struct dc *dc, bool enable); - -void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context); - -bool dcn32_set_mcm_luts(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - -bool dcn32_set_input_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - -bool dcn32_set_mpc_shaper_3dlut( - struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream); - -bool dcn32_set_output_transfer_func(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); - -void dcn32_init_hw(struct dc *dc); - -void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context); - -void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context); - -void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context); - -void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); - -unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div); - -void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx); - -void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context); - -void dcn32_subvp_pipe_control_lock(struct dc *dc, - struct dc_state *context, - bool lock, - bool should_lock_all_pipes, - struct pipe_ctx *top_pipe_to_program, - bool subvp_prev_use); - -void dcn32_subvp_pipe_control_lock_fast(union block_sequence_params *params); - -void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings); - -bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx); - -void dcn32_disable_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal); - -void dcn32_update_phantom_vp_position(struct dc *dc, - struct dc_state *context, - struct pipe_ctx *phantom_pipe); - -void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe); - -bool dcn32_dsc_pg_status( - struct dce_hwseq *hws, - unsigned int dsc_inst); - -void dcn32_update_dsc_pg(struct dc *dc, - struct dc_state *context, - bool safe_to_disable); - -void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context); - -void dcn32_init_blank( - struct dc *dc, - struct timing_generator *tg); - -void dcn32_blank_phantom(struct dc *dc, - struct timing_generator *tg, - int width, - int height); - -bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc, - const struct dc_state *cur_ctx, - const struct dc_state *new_ctx); - -#endif /* __DC_HWSS_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c index 6e7f6df1d423..90f061edb64c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c @@ -23,13 +23,13 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" #include "dcn21/dcn21_hwseq.h" #include "dcn30/dcn30_hwseq.h" #include "dcn31/dcn31_hwseq.h" -#include "dcn32_hwseq.h" +#include "dcn32/dcn32_hwseq.h" #include "dcn32_init.h" static const struct hw_sequencer_funcs dcn32_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c index 4eda12eb982a..81b0588fa80b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c @@ -47,7 +47,7 @@ #include "dcn32/dcn32_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c index 2cb6369f3517..44caf6711589 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c @@ -50,7 +50,7 @@ #include "dcn32/dcn32_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn30/dcn30_opp.h" #include "dcn20/dcn20_dsc.h" #include "dcn30/dcn30_vpg.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile index c01d4ab4cdb6..20d0eef1a13b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile @@ -10,7 +10,7 @@ # # Makefile for DCN35. -DCN35 = dcn35_resource.o dcn35_hwseq.o dcn35_init.o dcn35_dio_stream_encoder.o \ +DCN35 = dcn35_resource.o dcn35_init.o dcn35_dio_stream_encoder.o \ dcn35_dio_link_encoder.o dcn35_dccg.o dcn35_optc.o \ dcn35_dsc.o dcn35_hubp.o dcn35_hubbub.o \ dcn35_mmhubbub.o dcn35_opp.o dcn35_dpp.o dcn35_pg_cntl.o dcn35_dwb.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c deleted file mode 100644 index 2be2a2f91434..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.c +++ /dev/null @@ -1,1205 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright 2023 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "dm_services.h" -#include "dm_helpers.h" -#include "core_types.h" -#include "resource.h" -#include "dccg.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "reg_helper.h" -#include "abm.h" -#include "hubp.h" -#include "dchubbub.h" -#include "timing_generator.h" -#include "opp.h" -#include "ipp.h" -#include "mpc.h" -#include "mcif_wb.h" -#include "dc_dmub_srv.h" -#include "dcn35_hwseq.h" -#include "dcn35/dcn35_dccg.h" -#include "link_hwss.h" -#include "dpcd_defs.h" -#include "dce/dmub_outbox.h" -#include "link.h" -#include "dcn10/dcn10_hw_sequencer.h" -#include "inc/link_enc_cfg.h" -#include "dcn30/dcn30_vpg.h" -#include "dce/dce_i2c_hw.h" -#include "dsc.h" -#include "dcn20/dcn20_optc.h" -#include "dcn30/dcn30_cm_common.h" -#include "dcn31/dcn31_hwseq.h" -#include "dcn20/dcn20_hwseq.h" - -#define DC_LOGGER_INIT(logger) \ - struct dal_logger *dc_logger = logger - -#define CTX \ - hws->ctx -#define REG(reg)\ - hws->regs->reg -#define DC_LOGGER \ - dc_logger - - -#undef FN -#define FN(reg_name, field_name) \ - hws->shifts->field_name, hws->masks->field_name -#if 0 -static void enable_memory_low_power(struct dc *dc) -{ - struct dce_hwseq *hws = dc->hwseq; - int i; - - if (dc->debug.enable_mem_low_power.bits.dmcu) { - // Force ERAM to shutdown if DMCU is not enabled - if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { - REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); - } - } - /*dcn35 has default MEM_PWR enabled, make sure wake them up*/ - // Set default OPTC memory power states - if (dc->debug.enable_mem_low_power.bits.optc) { - // Shutdown when unassigned and light sleep in VBLANK - REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); - } - - if (dc->debug.enable_mem_low_power.bits.vga) { - // Power down VGA memory - REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); - } - - if (dc->debug.enable_mem_low_power.bits.mpc && - dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode) - dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc); - - if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) { - // Power down VPGs - for (i = 0; i < dc->res_pool->stream_enc_count; i++) - dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); -#if defined(CONFIG_DRM_AMD_DC_DP2_0) - for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) - dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); -#endif - } - -} -#endif - -void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable) -{ - REG_UPDATE_3(DMU_CLK_CNTL, - RBBMIF_FGCG_REP_DIS, !enable, - IHC_FGCG_REP_DIS, !enable, - LONO_FGCG_REP_DIS, !enable - ); -} - -void dcn35_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) -{ - REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable); -} - -void dcn35_init_hw(struct dc *dc) -{ - struct abm **abms = dc->res_pool->multiple_abms; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct resource_pool *res_pool = dc->res_pool; - uint32_t backlight = MAX_BACKLIGHT_LEVEL; - int i; - - if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) - dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0x3F000000); - REG_WRITE(DCCG_GATE_DISABLE_CNTL5, 0x1f7c3fcf); - - //dcn35_set_dmu_fgcg(hws, dc->debug.enable_fine_grain_clock_gating.bits.dmu); - - if (!dcb->funcs->is_accelerated_mode(dcb)) { - /*this calls into dmubfw to do the init*/ - hws->funcs.bios_golden_init(dc); - } - // Initialize the dccg - if (res_pool->dccg->funcs->dccg_init) - res_pool->dccg->funcs->dccg_init(res_pool->dccg); - - //enable_memory_low_power(dc); - - if (dc->ctx->dc_bios->fw_info_valid) { - res_pool->ref_clocks.xtalin_clock_inKhz = - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - - if (res_pool->dccg && res_pool->hubbub) { - - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = - res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - if (link->ep_type != DISPLAY_ENDPOINT_PHY) - continue; - - link->link_enc->funcs->hw_init(link->link_enc); - - /* Check for enabled DIG to identify enabled display */ - if (link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc)) { - link->link_status.link_active = true; - if (link->link_enc->funcs->fec_is_active && - link->link_enc->funcs->fec_is_active(link->link_enc)) - link->fec_state = dc_link_fec_enabled; - } - } - - /* we want to turn off all dp displays before doing detection */ - dc->link_srv->blank_all_dp_displays(dc); -/* - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); -*/ - if (res_pool->hubbub->funcs->dchubbub_init) - res_pool->hubbub->funcs->dchubbub_init(dc->res_pool->hubbub); - /* If taking control over from VBIOS, we may want to optimize our first - * mode set, so we need to skip powering down pipes until we know which - * pipes we want to use. - * Otherwise, if taking control is not possible, we need to power - * everything down. - */ - if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { - - // we want to turn off edp displays if odm is enabled and no seamless boot - if (!dc->caps.seamless_odm) { - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - uint32_t num_opps, opp_id_src0, opp_id_src1; - - num_opps = 1; - if (tg) { - if (tg->funcs->is_tg_enabled(tg) && tg->funcs->get_optc_source) { - tg->funcs->get_optc_source(tg, &num_opps, - &opp_id_src0, &opp_id_src1); - } - } - - if (num_opps > 1) { - dc->link_srv->blank_all_edp_displays(dc); - break; - } - } - } - - hws->funcs.init_pipes(dc, dc->current_state); - if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) - dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, - !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); - } - - for (i = 0; i < res_pool->audio_count; i++) { - struct audio *audio = res_pool->audios[i]; - - audio->funcs->hw_init(audio); - } - - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->panel_cntl) - backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); - } - if (dc->ctx->dmub_srv) { - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (abms[i] != NULL && abms[i]->funcs != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); - } - } - - /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - // Set i2c to light sleep until engine is setup - if (dc->debug.enable_mem_low_power.bits.i2c) - REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0); - - if (hws->funcs.setup_hpo_hw_control) - hws->funcs.setup_hpo_hw_control(hws, false); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - if (dc->debug.disable_mem_low_power) { - REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 1); - } - if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) - dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); - - if (dc->clk_mgr->funcs->notify_wm_ranges) - dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); - - if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) - dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); - - - - if (dc->res_pool->hubbub->funcs->force_pstate_change_control) - dc->res_pool->hubbub->funcs->force_pstate_change_control( - dc->res_pool->hubbub, false, false); - - if (dc->res_pool->hubbub->funcs->init_crb) - dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); - - if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0) - 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); - // Get DMCUB capabilities - if (dc->ctx->dmub_srv) { - dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); - dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; - dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; - } - - if (dc->res_pool->pg_cntl) { - if (dc->res_pool->pg_cntl->funcs->init_pg_status) - dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl); - } -} - -static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, - int opp_cnt) -{ - bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); - int flow_ctrl_cnt; - - if (opp_cnt >= 2) - hblank_halved = true; - - flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - - stream->timing.h_border_left - - stream->timing.h_border_right; - - if (hblank_halved) - flow_ctrl_cnt /= 2; - - /* ODM combine 4:1 case */ - if (opp_cnt == 4) - flow_ctrl_cnt /= 2; - - return flow_ctrl_cnt; -} - -static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) -{ - struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; - struct dc_stream_state *stream = pipe_ctx->stream; - struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - - DC_LOGGER_INIT(stream->ctx->logger); - - ASSERT(dsc); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - opp_cnt++; - - if (enable) { - struct dsc_config dsc_cfg; - struct dsc_optc_config dsc_optc_cfg; - enum optc_dsc_mode optc_dsc_mode; - - /* Enable DSC hw block */ - dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; - dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; - dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; - dsc_cfg.color_depth = stream->timing.display_color_depth; - dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; - dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; - ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); - dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; - - dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); - dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; - - ASSERT(odm_dsc); - odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); - odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); - } - dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; - dsc_cfg.pic_width *= opp_cnt; - - optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; - - /* Enable DSC in OPTC */ - DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); - pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, - optc_dsc_mode, - dsc_optc_cfg.bytes_per_pixel, - dsc_optc_cfg.slice_width); - } else { - /* disable DSC in OPTC */ - pipe_ctx->stream_res.tg->funcs->set_dsc_config( - pipe_ctx->stream_res.tg, - OPTC_DSC_DISABLED, 0, 0); - - /* disable DSC block */ - dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - ASSERT(odm_pipe->stream_res.dsc); - odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); - } - } -} - -// Given any pipe_ctx, return the total ODM combine factor, and optionally return -// the OPPids which are used -static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) -{ - unsigned int opp_count = 1; - struct pipe_ctx *odm_pipe; - - // First get to the top pipe - for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) - ; - - // First pipe is always used - if (opp_instances) - opp_instances[0] = odm_pipe->stream_res.opp->inst; - - // Find and count odm pipes, if any - for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - if (opp_instances) - opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; - opp_count++; - } - - return opp_count; -} - -void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *odm_pipe; - int opp_cnt = 0; - int opp_inst[MAX_PIPES] = {0}; - bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); - struct mpc_dwb_flow_control flow_control; - struct mpc *mpc = dc->res_pool->mpc; - int i; - - opp_cnt = get_odm_config(pipe_ctx, opp_inst); - - if (opp_cnt > 1) - pipe_ctx->stream_res.tg->funcs->set_odm_combine( - pipe_ctx->stream_res.tg, - opp_inst, opp_cnt, - &pipe_ctx->stream->timing); - else - pipe_ctx->stream_res.tg->funcs->set_odm_bypass( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - - rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; - flow_control.flow_ctrl_mode = 0; - flow_control.flow_ctrl_cnt0 = 0x80; - flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt); - if (mpc->funcs->set_out_rate_control) { - for (i = 0; i < opp_cnt; ++i) { - mpc->funcs->set_out_rate_control( - mpc, opp_inst[i], - true, - rate_control_2x_pclk, - &flow_control); - } - } - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( - odm_pipe->stream_res.opp, - true); - } - - if (pipe_ctx->stream_res.dsc) { - struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; - - update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); - - /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ - if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && - current_pipe_ctx->next_odm_pipe->stream_res.dsc) { - struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; - /* disconnect DSC block from stream */ - dsc->funcs->dsc_disconnect(dsc); - } - } -} - -void dcn35_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on) -{ - if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp) - return; - - if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control) { - hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control( - hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on); - } -} - -void dcn35_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on) -{ - uint32_t power_gate = power_on ? 0 : 1; - uint32_t pwr_status = power_on ? 0 : 2; - uint32_t org_ip_request_cntl = 0; - - if (hws->ctx->dc->debug.disable_dsc_power_gate) - return; - if (hws->ctx->dc->debug.ignore_pg) - return; - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - - switch (dsc_inst) { - case 0: /* DSC0 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN16_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 1: /* DSC1 */ - REG_UPDATE(DOMAIN17_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN17_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 2: /* DSC2 */ - REG_UPDATE(DOMAIN18_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN18_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - case 3: /* DSC3 */ - REG_UPDATE(DOMAIN19_PG_CONFIG, - DOMAIN_POWER_GATE, power_gate); - - REG_WAIT(DOMAIN19_PG_STATUS, - DOMAIN_PGFSM_PWR_STATUS, pwr_status, - 1, 1000); - break; - default: - BREAK_TO_DEBUGGER(); - break; - } - - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); -} - -void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) -{ - bool force_on = true; /* disable power gating */ - uint32_t org_ip_request_cntl = 0; - - if (hws->ctx->dc->debug.disable_hubp_power_gate) - return; - if (hws->ctx->dc->debug.ignore_pg) - return; - REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); - if (org_ip_request_cntl == 0) - REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - /* DCHUBP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - /* DPP0/1/2/3/4/5 */ - REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - force_on = true; /* disable power gating */ - if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) - force_on = false; - - /* DCS0/1/2/3/4 */ - REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - - -} - -/* In headless boot cases, DIG may be turned - * on which causes HW/SW discrepancies. - * To avoid this, power down hardware on boot - * if DIG is turned on - */ -void dcn35_power_down_on_boot(struct dc *dc) -{ - struct dc_link *edp_links[MAX_NUM_EDP]; - struct dc_link *edp_link = NULL; - int edp_num; - int i = 0; - - dc_get_edp_links(dc, edp_links, &edp_num); - if (edp_num) - edp_link = edp_links[0]; - - if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && - edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && - dc->hwseq->funcs.edp_backlight_control && - dc->hwss.power_down && - dc->hwss.edp_power_control) { - dc->hwseq->funcs.edp_backlight_control(edp_link, false); - dc->hwss.power_down(dc); - dc->hwss.edp_power_control(edp_link, false); - } else { - for (i = 0; i < dc->link_count; i++) { - struct dc_link *link = dc->links[i]; - - if (link->link_enc && link->link_enc->funcs->is_dig_enabled && - link->link_enc->funcs->is_dig_enabled(link->link_enc) && - dc->hwss.power_down) { - dc->hwss.power_down(dc); - break; - } - - } - } - - /* - * Call update_clocks with empty context - * to send DISPLAY_OFF - * Otherwise DISPLAY_OFF may not be asserted - */ - if (dc->clk_mgr->funcs->set_low_power_state) - dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr); - - if (dc->clk_mgr->clks.pwr_state == DCN_PWR_STATE_LOW_POWER) { - if (!dc->idle_optimizations_allowed) { - dc_dmub_srv_notify_idle(dc, true); - dc->idle_optimizations_allowed = true; - } - } -} - -bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) -{ - struct dc_link *edp_links[MAX_NUM_EDP]; - int edp_num; - if (dc->debug.dmcub_emulation) - return true; - - if (enable) { - dc_get_edp_links(dc, edp_links, &edp_num); - if (edp_num == 0 || edp_num > 1) - return false; - } - - // TODO: review other cases when idle optimization is allowed - - if (!enable) - dc_dmub_srv_exit_low_power_state(dc); - else - dc_dmub_srv_notify_idle(dc, enable); - - return true; -} - -void dcn35_z10_restore(const struct dc *dc) -{ - if (dc->debug.disable_z10) - return; - - dc_dmub_srv_exit_low_power_state(dc); - - dcn31_z10_restore(dc); -} - -void dcn35_init_pipes(struct dc *dc, struct dc_state *context) -{ - int i; - struct dce_hwseq *hws = dc->hwseq; - struct hubbub *hubbub = dc->res_pool->hubbub; - struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; - bool can_apply_seamless_boot = false; - - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->apply_seamless_boot_optimization) { - can_apply_seamless_boot = true; - break; - } - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* There is assumption that pipe_ctx is not mapping irregularly - * to non-preferred front end. If pipe_ctx->stream is not NULL, - * we will use the pipe, so don't disable - */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - /* Blank controller using driver code instead of - * command table. - */ - if (tg->funcs->is_tg_enabled(tg)) { - if (hws->funcs.init_blank != NULL) { - hws->funcs.init_blank(dc, tg); - tg->funcs->lock(tg); - } else { - tg->funcs->lock(tg); - tg->funcs->set_blank(tg, true); - hwss_wait_for_blank_complete(tg); - } - } - } - - /* Reset det size */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - - /* Do not need to reset for seamless boot */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - if (hubbub && hubp) { - if (hubbub->funcs->program_det_size) - hubbub->funcs->program_det_size(hubbub, hubp->inst, 0); - } - } - - /* num_opp will be equal to number of mpcc */ - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* Cannot reset the MPC mux if seamless boot */ - if (pipe_ctx->stream != NULL && can_apply_seamless_boot) - continue; - - dc->res_pool->mpc->funcs->mpc_init_single_inst( - dc->res_pool->mpc, i); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct hubp *hubp = dc->res_pool->hubps[i]; - struct dpp *dpp = dc->res_pool->dpps[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - /* There is assumption that pipe_ctx is not mapping irregularly - * to non-preferred front end. If pipe_ctx->stream is not NULL, - * we will use the pipe, so don't disable - */ - if (can_apply_seamless_boot && - pipe_ctx->stream != NULL && - pipe_ctx->stream_res.tg->funcs->is_tg_enabled( - pipe_ctx->stream_res.tg)) { - // Enable double buffering for OTG_BLANK no matter if - // seamless boot is enabled or not to suppress global sync - // signals when OTG blanked. This is to prevent pipe from - // requesting data while in PSR. - tg->funcs->tg_init(tg); - hubp->power_gated = true; - continue; - } - - /* Disable on the current state so the new one isn't cleared. */ - pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - dpp->funcs->dpp_reset(dpp); - - pipe_ctx->stream_res.tg = tg; - pipe_ctx->pipe_idx = i; - - pipe_ctx->plane_res.hubp = hubp; - pipe_ctx->plane_res.dpp = dpp; - pipe_ctx->plane_res.mpcc_inst = dpp->inst; - hubp->mpcc_id = dpp->inst; - hubp->opp_id = OPP_ID_INVALID; - hubp->power_gated = false; - - dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; - dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; - dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; - pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); - - if (tg->funcs->is_tg_enabled(tg)) - tg->funcs->unlock(tg); - - dc->hwss.disable_plane(dc, pipe_ctx); - - pipe_ctx->stream_res.tg = NULL; - pipe_ctx->plane_res.hubp = NULL; - - if (tg->funcs->is_tg_enabled(tg)) { - if (tg->funcs->init_odm) - tg->funcs->init_odm(tg); - } - - tg->funcs->tg_init(tg); - } - - if (pg_cntl != NULL) { - if (pg_cntl->funcs->dsc_pg_control != NULL) { - uint32_t num_opps = 0; - uint32_t opp_id_src0 = OPP_ID_INVALID; - uint32_t opp_id_src1 = OPP_ID_INVALID; - - // Step 1: To find out which OPTC is running & OPTC DSC is ON - // We can't use res_pool->res_cap->num_timing_generator to check - // Because it records display pipes default setting built in driver, - // not display pipes of the current chip. - // Some ASICs would be fused display pipes less than the default setting. - // In dcnxx_resource_construct function, driver would obatin real information. - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - uint32_t optc_dsc_state = 0; - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - - if (tg->funcs->is_tg_enabled(tg)) { - if (tg->funcs->get_dsc_status) - tg->funcs->get_dsc_status(tg, &optc_dsc_state); - // Only one OPTC with DSC is ON, so if we got one result, - // we would exit this block. non-zero value is DSC enabled - if (optc_dsc_state != 0) { - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - break; - } - } - } - - // Step 2: To power down DSC but skip DSC of running OPTC - for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { - struct dcn_dsc_state s = {0}; - - dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); - - if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && - s.dsc_clock_en && s.dsc_fw_en) - continue; - - pg_cntl->funcs->dsc_pg_control(pg_cntl, dc->res_pool->dscs[i]->inst, false); - } - } - } -} - -void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_state *context) -{ - /* enable DCFCLK current DCHUB */ - pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); - - /* initialize HUBP on power up */ - pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp); - - /* make sure OPP_PIPE_CLOCK_EN = 1 */ - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( - pipe_ctx->stream_res.opp, - true); - /*to do: insert PG here*/ - if (dc->vm_pa_config.valid) { - struct vm_system_aperture_param apt; - - apt.sys_default.quad_part = 0; - - apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr; - apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr; - - // Program system aperture settings - pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); - } - - if (!pipe_ctx->top_pipe - && pipe_ctx->plane_state - && pipe_ctx->plane_state->flip_int_enabled - && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) - pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); -} - -/* disable HW used by plane. - * note: cannot disable until disconnect is complete - */ -void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct dpp *dpp = pipe_ctx->plane_res.dpp; - - dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); - - /* In flip immediate with pipe splitting case GSL is used for - * synchronization so we must disable it when the plane is disabled. - */ - if (pipe_ctx->stream_res.gsl_group != 0) - dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false); -/* - if (hubp->funcs->hubp_update_mall_sel) - hubp->funcs->hubp_update_mall_sel(hubp, 0, false); -*/ - dc->hwss.set_flip_control_gsl(pipe_ctx, false); - - hubp->funcs->hubp_clk_cntl(hubp, false); - - dpp->funcs->dpp_dppclk_control(dpp, false, false); -/*to do, need to support both case*/ - hubp->power_gated = true; - - dpp->funcs->dpp_reset(dpp); - - pipe_ctx->stream = NULL; - memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); - memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); - pipe_ctx->top_pipe = NULL; - pipe_ctx->bottom_pipe = NULL; - pipe_ctx->plane_state = NULL; -} - -void dcn35_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) -{ - struct dce_hwseq *hws = dc->hwseq; - bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom; - struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) - return; - - if (hws->funcs.plane_atomic_disable) - hws->funcs.plane_atomic_disable(dc, pipe_ctx); - - /* Turn back off the phantom OTG after the phantom plane is fully disabled - */ - if (is_phantom) - if (tg && tg->funcs->disable_phantom_crtc) - tg->funcs->disable_phantom_crtc(tg); - - DC_LOG_DC("Power down front end %d\n", - pipe_ctx->pipe_idx); -} - -void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, - struct pg_block_update *update_state) -{ - bool hpo_frl_stream_enc_acquired = false; - bool hpo_dp_stream_enc_acquired = false; - int i = 0, j = 0; - - memset(update_state, 0, sizeof(struct pg_block_update)); - - for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) { - if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] && - dc->res_pool->hpo_dp_stream_enc[i]) { - hpo_dp_stream_enc_acquired = true; - break; - } - } - - if (!hpo_frl_stream_enc_acquired && !hpo_dp_stream_enc_acquired) - update_state->pg_res_update[PG_HPO] = true; - - update_state->pg_res_update[PG_DWB] = true; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) - update_state->pg_pipe_res_update[j][i] = true; - - if (!pipe_ctx) - continue; - - if (pipe_ctx->plane_res.hubp) - update_state->pg_pipe_res_update[PG_HUBP][pipe_ctx->plane_res.hubp->inst] = false; - - if (pipe_ctx->plane_res.dpp) - update_state->pg_pipe_res_update[PG_DPP][pipe_ctx->plane_res.hubp->inst] = false; - - if ((pipe_ctx->plane_res.dpp || pipe_ctx->stream_res.opp) && - pipe_ctx->plane_res.mpcc_inst >= 0) - update_state->pg_pipe_res_update[PG_MPCC][pipe_ctx->plane_res.mpcc_inst] = false; - - if (pipe_ctx->stream_res.dsc) - update_state->pg_pipe_res_update[PG_DSC][pipe_ctx->stream_res.dsc->inst] = false; - - if (pipe_ctx->stream_res.opp) - update_state->pg_pipe_res_update[PG_OPP][pipe_ctx->stream_res.opp->inst] = false; - - if (pipe_ctx->stream_res.tg) - update_state->pg_pipe_res_update[PG_OPTC][pipe_ctx->stream_res.tg->inst] = false; - } -} - -void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, - struct pg_block_update *update_state) -{ - bool hpo_frl_stream_enc_acquired = false; - bool hpo_dp_stream_enc_acquired = false; - int i = 0, j = 0; - - memset(update_state, 0, sizeof(struct pg_block_update)); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *cur_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; - - if (cur_pipe == NULL || new_pipe == NULL) - continue; - - if ((!cur_pipe->plane_state && new_pipe->plane_state) || - (!cur_pipe->stream && new_pipe->stream)) { - // New pipe addition - for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) { - if (j == PG_HUBP && new_pipe->plane_res.hubp) - update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true; - - if (j == PG_DPP && new_pipe->plane_res.dpp) - update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true; - - if (j == PG_MPCC && new_pipe->plane_res.dpp) - update_state->pg_pipe_res_update[j][new_pipe->plane_res.mpcc_inst] = true; - - if (j == PG_DSC && new_pipe->stream_res.dsc) - update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true; - - if (j == PG_OPP && new_pipe->stream_res.opp) - update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true; - - if (j == PG_OPTC && new_pipe->stream_res.tg) - update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true; - } - } else if (cur_pipe->plane_state == new_pipe->plane_state || - cur_pipe == new_pipe) { - //unchanged pipes - for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) { - if (j == PG_HUBP && - cur_pipe->plane_res.hubp != new_pipe->plane_res.hubp && - new_pipe->plane_res.hubp) - update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true; - - if (j == PG_DPP && - cur_pipe->plane_res.dpp != new_pipe->plane_res.dpp && - new_pipe->plane_res.dpp) - update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true; - - if (j == PG_OPP && - cur_pipe->stream_res.opp != new_pipe->stream_res.opp && - new_pipe->stream_res.opp) - update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true; - - if (j == PG_DSC && - cur_pipe->stream_res.dsc != new_pipe->stream_res.dsc && - new_pipe->stream_res.dsc) - update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true; - - if (j == PG_OPTC && - cur_pipe->stream_res.tg != new_pipe->stream_res.tg && - new_pipe->stream_res.tg) - update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true; - } - } - } - - for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) { - if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] && - dc->res_pool->hpo_dp_stream_enc[i]) { - hpo_dp_stream_enc_acquired = true; - break; - } - } - - if (hpo_frl_stream_enc_acquired || hpo_dp_stream_enc_acquired) - update_state->pg_res_update[PG_HPO] = true; - -} - -void dcn35_block_power_control(struct dc *dc, - struct pg_block_update *update_state, bool power_on) -{ - int i = 0; - struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; - - if (!pg_cntl) - return; - if (dc->debug.ignore_pg) - return; - if (update_state->pg_res_update[PG_HPO]) { - if (pg_cntl->funcs->hpo_pg_control) - pg_cntl->funcs->hpo_pg_control(pg_cntl, power_on); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (update_state->pg_pipe_res_update[PG_HUBP][i] && - update_state->pg_pipe_res_update[PG_DPP][i]) { - if (pg_cntl->funcs->hubp_dpp_pg_control) - pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, power_on); - } - - if (update_state->pg_pipe_res_update[PG_DSC][i]) { - if (pg_cntl->funcs->dsc_pg_control) - pg_cntl->funcs->dsc_pg_control(pg_cntl, i, power_on); - } - - if (update_state->pg_pipe_res_update[PG_MPCC][i]) { - if (pg_cntl->funcs->mpcc_pg_control) - pg_cntl->funcs->mpcc_pg_control(pg_cntl, i, power_on); - } - - if (update_state->pg_pipe_res_update[PG_OPP][i]) { - if (pg_cntl->funcs->opp_pg_control) - pg_cntl->funcs->opp_pg_control(pg_cntl, i, power_on); - } - - if (update_state->pg_pipe_res_update[PG_OPTC][i]) { - if (pg_cntl->funcs->optc_pg_control) - pg_cntl->funcs->optc_pg_control(pg_cntl, i, power_on); - } - } - - if (update_state->pg_res_update[PG_DWB]) { - if (pg_cntl->funcs->dwb_pg_control) - pg_cntl->funcs->dwb_pg_control(pg_cntl, power_on); - } - - if (pg_cntl->funcs->plane_otg_pg_control) - pg_cntl->funcs->plane_otg_pg_control(pg_cntl, power_on); -} - -void dcn35_root_clock_control(struct dc *dc, - struct pg_block_update *update_state, bool power_on) -{ - int i = 0; - struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; - - if (!pg_cntl) - return; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (update_state->pg_pipe_res_update[PG_HUBP][i] && - update_state->pg_pipe_res_update[PG_DPP][i]) { - if (dc->hwseq->funcs.dpp_root_clock_control) - dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on); - } - - if (update_state->pg_pipe_res_update[PG_DSC][i]) { - if (power_on) { - if (dc->res_pool->dccg->funcs->enable_dsc) - dc->res_pool->dccg->funcs->enable_dsc(dc->res_pool->dccg, i); - } else { - if (dc->res_pool->dccg->funcs->disable_dsc) - dc->res_pool->dccg->funcs->disable_dsc(dc->res_pool->dccg, i); - } - } - } -} - -void dcn35_prepare_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct pg_block_update pg_update_state; - - if (dc->hwss.calc_blocks_to_ungate) { - dc->hwss.calc_blocks_to_ungate(dc, context, &pg_update_state); - - if (dc->hwss.root_clock_control) - dc->hwss.root_clock_control(dc, &pg_update_state, true); - - if (dc->hwss.block_power_control) - dc->hwss.block_power_control(dc, &pg_update_state, true); - } - - dcn20_prepare_bandwidth(dc, context); -} - -void dcn35_optimize_bandwidth( - struct dc *dc, - struct dc_state *context) -{ - struct pg_block_update pg_update_state; - - dcn20_optimize_bandwidth(dc, context); - - if (dc->hwss.calc_blocks_to_gate) { - dc->hwss.calc_blocks_to_gate(dc, context, &pg_update_state); - - if (dc->hwss.block_power_control) - dc->hwss.block_power_control(dc, &pg_update_state, false); - - if (dc->hwss.root_clock_control) - dc->hwss.root_clock_control(dc, &pg_update_state, false); - } -} - -void dcn35_set_idle_state(const struct dc *dc, bool allow_idle) -{ - // TODO: Find a more suitable communcation - if (dc->clk_mgr->funcs->set_idle_state) - dc->clk_mgr->funcs->set_idle_state(dc->clk_mgr, allow_idle); -} - -uint32_t dcn35_get_idle_state(const struct dc *dc) -{ - // TODO: Find a more suitable communcation - if (dc->clk_mgr->funcs->get_idle_state) - return dc->clk_mgr->funcs->get_idle_state(dc->clk_mgr); - - return 0; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h deleted file mode 100644 index 14bbdb0fa634..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_hwseq.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright 2023 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __DC_HWSS_DCN35_H__ -#define __DC_HWSS_DCN35_H__ - -#include "hw_sequencer_private.h" - -struct dc; - -void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); - -void dcn35_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); - -void dcn35_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on); - -void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable); - -void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable); - -void dcn35_init_hw(struct dc *dc); - -void dcn35_disable_link_output(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal); - -void dcn35_power_down_on_boot(struct dc *dc); - -bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable); - -void dcn35_z10_restore(const struct dc *dc); - -void dcn35_init_pipes(struct dc *dc, struct dc_state *context); -void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_state *context); -void dcn35_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); - -void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, - struct pg_block_update *update_state); -void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, - struct pg_block_update *update_state); -void dcn35_block_power_control(struct dc *dc, - struct pg_block_update *update_state, bool power_on); -void dcn35_root_clock_control(struct dc *dc, - struct pg_block_update *update_state, bool power_on); - -void dcn35_prepare_bandwidth( - struct dc *dc, - struct dc_state *context); - -void dcn35_optimize_bandwidth( - struct dc *dc, - struct dc_state *context); - -void dcn35_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); -void dcn35_dsc_pg_control( - struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on); - -void dcn35_set_idle_state(const struct dc *dc, bool allow_idle); -uint32_t dcn35_get_idle_state(const struct dc *dc); -#endif /* __DC_HWSS_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c index ae828d5f4e34..534223dbe595 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c @@ -22,8 +22,8 @@ * */ -#include "dce110/dce110_hw_sequencer.h" -#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" #include "dcn20/dcn20_hwseq.h" #include "dcn21/dcn21_hwseq.h" #include "dcn30/dcn30_hwseq.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c index afc14259a7b5..99d55b958977 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c @@ -49,7 +49,7 @@ #include "dcn35/dcn35_optc.h" #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hw_sequencer.h" +#include "dce110/dce110_hwseq.h" #include "dcn35/dcn35_opp.h" #include "dcn35/dcn35_dsc.h" #include "dcn30/dcn30_vpg.h" @@ -75,7 +75,7 @@ #include "dcn35/dcn35_pg_cntl.h" #include "dcn10/dcn10_resource.h" #include "dcn31/dcn31_panel_cntl.h" -#include "dcn35_hwseq.h" +#include "dcn35/dcn35_hwseq.h" #include "dcn35_dio_link_encoder.h" #include "dml/dcn31/dcn31_fpu.h" /*todo*/ #include "dml/dcn35/dcn35_fpu.h" diff --git a/drivers/gpu/drm/amd/display/dc/hwss/Makefile b/drivers/gpu/drm/amd/display/dc/hwss/Makefile new file mode 100644 index 000000000000..bccd46bd1815 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/Makefile @@ -0,0 +1,183 @@ + +# Copyright 2022 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# Makefile for the 'hwss' sub-component of DAL. +# + + +############################################################################### +# DCE +############################################################################### + +HWSS_DCE = dce_hwseq.o + +AMD_DAL_HWSS_DCE = $(addprefix $(AMDDALPATH)/dc/hwss/dce/,$(HWSS_DCE)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE) + +############################################################################### + +HWSS_DCE100 = dce100_hwseq.o + +AMD_DAL_HWSS_DCE100 = $(addprefix $(AMDDALPATH)/dc/hwss/dce100/,$(HWSS_DCE100)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE100) + +############################################################################### + +HWSS_DCE110 = dce110_hwseq.o + +AMD_DAL_HWSS_DCE110 = $(addprefix $(AMDDALPATH)/dc/hwss/dce110/,$(HWSS_DCE110)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE110) + +############################################################################### + +HWSS_DCE112 = dce112_hwseq.o + +AMD_DAL_HWSS_DCE112 = $(addprefix $(AMDDALPATH)/dc/hwss/dce112/,$(HWSS_DCE112)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE112) + +############################################################################### + +HWSS_DCE120 = dce120_hwseq.o + +AMD_DAL_HWSS_DCE120 = $(addprefix $(AMDDALPATH)/dc/hwss/dce120/,$(HWSS_DCE120)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE120) + +############################################################################### + +HWSS_DCE80 = dce80_hwseq.o + +AMD_DAL_HWSS_DCE80 = $(addprefix $(AMDDALPATH)/dc/hwss/dce80/,$(HWSS_DCE80)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE80) + +ifdef CONFIG_DRM_AMD_DC_FP +############################################################################### +# DCN +############################################################################### + +HWSS_DCN10 = dcn10_hwseq.o + +AMD_DAL_HWSS_DCN10 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn10/,$(HWSS_DCN10)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN10) + +############################################################################### + +HWSS_DCN20 = dcn20_hwseq.o + +AMD_DAL_HWSS_DCN20 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn20/,$(HWSS_DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN20) + +############################################################################### + +HWSS_DCN201 = dcn201_hwseq.o + +AMD_DAL_HWSS_DCN201 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn201/,$(HWSS_DCN201)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN201) + +############################################################################### + +HWSS_DCN21 = dcn21_hwseq.o + +AMD_DAL_HWSS_DCN21 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn21/,$(HWSS_DCN21)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN21) + +############################################################################### + +############################################################################### + +############################################################################### + +HWSS_DCN30 = dcn30_hwseq.o + +AMD_DAL_HWSS_DCN30 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn30/,$(HWSS_DCN30)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN30) + +############################################################################### + +HWSS_DCN301 = dcn301_hwseq.o + +AMD_DAL_HWSS_DCN301 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn301/,$(HWSS_DCN301)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN301) + +############################################################################### + +HWSS_DCN302 = dcn302_hwseq.o + +AMD_DAL_HWSS_DCN302 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn302/,$(HWSS_DCN302)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN302) + +############################################################################### + +HWSS_DCN303 = dcn303_hwseq.o + +AMD_DAL_HWSS_DCN303 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn303/,$(HWSS_DCN303)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN303) + +############################################################################### + +HWSS_DCN31 = dcn31_hwseq.o + +AMD_DAL_HWSS_DCN31 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn31/,$(HWSS_DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN31) + +############################################################################### + +HWSS_DCN314 = dcn314_hwseq.o + +AMD_DAL_HWSS_DCN314 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn314/,$(HWSS_DCN314)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN314) + +############################################################################### + +HWSS_DCN32 = dcn32_hwseq.o + +AMD_DAL_HWSS_DCN32 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn32/,$(HWSS_DCN32)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN32) + +############################################################################### + +HWSS_DCN35 = dcn35_hwseq.o + +AMD_DAL_HWSS_DCN35 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn35/,$(HWSS_DCN35)) + +AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN35) + +############################################################################### + +############################################################################### + +endif \ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.c new file mode 100644 index 000000000000..4202fadb2c0e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.c @@ -0,0 +1,219 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dce_hwseq.h" +#include "reg_helper.h" +#include "hw_sequencer_private.h" +#include "core_types.h" + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +void dce_enable_fe_clock(struct dce_hwseq *hws, + unsigned int fe_inst, bool enable) +{ + REG_UPDATE(DCFE_CLOCK_CONTROL[fe_inst], + DCFE_CLOCK_ENABLE, enable); +} + +void dce_pipe_control_lock(struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + uint32_t lock_val = lock ? 1 : 0; + uint32_t dcp_grph, scl, blnd, update_lock_mode, val; + struct dce_hwseq *hws = dc->hwseq; + + /* Not lock pipe when blank */ + if (lock && pipe->stream_res.tg->funcs->is_blanked && + pipe->stream_res.tg->funcs->is_blanked(pipe->stream_res.tg)) + return; + + val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], + BLND_DCP_GRPH_V_UPDATE_LOCK, &dcp_grph, + BLND_SCL_V_UPDATE_LOCK, &scl, + BLND_BLND_V_UPDATE_LOCK, &blnd, + BLND_V_UPDATE_LOCK_MODE, &update_lock_mode); + + dcp_grph = lock_val; + scl = lock_val; + blnd = lock_val; + update_lock_mode = lock_val; + + REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, + BLND_DCP_GRPH_V_UPDATE_LOCK, dcp_grph, + BLND_SCL_V_UPDATE_LOCK, scl); + + if (hws->masks->BLND_BLND_V_UPDATE_LOCK != 0) + REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, + BLND_BLND_V_UPDATE_LOCK, blnd, + BLND_V_UPDATE_LOCK_MODE, update_lock_mode); + + if (hws->wa.blnd_crtc_trigger) { + if (!lock) { + uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst]); + REG_WRITE(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst], value); + } + } +} + +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_pipe_control_lock(struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + /* DCE6 has no BLND_V_UPDATE_LOCK register */ +} +#endif + +void dce_set_blender_mode(struct dce_hwseq *hws, + unsigned int blnd_inst, + enum blnd_mode mode) +{ + uint32_t feedthrough = 1; + uint32_t blnd_mode = 0; + uint32_t multiplied_mode = 0; + uint32_t alpha_mode = 2; + + switch (mode) { + case BLND_MODE_OTHER_PIPE: + feedthrough = 0; + blnd_mode = 1; + alpha_mode = 0; + break; + case BLND_MODE_BLENDING: + feedthrough = 0; + blnd_mode = 2; + alpha_mode = 0; + multiplied_mode = 1; + break; + case BLND_MODE_CURRENT_PIPE: + default: + if (REG(BLND_CONTROL[blnd_inst]) == REG(BLNDV_CONTROL) || + blnd_inst == 0) + feedthrough = 0; + break; + } + + REG_UPDATE(BLND_CONTROL[blnd_inst], + BLND_MODE, blnd_mode); + + if (hws->masks->BLND_ALPHA_MODE != 0) { + REG_UPDATE_3(BLND_CONTROL[blnd_inst], + BLND_FEEDTHROUGH_EN, feedthrough, + BLND_ALPHA_MODE, alpha_mode, + BLND_MULTIPLIED_MODE, multiplied_mode); + } +} + + +static void dce_disable_sram_shut_down(struct dce_hwseq *hws) +{ + if (REG(DC_MEM_GLOBAL_PWR_REQ_CNTL)) + REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, + DC_MEM_GLOBAL_PWR_REQ_DIS, 1); +} + +static void dce_underlay_clock_enable(struct dce_hwseq *hws) +{ + /* todo: why do we need this at boot? is dce_enable_fe_clock enough? */ + if (REG(DCFEV_CLOCK_CONTROL)) + REG_UPDATE(DCFEV_CLOCK_CONTROL, + DCFEV_CLOCK_ENABLE, 1); +} + +static void enable_hw_base_light_sleep(void) +{ + /* TODO: implement */ +} + +static void disable_sw_manual_control_light_sleep(void) +{ + /* TODO: implement */ +} + +void dce_clock_gating_power_up(struct dce_hwseq *hws, + bool enable) +{ + if (enable) { + enable_hw_base_light_sleep(); + disable_sw_manual_control_light_sleep(); + } else { + dce_disable_sram_shut_down(hws); + dce_underlay_clock_enable(hws); + } +} + +void dce_crtc_switch_to_clk_src(struct dce_hwseq *hws, + struct clock_source *clk_src, + unsigned int tg_inst) +{ + if (clk_src->id == CLOCK_SOURCE_ID_DP_DTO || clk_src->dp_clk_src) { + REG_UPDATE(PIXEL_RATE_CNTL[tg_inst], + DP_DTO0_ENABLE, 1); + + } else if (clk_src->id >= CLOCK_SOURCE_COMBO_PHY_PLL0) { + uint32_t rate_source = clk_src->id - CLOCK_SOURCE_COMBO_PHY_PLL0; + + REG_UPDATE_2(PHYPLL_PIXEL_RATE_CNTL[tg_inst], + PHYPLL_PIXEL_RATE_SOURCE, rate_source, + PIXEL_RATE_PLL_SOURCE, 0); + + REG_UPDATE(PIXEL_RATE_CNTL[tg_inst], + DP_DTO0_ENABLE, 0); + + } else if (clk_src->id <= CLOCK_SOURCE_ID_PLL2) { + uint32_t rate_source = clk_src->id - CLOCK_SOURCE_ID_PLL0; + + REG_UPDATE_2(PIXEL_RATE_CNTL[tg_inst], + PIXEL_RATE_SOURCE, rate_source, + DP_DTO0_ENABLE, 0); + + if (REG(PHYPLL_PIXEL_RATE_CNTL[tg_inst])) + REG_UPDATE(PHYPLL_PIXEL_RATE_CNTL[tg_inst], + PIXEL_RATE_PLL_SOURCE, 1); + } else { + DC_ERR("Unknown clock source. clk_src id: %d, TG_inst: %d", + clk_src->id, tg_inst); + } +} + +/* Only use LUT for 8 bit formats */ +bool dce_use_lut(enum surface_pixel_format format) +{ + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + return true; + default: + return false; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h new file mode 100644 index 000000000000..2fefdf40612d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h @@ -0,0 +1,1241 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#ifndef __DCE_HWSEQ_H__ +#define __DCE_HWSEQ_H__ + +#include "dc_types.h" + +#define HWSEQ_DCEF_REG_LIST_DCE8() \ + .DCFE_CLOCK_CONTROL[0] = mmCRTC0_CRTC_DCFE_CLOCK_CONTROL, \ + .DCFE_CLOCK_CONTROL[1] = mmCRTC1_CRTC_DCFE_CLOCK_CONTROL, \ + .DCFE_CLOCK_CONTROL[2] = mmCRTC2_CRTC_DCFE_CLOCK_CONTROL, \ + .DCFE_CLOCK_CONTROL[3] = mmCRTC3_CRTC_DCFE_CLOCK_CONTROL, \ + .DCFE_CLOCK_CONTROL[4] = mmCRTC4_CRTC_DCFE_CLOCK_CONTROL, \ + .DCFE_CLOCK_CONTROL[5] = mmCRTC5_CRTC_DCFE_CLOCK_CONTROL + +#define HWSEQ_DCEF_REG_LIST() \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 0), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 1), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 2), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 3), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 4), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 5), \ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL) + +#define HWSEQ_BLND_REG_LIST() \ + SRII(BLND_V_UPDATE_LOCK, BLND, 0), \ + SRII(BLND_V_UPDATE_LOCK, BLND, 1), \ + SRII(BLND_V_UPDATE_LOCK, BLND, 2), \ + SRII(BLND_V_UPDATE_LOCK, BLND, 3), \ + SRII(BLND_V_UPDATE_LOCK, BLND, 4), \ + SRII(BLND_V_UPDATE_LOCK, BLND, 5), \ + SRII(BLND_CONTROL, BLND, 0), \ + SRII(BLND_CONTROL, BLND, 1), \ + SRII(BLND_CONTROL, BLND, 2), \ + SRII(BLND_CONTROL, BLND, 3), \ + SRII(BLND_CONTROL, BLND, 4), \ + SRII(BLND_CONTROL, BLND, 5) + +#define HSWEQ_DCN_PIXEL_RATE_REG_LIST(blk, inst) \ + SRII(PIXEL_RATE_CNTL, blk, inst), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, inst) + +#define HWSEQ_PIXEL_RATE_REG_LIST(blk) \ + SRII(PIXEL_RATE_CNTL, blk, 0), \ + SRII(PIXEL_RATE_CNTL, blk, 1), \ + SRII(PIXEL_RATE_CNTL, blk, 2), \ + SRII(PIXEL_RATE_CNTL, blk, 3), \ + SRII(PIXEL_RATE_CNTL, blk, 4), \ + SRII(PIXEL_RATE_CNTL, blk, 5) + +#define HWSEQ_PIXEL_RATE_REG_LIST_201(blk) \ + SRII(PIXEL_RATE_CNTL, blk, 0), \ + SRII(PIXEL_RATE_CNTL, blk, 1) + +#define HWSEQ_PHYPLL_REG_LIST(blk) \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 5) + +#define HWSEQ_PIXEL_RATE_REG_LIST_3(blk) \ + SRII(PIXEL_RATE_CNTL, blk, 0), \ + SRII(PIXEL_RATE_CNTL, blk, 1),\ + SRII(PIXEL_RATE_CNTL, blk, 2),\ + SRII(PIXEL_RATE_CNTL, blk, 3), \ + SRII(PIXEL_RATE_CNTL, blk, 4), \ + SRII(PIXEL_RATE_CNTL, blk, 5) + +#define HWSEQ_PHYPLL_REG_LIST_3(blk) \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 5) + +#define HWSEQ_PIXEL_RATE_REG_LIST_302(blk) \ + SRII(PIXEL_RATE_CNTL, blk, 0), \ + SRII(PIXEL_RATE_CNTL, blk, 1),\ + SRII(PIXEL_RATE_CNTL, blk, 2),\ + SRII(PIXEL_RATE_CNTL, blk, 3), \ + SRII(PIXEL_RATE_CNTL, blk, 4) + +#define HWSEQ_PHYPLL_REG_LIST_302(blk) \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 3), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 4) + +#define HWSEQ_PIXEL_RATE_REG_LIST_303(blk) \ + SRII(PIXEL_RATE_CNTL, blk, 0), \ + SRII(PIXEL_RATE_CNTL, blk, 1) + +#define HWSEQ_PHYPLL_REG_LIST_303(blk) \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1) + + +#define HWSEQ_PHYPLL_REG_LIST_201(blk) \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 0), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, 1) + +#define HWSEQ_DCE11_REG_LIST_BASE() \ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SR(DCFEV_CLOCK_CONTROL), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 0), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 1), \ + SRII(CRTC_H_BLANK_START_END, CRTC, 0),\ + SRII(CRTC_H_BLANK_START_END, CRTC, 1),\ + SRII(BLND_V_UPDATE_LOCK, BLND, 0),\ + SRII(BLND_V_UPDATE_LOCK, BLND, 1),\ + SRII(BLND_CONTROL, BLND, 0),\ + SRII(BLND_CONTROL, BLND, 1),\ + SR(BLNDV_CONTROL),\ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC) + +#if defined(CONFIG_DRM_AMD_DC_SI) +#define HWSEQ_DCE6_REG_LIST() \ + HWSEQ_DCEF_REG_LIST_DCE8(), \ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC) +#endif + +#define HWSEQ_DCE8_REG_LIST() \ + HWSEQ_DCEF_REG_LIST_DCE8(), \ + HWSEQ_BLND_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC) + +#define HWSEQ_DCE10_REG_LIST() \ + HWSEQ_DCEF_REG_LIST(), \ + HWSEQ_BLND_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC) + +#define HWSEQ_ST_REG_LIST() \ + HWSEQ_DCE11_REG_LIST_BASE(), \ + .DCFE_CLOCK_CONTROL[2] = mmDCFEV_CLOCK_CONTROL, \ + .CRTC_H_BLANK_START_END[2] = mmCRTCV_H_BLANK_START_END, \ + .BLND_V_UPDATE_LOCK[2] = mmBLNDV_V_UPDATE_LOCK, \ + .BLND_CONTROL[2] = mmBLNDV_CONTROL + +#define HWSEQ_CZ_REG_LIST() \ + HWSEQ_DCE11_REG_LIST_BASE(), \ + SRII(DCFE_CLOCK_CONTROL, DCFE, 2), \ + SRII(CRTC_H_BLANK_START_END, CRTC, 2), \ + SRII(BLND_V_UPDATE_LOCK, BLND, 2), \ + SRII(BLND_CONTROL, BLND, 2), \ + .DCFE_CLOCK_CONTROL[3] = mmDCFEV_CLOCK_CONTROL, \ + .CRTC_H_BLANK_START_END[3] = mmCRTCV_H_BLANK_START_END, \ + .BLND_V_UPDATE_LOCK[3] = mmBLNDV_V_UPDATE_LOCK, \ + .BLND_CONTROL[3] = mmBLNDV_CONTROL + +#define HWSEQ_DCE120_REG_LIST() \ + HWSEQ_DCE10_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \ + HWSEQ_PHYPLL_REG_LIST(CRTC), \ + SR(DCHUB_FB_LOCATION),\ + SR(DCHUB_AGP_BASE),\ + SR(DCHUB_AGP_BOT),\ + SR(DCHUB_AGP_TOP) + +#define HWSEQ_VG20_REG_LIST() \ + HWSEQ_DCE120_REG_LIST(),\ + MMHUB_SR(MC_VM_XGMI_LFB_CNTL) + +#define HWSEQ_DCE112_REG_LIST() \ + HWSEQ_DCE10_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \ + HWSEQ_PHYPLL_REG_LIST(CRTC) + +#define HWSEQ_DCN_REG_LIST()\ + SR(REFCLK_CNTL), \ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DCFCLK_CNTL), \ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL) + + +#define MMHUB_DCN_REG_LIST()\ + /* todo: get these from GVM instead of reading registers ourselves */\ + MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32),\ + MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32),\ + MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32),\ + MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32),\ + MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32),\ + MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32),\ + MMHUB_SR(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32),\ + MMHUB_SR(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32),\ + MMHUB_SR(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB),\ + MMHUB_SR(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB),\ + MMHUB_SR(MC_VM_SYSTEM_APERTURE_LOW_ADDR),\ + MMHUB_SR(MC_VM_SYSTEM_APERTURE_HIGH_ADDR) + + +#define HWSEQ_DCN1_REG_LIST()\ + HWSEQ_DCN_REG_LIST(), \ + MMHUB_DCN_REG_LIST(), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ + SR(DCHUBBUB_SDPIF_FB_BASE),\ + SR(DCHUBBUB_SDPIF_FB_OFFSET),\ + SR(DCHUBBUB_SDPIF_AGP_BASE),\ + SR(DCHUBBUB_SDPIF_AGP_BOT),\ + SR(DCHUBBUB_SDPIF_AGP_TOP),\ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN4_PG_CONFIG), \ + SR(DOMAIN5_PG_CONFIG), \ + SR(DOMAIN6_PG_CONFIG), \ + SR(DOMAIN7_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN4_PG_STATUS), \ + SR(DOMAIN5_PG_STATUS), \ + SR(DOMAIN6_PG_STATUS), \ + SR(DOMAIN7_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(VGA_TEST_CONTROL), \ + SR(DC_IP_REQUEST_CNTL) + +#define HWSEQ_DCN2_REG_LIST()\ + HWSEQ_DCN_REG_LIST(), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 4), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 5), \ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN4_PG_CONFIG), \ + SR(DOMAIN5_PG_CONFIG), \ + SR(DOMAIN6_PG_CONFIG), \ + SR(DOMAIN7_PG_CONFIG), \ + SR(DOMAIN8_PG_CONFIG), \ + SR(DOMAIN9_PG_CONFIG), \ +/* SR(DOMAIN10_PG_CONFIG), Navi1x HUBP5 not powergate-able*/\ +/* SR(DOMAIN11_PG_CONFIG), Navi1x DPP5 is not powergate-able */\ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN19_PG_CONFIG), \ + SR(DOMAIN20_PG_CONFIG), \ + SR(DOMAIN21_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN4_PG_STATUS), \ + SR(DOMAIN5_PG_STATUS), \ + SR(DOMAIN6_PG_STATUS), \ + SR(DOMAIN7_PG_STATUS), \ + SR(DOMAIN8_PG_STATUS), \ + SR(DOMAIN9_PG_STATUS), \ + SR(DOMAIN10_PG_STATUS), \ + SR(DOMAIN11_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(DOMAIN19_PG_STATUS), \ + SR(DOMAIN20_PG_STATUS), \ + SR(DOMAIN21_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL) + +#define HWSEQ_DCN21_REG_LIST()\ + HWSEQ_DCN_REG_LIST(), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ + MMHUB_DCN_REG_LIST(), \ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN4_PG_CONFIG), \ + SR(DOMAIN5_PG_CONFIG), \ + SR(DOMAIN6_PG_CONFIG), \ + SR(DOMAIN7_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN4_PG_STATUS), \ + SR(DOMAIN5_PG_STATUS), \ + SR(DOMAIN6_PG_STATUS), \ + SR(DOMAIN7_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL) + +#define HWSEQ_DCN201_REG_LIST()\ + HWSEQ_DCN_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST_201(OTG), \ + HWSEQ_PHYPLL_REG_LIST_201(OTG), \ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + MMHUB_SR(MC_VM_FB_LOCATION_BASE), \ + MMHUB_SR(MC_VM_FB_LOCATION_TOP), \ + MMHUB_SR(MC_VM_FB_OFFSET) + +#define HWSEQ_DCN30_REG_LIST()\ + HWSEQ_DCN2_REG_LIST(),\ + HWSEQ_DCN_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST_3(OTG), \ + HWSEQ_PHYPLL_REG_LIST_3(OTG), \ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_CLOCK_CONTROL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(DMU_MEM_PWR_CNTL), \ + SR(MMHUBBUB_MEM_PWR_CNTL) + +#define HWSEQ_DCN301_REG_LIST()\ + SR(REFCLK_CNTL), \ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DCFCLK_CNTL), \ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN4_PG_CONFIG), \ + SR(DOMAIN5_PG_CONFIG), \ + SR(DOMAIN6_PG_CONFIG), \ + SR(DOMAIN7_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN4_PG_STATUS), \ + SR(DOMAIN5_PG_STATUS), \ + SR(DOMAIN6_PG_STATUS), \ + SR(DOMAIN7_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING) + +#define HWSEQ_DCN302_REG_LIST()\ + HWSEQ_DCN_REG_LIST(), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 4), \ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN4_PG_CONFIG), \ + SR(DOMAIN5_PG_CONFIG), \ + SR(DOMAIN6_PG_CONFIG), \ + SR(DOMAIN7_PG_CONFIG), \ + SR(DOMAIN8_PG_CONFIG), \ + SR(DOMAIN9_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN19_PG_CONFIG), \ + SR(DOMAIN20_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN4_PG_STATUS), \ + SR(DOMAIN5_PG_STATUS), \ + SR(DOMAIN6_PG_STATUS), \ + SR(DOMAIN7_PG_STATUS), \ + SR(DOMAIN8_PG_STATUS), \ + SR(DOMAIN9_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(DOMAIN19_PG_STATUS), \ + SR(DOMAIN20_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + HWSEQ_PIXEL_RATE_REG_LIST_302(OTG), \ + HWSEQ_PHYPLL_REG_LIST_302(OTG), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_CLOCK_CONTROL) + +#define HWSEQ_DCN303_REG_LIST() \ + HWSEQ_DCN_REG_LIST(), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + HWSEQ_PIXEL_RATE_REG_LIST_303(OTG), \ + HWSEQ_PHYPLL_REG_LIST_303(OTG), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_CLOCK_CONTROL) + +struct dce_hwseq_registers { + uint32_t DCFE_CLOCK_CONTROL[6]; + uint32_t DCFEV_CLOCK_CONTROL; + uint32_t DC_MEM_GLOBAL_PWR_REQ_CNTL; + uint32_t BLND_V_UPDATE_LOCK[6]; + uint32_t BLND_CONTROL[6]; + uint32_t BLNDV_CONTROL; + uint32_t CRTC_H_BLANK_START_END[6]; + uint32_t PIXEL_RATE_CNTL[6]; + uint32_t PHYPLL_PIXEL_RATE_CNTL[6]; + /*DCHUB*/ + uint32_t DCHUB_FB_LOCATION; + uint32_t DCHUB_AGP_BASE; + uint32_t DCHUB_AGP_BOT; + uint32_t DCHUB_AGP_TOP; + + uint32_t REFCLK_CNTL; + + uint32_t DCHUBBUB_GLOBAL_TIMER_CNTL; + uint32_t DCHUBBUB_SDPIF_FB_BASE; + uint32_t DCHUBBUB_SDPIF_FB_OFFSET; + uint32_t DCHUBBUB_SDPIF_AGP_BASE; + uint32_t DCHUBBUB_SDPIF_AGP_BOT; + uint32_t DCHUBBUB_SDPIF_AGP_TOP; + uint32_t DC_IP_REQUEST_CNTL; + uint32_t DOMAIN0_PG_CONFIG; + uint32_t DOMAIN1_PG_CONFIG; + uint32_t DOMAIN2_PG_CONFIG; + uint32_t DOMAIN3_PG_CONFIG; + uint32_t DOMAIN4_PG_CONFIG; + uint32_t DOMAIN5_PG_CONFIG; + uint32_t DOMAIN6_PG_CONFIG; + uint32_t DOMAIN7_PG_CONFIG; + uint32_t DOMAIN8_PG_CONFIG; + uint32_t DOMAIN9_PG_CONFIG; + uint32_t DOMAIN10_PG_CONFIG; + uint32_t DOMAIN11_PG_CONFIG; + uint32_t DOMAIN16_PG_CONFIG; + uint32_t DOMAIN17_PG_CONFIG; + uint32_t DOMAIN18_PG_CONFIG; + uint32_t DOMAIN19_PG_CONFIG; + uint32_t DOMAIN20_PG_CONFIG; + uint32_t DOMAIN21_PG_CONFIG; + uint32_t DOMAIN0_PG_STATUS; + uint32_t DOMAIN1_PG_STATUS; + uint32_t DOMAIN2_PG_STATUS; + uint32_t DOMAIN3_PG_STATUS; + uint32_t DOMAIN4_PG_STATUS; + uint32_t DOMAIN5_PG_STATUS; + uint32_t DOMAIN6_PG_STATUS; + uint32_t DOMAIN7_PG_STATUS; + uint32_t DOMAIN8_PG_STATUS; + uint32_t DOMAIN9_PG_STATUS; + uint32_t DOMAIN10_PG_STATUS; + uint32_t DOMAIN11_PG_STATUS; + uint32_t DOMAIN16_PG_STATUS; + uint32_t DOMAIN17_PG_STATUS; + uint32_t DOMAIN18_PG_STATUS; + uint32_t DOMAIN19_PG_STATUS; + uint32_t DOMAIN20_PG_STATUS; + uint32_t DOMAIN21_PG_STATUS; + uint32_t DIO_MEM_PWR_CTRL; + uint32_t DCCG_GATE_DISABLE_CNTL; + uint32_t DCCG_GATE_DISABLE_CNTL2; + uint32_t DCFCLK_CNTL; + uint32_t MICROSECOND_TIME_BASE_DIV; + uint32_t MILLISECOND_TIME_BASE_DIV; + uint32_t DISPCLK_FREQ_CHANGE_CNTL; + uint32_t RBBMIF_TIMEOUT_DIS; + uint32_t RBBMIF_TIMEOUT_DIS_2; + uint32_t DCHUBBUB_CRC_CTRL; + uint32_t DPP_TOP0_DPP_CRC_CTRL; + uint32_t DPP_TOP0_DPP_CRC_VAL_R_G; + uint32_t DPP_TOP0_DPP_CRC_VAL_B_A; + uint32_t MPC_CRC_CTRL; + uint32_t MPC_CRC_RESULT_GB; + uint32_t MPC_CRC_RESULT_C; + uint32_t MPC_CRC_RESULT_AR; + uint32_t D1VGA_CONTROL; + uint32_t D2VGA_CONTROL; + uint32_t D3VGA_CONTROL; + uint32_t D4VGA_CONTROL; + uint32_t D5VGA_CONTROL; + uint32_t D6VGA_CONTROL; + uint32_t VGA_TEST_CONTROL; + /* MMHUB registers. read only. temporary hack */ + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32; + uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32; + uint32_t VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32; + uint32_t VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32; + uint32_t VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32; + uint32_t VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32; + uint32_t VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32; + uint32_t VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32; + uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB; + uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB; + uint32_t MC_VM_SYSTEM_APERTURE_LOW_ADDR; + uint32_t MC_VM_SYSTEM_APERTURE_HIGH_ADDR; + uint32_t MC_VM_XGMI_LFB_CNTL; + uint32_t AZALIA_AUDIO_DTO; + uint32_t AZALIA_CONTROLLER_CLOCK_GATING; + /* MMHUB VM */ + uint32_t MC_VM_FB_LOCATION_BASE; + uint32_t MC_VM_FB_LOCATION_TOP; + uint32_t MC_VM_FB_OFFSET; + uint32_t MMHUBBUB_MEM_PWR_CNTL; + uint32_t HPO_TOP_CLOCK_CONTROL; + uint32_t ODM_MEM_PWR_CTRL3; + uint32_t DMU_MEM_PWR_CNTL; + uint32_t DCHUBBUB_ARB_HOSTVM_CNTL; + uint32_t HPO_TOP_HW_CONTROL; + uint32_t DMU_CLK_CNTL; + uint32_t DCCG_GATE_DISABLE_CNTL5; +}; + /* set field name */ +#define HWS_SF(blk_name, reg_name, field_name, post_fix)\ + .field_name = blk_name ## reg_name ## __ ## field_name ## post_fix + +#define HWS_SF1(blk_name, reg_name, field_name, post_fix)\ + .field_name = blk_name ## reg_name ## __ ## blk_name ## field_name ## post_fix + + +#define HWSEQ_DCEF_MASK_SH_LIST(mask_sh, blk)\ + HWS_SF(blk, CLOCK_CONTROL, DCFE_CLOCK_ENABLE, mask_sh),\ + SF(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, mask_sh) + +#define HWSEQ_BLND_MASK_SH_LIST(mask_sh, blk)\ + HWS_SF(blk, V_UPDATE_LOCK, BLND_DCP_GRPH_V_UPDATE_LOCK, mask_sh),\ + HWS_SF(blk, V_UPDATE_LOCK, BLND_SCL_V_UPDATE_LOCK, mask_sh),\ + HWS_SF(blk, V_UPDATE_LOCK, BLND_DCP_GRPH_SURF_V_UPDATE_LOCK, mask_sh),\ + HWS_SF(blk, V_UPDATE_LOCK, BLND_BLND_V_UPDATE_LOCK, mask_sh),\ + HWS_SF(blk, V_UPDATE_LOCK, BLND_V_UPDATE_LOCK_MODE, mask_sh),\ + HWS_SF(blk, CONTROL, BLND_FEEDTHROUGH_EN, mask_sh),\ + HWS_SF(blk, CONTROL, BLND_ALPHA_MODE, mask_sh),\ + HWS_SF(blk, CONTROL, BLND_MODE, mask_sh),\ + HWS_SF(blk, CONTROL, BLND_MULTIPLIED_MODE, mask_sh) + +#define HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, blk)\ + HWS_SF1(blk, PIXEL_RATE_CNTL, PIXEL_RATE_SOURCE, mask_sh),\ + HWS_SF(blk, PIXEL_RATE_CNTL, DP_DTO0_ENABLE, mask_sh) + +#define HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, blk)\ + HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh),\ + HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PIXEL_RATE_PLL_SOURCE, mask_sh) + +#if defined(CONFIG_DRM_AMD_DC_SI) +#define HWSEQ_DCE6_MASK_SH_LIST(mask_sh)\ + .DCFE_CLOCK_ENABLE = CRTC_DCFE_CLOCK_CONTROL__CRTC_DCFE_CLOCK_ENABLE ## mask_sh, \ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) +#endif + +#define HWSEQ_DCE8_MASK_SH_LIST(mask_sh)\ + .DCFE_CLOCK_ENABLE = CRTC_DCFE_CLOCK_CONTROL__CRTC_DCFE_CLOCK_ENABLE ## mask_sh, \ + HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_V_UPDATE_LOCK, mask_sh),\ + HWS_SF(BLND_, V_UPDATE_LOCK, BLND_SCL_V_UPDATE_LOCK, mask_sh),\ + HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_SURF_V_UPDATE_LOCK, mask_sh),\ + HWS_SF(BLND_, CONTROL, BLND_MODE, mask_sh),\ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) + +#define HWSEQ_DCE10_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE_),\ + HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND_),\ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) + +#define HWSEQ_DCE11_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ + SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, mask_sh),\ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) + +#define HWSEQ_DCE112_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ + HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_) + +#define HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh)\ + SF(DCHUB_FB_LOCATION, FB_TOP, mask_sh),\ + SF(DCHUB_FB_LOCATION, FB_BASE, mask_sh),\ + SF(DCHUB_AGP_BASE, AGP_BASE, mask_sh),\ + SF(DCHUB_AGP_BOT, AGP_BOT, mask_sh),\ + SF(DCHUB_AGP_TOP, AGP_TOP, mask_sh) + +#define HWSEQ_DCE12_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE0_DCFE_),\ + HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND0_BLND_),\ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\ + HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_),\ + HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh) + +#define HWSEQ_VG20_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCE12_MASK_SH_LIST(mask_sh),\ + HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_LFB_REGION, mask_sh),\ + HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, mask_sh) + +#define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\ + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\ + HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ + HWS_SF(, DCFCLK_CNTL, DCFCLK_GATE_DIS, mask_sh), \ + HWS_SF(, DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, mask_sh) + +#define HWSEQ_DCN1_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PIXEL_RATE_PLL_SOURCE, mask_sh), \ + HWS_SF(, DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, mask_sh), \ + HWS_SF(, DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, mask_sh), \ + HWS_SF(, DCHUBBUB_SDPIF_AGP_BASE, SDPIF_AGP_BASE, mask_sh), \ + HWS_SF(, DCHUBBUB_SDPIF_AGP_BOT, SDPIF_AGP_BOT, mask_sh), \ + HWS_SF(, DCHUBBUB_SDPIF_AGP_TOP, SDPIF_AGP_TOP, mask_sh), \ + /* todo: get these from GVM instead of reading registers ourselves */\ + HWS_SF(, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, PAGE_DIRECTORY_ENTRY_HI32, mask_sh),\ + HWS_SF(, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, PAGE_DIRECTORY_ENTRY_LO32, mask_sh),\ + HWS_SF(, VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, LOGICAL_PAGE_NUMBER_HI4, mask_sh),\ + HWS_SF(, VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, LOGICAL_PAGE_NUMBER_LO32, mask_sh),\ + HWS_SF(, VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, PHYSICAL_PAGE_ADDR_HI4, mask_sh),\ + HWS_SF(, VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, PHYSICAL_PAGE_ADDR_LO32, mask_sh),\ + HWS_SF(, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, PHYSICAL_PAGE_NUMBER_MSB, mask_sh),\ + HWS_SF(, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, PHYSICAL_PAGE_NUMBER_LSB, mask_sh),\ + HWS_SF(, MC_VM_SYSTEM_APERTURE_LOW_ADDR, LOGICAL_ADDR, mask_sh),\ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D2VGA_CONTROL, D2VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D3VGA_CONTROL, D3VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, D4VGA_CONTROL, D4VGA_MODE_ENABLE, mask_sh),\ + HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ + HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh) + +#define HWSEQ_DCN2_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN10_PG_CONFIG, DOMAIN10_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN10_PG_CONFIG, DOMAIN10_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN11_PG_CONFIG, DOMAIN11_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN11_PG_CONFIG, DOMAIN11_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN21_PG_CONFIG, DOMAIN21_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN8_PG_STATUS, DOMAIN8_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN9_PG_STATUS, DOMAIN9_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN10_PG_STATUS, DOMAIN10_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN11_PG_STATUS, DOMAIN11_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN19_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN20_PG_STATUS, DOMAIN20_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN21_PG_STATUS, DOMAIN21_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) + +#define HWSEQ_DCN21_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, MMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, PAGE_DIRECTORY_ENTRY_HI32, mask_sh),\ + HWS_SF(, MMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, PAGE_DIRECTORY_ENTRY_LO32, mask_sh),\ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) + +#define HWSEQ_DCN201_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh) + +#define HWSEQ_DCN30_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN2_MASK_SH_LIST(mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) + +#define HWSEQ_DCN301_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, PANEL_PWRSEQ0_CNTL, PANEL_BLON, mask_sh),\ + HWS_SF(, PANEL_PWRSEQ0_CNTL, PANEL_DIGON, mask_sh),\ + HWS_SF(, PANEL_PWRSEQ0_CNTL, PANEL_DIGON_OVRD, mask_sh),\ + HWS_SF(, PANEL_PWRSEQ0_STATE, PANEL_PWRSEQ_TARGET_STATE_R, mask_sh),\ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh) + +#define HWSEQ_DCN302_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN8_PG_STATUS, DOMAIN8_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN9_PG_STATUS, DOMAIN9_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN19_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN20_PG_STATUS, DOMAIN20_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh) + +#define HWSEQ_DCN303_MASK_SH_LIST(mask_sh) \ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_GATE_DIS, mask_sh) + +#define HWSEQ_REG_FIELD_LIST(type) \ + type DCFE_CLOCK_ENABLE; \ + type DCFEV_CLOCK_ENABLE; \ + type DC_MEM_GLOBAL_PWR_REQ_DIS; \ + type BLND_DCP_GRPH_V_UPDATE_LOCK; \ + type BLND_SCL_V_UPDATE_LOCK; \ + type BLND_DCP_GRPH_SURF_V_UPDATE_LOCK; \ + type BLND_BLND_V_UPDATE_LOCK; \ + type BLND_V_UPDATE_LOCK_MODE; \ + type BLND_FEEDTHROUGH_EN; \ + type BLND_ALPHA_MODE; \ + type BLND_MODE; \ + type BLND_MULTIPLIED_MODE; \ + type DP_DTO0_ENABLE; \ + type PIXEL_RATE_SOURCE; \ + type PHYPLL_PIXEL_RATE_SOURCE; \ + type PIXEL_RATE_PLL_SOURCE; \ + /* todo: get these from GVM instead of reading registers ourselves */\ + type PAGE_DIRECTORY_ENTRY_HI32;\ + type PAGE_DIRECTORY_ENTRY_LO32;\ + type LOGICAL_PAGE_NUMBER_HI4;\ + type LOGICAL_PAGE_NUMBER_LO32;\ + type PHYSICAL_PAGE_ADDR_HI4;\ + type PHYSICAL_PAGE_ADDR_LO32;\ + type PHYSICAL_PAGE_NUMBER_MSB;\ + type PHYSICAL_PAGE_NUMBER_LSB;\ + type LOGICAL_ADDR; \ + type PF_LFB_REGION;\ + type PF_MAX_REGION;\ + type ENABLE_L1_TLB;\ + type SYSTEM_ACCESS_MODE; + +#define HWSEQ_DCN_REG_FIELD_LIST(type) \ + type HUBP_VTG_SEL; \ + type HUBP_CLOCK_ENABLE; \ + type DPP_CLOCK_ENABLE; \ + type SDPIF_FB_BASE;\ + type SDPIF_FB_OFFSET;\ + type SDPIF_AGP_BASE;\ + type SDPIF_AGP_BOT;\ + type SDPIF_AGP_TOP;\ + type FB_TOP;\ + type FB_BASE;\ + type FB_OFFSET;\ + type AGP_BASE;\ + type AGP_BOT;\ + type AGP_TOP;\ + type DCHUBBUB_GLOBAL_TIMER_ENABLE; \ + type OPP_PIPE_CLOCK_EN;\ + type IP_REQUEST_EN; \ + type DOMAIN0_POWER_FORCEON; \ + type DOMAIN0_POWER_GATE; \ + type DOMAIN1_POWER_FORCEON; \ + type DOMAIN1_POWER_GATE; \ + type DOMAIN2_POWER_FORCEON; \ + type DOMAIN2_POWER_GATE; \ + type DOMAIN3_POWER_FORCEON; \ + type DOMAIN3_POWER_GATE; \ + type DOMAIN4_POWER_FORCEON; \ + type DOMAIN4_POWER_GATE; \ + type DOMAIN5_POWER_FORCEON; \ + type DOMAIN5_POWER_GATE; \ + type DOMAIN6_POWER_FORCEON; \ + type DOMAIN6_POWER_GATE; \ + type DOMAIN7_POWER_FORCEON; \ + type DOMAIN7_POWER_GATE; \ + type DOMAIN8_POWER_FORCEON; \ + type DOMAIN8_POWER_GATE; \ + type DOMAIN9_POWER_FORCEON; \ + type DOMAIN9_POWER_GATE; \ + type DOMAIN10_POWER_FORCEON; \ + type DOMAIN10_POWER_GATE; \ + type DOMAIN11_POWER_FORCEON; \ + type DOMAIN11_POWER_GATE; \ + type DOMAIN16_POWER_FORCEON; \ + type DOMAIN16_POWER_GATE; \ + type DOMAIN17_POWER_FORCEON; \ + type DOMAIN17_POWER_GATE; \ + type DOMAIN18_POWER_FORCEON; \ + type DOMAIN18_POWER_GATE; \ + type DOMAIN19_POWER_FORCEON; \ + type DOMAIN19_POWER_GATE; \ + type DOMAIN20_POWER_FORCEON; \ + type DOMAIN20_POWER_GATE; \ + type DOMAIN21_POWER_FORCEON; \ + type DOMAIN21_POWER_GATE; \ + type DOMAIN0_PGFSM_PWR_STATUS; \ + type DOMAIN1_PGFSM_PWR_STATUS; \ + type DOMAIN2_PGFSM_PWR_STATUS; \ + type DOMAIN3_PGFSM_PWR_STATUS; \ + type DOMAIN4_PGFSM_PWR_STATUS; \ + type DOMAIN5_PGFSM_PWR_STATUS; \ + type DOMAIN6_PGFSM_PWR_STATUS; \ + type DOMAIN7_PGFSM_PWR_STATUS; \ + type DOMAIN8_PGFSM_PWR_STATUS; \ + type DOMAIN9_PGFSM_PWR_STATUS; \ + type DOMAIN10_PGFSM_PWR_STATUS; \ + type DOMAIN11_PGFSM_PWR_STATUS; \ + type DOMAIN16_PGFSM_PWR_STATUS; \ + type DOMAIN17_PGFSM_PWR_STATUS; \ + type DOMAIN18_PGFSM_PWR_STATUS; \ + type DOMAIN19_PGFSM_PWR_STATUS; \ + type DOMAIN20_PGFSM_PWR_STATUS; \ + type DOMAIN21_PGFSM_PWR_STATUS; \ + type DCFCLK_GATE_DIS; \ + type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ + type VGA_TEST_ENABLE; \ + type VGA_TEST_RENDER_START; \ + type D1VGA_MODE_ENABLE; \ + type D2VGA_MODE_ENABLE; \ + type D3VGA_MODE_ENABLE; \ + type D4VGA_MODE_ENABLE; \ + type AZALIA_AUDIO_DTO_MODULE; \ + type ODM_MEM_UNASSIGNED_PWR_MODE; \ + type ODM_MEM_VBLANK_PWR_MODE; \ + type DMCU_ERAM_MEM_PWR_FORCE; \ + type VGA_MEM_PWR_FORCE; + +#define HWSEQ_DCN3_REG_FIELD_LIST(type) \ + type HPO_HDMISTREAMCLK_GATE_DIS; + +#define HWSEQ_DCN301_REG_FIELD_LIST(type) \ + type PANEL_BLON;\ + type PANEL_DIGON;\ + type PANEL_DIGON_OVRD;\ + type PANEL_PWRSEQ_TARGET_STATE_R; + +#define HWSEQ_DCN31_REG_FIELD_LIST(type) \ + type DOMAIN_POWER_FORCEON;\ + type DOMAIN_POWER_GATE;\ + type DOMAIN_PGFSM_PWR_STATUS;\ + type HPO_HDMISTREAMCLK_G_GATE_DIS;\ + type DISABLE_HOSTVM_FORCE_ALLOW_PSTATE;\ + type I2C_LIGHT_SLEEP_FORCE;\ + type HPO_IO_EN; + +#define HWSEQ_DCN35_REG_FIELD_LIST(type) \ + type DISPCLK_R_DMU_GATE_DIS;\ + type DISPCLK_G_RBBMIF_GATE_DIS;\ + type RBBMIF_FGCG_REP_DIS;\ + type IHC_FGCG_REP_DIS;\ + type DPREFCLK_ALLOW_DS_CLKSTOP;\ + type DISPCLK_ALLOW_DS_CLKSTOP;\ + type DPPCLK_ALLOW_DS_CLKSTOP;\ + type DTBCLK_ALLOW_DS_CLKSTOP;\ + type DCFCLK_ALLOW_DS_CLKSTOP;\ + type DPIACLK_ALLOW_DS_CLKSTOP;\ + type LONO_FGCG_REP_DIS;\ + type LONO_DISPCLK_GATE_DISABLE;\ + type LONO_SOCCLK_GATE_DISABLE;\ + type LONO_DMCUBCLK_GATE_DISABLE; + +struct dce_hwseq_shift { + HWSEQ_REG_FIELD_LIST(uint8_t) + HWSEQ_DCN_REG_FIELD_LIST(uint8_t) + HWSEQ_DCN3_REG_FIELD_LIST(uint8_t) + HWSEQ_DCN301_REG_FIELD_LIST(uint8_t) + HWSEQ_DCN31_REG_FIELD_LIST(uint8_t) + HWSEQ_DCN35_REG_FIELD_LIST(uint8_t) +}; + +struct dce_hwseq_mask { + HWSEQ_REG_FIELD_LIST(uint32_t) + HWSEQ_DCN_REG_FIELD_LIST(uint32_t) + HWSEQ_DCN3_REG_FIELD_LIST(uint32_t) + HWSEQ_DCN301_REG_FIELD_LIST(uint32_t) + HWSEQ_DCN31_REG_FIELD_LIST(uint32_t) + HWSEQ_DCN35_REG_FIELD_LIST(uint32_t) +}; + + +enum blnd_mode { + BLND_MODE_CURRENT_PIPE = 0,/* Data from current pipe only */ + BLND_MODE_OTHER_PIPE, /* Data from other pipe only */ + BLND_MODE_BLENDING,/* Alpha blending - blend 'current' and 'other' */ +}; + +struct dce_hwseq; +struct pipe_ctx; +struct clock_source; + +void dce_enable_fe_clock(struct dce_hwseq *hwss, + unsigned int inst, bool enable); + +void dce_pipe_control_lock(struct dc *dc, + struct pipe_ctx *pipe, + bool lock); + +void dce_set_blender_mode(struct dce_hwseq *hws, + unsigned int blnd_inst, enum blnd_mode mode); + +#if defined(CONFIG_DRM_AMD_DC_SI) +void dce60_pipe_control_lock(struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +#endif + +void dce_clock_gating_power_up(struct dce_hwseq *hws, + bool enable); + +void dce_crtc_switch_to_clk_src(struct dce_hwseq *hws, + struct clock_source *clk_src, + unsigned int tg_inst); + +bool dce_use_lut(enum surface_pixel_format format); +#endif /*__DCE_HWSEQ_H__*/ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce100/dce100_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce100/dce100_hwseq.c new file mode 100644 index 000000000000..f1f14796a3da --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce100/dce100_hwseq.c @@ -0,0 +1,142 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" +#include "clk_mgr.h" +#include "dce100_hwseq.h" +#include "resource.h" + +#include "dce110/dce110_hwseq.h" + +/* include DCE10 register header files */ +#include "dce/dce_10_0_d.h" +#include "dce/dce_10_0_sh_mask.h" + +struct dce100_hw_seq_reg_offsets { + uint32_t blnd; + uint32_t crtc; +}; + +static const struct dce100_hw_seq_reg_offsets reg_offsets[] = { +{ + .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +} +}; + +#define HW_REG_CRTC(reg, id)\ + (reg + reg_offsets[id].crtc) + +/******************************************************************************* + * Private definitions + ******************************************************************************/ +/***************************PIPE_CONTROL***********************************/ + +bool dce100_enable_display_power_gating( + struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating) +{ + enum bp_result bp_result = BP_RESULT_OK; + enum bp_pipe_control_action cntl; + struct dc_context *ctx = dc->ctx; + + if (power_gating == PIPE_GATING_CONTROL_INIT) + cntl = ASIC_PIPE_INIT; + else if (power_gating == PIPE_GATING_CONTROL_ENABLE) + cntl = ASIC_PIPE_ENABLE; + else + cntl = ASIC_PIPE_DISABLE; + + if (!(power_gating == PIPE_GATING_CONTROL_INIT && controller_id != 0)){ + + bp_result = dcb->funcs->enable_disp_power_gating( + dcb, controller_id + 1, cntl); + + /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 + * by default when command table is called + */ + dm_write_reg(ctx, + HW_REG_CRTC(mmMASTER_UPDATE_MODE, controller_id), + 0); + } + + if (bp_result == BP_RESULT_OK) + return true; + else + return false; +} + +void dce100_prepare_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + false); +} + +void dce100_optimize_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + true); +} + +/**************************************************************************/ + +void dce100_hw_sequencer_construct(struct dc *dc) +{ + dce110_hw_sequencer_construct(dc); + + dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; + dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; + dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; +} + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce100/dce100_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce100/dce100_hwseq.h new file mode 100644 index 000000000000..34518da20009 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce100/dce100_hwseq.h @@ -0,0 +1,50 @@ +/* +* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCE100_H__ +#define __DC_HWSS_DCE100_H__ + +#include "core_types.h" +#include "hw_sequencer_private.h" + +struct dc; +struct dc_state; + +void dce100_hw_sequencer_construct(struct dc *dc); + +void dce100_prepare_bandwidth( + struct dc *dc, + struct dc_state *context); + +void dce100_optimize_bandwidth( + struct dc *dc, + struct dc_state *context); + +bool dce100_enable_display_power_gating(struct dc *dc, uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating); + +#endif /* __DC_HWSS_DCE100_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c new file mode 100644 index 000000000000..74602a5fd6dd --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -0,0 +1,3201 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dc.h" +#include "dc_bios_types.h" +#include "core_types.h" +#include "core_status.h" +#include "resource.h" +#include "dm_helpers.h" +#include "dce110_hwseq.h" +#include "dce110/dce110_timing_generator.h" +#include "dce/dce_hwseq.h" +#include "gpio_service_interface.h" + +#include "dce110/dce110_compressor.h" + +#include "bios/bios_parser_helper.h" +#include "timing_generator.h" +#include "mem_input.h" +#include "opp.h" +#include "ipp.h" +#include "transform.h" +#include "stream_encoder.h" +#include "link_encoder.h" +#include "link_enc_cfg.h" +#include "link_hwss.h" +#include "link.h" +#include "dccg.h" +#include "clock_source.h" +#include "clk_mgr.h" +#include "abm.h" +#include "audio.h" +#include "reg_helper.h" +#include "panel_cntl.h" +#include "dpcd_defs.h" +/* include DCE11 register header files */ +#include "dce/dce_11_0_d.h" +#include "dce/dce_11_0_sh_mask.h" +#include "custom_float.h" + +#include "atomfirmware.h" + +#include "dcn10/dcn10_hwseq.h" + +#include "dce110_hwseq.h" + +#define GAMMA_HW_POINTS_NUM 256 + +/* + * All values are in milliseconds; + * For eDP, after power-up/power/down, + * 300/500 msec max. delay from LCDVCC to black video generation + */ +#define PANEL_POWER_UP_TIMEOUT 300 +#define PANEL_POWER_DOWN_TIMEOUT 500 +#define HPD_CHECK_INTERVAL 10 +#define OLED_POST_T7_DELAY 100 +#define OLED_PRE_T11_DELAY 150 + +#define CTX \ + hws->ctx + +#define DC_LOGGER \ + ctx->logger +#define DC_LOGGER_INIT() \ + struct dc_context *ctx = dc->ctx + +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +struct dce110_hw_seq_reg_offsets { + uint32_t crtc; +}; + +static const struct dce110_hw_seq_reg_offsets reg_offsets[] = { +{ + .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTCV_GSL_CONTROL - mmCRTC_GSL_CONTROL), +} +}; + +#define HW_REG_BLND(reg, id)\ + (reg + reg_offsets[id].blnd) + +#define HW_REG_CRTC(reg, id)\ + (reg + reg_offsets[id].crtc) + +#define MAX_WATERMARK 0xFFFF +#define SAFE_NBP_MARK 0x7FFF + +/******************************************************************************* + * Private definitions + ******************************************************************************/ +/***************************PIPE_CONTROL***********************************/ +static void dce110_init_pte(struct dc_context *ctx) +{ + uint32_t addr; + uint32_t value = 0; + uint32_t chunk_int = 0; + uint32_t chunk_mul = 0; + + addr = mmUNP_DVMM_PTE_CONTROL; + value = dm_read_reg(ctx, addr); + + set_reg_field_value( + value, + 0, + DVMM_PTE_CONTROL, + DVMM_USE_SINGLE_PTE); + + set_reg_field_value( + value, + 1, + DVMM_PTE_CONTROL, + DVMM_PTE_BUFFER_MODE0); + + set_reg_field_value( + value, + 1, + DVMM_PTE_CONTROL, + DVMM_PTE_BUFFER_MODE1); + + dm_write_reg(ctx, addr, value); + + addr = mmDVMM_PTE_REQ; + value = dm_read_reg(ctx, addr); + + chunk_int = get_reg_field_value( + value, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_INT); + + chunk_mul = get_reg_field_value( + value, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); + + if (chunk_int != 0x4 || chunk_mul != 0x4) { + + set_reg_field_value( + value, + 255, + DVMM_PTE_REQ, + MAX_PTEREQ_TO_ISSUE); + + set_reg_field_value( + value, + 4, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_INT); + + set_reg_field_value( + value, + 4, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); + + dm_write_reg(ctx, addr, value); + } +} +/**************************************************************************/ + +static void enable_display_pipe_clock_gating( + struct dc_context *ctx, + bool clock_gating) +{ + /*TODO*/ +} + +static bool dce110_enable_display_power_gating( + struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating) +{ + enum bp_result bp_result = BP_RESULT_OK; + enum bp_pipe_control_action cntl; + struct dc_context *ctx = dc->ctx; + unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; + + if (power_gating == PIPE_GATING_CONTROL_INIT) + cntl = ASIC_PIPE_INIT; + else if (power_gating == PIPE_GATING_CONTROL_ENABLE) + cntl = ASIC_PIPE_ENABLE; + else + cntl = ASIC_PIPE_DISABLE; + + if (controller_id == underlay_idx) + controller_id = CONTROLLER_ID_UNDERLAY0 - 1; + + if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0) { + + bp_result = dcb->funcs->enable_disp_power_gating( + dcb, controller_id + 1, cntl); + + /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 + * by default when command table is called + * + * Bios parser accepts controller_id = 6 as indicative of + * underlay pipe in dce110. But we do not support more + * than 3. + */ + if (controller_id < CONTROLLER_ID_MAX - 1) + dm_write_reg(ctx, + HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id), + 0); + } + + if (power_gating != PIPE_GATING_CONTROL_ENABLE) + dce110_init_pte(ctx); + + if (bp_result == BP_RESULT_OK) + return true; + else + return false; +} + +static void build_prescale_params(struct ipp_prescale_params *prescale_params, + const struct dc_plane_state *plane_state) +{ + prescale_params->mode = IPP_PRESCALE_MODE_FIXED_UNSIGNED; + + switch (plane_state->format) { + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + prescale_params->scale = 0x2082; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + prescale_params->scale = 0x2020; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + prescale_params->scale = 0x2008; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: + prescale_params->scale = 0x2000; + break; + default: + ASSERT(false); + break; + } +} + +static bool +dce110_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) +{ + struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; + const struct dc_transfer_func *tf = NULL; + struct ipp_prescale_params prescale_params = { 0 }; + bool result = true; + + if (ipp == NULL) + return false; + + if (plane_state->in_transfer_func) + tf = plane_state->in_transfer_func; + + build_prescale_params(&prescale_params, plane_state); + ipp->funcs->ipp_program_prescale(ipp, &prescale_params); + + if (plane_state->gamma_correction && + !plane_state->gamma_correction->is_identity && + dce_use_lut(plane_state->format)) + ipp->funcs->ipp_program_input_lut(ipp, plane_state->gamma_correction); + + if (tf == NULL) { + /* Default case if no input transfer function specified */ + ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_sRGB); + } else if (tf->type == TF_TYPE_PREDEFINED) { + switch (tf->tf) { + case TRANSFER_FUNCTION_SRGB: + ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_sRGB); + break; + case TRANSFER_FUNCTION_BT709: + ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_HW_xvYCC); + break; + case TRANSFER_FUNCTION_LINEAR: + ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS); + break; + case TRANSFER_FUNCTION_PQ: + default: + result = false; + break; + } + } else if (tf->type == TF_TYPE_BYPASS) { + ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS); + } else { + /*TF_TYPE_DISTRIBUTED_POINTS - Not supported in DCE 11*/ + result = false; + } + + return result; +} + +static bool convert_to_custom_float(struct pwl_result_data *rgb_resulted, + struct curve_points *arr_points, + uint32_t hw_points_num) +{ + struct custom_float_format fmt; + + struct pwl_result_data *rgb = rgb_resulted; + + uint32_t i = 0; + + fmt.exponenta_bits = 6; + fmt.mantissa_bits = 12; + fmt.sign = true; + + if (!convert_to_custom_float_format(arr_points[0].x, &fmt, + &arr_points[0].custom_float_x)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(arr_points[0].offset, &fmt, + &arr_points[0].custom_float_offset)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(arr_points[0].slope, &fmt, + &arr_points[0].custom_float_slope)) { + BREAK_TO_DEBUGGER(); + return false; + } + + fmt.mantissa_bits = 10; + fmt.sign = false; + + if (!convert_to_custom_float_format(arr_points[1].x, &fmt, + &arr_points[1].custom_float_x)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(arr_points[1].y, &fmt, + &arr_points[1].custom_float_y)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(arr_points[1].slope, &fmt, + &arr_points[1].custom_float_slope)) { + BREAK_TO_DEBUGGER(); + return false; + } + + fmt.mantissa_bits = 12; + fmt.sign = true; + + while (i != hw_points_num) { + if (!convert_to_custom_float_format(rgb->red, &fmt, + &rgb->red_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->green, &fmt, + &rgb->green_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->blue, &fmt, + &rgb->blue_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->delta_red, &fmt, + &rgb->delta_red_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->delta_green, &fmt, + &rgb->delta_green_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->delta_blue, &fmt, + &rgb->delta_blue_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + ++rgb; + ++i; + } + + return true; +} + +#define MAX_LOW_POINT 25 +#define NUMBER_REGIONS 16 +#define NUMBER_SW_SEGMENTS 16 + +static bool +dce110_translate_regamma_to_hw_format(const struct dc_transfer_func *output_tf, + struct pwl_params *regamma_params) +{ + struct curve_points *arr_points; + struct pwl_result_data *rgb_resulted; + struct pwl_result_data *rgb; + struct pwl_result_data *rgb_plus_1; + struct fixed31_32 y_r; + struct fixed31_32 y_g; + struct fixed31_32 y_b; + struct fixed31_32 y1_min; + struct fixed31_32 y3_max; + + int32_t region_start, region_end; + uint32_t i, j, k, seg_distr[NUMBER_REGIONS], increment, start_index, hw_points; + + if (output_tf == NULL || regamma_params == NULL || output_tf->type == TF_TYPE_BYPASS) + return false; + + arr_points = regamma_params->arr_points; + rgb_resulted = regamma_params->rgb_resulted; + hw_points = 0; + + memset(regamma_params, 0, sizeof(struct pwl_params)); + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* 16 segments + * segments are from 2^-11 to 2^5 + */ + region_start = -11; + region_end = region_start + NUMBER_REGIONS; + + for (i = 0; i < NUMBER_REGIONS; i++) + seg_distr[i] = 4; + + } else { + /* 10 segments + * segment is from 2^-10 to 2^1 + * We include an extra segment for range [2^0, 2^1). This is to + * ensure that colors with normalized values of 1 don't miss the + * LUT. + */ + region_start = -10; + region_end = 1; + + seg_distr[0] = 4; + seg_distr[1] = 4; + seg_distr[2] = 4; + seg_distr[3] = 4; + seg_distr[4] = 4; + seg_distr[5] = 4; + seg_distr[6] = 4; + seg_distr[7] = 4; + seg_distr[8] = 4; + seg_distr[9] = 4; + seg_distr[10] = 0; + seg_distr[11] = -1; + seg_distr[12] = -1; + seg_distr[13] = -1; + seg_distr[14] = -1; + seg_distr[15] = -1; + } + + for (k = 0; k < 16; k++) { + if (seg_distr[k] != -1) + hw_points += (1 << seg_distr[k]); + } + + j = 0; + for (k = 0; k < (region_end - region_start); k++) { + increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); + start_index = (region_start + k + MAX_LOW_POINT) * + NUMBER_SW_SEGMENTS; + for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; + i += increment) { + if (j == hw_points - 1) + break; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; + j++; + } + } + + /* last point */ + start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; + rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; + rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; + rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; + + arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2), + dc_fixpt_from_int(region_start)); + arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2), + dc_fixpt_from_int(region_end)); + + y_r = rgb_resulted[0].red; + y_g = rgb_resulted[0].green; + y_b = rgb_resulted[0].blue; + + y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b)); + + arr_points[0].y = y1_min; + arr_points[0].slope = dc_fixpt_div(arr_points[0].y, + arr_points[0].x); + + y_r = rgb_resulted[hw_points - 1].red; + y_g = rgb_resulted[hw_points - 1].green; + y_b = rgb_resulted[hw_points - 1].blue; + + /* see comment above, m_arrPoints[1].y should be the Y value for the + * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) + */ + y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b)); + + arr_points[1].y = y3_max; + + arr_points[1].slope = dc_fixpt_zero; + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* for PQ, we want to have a straight line from last HW X point, + * and the slope to be such that we hit 1.0 at 10000 nits. + */ + const struct fixed31_32 end_value = dc_fixpt_from_int(125); + + arr_points[1].slope = dc_fixpt_div( + dc_fixpt_sub(dc_fixpt_one, arr_points[1].y), + dc_fixpt_sub(end_value, arr_points[1].x)); + } + + regamma_params->hw_points_num = hw_points; + + k = 0; + for (i = 1; i < 16; i++) { + if (seg_distr[k] != -1) { + regamma_params->arr_curve_points[k].segments_num = seg_distr[k]; + regamma_params->arr_curve_points[i].offset = + regamma_params->arr_curve_points[k].offset + (1 << seg_distr[k]); + } + k++; + } + + if (seg_distr[k] != -1) + regamma_params->arr_curve_points[k].segments_num = seg_distr[k]; + + rgb = rgb_resulted; + rgb_plus_1 = rgb_resulted + 1; + + i = 1; + + while (i != hw_points + 1) { + if (dc_fixpt_lt(rgb_plus_1->red, rgb->red)) + rgb_plus_1->red = rgb->red; + if (dc_fixpt_lt(rgb_plus_1->green, rgb->green)) + rgb_plus_1->green = rgb->green; + if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue)) + rgb_plus_1->blue = rgb->blue; + + rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red); + rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green); + rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue); + + ++rgb_plus_1; + ++rgb; + ++i; + } + + convert_to_custom_float(rgb_resulted, arr_points, hw_points); + + return true; +} + +static bool +dce110_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + struct transform *xfm = pipe_ctx->plane_res.xfm; + + xfm->funcs->opp_power_on_regamma_lut(xfm, true); + xfm->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; + + if (stream->out_transfer_func && + stream->out_transfer_func->type == TF_TYPE_PREDEFINED && + stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) { + xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_SRGB); + } else if (dce110_translate_regamma_to_hw_format(stream->out_transfer_func, + &xfm->regamma_params)) { + xfm->funcs->opp_program_regamma_pwl(xfm, &xfm->regamma_params); + xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_USER); + } else { + xfm->funcs->opp_set_regamma_mode(xfm, OPP_REGAMMA_BYPASS); + } + + xfm->funcs->opp_power_on_regamma_lut(xfm, false); + + return true; +} + +void dce110_update_info_frame(struct pipe_ctx *pipe_ctx) +{ + bool is_hdmi_tmds; + bool is_dp; + + ASSERT(pipe_ctx->stream); + + if (pipe_ctx->stream_res.stream_enc == NULL) + return; /* this is not root pipe */ + + is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); + is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); + + if (!is_hdmi_tmds && !is_dp) + return; + + if (is_hdmi_tmds) + pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + else { + if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num) + pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + + pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + } +} + +void dce110_enable_stream(struct pipe_ctx *pipe_ctx) +{ + enum dc_lane_count lane_count = + pipe_ctx->stream->link->cur_link_settings.lane_count; + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + struct dc_link *link = pipe_ctx->stream->link; + const struct dc *dc = link->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + uint32_t active_total_with_borders; + uint32_t early_control = 0; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + + link_hwss->setup_stream_encoder(pipe_ctx); + + dc->hwss.update_info_frame(pipe_ctx); + + /* enable early control to avoid corruption on DP monitor*/ + active_total_with_borders = + timing->h_addressable + + timing->h_border_left + + timing->h_border_right; + + if (lane_count != 0) + early_control = active_total_with_borders % lane_count; + + if (early_control == 0) + early_control = lane_count; + + tg->funcs->set_early_control(tg, early_control); +} + +static enum bp_result link_transmitter_control( + struct dc_bios *bios, + struct bp_transmitter_control *cntl) +{ + enum bp_result result; + + result = bios->funcs->transmitter_control(bios, cntl); + + return result; +} + +/* + * @brief + * eDP only. + */ +void dce110_edp_wait_for_hpd_ready( + struct dc_link *link, + bool power_up) +{ + struct dc_context *ctx = link->ctx; + struct graphics_object_id connector = link->link_enc->connector; + struct gpio *hpd; + bool edp_hpd_high = false; + uint32_t time_elapsed = 0; + uint32_t timeout = power_up ? + PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT; + + if (dal_graphics_object_id_get_connector_id(connector) + != CONNECTOR_ID_EDP) { + BREAK_TO_DEBUGGER(); + return; + } + + if (!power_up) + /* + * From KV, we will not HPD low after turning off VCC - + * instead, we will check the SW timer in power_up(). + */ + return; + + /* + * When we power on/off the eDP panel, + * we need to wait until SENSE bit is high/low. + */ + + /* obtain HPD */ + /* TODO what to do with this? */ + hpd = ctx->dc->link_srv->get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service); + + if (!hpd) { + BREAK_TO_DEBUGGER(); + return; + } + + if (link != NULL) { + if (link->panel_config.pps.extra_t3_ms > 0) { + int extra_t3_in_ms = link->panel_config.pps.extra_t3_ms; + + msleep(extra_t3_in_ms); + } + } + + dal_gpio_open(hpd, GPIO_MODE_INTERRUPT); + + /* wait until timeout or panel detected */ + + do { + uint32_t detected = 0; + + dal_gpio_get_value(hpd, &detected); + + if (!(detected ^ power_up)) { + edp_hpd_high = true; + break; + } + + msleep(HPD_CHECK_INTERVAL); + + time_elapsed += HPD_CHECK_INTERVAL; + } while (time_elapsed < timeout); + + dal_gpio_close(hpd); + + dal_gpio_destroy_irq(&hpd); + + /* ensure that the panel is detected */ + if (!edp_hpd_high) + DC_LOG_DC("%s: wait timed out!\n", __func__); +} + +void dce110_edp_power_control( + struct dc_link *link, + bool power_up) +{ + struct dc_context *ctx = link->ctx; + struct bp_transmitter_control cntl = { 0 }; + enum bp_result bp_result; + uint8_t panel_instance; + + + if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) + != CONNECTOR_ID_EDP) { + BREAK_TO_DEBUGGER(); + return; + } + + if (!link->panel_cntl) + return; + if (power_up != + link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl)) { + + unsigned long long current_ts = dm_get_timestamp(ctx); + unsigned long long time_since_edp_poweroff_ms = + div64_u64(dm_get_elapse_time_in_ns( + ctx, + current_ts, + ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link)), 1000000); + unsigned long long time_since_edp_poweron_ms = + div64_u64(dm_get_elapse_time_in_ns( + ctx, + current_ts, + ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link)), 1000000); + DC_LOG_HW_RESUME_S3( + "%s: transition: power_up=%d current_ts=%llu edp_poweroff=%llu edp_poweron=%llu time_since_edp_poweroff_ms=%llu time_since_edp_poweron_ms=%llu", + __func__, + power_up, + current_ts, + ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link), + ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link), + time_since_edp_poweroff_ms, + time_since_edp_poweron_ms); + + /* Send VBIOS command to prompt eDP panel power */ + if (power_up) { + /* edp requires a min of 500ms from LCDVDD off to on */ + unsigned long long remaining_min_edp_poweroff_time_ms = 500; + + /* add time defined by a patch, if any (usually patch extra_t12_ms is 0) */ + if (link->local_sink != NULL) + remaining_min_edp_poweroff_time_ms += + link->panel_config.pps.extra_t12_ms; + + /* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */ + if (ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link) != 0) { + if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms) + remaining_min_edp_poweroff_time_ms = + remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms; + else + remaining_min_edp_poweroff_time_ms = 0; + } + + if (remaining_min_edp_poweroff_time_ms) { + DC_LOG_HW_RESUME_S3( + "%s: remaining_min_edp_poweroff_time_ms=%llu: begin wait.\n", + __func__, remaining_min_edp_poweroff_time_ms); + msleep(remaining_min_edp_poweroff_time_ms); + DC_LOG_HW_RESUME_S3( + "%s: remaining_min_edp_poweroff_time_ms=%llu: end wait.\n", + __func__, remaining_min_edp_poweroff_time_ms); + dm_output_to_console("%s: wait %lld ms to power on eDP.\n", + __func__, remaining_min_edp_poweroff_time_ms); + } else { + DC_LOG_HW_RESUME_S3( + "%s: remaining_min_edp_poweroff_time_ms=%llu: no wait required.\n", + __func__, remaining_min_edp_poweroff_time_ms); + } + } + + DC_LOG_HW_RESUME_S3( + "%s: BEGIN: Panel Power action: %s\n", + __func__, (power_up ? "On":"Off")); + + cntl.action = power_up ? + TRANSMITTER_CONTROL_POWER_ON : + TRANSMITTER_CONTROL_POWER_OFF; + cntl.transmitter = link->link_enc->transmitter; + cntl.connector_obj_id = link->link_enc->connector; + cntl.coherent = false; + cntl.lanes_number = LANE_COUNT_FOUR; + cntl.hpd_sel = link->link_enc->hpd_source; + panel_instance = link->panel_cntl->inst; + + if (ctx->dc->ctx->dmub_srv && + ctx->dc->debug.dmub_command_table) { + + if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) { + bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_POWER_ON, + panel_instance, link->link_powered_externally); + } else { + bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_POWER_OFF, + panel_instance, link->link_powered_externally); + } + } + + bp_result = link_transmitter_control(ctx->dc_bios, &cntl); + + DC_LOG_HW_RESUME_S3( + "%s: END: Panel Power action: %s bp_result=%u\n", + __func__, (power_up ? "On":"Off"), + bp_result); + + ctx->dc->link_srv->dp_trace_set_edp_power_timestamp(link, power_up); + + DC_LOG_HW_RESUME_S3( + "%s: updated values: edp_poweroff=%llu edp_poweron=%llu\n", + __func__, + ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link), + ctx->dc->link_srv->dp_trace_get_edp_poweron_timestamp(link)); + + if (bp_result != BP_RESULT_OK) + DC_LOG_ERROR( + "%s: Panel Power bp_result: %d\n", + __func__, bp_result); + } else { + DC_LOG_HW_RESUME_S3( + "%s: Skipping Panel Power action: %s\n", + __func__, (power_up ? "On":"Off")); + } +} + +void dce110_edp_wait_for_T12( + struct dc_link *link) +{ + struct dc_context *ctx = link->ctx; + + if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) + != CONNECTOR_ID_EDP) { + BREAK_TO_DEBUGGER(); + return; + } + + if (!link->panel_cntl) + return; + + if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) && + ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link) != 0) { + unsigned int t12_duration = 500; // Default T12 as per spec + unsigned long long current_ts = dm_get_timestamp(ctx); + unsigned long long time_since_edp_poweroff_ms = + div64_u64(dm_get_elapse_time_in_ns( + ctx, + current_ts, + ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link)), 1000000); + + t12_duration += link->panel_config.pps.extra_t12_ms; // Add extra T12 + + if (time_since_edp_poweroff_ms < t12_duration) + msleep(t12_duration - time_since_edp_poweroff_ms); + } +} +/*todo: cloned in stream enc, fix*/ +/* + * @brief + * eDP only. Control the backlight of the eDP panel + */ +void dce110_edp_backlight_control( + struct dc_link *link, + bool enable) +{ + struct dc_context *ctx = link->ctx; + struct bp_transmitter_control cntl = { 0 }; + uint8_t panel_instance; + unsigned int pre_T11_delay = OLED_PRE_T11_DELAY; + unsigned int post_T7_delay = OLED_POST_T7_DELAY; + + if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) + != CONNECTOR_ID_EDP) { + BREAK_TO_DEBUGGER(); + return; + } + + if (link->panel_cntl && !(link->dpcd_sink_ext_caps.bits.oled || + link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 || + link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)) { + bool is_backlight_on = link->panel_cntl->funcs->is_panel_backlight_on(link->panel_cntl); + + if ((enable && is_backlight_on) || (!enable && !is_backlight_on)) { + DC_LOG_HW_RESUME_S3( + "%s: panel already powered up/off. Do nothing.\n", + __func__); + return; + } + } + + /* Send VBIOS command to control eDP panel backlight */ + + DC_LOG_HW_RESUME_S3( + "%s: backlight action: %s\n", + __func__, (enable ? "On":"Off")); + + cntl.action = enable ? + TRANSMITTER_CONTROL_BACKLIGHT_ON : + TRANSMITTER_CONTROL_BACKLIGHT_OFF; + + /*cntl.engine_id = ctx->engine;*/ + cntl.transmitter = link->link_enc->transmitter; + cntl.connector_obj_id = link->link_enc->connector; + /*todo: unhardcode*/ + cntl.lanes_number = LANE_COUNT_FOUR; + cntl.hpd_sel = link->link_enc->hpd_source; + cntl.signal = SIGNAL_TYPE_EDP; + + /* For eDP, the following delays might need to be considered + * after link training completed: + * idle period - min. accounts for required BS-Idle pattern, + * max. allows for source frame synchronization); + * 50 msec max. delay from valid video data from source + * to video on dislpay or backlight enable. + * + * Disable the delay for now. + * Enable it in the future if necessary. + */ + /* dc_service_sleep_in_milliseconds(50); */ + /*edp 1.2*/ + panel_instance = link->panel_cntl->inst; + + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { + if (!link->dc->config.edp_no_power_sequencing) + /* + * Sometimes, DP receiver chip power-controlled externally by an + * Embedded Controller could be treated and used as eDP, + * if it drives mobile display. In this case, + * we shouldn't be doing power-sequencing, hence we can skip + * waiting for T7-ready. + */ + ctx->dc->link_srv->edp_receiver_ready_T7(link); + else + DC_LOG_DC("edp_receiver_ready_T7 skipped\n"); + } + + /* Setting link_powered_externally will bypass delays in the backlight + * as they are not required if the link is being powered by a different + * source. + */ + if (ctx->dc->ctx->dmub_srv && + ctx->dc->debug.dmub_command_table) { + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) + ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_LCD_BLON, + panel_instance, link->link_powered_externally); + else + ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, + LVTMA_CONTROL_LCD_BLOFF, + panel_instance, link->link_powered_externally); + } + + link_transmitter_control(ctx->dc_bios, &cntl); + + if (enable && link->dpcd_sink_ext_caps.bits.oled && + !link->dc->config.edp_no_power_sequencing) { + post_T7_delay += link->panel_config.pps.extra_post_t7_ms; + msleep(post_T7_delay); + } + + if (link->dpcd_sink_ext_caps.bits.oled || + link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 || + link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1) + ctx->dc->link_srv->edp_backlight_enable_aux(link, enable); + + /*edp 1.2*/ + if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) { + if (!link->dc->config.edp_no_power_sequencing) + /* + * Sometimes, DP receiver chip power-controlled externally by an + * Embedded Controller could be treated and used as eDP, + * if it drives mobile display. In this case, + * we shouldn't be doing power-sequencing, hence we can skip + * waiting for T9-ready. + */ + ctx->dc->link_srv->edp_add_delay_for_T9(link); + else + DC_LOG_DC("edp_receiver_ready_T9 skipped\n"); + } + + if (!enable && link->dpcd_sink_ext_caps.bits.oled) { + pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms; + msleep(pre_T11_delay); + } +} + +void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) +{ + /* notify audio driver for audio modes of monitor */ + struct dc *dc; + struct clk_mgr *clk_mgr; + unsigned int i, num_audio = 1; + const struct link_hwss *link_hwss; + + if (!pipe_ctx->stream) + return; + + dc = pipe_ctx->stream->ctx->dc; + clk_mgr = dc->clk_mgr; + link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res); + + if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true) + return; + + if (pipe_ctx->stream_res.audio) { + for (i = 0; i < MAX_PIPES; i++) { + /*current_state not updated yet*/ + if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) + num_audio++; + } + + pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); + + if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) + /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ + clk_mgr->funcs->enable_pme_wa(clk_mgr); + + link_hwss->enable_audio_packet(pipe_ctx); + + if (pipe_ctx->stream_res.audio) + pipe_ctx->stream_res.audio->enabled = true; + } +} + +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx) +{ + struct dc *dc; + struct clk_mgr *clk_mgr; + const struct link_hwss *link_hwss; + + if (!pipe_ctx || !pipe_ctx->stream) + return; + + dc = pipe_ctx->stream->ctx->dc; + clk_mgr = dc->clk_mgr; + link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res); + + if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false) + return; + + link_hwss->disable_audio_packet(pipe_ctx); + + if (pipe_ctx->stream_res.audio) { + pipe_ctx->stream_res.audio->enabled = false; + + if (clk_mgr->funcs->enable_pme_wa) + /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ + clk_mgr->funcs->enable_pme_wa(clk_mgr); + + /* TODO: notify audio driver for if audio modes list changed + * add audio mode list change flag */ + /* dal_audio_disable_azalia_audio_jack_presence(stream->audio, + * stream->stream_engine_id); + */ + } +} + +void dce110_disable_stream(struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct dc *dc = pipe_ctx->stream->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + struct dccg *dccg = dc->res_pool->dccg; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + struct dtbclk_dto_params dto_params = {0}; + int dp_hpo_inst; + struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link); + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + + if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) { + pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( + pipe_ctx->stream_res.stream_enc); + pipe_ctx->stream_res.stream_enc->funcs->hdmi_reset_stream_attribute( + pipe_ctx->stream_res.stream_enc); + } + + if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets( + pipe_ctx->stream_res.hpo_dp_stream_enc); + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets( + pipe_ctx->stream_res.stream_enc); + + dc->hwss.disable_audio_stream(pipe_ctx); + + link_hwss->reset_stream_encoder(pipe_ctx); + + if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) && dccg) { + dto_params.otg_inst = tg->inst; + dto_params.timing = &pipe_ctx->stream->timing; + dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; + + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); + dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst); + } else if (dccg && dccg->funcs->disable_symclk_se) { + dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst, + link_enc->transmitter - TRANSMITTER_UNIPHY_A); + } + + if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + /* TODO: This looks like a bug to me as we are disabling HPO IO when + * we are just disabling a single HPO stream. Shouldn't we disable HPO + * HW control only when HPOs for all streams are disabled? + */ + if (pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control) + pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control( + pipe_ctx->stream->ctx->dc->hwseq, false); + } +} + +void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings) +{ + struct encoder_unblank_param params = { { 0 } }; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; + + /* only 3 items below are used by unblank */ + params.timing = pipe_ctx->stream->timing; + params.link_settings.link_rate = link_settings->link_rate; + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + hws->funcs.edp_backlight_control(link, true); + } +} + +void dce110_blank_stream(struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + if (!link->skip_implict_edp_power_control) + hws->funcs.edp_backlight_control(link, false); + link->dc->hwss.set_abm_immediate_disable(pipe_ctx); + } + + if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank( + pipe_ctx->stream_res.hpo_dp_stream_enc); + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + pipe_ctx->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc); + + if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) { + /* + * After output is idle pattern some sinks need time to recognize the stream + * has changed or they enter protection state and hang. + */ + msleep(60); + } else if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) { + if (!link->dc->config.edp_no_power_sequencing) { + /* + * Sometimes, DP receiver chip power-controlled externally by an + * Embedded Controller could be treated and used as eDP, + * if it drives mobile display. In this case, + * we shouldn't be doing power-sequencing, hence we can skip + * waiting for T9-ready. + */ + link->dc->link_srv->edp_receiver_ready_T9(link); + } + } + } + +} + + +void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) +{ + if (pipe_ctx != NULL && pipe_ctx->stream_res.stream_enc != NULL) + pipe_ctx->stream_res.stream_enc->funcs->set_avmute(pipe_ctx->stream_res.stream_enc, enable); +} + +static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id) +{ + switch (crtc_id) { + case CONTROLLER_ID_D0: + return DTO_SOURCE_ID0; + case CONTROLLER_ID_D1: + return DTO_SOURCE_ID1; + case CONTROLLER_ID_D2: + return DTO_SOURCE_ID2; + case CONTROLLER_ID_D3: + return DTO_SOURCE_ID3; + case CONTROLLER_ID_D4: + return DTO_SOURCE_ID4; + case CONTROLLER_ID_D5: + return DTO_SOURCE_ID5; + default: + return DTO_SOURCE_UNKNOWN; + } +} + +static void build_audio_output( + struct dc_state *state, + const struct pipe_ctx *pipe_ctx, + struct audio_output *audio_output) +{ + const struct dc_stream_state *stream = pipe_ctx->stream; + audio_output->engine_id = pipe_ctx->stream_res.stream_enc->id; + + audio_output->signal = pipe_ctx->stream->signal; + + /* audio_crtc_info */ + + audio_output->crtc_info.h_total = + stream->timing.h_total; + + /* + * Audio packets are sent during actual CRTC blank physical signal, we + * need to specify actual active signal portion + */ + audio_output->crtc_info.h_active = + stream->timing.h_addressable + + stream->timing.h_border_left + + stream->timing.h_border_right; + + audio_output->crtc_info.v_active = + stream->timing.v_addressable + + stream->timing.v_border_top + + stream->timing.v_border_bottom; + + audio_output->crtc_info.pixel_repetition = 1; + + audio_output->crtc_info.interlaced = + stream->timing.flags.INTERLACE; + + audio_output->crtc_info.refresh_rate = + (stream->timing.pix_clk_100hz*100)/ + (stream->timing.h_total*stream->timing.v_total); + + audio_output->crtc_info.color_depth = + stream->timing.display_color_depth; + + audio_output->crtc_info.requested_pixel_clock_100Hz = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz; + + audio_output->crtc_info.calculated_pixel_clock_100Hz = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz; + +/*for HDMI, audio ACR is with deep color ratio factor*/ + if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) && + audio_output->crtc_info.requested_pixel_clock_100Hz == + (stream->timing.pix_clk_100hz)) { + if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) { + audio_output->crtc_info.requested_pixel_clock_100Hz = + audio_output->crtc_info.requested_pixel_clock_100Hz/2; + audio_output->crtc_info.calculated_pixel_clock_100Hz = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/2; + + } + } + + if (state->clk_mgr && + (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT || + pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)) { + audio_output->pll_info.dp_dto_source_clock_in_khz = + state->clk_mgr->funcs->get_dp_ref_clk_frequency( + state->clk_mgr); + } + + audio_output->pll_info.feed_back_divider = + pipe_ctx->pll_settings.feedback_divider; + + audio_output->pll_info.dto_source = + translate_to_dto_source( + pipe_ctx->stream_res.tg->inst + 1); + + /* TODO hard code to enable for now. Need get from stream */ + audio_output->pll_info.ss_enabled = true; + + audio_output->pll_info.ss_percentage = + pipe_ctx->pll_settings.ss_percentage; +} + +static void program_scaler(const struct dc *dc, + const struct pipe_ctx *pipe_ctx) +{ + struct tg_color color = {0}; + + /* TOFPGA */ + if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL) + return; + + if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) + get_surface_visual_confirm_color(pipe_ctx, &color); + else + color_space_to_black_color(dc, + pipe_ctx->stream->output_color_space, + &color); + + pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth( + pipe_ctx->plane_res.xfm, + pipe_ctx->plane_res.scl_data.lb_params.depth, + &pipe_ctx->stream->bit_depth_params); + + if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) { + /* + * The way 420 is packed, 2 channels carry Y component, 1 channel + * alternate between Cb and Cr, so both channels need the pixel + * value for Y + */ + if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + color.color_r_cr = color.color_g_y; + + pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color( + pipe_ctx->stream_res.tg, + &color); + } + + pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm, + &pipe_ctx->plane_res.scl_data); +} + +static enum dc_status dce110_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx. + pipe_ctx[pipe_ctx->pipe_idx]; + struct tg_color black_color = {0}; + + if (!pipe_ctx_old->stream) { + + /* program blank color */ + color_space_to_black_color(dc, + stream->output_color_space, &black_color); + pipe_ctx->stream_res.tg->funcs->set_blank_color( + pipe_ctx->stream_res.tg, + &black_color); + + /* + * Must blank CRTC after disabling power gating and before any + * programming, otherwise CRTC will be hung in bad state + */ + pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); + + if (false == pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + if (dc_is_hdmi_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + else + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + } + + pipe_ctx->stream_res.tg->funcs->program_timing( + pipe_ctx->stream_res.tg, + &stream->timing, + 0, + 0, + 0, + 0, + pipe_ctx->stream->signal, + true); + } + + if (!pipe_ctx_old->stream) { + if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc( + pipe_ctx->stream_res.tg)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + } + + return DC_OK; +} + +static enum dc_status apply_single_controller_ctx_to_hw( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct drr_params params = {0}; + unsigned int event_triggers = 0; + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + struct dce_hwseq *hws = dc->hwseq; + const struct link_hwss *link_hwss = get_link_hwss( + link, &pipe_ctx->link_res); + + + if (hws->funcs.disable_stream_gating) { + hws->funcs.disable_stream_gating(dc, pipe_ctx); + } + + if (pipe_ctx->stream_res.audio != NULL) { + struct audio_output audio_output; + + build_audio_output(context, pipe_ctx, &audio_output); + + link_hwss->setup_audio_output(pipe_ctx, &audio_output, + pipe_ctx->stream_res.audio->inst); + + pipe_ctx->stream_res.audio->funcs->az_configure( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &pipe_ctx->stream->audio_info); + } + + /* make sure no pipes syncd to the pipe being enabled */ + if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic) + check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx); + + pipe_ctx->stream_res.opp->funcs->opp_program_fmt( + pipe_ctx->stream_res.opp, + &stream->bit_depth_params, + &stream->clamping); + + pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion( + pipe_ctx->stream_res.opp, + COLOR_SPACE_YCBCR601, + stream->timing.display_color_depth, + stream->signal); + + while (odm_pipe) { + odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion( + odm_pipe->stream_res.opp, + COLOR_SPACE_YCBCR601, + stream->timing.display_color_depth, + stream->signal); + + odm_pipe->stream_res.opp->funcs->opp_program_fmt( + odm_pipe->stream_res.opp, + &stream->bit_depth_params, + &stream->clamping); + odm_pipe = odm_pipe->next_odm_pipe; + } + + /* DCN3.1 FPGA Workaround + * Need to enable HPO DP Stream Encoder before setting OTG master enable. + * To do so, move calling function enable_stream_timing to only be done AFTER calling + * function core_link_enable_stream + */ + if (!(hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))) + /* */ + /* Do not touch stream timing on seamless boot optimization. */ + if (!pipe_ctx->stream->apply_seamless_boot_optimization) + hws->funcs.enable_stream_timing(pipe_ctx, context, dc); + + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); + + params.vertical_total_min = stream->adjust.v_total_min; + params.vertical_total_max = stream->adjust.v_total_max; + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, ¶ms); + + // DRR should set trigger event to monitor surface update event + if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) + event_triggers = 0x80; + /* Event triggers and num frames initialized for DRR, but can be + * later updated for PSR use. Note DRR trigger events are generated + * regardless of whether num frames met. + */ + if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) + pipe_ctx->stream_res.tg->funcs->set_static_screen_control( + pipe_ctx->stream_res.tg, event_triggers, 2); + + if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.tg->inst); + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG); + + if (!stream->dpms_off) + dc->link_srv->set_dpms_on(context, pipe_ctx); + + /* DCN3.1 FPGA Workaround + * Need to enable HPO DP Stream Encoder before setting OTG master enable. + * To do so, move calling function enable_stream_timing to only be done AFTER calling + * function core_link_enable_stream + */ + if (hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + if (!pipe_ctx->stream->apply_seamless_boot_optimization) + hws->funcs.enable_stream_timing(pipe_ctx, context, dc); + } + + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL; + + /* Phantom and main stream share the same link (because the stream + * is constructed with the same sink). Make sure not to override + * and link programming on the main. + */ + if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { + pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false; + pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false; + } + return DC_OK; +} + +/******************************************************************************/ + +static void power_down_encoders(struct dc *dc) +{ + int i; + + for (i = 0; i < dc->link_count; i++) { + enum signal_type signal = dc->links[i]->connector_signal; + + dc->link_srv->blank_dp_stream(dc->links[i], false); + + if (signal != SIGNAL_TYPE_EDP) + signal = SIGNAL_TYPE_NONE; + + if (dc->links[i]->ep_type == DISPLAY_ENDPOINT_PHY) + dc->links[i]->link_enc->funcs->disable_output( + dc->links[i]->link_enc, signal); + + dc->links[i]->link_status.link_active = false; + memset(&dc->links[i]->cur_link_settings, 0, + sizeof(dc->links[i]->cur_link_settings)); + } +} + +static void power_down_controllers(struct dc *dc) +{ + int i; + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + dc->res_pool->timing_generators[i]->funcs->disable_crtc( + dc->res_pool->timing_generators[i]); + } +} + +static void power_down_clock_sources(struct dc *dc) +{ + int i; + + if (dc->res_pool->dp_clock_source->funcs->cs_power_down( + dc->res_pool->dp_clock_source) == false) + dm_error("Failed to power down pll! (dp clk src)\n"); + + for (i = 0; i < dc->res_pool->clk_src_count; i++) { + if (dc->res_pool->clock_sources[i]->funcs->cs_power_down( + dc->res_pool->clock_sources[i]) == false) + dm_error("Failed to power down pll! (clk src index=%d)\n", i); + } +} + +static void power_down_all_hw_blocks(struct dc *dc) +{ + power_down_encoders(dc); + + power_down_controllers(dc); + + power_down_clock_sources(dc); + + if (dc->fbc_compressor) + dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); +} + +static void disable_vga_and_power_gate_all_controllers( + struct dc *dc) +{ + int i; + struct timing_generator *tg; + struct dc_context *ctx = dc->ctx; + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->disable_vga) + tg->funcs->disable_vga(tg); + } + for (i = 0; i < dc->res_pool->pipe_count; i++) { + /* Enable CLOCK gating for each pipe BEFORE controller + * powergating. */ + enable_display_pipe_clock_gating(ctx, + true); + + dc->current_state->res_ctx.pipe_ctx[i].pipe_idx = i; + dc->hwss.disable_plane(dc, + &dc->current_state->res_ctx.pipe_ctx[i]); + } +} + + +static void get_edp_streams(struct dc_state *context, + struct dc_stream_state **edp_streams, + int *edp_stream_num) +{ + int i; + + *edp_stream_num = 0; + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->signal == SIGNAL_TYPE_EDP) { + edp_streams[*edp_stream_num] = context->streams[i]; + if (++(*edp_stream_num) == MAX_NUM_EDP) + return; + } + } +} + +static void get_edp_links_with_sink( + struct dc *dc, + struct dc_link **edp_links_with_sink, + int *edp_with_sink_num) +{ + int i; + + /* check if there is an eDP panel not in use */ + *edp_with_sink_num = 0; + for (i = 0; i < dc->link_count; i++) { + if (dc->links[i]->local_sink && + dc->links[i]->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + edp_links_with_sink[*edp_with_sink_num] = dc->links[i]; + if (++(*edp_with_sink_num) == MAX_NUM_EDP) + return; + } + } +} + +/* + * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need: + * 1. Power down all DC HW blocks + * 2. Disable VGA engine on all controllers + * 3. Enable power gating for controller + * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS) + */ +void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) +{ + struct dc_link *edp_links_with_sink[MAX_NUM_EDP]; + struct dc_link *edp_links[MAX_NUM_EDP]; + struct dc_stream_state *edp_streams[MAX_NUM_EDP]; + struct dc_link *edp_link_with_sink = NULL; + struct dc_link *edp_link = NULL; + struct dce_hwseq *hws = dc->hwseq; + int edp_with_sink_num; + int edp_num; + int edp_stream_num; + int i; + bool can_apply_edp_fast_boot = false; + bool can_apply_seamless_boot = false; + bool keep_edp_vdd_on = false; + DC_LOGGER_INIT(); + + + get_edp_links_with_sink(dc, edp_links_with_sink, &edp_with_sink_num); + dc_get_edp_links(dc, edp_links, &edp_num); + + if (hws->funcs.init_pipes) + hws->funcs.init_pipes(dc, context); + + get_edp_streams(context, edp_streams, &edp_stream_num); + + // Check fastboot support, disable on DCE8 because of blank screens + if (edp_num && edp_stream_num && dc->ctx->dce_version != DCE_VERSION_8_0 && + dc->ctx->dce_version != DCE_VERSION_8_1 && + dc->ctx->dce_version != DCE_VERSION_8_3) { + for (i = 0; i < edp_num; i++) { + edp_link = edp_links[i]; + if (edp_link != edp_streams[0]->link) + continue; + // enable fastboot if backend is enabled on eDP + if (edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + edp_link->link_status.link_active) { + struct dc_stream_state *edp_stream = edp_streams[0]; + + can_apply_edp_fast_boot = dc_validate_boot_timing(dc, + edp_stream->sink, &edp_stream->timing); + edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot; + if (can_apply_edp_fast_boot) + DC_LOG_EVENT_LINK_TRAINING("eDP fast boot disabled to optimize link rate\n"); + + break; + } + } + // We are trying to enable eDP, don't power down VDD + if (can_apply_edp_fast_boot) + keep_edp_vdd_on = true; + } + + // Check seamless boot support + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->apply_seamless_boot_optimization) { + can_apply_seamless_boot = true; + break; + } + } + + /* eDP should not have stream in resume from S4 and so even with VBios post + * it should get turned off + */ + if (edp_with_sink_num) + edp_link_with_sink = edp_links_with_sink[0]; + + if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) { + if (edp_link_with_sink && !keep_edp_vdd_on) { + /*turn off backlight before DP_blank and encoder powered down*/ + hws->funcs.edp_backlight_control(edp_link_with_sink, false); + } + /*resume from S3, no vbios posting, no need to power down again*/ + clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr); + + power_down_all_hw_blocks(dc); + disable_vga_and_power_gate_all_controllers(dc); + if (edp_link_with_sink && !keep_edp_vdd_on) + dc->hwss.edp_power_control(edp_link_with_sink, false); + clk_mgr_optimize_pwr_state(dc, dc->clk_mgr); + } + bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1); +} + +static uint32_t compute_pstate_blackout_duration( + struct bw_fixed blackout_duration, + const struct dc_stream_state *stream) +{ + uint32_t total_dest_line_time_ns; + uint32_t pstate_blackout_duration_ns; + + pstate_blackout_duration_ns = 1000 * blackout_duration.value >> 24; + + total_dest_line_time_ns = 1000000UL * + (stream->timing.h_total * 10) / + stream->timing.pix_clk_100hz + + pstate_blackout_duration_ns; + + return total_dest_line_time_ns; +} + +static void dce110_set_displaymarks( + const struct dc *dc, + struct dc_state *context) +{ + uint8_t i, num_pipes; + unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; + + for (i = 0, num_pipes = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + uint32_t total_dest_line_time_ns; + + if (pipe_ctx->stream == NULL) + continue; + + total_dest_line_time_ns = compute_pstate_blackout_duration( + dc->bw_vbios->blackout_duration, pipe_ctx->stream); + pipe_ctx->plane_res.mi->funcs->mem_input_program_display_marks( + pipe_ctx->plane_res.mi, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[num_pipes], + context->bw_ctx.bw.dce.stutter_exit_wm_ns[num_pipes], + context->bw_ctx.bw.dce.stutter_entry_wm_ns[num_pipes], + context->bw_ctx.bw.dce.urgent_wm_ns[num_pipes], + total_dest_line_time_ns); + if (i == underlay_idx) { + num_pipes++; + pipe_ctx->plane_res.mi->funcs->mem_input_program_chroma_display_marks( + pipe_ctx->plane_res.mi, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[num_pipes], + context->bw_ctx.bw.dce.stutter_exit_wm_ns[num_pipes], + context->bw_ctx.bw.dce.urgent_wm_ns[num_pipes], + total_dest_line_time_ns); + } + num_pipes++; + } +} + +void dce110_set_safe_displaymarks( + struct resource_context *res_ctx, + const struct resource_pool *pool) +{ + int i; + int underlay_idx = pool->underlay_pipe_index; + struct dce_watermarks max_marks = { + MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK, MAX_WATERMARK }; + struct dce_watermarks nbp_marks = { + SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK }; + struct dce_watermarks min_marks = { 0, 0, 0, 0}; + + for (i = 0; i < MAX_PIPES; i++) { + if (res_ctx->pipe_ctx[i].stream == NULL || res_ctx->pipe_ctx[i].plane_res.mi == NULL) + continue; + + res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_display_marks( + res_ctx->pipe_ctx[i].plane_res.mi, + nbp_marks, + max_marks, + min_marks, + max_marks, + MAX_WATERMARK); + + if (i == underlay_idx) + res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_chroma_display_marks( + res_ctx->pipe_ctx[i].plane_res.mi, + nbp_marks, + max_marks, + max_marks, + MAX_WATERMARK); + + } +} + +/******************************************************************************* + * Public functions + ******************************************************************************/ + +static void set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, struct dc_crtc_timing_adjust adjust) +{ + int i = 0; + struct drr_params params = {0}; + // DRR should set trigger event to monitor surface update event + unsigned int event_triggers = 0x80; + // Note DRR trigger events are generated regardless of whether num frames met. + unsigned int num_frames = 2; + + params.vertical_total_max = adjust.v_total_max; + params.vertical_total_min = adjust.v_total_min; + + /* TODO: If multiple pipes are to be supported, you need + * some GSL stuff. Static screen triggers may be programmed differently + * as well. + */ + for (i = 0; i < num_pipes; i++) { + pipe_ctx[i]->stream_res.tg->funcs->set_drr( + pipe_ctx[i]->stream_res.tg, ¶ms); + + if (adjust.v_total_max != 0 && adjust.v_total_min != 0) + pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( + pipe_ctx[i]->stream_res.tg, + event_triggers, num_frames); + } +} + +static void get_position(struct pipe_ctx **pipe_ctx, + int num_pipes, + struct crtc_position *position) +{ + int i = 0; + + /* TODO: handle pipes > 1 + */ + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); +} + +static void set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params) +{ + unsigned int i; + unsigned int triggers = 0; + + if (params->triggers.overlay_update) + triggers |= 0x100; + if (params->triggers.surface_update) + triggers |= 0x80; + if (params->triggers.cursor_update) + triggers |= 0x2; + if (params->triggers.force_trigger) + triggers |= 0x1; + + if (num_pipes) { + struct dc *dc = pipe_ctx[0]->stream->ctx->dc; + + if (dc->fbc_compressor) + triggers |= 0x84; + } + + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs-> + set_static_screen_control(pipe_ctx[i]->stream_res.tg, + triggers, params->num_frames); +} + +/* + * Check if FBC can be enabled + */ +static bool should_enable_fbc(struct dc *dc, + struct dc_state *context, + uint32_t *pipe_idx) +{ + uint32_t i; + struct pipe_ctx *pipe_ctx = NULL; + struct resource_context *res_ctx = &context->res_ctx; + unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; + + + ASSERT(dc->fbc_compressor); + + /* FBC memory should be allocated */ + if (!dc->ctx->fbc_gpu_addr) + return false; + + /* Only supports single display */ + if (context->stream_count != 1) + return false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (res_ctx->pipe_ctx[i].stream) { + + pipe_ctx = &res_ctx->pipe_ctx[i]; + + /* fbc not applicable on underlay pipe */ + if (pipe_ctx->pipe_idx != underlay_idx) { + *pipe_idx = i; + break; + } + } + } + + if (i == dc->res_pool->pipe_count) + return false; + + if (!pipe_ctx->stream->link) + return false; + + /* Only supports eDP */ + if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP) + return false; + + /* PSR should not be enabled */ + if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled) + return false; + + /* Replay should not be enabled */ + if (pipe_ctx->stream->link->replay_settings.replay_feature_enabled) + return false; + + /* Nothing to compress */ + if (!pipe_ctx->plane_state) + return false; + + /* Only for non-linear tiling */ + if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL) + return false; + + return true; +} + +/* + * Enable FBC + */ +static void enable_fbc( + struct dc *dc, + struct dc_state *context) +{ + uint32_t pipe_idx = 0; + + if (should_enable_fbc(dc, context, &pipe_idx)) { + /* Program GRPH COMPRESSED ADDRESS and PITCH */ + struct compr_addr_and_pitch_params params = {0, 0, 0}; + struct compressor *compr = dc->fbc_compressor; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; + + params.source_view_width = pipe_ctx->stream->timing.h_addressable; + params.source_view_height = pipe_ctx->stream->timing.v_addressable; + params.inst = pipe_ctx->stream_res.tg->inst; + compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr; + + compr->funcs->surface_address_and_pitch(compr, ¶ms); + compr->funcs->set_fbc_invalidation_triggers(compr, 1); + + compr->funcs->enable_fbc(compr, ¶ms); + } +} + +static void dce110_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + + /* Reset old context */ + /* look up the targets that have been removed since last commit */ + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* Note: We need to disable output if clock sources change, + * since bios does optimization and doesn't apply if changing + * PHY when not already disabled. + */ + + /* Skip underlay pipe since it will be handled in commit surface*/ + if (!pipe_ctx_old->stream || pipe_ctx_old->top_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + /* Disable if new stream is null. O/w, if stream is + * disabled already, no need to disable again. + */ + if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off) { + dc->link_srv->set_dpms_off(pipe_ctx_old); + + /* free acquired resources*/ + if (pipe_ctx_old->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx_old->stream_res.audio->funcs-> + az_disable(pipe_ctx_old->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx_old->stream_res.audio, false); + pipe_ctx_old->stream_res.audio = NULL; + } + } + } + + pipe_ctx_old->stream_res.tg->funcs->set_blank(pipe_ctx_old->stream_res.tg, true); + if (!hwss_wait_for_blank_complete(pipe_ctx_old->stream_res.tg)) { + dm_error("DC: failed to blank crtc!\n"); + BREAK_TO_DEBUGGER(); + } + pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); + pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; + pipe_ctx_old->plane_res.mi->funcs->free_mem_input( + pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); + + if (old_clk && 0 == resource_get_clock_source_reference(&context->res_ctx, + dc->res_pool, + old_clk)) + old_clk->funcs->cs_power_down(old_clk); + + dc->hwss.disable_plane(dc, pipe_ctx_old); + + pipe_ctx_old->stream = NULL; + } + } +} + +static void dce110_setup_audio_dto( + struct dc *dc, + struct dc_state *context) +{ + int i; + + /* program audio wall clock. use HDMI as clock source if HDMI + * audio active. Otherwise, use DP as clock source + * first, loop to find any HDMI audio, if not, loop find DP audio + */ + /* Setup audio rate clock source */ + /* Issue: + * Audio lag happened on DP monitor when unplug a HDMI monitor + * + * Cause: + * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL + * is set to either dto0 or dto1, audio should work fine. + * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1, + * set to dto0 will cause audio lag. + * + * Solution: + * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx, + * find first available pipe with audio, setup audio wall DTO per topology + * instead of per pipe. + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL) + continue; + + if (pipe_ctx->top_pipe) + continue; + if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A) + continue; + if (pipe_ctx->stream_res.audio != NULL) { + struct audio_output audio_output; + + build_audio_output(context, pipe_ctx, &audio_output); + + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) { + struct dtbclk_dto_params dto_params = {0}; + + dc->res_pool->dccg->funcs->set_audio_dtbclk_dto( + dc->res_pool->dccg, &dto_params); + + pipe_ctx->stream_res.audio->funcs->wall_dto_setup( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &audio_output.pll_info); + } else + pipe_ctx->stream_res.audio->funcs->wall_dto_setup( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &audio_output.pll_info); + break; + } + } + + /* no HDMI audio is found, try DP audio */ + if (i == dc->res_pool->pipe_count) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL) + continue; + + if (pipe_ctx->top_pipe) + continue; + + if (!dc_is_dp_signal(pipe_ctx->stream->signal)) + continue; + + if (pipe_ctx->stream_res.audio != NULL) { + struct audio_output audio_output; + + build_audio_output(context, pipe_ctx, &audio_output); + + pipe_ctx->stream_res.audio->funcs->wall_dto_setup( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &audio_output.pll_info); + break; + } + } + } +} + +enum dc_status dce110_apply_ctx_to_hw( + struct dc *dc, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + enum dc_status status; + int i; + + /* reset syncd pipes from disabled pipes */ + if (dc->config.use_pipe_ctx_sync_logic) + reset_syncd_pipes_from_disabled_pipes(dc, context); + + /* Reset old context */ + /* look up the targets that have been removed since last commit */ + hws->funcs.reset_hw_ctx_wrap(dc, context); + + /* Skip applying if no targets */ + if (context->stream_count <= 0) + return DC_OK; + + /* Apply new context */ + dcb->funcs->set_scratch_critical_state(dcb, true); + + /* below is for real asic only */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL || pipe_ctx->top_pipe) + continue; + + if (pipe_ctx->stream == pipe_ctx_old->stream) { + if (pipe_ctx_old->clock_source != pipe_ctx->clock_source) + dce_crtc_switch_to_clk_src(dc->hwseq, + pipe_ctx->clock_source, i); + continue; + } + + hws->funcs.enable_display_power_gating( + dc, i, dc->ctx->dc_bios, + PIPE_GATING_CONTROL_DISABLE); + } + + if (dc->fbc_compressor) + dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); + + dce110_setup_audio_dto(dc, context); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL) + continue; + + if (pipe_ctx->stream == pipe_ctx_old->stream && + pipe_ctx->stream->link->link_state_valid) { + continue; + } + + if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) + continue; + + if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe) + continue; + + status = apply_single_controller_ctx_to_hw( + pipe_ctx, + context, + dc); + + if (DC_OK != status) + return status; + +#ifdef CONFIG_DRM_AMD_DC_FP + if (hws->funcs.resync_fifo_dccg_dio) + hws->funcs.resync_fifo_dccg_dio(hws, dc, context); +#endif + } + + if (dc->fbc_compressor) + enable_fbc(dc, dc->current_state); + + dcb->funcs->set_scratch_critical_state(dcb, false); + + return DC_OK; +} + +/******************************************************************************* + * Front End programming + ******************************************************************************/ +static void set_default_colors(struct pipe_ctx *pipe_ctx) +{ + struct default_adjustment default_adjust = { 0 }; + + default_adjust.force_hw_default = false; + default_adjust.in_color_space = pipe_ctx->plane_state->color_space; + default_adjust.out_color_space = pipe_ctx->stream->output_color_space; + default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW; + default_adjust.surface_pixel_format = pipe_ctx->plane_res.scl_data.format; + + /* display color depth */ + default_adjust.color_depth = + pipe_ctx->stream->timing.display_color_depth; + + /* Lb color depth */ + default_adjust.lb_color_depth = pipe_ctx->plane_res.scl_data.lb_params.depth; + + pipe_ctx->plane_res.xfm->funcs->opp_set_csc_default( + pipe_ctx->plane_res.xfm, &default_adjust); +} + + +/******************************************************************************* + * In order to turn on/off specific surface we will program + * Blender + CRTC + * + * In case that we have two surfaces and they have a different visibility + * we can't turn off the CRTC since it will turn off the entire display + * + * |----------------------------------------------- | + * |bottom pipe|curr pipe | | | + * |Surface |Surface | Blender | CRCT | + * |visibility |visibility | Configuration| | + * |------------------------------------------------| + * | off | off | CURRENT_PIPE | blank | + * | off | on | CURRENT_PIPE | unblank | + * | on | off | OTHER_PIPE | unblank | + * | on | on | BLENDING | unblank | + * -------------------------------------------------| + * + ******************************************************************************/ +static void program_surface_visibility(const struct dc *dc, + struct pipe_ctx *pipe_ctx) +{ + enum blnd_mode blender_mode = BLND_MODE_CURRENT_PIPE; + bool blank_target = false; + + if (pipe_ctx->bottom_pipe) { + + /* For now we are supporting only two pipes */ + ASSERT(pipe_ctx->bottom_pipe->bottom_pipe == NULL); + + if (pipe_ctx->bottom_pipe->plane_state->visible) { + if (pipe_ctx->plane_state->visible) + blender_mode = BLND_MODE_BLENDING; + else + blender_mode = BLND_MODE_OTHER_PIPE; + + } else if (!pipe_ctx->plane_state->visible) + blank_target = true; + + } else if (!pipe_ctx->plane_state->visible) + blank_target = true; + + dce_set_blender_mode(dc->hwseq, pipe_ctx->stream_res.tg->inst, blender_mode); + pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, blank_target); + +} + +static void program_gamut_remap(struct pipe_ctx *pipe_ctx) +{ + int i = 0; + struct xfm_grph_csc_adjustment adjust; + memset(&adjust, 0, sizeof(adjust)); + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + + if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + } + + pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); +} +static void update_plane_addr(const struct dc *dc, + struct pipe_ctx *pipe_ctx) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + + if (plane_state == NULL) + return; + + pipe_ctx->plane_res.mi->funcs->mem_input_program_surface_flip_and_addr( + pipe_ctx->plane_res.mi, + &plane_state->address, + plane_state->flip_immediate); + + plane_state->status.requested_address = plane_state->address; +} + +static void dce110_update_pending_status(struct pipe_ctx *pipe_ctx) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + + if (plane_state == NULL) + return; + + plane_state->status.is_flip_pending = + pipe_ctx->plane_res.mi->funcs->mem_input_is_flip_pending( + pipe_ctx->plane_res.mi); + + if (plane_state->status.is_flip_pending && !plane_state->visible) + pipe_ctx->plane_res.mi->current_address = pipe_ctx->plane_res.mi->request_address; + + plane_state->status.current_address = pipe_ctx->plane_res.mi->current_address; + if (pipe_ctx->plane_res.mi->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && + pipe_ctx->stream_res.tg->funcs->is_stereo_left_eye) { + plane_state->status.is_right_eye =\ + !pipe_ctx->stream_res.tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); + } +} + +void dce110_power_down(struct dc *dc) +{ + power_down_all_hw_blocks(dc); + disable_vga_and_power_gate_all_controllers(dc); +} + +static bool wait_for_reset_trigger_to_occur( + struct dc_context *dc_ctx, + struct timing_generator *tg) +{ + struct dc_context *ctx = dc_ctx; + bool rc = false; + + /* To avoid endless loop we wait at most + * frames_to_wait_on_triggered_reset frames for the reset to occur. */ + const uint32_t frames_to_wait_on_triggered_reset = 10; + uint32_t i; + + for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { + + if (!tg->funcs->is_counter_moving(tg)) { + DC_ERROR("TG counter is not moving!\n"); + break; + } + + if (tg->funcs->did_triggered_reset_occur(tg)) { + rc = true; + /* usually occurs at i=1 */ + DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", + i); + break; + } + + /* Wait for one frame. */ + tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); + tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); + } + + if (false == rc) + DC_ERROR("GSL: Timeout on reset trigger!\n"); + + return rc; +} + +/* Enable timing synchronization for a group of Timing Generators. */ +static void dce110_enable_timing_synchronization( + struct dc *dc, + int group_index, + int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + struct dcp_gsl_params gsl_params = { 0 }; + int i; + DC_LOGGER_INIT(); + + DC_SYNC_INFO("GSL: Setting-up...\n"); + + /* Designate a single TG in the group as a master. + * Since HW doesn't care which one, we always assign + * the 1st one in the group. */ + gsl_params.gsl_group = 0; + gsl_params.gsl_master = grouped_pipes[0]->stream_res.tg->inst; + + for (i = 0; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock( + grouped_pipes[i]->stream_res.tg, &gsl_params); + + /* Reset slave controllers on master VSync */ + DC_SYNC_INFO("GSL: enabling trigger-reset\n"); + + for (i = 1 /* skip the master */; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( + grouped_pipes[i]->stream_res.tg, + gsl_params.gsl_group); + + for (i = 1 /* skip the master */; i < group_size; i++) { + DC_SYNC_INFO("GSL: waiting for reset to occur.\n"); + wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); + grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( + grouped_pipes[i]->stream_res.tg); + } + + /* GSL Vblank synchronization is a one time sync mechanism, assumption + * is that the sync'ed displays will not drift out of sync over time*/ + DC_SYNC_INFO("GSL: Restoring register states.\n"); + for (i = 0; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->stream_res.tg); + + DC_SYNC_INFO("GSL: Set-up complete.\n"); +} + +static void dce110_enable_per_frame_crtc_position_reset( + struct dc *dc, + int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + struct dcp_gsl_params gsl_params = { 0 }; + int i; + DC_LOGGER_INIT(); + + gsl_params.gsl_group = 0; + gsl_params.gsl_master = 0; + + for (i = 0; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock( + grouped_pipes[i]->stream_res.tg, &gsl_params); + + DC_SYNC_INFO("GSL: enabling trigger-reset\n"); + + for (i = 1; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( + grouped_pipes[i]->stream_res.tg, + gsl_params.gsl_master, + &grouped_pipes[i]->stream->triggered_crtc_reset); + + DC_SYNC_INFO("GSL: waiting for reset to occur.\n"); + for (i = 1; i < group_size; i++) + wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); + + for (i = 0; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->tear_down_global_swap_lock(grouped_pipes[i]->stream_res.tg); + +} + +static void init_pipes(struct dc *dc, struct dc_state *context) +{ + // Do nothing +} + +static void init_hw(struct dc *dc) +{ + int i; + struct dc_bios *bp; + struct transform *xfm; + struct abm *abm; + struct dmcu *dmcu; + struct dce_hwseq *hws = dc->hwseq; + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + + bp = dc->ctx->dc_bios; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + xfm = dc->res_pool->transforms[i]; + xfm->funcs->transform_reset(xfm); + + hws->funcs.enable_display_power_gating( + dc, i, bp, + PIPE_GATING_CONTROL_INIT); + hws->funcs.enable_display_power_gating( + dc, i, bp, + PIPE_GATING_CONTROL_DISABLE); + hws->funcs.enable_display_pipe_clock_gating( + dc->ctx, + true); + } + + dce_clock_gating_power_up(dc->hwseq, false); + /***************************************/ + + for (i = 0; i < dc->link_count; i++) { + /****************************************/ + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). */ + struct dc_link *link = dc->links[i]; + + link->link_enc->funcs->hw_init(link->link_enc); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + tg->funcs->disable_vga(tg); + + /* Blank controller using driver code instead of + * command table. */ + tg->funcs->set_blank(tg, true); + hwss_wait_for_blank_complete(tg); + } + + for (i = 0; i < dc->res_pool->audio_count; i++) { + struct audio *audio = dc->res_pool->audios[i]; + audio->funcs->hw_init(audio); + } + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } + + abm = dc->res_pool->abm; + if (abm != NULL) + abm->funcs->abm_init(abm, backlight); + + dmcu = dc->res_pool->dmcu; + if (dmcu != NULL && abm != NULL) + abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); + + if (dc->fbc_compressor) + dc->fbc_compressor->funcs->power_up_fbc(dc->fbc_compressor); + +} + + +void dce110_prepare_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct clk_mgr *dccg = dc->clk_mgr; + + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + if (dccg) + dccg->funcs->update_clocks( + dccg, + context, + false); +} + +void dce110_optimize_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct clk_mgr *dccg = dc->clk_mgr; + + dce110_set_displaymarks(dc, context); + + if (dccg) + dccg->funcs->update_clocks( + dccg, + context, + true); +} + +static void dce110_program_front_end_for_pipe( + struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct mem_input *mi = pipe_ctx->plane_res.mi; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct xfm_grph_csc_adjustment adjust; + struct out_csc_color_matrix tbl_entry; + unsigned int i; + struct dce_hwseq *hws = dc->hwseq; + + memset(&tbl_entry, 0, sizeof(tbl_entry)); + + memset(&adjust, 0, sizeof(adjust)); + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + dce_enable_fe_clock(dc->hwseq, mi->inst, true); + + set_default_colors(pipe_ctx); + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment + == true) { + tbl_entry.color_space = + pipe_ctx->stream->output_color_space; + + for (i = 0; i < 12; i++) + tbl_entry.regval[i] = + pipe_ctx->stream->csc_color_matrix.matrix[i]; + + pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment + (pipe_ctx->plane_res.xfm, &tbl_entry); + } + + if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + } + + pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust); + + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL; + + program_scaler(dc, pipe_ctx); + + mi->funcs->mem_input_program_surface_config( + mi, + plane_state->format, + &plane_state->tiling_info, + &plane_state->plane_size, + plane_state->rotation, + NULL, + false); + if (mi->funcs->set_blank) + mi->funcs->set_blank(mi, pipe_ctx->plane_state->visible); + + if (dc->config.gpu_vm_support) + mi->funcs->mem_input_program_pte_vm( + pipe_ctx->plane_res.mi, + plane_state->format, + &plane_state->tiling_info, + plane_state->rotation); + + /* Moved programming gamma from dc to hwss */ + if (pipe_ctx->plane_state->update_flags.bits.full_update || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change) + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); + + if (pipe_ctx->plane_state->update_flags.bits.full_update) + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); + + DC_LOG_SURFACE( + "Pipe:%d %p: addr hi:0x%x, " + "addr low:0x%x, " + "src: %d, %d, %d," + " %d; dst: %d, %d, %d, %d;" + "clip: %d, %d, %d, %d\n", + pipe_ctx->pipe_idx, + (void *) pipe_ctx->plane_state, + pipe_ctx->plane_state->address.grph.addr.high_part, + pipe_ctx->plane_state->address.grph.addr.low_part, + pipe_ctx->plane_state->src_rect.x, + pipe_ctx->plane_state->src_rect.y, + pipe_ctx->plane_state->src_rect.width, + pipe_ctx->plane_state->src_rect.height, + pipe_ctx->plane_state->dst_rect.x, + pipe_ctx->plane_state->dst_rect.y, + pipe_ctx->plane_state->dst_rect.width, + pipe_ctx->plane_state->dst_rect.height, + pipe_ctx->plane_state->clip_rect.x, + pipe_ctx->plane_state->clip_rect.y, + pipe_ctx->plane_state->clip_rect.width, + pipe_ctx->plane_state->clip_rect.height); + + DC_LOG_SURFACE( + "Pipe %d: width, height, x, y\n" + "viewport:%d, %d, %d, %d\n" + "recout: %d, %d, %d, %d\n", + pipe_ctx->pipe_idx, + pipe_ctx->plane_res.scl_data.viewport.width, + pipe_ctx->plane_res.scl_data.viewport.height, + pipe_ctx->plane_res.scl_data.viewport.x, + pipe_ctx->plane_res.scl_data.viewport.y, + pipe_ctx->plane_res.scl_data.recout.width, + pipe_ctx->plane_res.scl_data.recout.height, + pipe_ctx->plane_res.scl_data.recout.x, + pipe_ctx->plane_res.scl_data.recout.y); +} + +static void dce110_apply_ctx_for_surface( + struct dc *dc, + const struct dc_stream_state *stream, + int num_planes, + struct dc_state *context) +{ + int i; + + if (num_planes == 0) + return; + + if (dc->fbc_compressor) + dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream != stream) + continue; + + /* Need to allocate mem before program front end for Fiji */ + pipe_ctx->plane_res.mi->funcs->allocate_mem_input( + pipe_ctx->plane_res.mi, + pipe_ctx->stream->timing.h_total, + pipe_ctx->stream->timing.v_total, + pipe_ctx->stream->timing.pix_clk_100hz / 10, + context->stream_count); + + dce110_program_front_end_for_pipe(dc, pipe_ctx); + + dc->hwss.update_plane_addr(dc, pipe_ctx); + + program_surface_visibility(dc, pipe_ctx); + + } + + if (dc->fbc_compressor) + enable_fbc(dc, context); +} + +static void dce110_post_unlock_program_front_end( + struct dc *dc, + struct dc_state *context) +{ +} + +static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + int fe_idx = pipe_ctx->plane_res.mi ? + pipe_ctx->plane_res.mi->inst : pipe_ctx->pipe_idx; + + /* Do not power down fe when stream is active on dce*/ + if (dc->current_state->res_ctx.pipe_ctx[fe_idx].stream) + return; + + hws->funcs.enable_display_power_gating( + dc, fe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE); + + dc->res_pool->transforms[fe_idx]->funcs->transform_reset( + dc->res_pool->transforms[fe_idx]); +} + +static void dce110_wait_for_mpcc_disconnect( + struct dc *dc, + struct resource_pool *res_pool, + struct pipe_ctx *pipe_ctx) +{ + /* do nothing*/ +} + +static void program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id) +{ + int i; + struct out_csc_color_matrix tbl_entry; + + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { + enum dc_color_space color_space = pipe_ctx->stream->output_color_space; + + for (i = 0; i < 12; i++) + tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i]; + + tbl_entry.color_space = color_space; + + pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment( + pipe_ctx->plane_res.xfm, &tbl_entry); + } +} + +static void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; + struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; + struct mem_input *mi = pipe_ctx->plane_res.mi; + struct dc_cursor_mi_param param = { + .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, + .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.xtalin_clock_inKhz, + .viewport = pipe_ctx->plane_res.scl_data.viewport, + .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, + .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, + .rotation = pipe_ctx->plane_state->rotation, + .mirror = pipe_ctx->plane_state->horizontal_mirror + }; + + /** + * If the cursor's source viewport is clipped then we need to + * translate the cursor to appear in the correct position on + * the screen. + * + * This translation isn't affected by scaling so it needs to be + * done *after* we adjust the position for the scale factor. + * + * This is only done by opt-in for now since there are still + * some usecases like tiled display that might enable the + * cursor on both streams while expecting dc to clip it. + */ + if (pos_cpy.translate_by_source) { + pos_cpy.x += pipe_ctx->plane_state->src_rect.x; + pos_cpy.y += pipe_ctx->plane_state->src_rect.y; + } + + if (pipe_ctx->plane_state->address.type + == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) + pos_cpy.enable = false; + + if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state) + pos_cpy.enable = false; + + if (ipp->funcs->ipp_cursor_set_position) + ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, ¶m); + if (mi->funcs->set_cursor_position) + mi->funcs->set_cursor_position(mi, &pos_cpy, ¶m); +} + +static void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; + + if (pipe_ctx->plane_res.ipp && + pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes) + pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes( + pipe_ctx->plane_res.ipp, attributes); + + if (pipe_ctx->plane_res.mi && + pipe_ctx->plane_res.mi->funcs->set_cursor_attributes) + pipe_ctx->plane_res.mi->funcs->set_cursor_attributes( + pipe_ctx->plane_res.mi, attributes); + + if (pipe_ctx->plane_res.xfm && + pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes) + pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes( + pipe_ctx->plane_res.xfm, attributes); +} + +bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx, + uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp) +{ + struct dc_link *link = pipe_ctx->stream->link; + struct dc *dc = link->ctx->dc; + struct abm *abm = pipe_ctx->stream_res.abm; + struct panel_cntl *panel_cntl = link->panel_cntl; + struct dmcu *dmcu = dc->res_pool->dmcu; + bool fw_set_brightness = true; + /* DMCU -1 for all controller id values, + * therefore +1 here + */ + uint32_t controller_id = pipe_ctx->stream_res.tg->inst + 1; + + if (abm == NULL || panel_cntl == NULL || (abm->funcs->set_backlight_level_pwm == NULL)) + return false; + + if (dmcu) + fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); + + if (!fw_set_brightness && panel_cntl->funcs->driver_set_backlight) + panel_cntl->funcs->driver_set_backlight(panel_cntl, backlight_pwm_u16_16); + else + abm->funcs->set_backlight_level_pwm( + abm, + backlight_pwm_u16_16, + frame_ramp, + controller_id, + link->panel_cntl->inst); + + return true; +} + +void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) +{ + struct abm *abm = pipe_ctx->stream_res.abm; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + + if (abm) + abm->funcs->set_abm_immediate_disable(abm, + pipe_ctx->stream->link->panel_cntl->inst); + + if (panel_cntl) + panel_cntl->funcs->store_backlight_level(panel_cntl); +} + +void dce110_set_pipe(struct pipe_ctx *pipe_ctx) +{ + struct abm *abm = pipe_ctx->stream_res.abm; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + uint32_t otg_inst = pipe_ctx->stream_res.tg->inst + 1; + + if (abm && panel_cntl) + abm->funcs->set_pipe(abm, otg_inst, panel_cntl->inst); +} + +void dce110_enable_lvds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum clock_source_id clock_source, + uint32_t pixel_clock) +{ + link->link_enc->funcs->enable_lvds_output( + link->link_enc, + clock_source, + pixel_clock); + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; +} + +void dce110_enable_tmds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, + uint32_t pixel_clock) +{ + link->link_enc->funcs->enable_tmds_output( + link->link_enc, + clock_source, + color_depth, + signal, + pixel_clock); + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; +} + +void dce110_enable_dp_link_output( + struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings) +{ + struct dc *dc = link->ctx->dc; + struct dmcu *dmcu = dc->res_pool->dmcu; + struct pipe_ctx *pipes = + link->dc->current_state->res_ctx.pipe_ctx; + struct clock_source *dp_cs = + link->dc->res_pool->dp_clock_source; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + unsigned int i; + + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (link->connector_signal == SIGNAL_TYPE_EDP) { + link->dc->hwss.edp_wait_for_hpd_ready(link, true); + } + + /* If the current pixel clock source is not DTO(happens after + * switching from HDMI passive dongle to DP on the same connector), + * switch the pixel clock source to DTO. + */ + + for (i = 0; i < MAX_PIPES; i++) { + if (pipes[i].stream != NULL && + pipes[i].stream->link == link) { + if (pipes[i].clock_source != NULL && + pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) { + pipes[i].clock_source = dp_cs; + pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz = + pipes[i].stream->timing.pix_clk_100hz; + pipes[i].clock_source->funcs->program_pix_clk( + pipes[i].clock_source, + &pipes[i].stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format(link_settings), + &pipes[i].pll_settings); + } + } + } + + if (dc->link_srv->dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) { + if (dc->clk_mgr->funcs->notify_link_rate_change) + dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); + } + + if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + if (link_hwss->ext.enable_dp_link_output) + link_hwss->ext.enable_dp_link_output(link, link_res, signal, + clock_source, link_settings); + + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + + if (dmcu != NULL && dmcu->funcs->unlock_phy) + dmcu->funcs->unlock_phy(dmcu); + + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY); +} + +void dce110_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->unlock_phy(dmcu); + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); +} + +static const struct hw_sequencer_funcs dce110_funcs = { + .program_gamut_remap = program_gamut_remap, + .program_output_csc = program_output_csc, + .init_hw = init_hw, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = dce110_apply_ctx_for_surface, + .post_unlock_program_front_end = dce110_post_unlock_program_front_end, + .update_plane_addr = update_plane_addr, + .update_pending_status = dce110_update_pending_status, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dce110_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dce110_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .enable_stream = dce110_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dce110_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dce110_power_down_fe, + .pipe_control_lock = dce_pipe_control_lock, + .interdependent_update_lock = NULL, + .cursor_lock = dce_pipe_control_lock, + .prepare_bandwidth = dce110_prepare_bandwidth, + .optimize_bandwidth = dce110_optimize_bandwidth, + .set_drr = set_drr, + .get_position = get_position, + .set_static_screen_control = set_static_screen_control, + .setup_stereo = NULL, + .set_avmute = dce110_set_avmute, + .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dce110_set_cursor_position, + .set_cursor_attribute = dce110_set_cursor_attribute, + .set_backlight_level = dce110_set_backlight_level, + .set_abm_immediate_disable = dce110_set_abm_immediate_disable, + .set_pipe = dce110_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, +}; + +static const struct hwseq_private_funcs dce110_private_funcs = { + .init_pipes = init_pipes, + .update_plane_addr = update_plane_addr, + .set_input_transfer_func = dce110_set_input_transfer_func, + .set_output_transfer_func = dce110_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating, + .enable_display_power_gating = dce110_enable_display_power_gating, + .reset_hw_ctx_wrap = dce110_reset_hw_ctx_wrap, + .enable_stream_timing = dce110_enable_stream_timing, + .disable_stream_gating = NULL, + .enable_stream_gating = NULL, + .edp_backlight_control = dce110_edp_backlight_control, +}; + +void dce110_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dce110_funcs; + dc->hwseq->funcs = dce110_private_funcs; +} + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h new file mode 100644 index 000000000000..08028a1779ae --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h @@ -0,0 +1,111 @@ +/* +* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCE110_H__ +#define __DC_HWSS_DCE110_H__ + +#include "core_types.h" +#include "hw_sequencer_private.h" + +struct dc; +struct dc_state; +struct dm_pp_display_configuration; + +void dce110_hw_sequencer_construct(struct dc *dc); + +enum dc_status dce110_apply_ctx_to_hw( + struct dc *dc, + struct dc_state *context); + + +void dce110_enable_stream(struct pipe_ctx *pipe_ctx); + +void dce110_disable_stream(struct pipe_ctx *pipe_ctx); + +void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); + +void dce110_blank_stream(struct pipe_ctx *pipe_ctx); + +void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx); + +void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); + +void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); +void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); + +void dce110_power_down(struct dc *dc); + +void dce110_set_safe_displaymarks( + struct resource_context *res_ctx, + const struct resource_pool *pool); + +void dce110_prepare_bandwidth( + struct dc *dc, + struct dc_state *context); + +void dce110_optimize_bandwidth( + struct dc *dc, + struct dc_state *context); + +void dce110_edp_power_control( + struct dc_link *link, + bool power_up); + +void dce110_edp_backlight_control( + struct dc_link *link, + bool enable); + +void dce110_edp_wait_for_hpd_ready( + struct dc_link *link, + bool power_up); + +bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx, + uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp); +void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx); +void dce110_set_pipe(struct pipe_ctx *pipe_ctx); +void dce110_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); +void dce110_enable_lvds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum clock_source_id clock_source, + uint32_t pixel_clock); +void dce110_enable_tmds_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, + uint32_t pixel_clock); +void dce110_enable_dp_link_output( + struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings); +#endif /* __DC_HWSS_DCE110_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce112/dce112_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce112/dce112_hwseq.c new file mode 100644 index 000000000000..ed9b0113a7a0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce112/dce112_hwseq.c @@ -0,0 +1,160 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" +#include "dce112_hwseq.h" + +#include "dce110/dce110_hwseq.h" + +/* include DCE11.2 register header files */ +#include "dce/dce_11_2_d.h" +#include "dce/dce_11_2_sh_mask.h" + +struct dce112_hw_seq_reg_offsets { + uint32_t crtc; +}; + + +static const struct dce112_hw_seq_reg_offsets reg_offsets[] = { +{ + .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC_GSL_CONTROL), +} +}; +#define HW_REG_CRTC(reg, id)\ + (reg + reg_offsets[id].crtc) + +/******************************************************************************* + * Private definitions + ******************************************************************************/ + +static void dce112_init_pte(struct dc_context *ctx) +{ + uint32_t addr; + uint32_t value = 0; + uint32_t chunk_int = 0; + uint32_t chunk_mul = 0; + + addr = mmDVMM_PTE_REQ; + value = dm_read_reg(ctx, addr); + + chunk_int = get_reg_field_value( + value, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_INT); + + chunk_mul = get_reg_field_value( + value, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); + + if (chunk_int != 0x4 || chunk_mul != 0x4) { + + set_reg_field_value( + value, + 255, + DVMM_PTE_REQ, + MAX_PTEREQ_TO_ISSUE); + + set_reg_field_value( + value, + 4, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_INT); + + set_reg_field_value( + value, + 4, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); + + dm_write_reg(ctx, addr, value); + } +} + +static bool dce112_enable_display_power_gating( + struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating) +{ + enum bp_result bp_result = BP_RESULT_OK; + enum bp_pipe_control_action cntl; + struct dc_context *ctx = dc->ctx; + + if (power_gating == PIPE_GATING_CONTROL_INIT) + cntl = ASIC_PIPE_INIT; + else if (power_gating == PIPE_GATING_CONTROL_ENABLE) + cntl = ASIC_PIPE_ENABLE; + else + cntl = ASIC_PIPE_DISABLE; + + if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0) { + + bp_result = dcb->funcs->enable_disp_power_gating( + dcb, controller_id + 1, cntl); + + /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 + * by default when command table is called + */ + dm_write_reg(ctx, + HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id), + 0); + } + + if (power_gating != PIPE_GATING_CONTROL_ENABLE) + dce112_init_pte(ctx); + + if (bp_result == BP_RESULT_OK) + return true; + else + return false; +} + +void dce112_hw_sequencer_construct(struct dc *dc) +{ + /* All registers used by dce11.2 match those in dce11 in offset and + * structure + */ + dce110_hw_sequencer_construct(dc); + dc->hwseq->funcs.enable_display_power_gating = dce112_enable_display_power_gating; +} + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce112/dce112_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce112/dce112_hwseq.h new file mode 100644 index 000000000000..943f1b2c5b2f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce112/dce112_hwseq.h @@ -0,0 +1,37 @@ +/* +* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCE112_H__ +#define __DC_HWSS_DCE112_H__ + +#include "core_types.h" +#include "hw_sequencer_private.h" + +struct dc; + +void dce112_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_HWSS_DCE112_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.c new file mode 100644 index 000000000000..22ee304ef9cf --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.c @@ -0,0 +1,268 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" +#include "dce120_hwseq.h" +#include "dce/dce_hwseq.h" + +#include "dce110/dce110_hwseq.h" + +#include "dce/dce_12_0_offset.h" +#include "dce/dce_12_0_sh_mask.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" +#include "reg_helper.h" + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +struct dce120_hw_seq_reg_offsets { + uint32_t crtc; +}; + +#if 0 +static const struct dce120_hw_seq_reg_offsets reg_offsets[] = { +{ + .crtc = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC3_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC4_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), +}, +{ + .crtc = (mmCRTC5_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL), +} +}; + +#define HW_REG_CRTC(reg, id)\ + (reg + reg_offsets[id].crtc) + +#define CNTL_ID(controller_id)\ + controller_id +/******************************************************************************* + * Private definitions + ******************************************************************************/ +static void dce120_init_pte(struct dc_context *ctx, uint8_t controller_id) +{ + uint32_t addr; + uint32_t value = 0; + uint32_t chunk_int = 0; + uint32_t chunk_mul = 0; +/* + addr = mmDCP0_DVMM_PTE_CONTROL + controller_id * + (mmDCP1_DVMM_PTE_CONTROL- mmDCP0_DVMM_PTE_CONTROL); + + value = dm_read_reg(ctx, addr); + + set_reg_field_value( + value, 0, DCP, controller_id, + DVMM_PTE_CONTROL, + DVMM_USE_SINGLE_PTE); + + set_reg_field_value_soc15( + value, 1, DCP, controller_id, + DVMM_PTE_CONTROL, + DVMM_PTE_BUFFER_MODE0); + + set_reg_field_value_soc15( + value, 1, DCP, controller_id, + DVMM_PTE_CONTROL, + DVMM_PTE_BUFFER_MODE1); + + dm_write_reg(ctx, addr, value);*/ + + addr = mmDVMM_PTE_REQ; + value = dm_read_reg(ctx, addr); + + chunk_int = get_reg_field_value( + value, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_INT); + + chunk_mul = get_reg_field_value( + value, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); + + if (chunk_int != 0x4 || chunk_mul != 0x4) { + + set_reg_field_value( + value, + 255, + DVMM_PTE_REQ, + MAX_PTEREQ_TO_ISSUE); + + set_reg_field_value( + value, + 4, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_INT); + + set_reg_field_value( + value, + 4, + DVMM_PTE_REQ, + HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER); + + dm_write_reg(ctx, addr, value); + } +} +#endif + +static bool dce120_enable_display_power_gating( + struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating) +{ + /* disable for bringup */ +#if 0 + enum bp_result bp_result = BP_RESULT_OK; + enum bp_pipe_control_action cntl; + struct dc_context *ctx = dc->ctx; + + if (power_gating == PIPE_GATING_CONTROL_INIT) + cntl = ASIC_PIPE_INIT; + else if (power_gating == PIPE_GATING_CONTROL_ENABLE) + cntl = ASIC_PIPE_ENABLE; + else + cntl = ASIC_PIPE_DISABLE; + + if (power_gating != PIPE_GATING_CONTROL_INIT || controller_id == 0) { + + bp_result = dcb->funcs->enable_disp_power_gating( + dcb, controller_id + 1, cntl); + + /* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 + * by default when command table is called + */ + dm_write_reg(ctx, + HW_REG_CRTC(mmCRTC0_CRTC_MASTER_UPDATE_MODE, controller_id), + 0); + } + + if (power_gating != PIPE_GATING_CONTROL_ENABLE) + dce120_init_pte(ctx, controller_id); + + if (bp_result == BP_RESULT_OK) + return true; + else + return false; +#endif + return false; +} + +static void dce120_update_dchub( + struct dce_hwseq *hws, + struct dchub_init_data *dh_data) +{ + /* TODO: port code from dal2 */ + switch (dh_data->fb_mode) { + case FRAME_BUFFER_MODE_ZFB_ONLY: + /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ + REG_UPDATE_2(DCHUB_FB_LOCATION, + FB_TOP, 0, + FB_BASE, 0x0FFFF); + + REG_UPDATE(DCHUB_AGP_BASE, + AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + + REG_UPDATE(DCHUB_AGP_BOT, + AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + + REG_UPDATE(DCHUB_AGP_TOP, + AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22); + break; + case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: + /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ + REG_UPDATE(DCHUB_AGP_BASE, + AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + + REG_UPDATE(DCHUB_AGP_BOT, + AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + + REG_UPDATE(DCHUB_AGP_TOP, + AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22); + break; + case FRAME_BUFFER_MODE_LOCAL_ONLY: + /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ + REG_UPDATE(DCHUB_AGP_BASE, + AGP_BASE, 0); + + REG_UPDATE(DCHUB_AGP_BOT, + AGP_BOT, 0x03FFFF); + + REG_UPDATE(DCHUB_AGP_TOP, + AGP_TOP, 0); + break; + default: + break; + } + + dh_data->dchub_initialzied = true; + dh_data->dchub_info_valid = false; +} + +/** + * dce121_xgmi_enabled() - Check if xGMI is enabled + * @hws: DCE hardware sequencer object + * + * Return true if xGMI is enabled. False otherwise. + */ +bool dce121_xgmi_enabled(struct dce_hwseq *hws) +{ + uint32_t pf_max_region; + + REG_GET(MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, &pf_max_region); + /* PF_MAX_REGION == 0 means xgmi is disabled */ + return !!pf_max_region; +} + +void dce120_hw_sequencer_construct(struct dc *dc) +{ + /* All registers used by dce11.2 match those in dce11 in offset and + * structure + */ + dce110_hw_sequencer_construct(dc); + dc->hwseq->funcs.enable_display_power_gating = dce120_enable_display_power_gating; + dc->hwss.update_dchub = dce120_update_dchub; +} + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.h new file mode 100644 index 000000000000..bc024534732f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce120/dce120_hwseq.h @@ -0,0 +1,38 @@ +/* +* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCE120_H__ +#define __DC_HWSS_DCE120_H__ + +#include "core_types.h" +#include "hw_sequencer_private.h" + +struct dc; + +bool dce121_xgmi_enabled(struct dce_hwseq *hws); +void dce120_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_HWSS_DCE112_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.c new file mode 100644 index 000000000000..0a054e880801 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.c @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dc.h" +#include "core_types.h" +#include "dce80_hwseq.h" + +#include "dce/dce_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dce100/dce100_hwseq.h" + +/* include DCE8 register header files */ +#include "dce/dce_8_0_d.h" +#include "dce/dce_8_0_sh_mask.h" + +/******************************************************************************* + * Private definitions + ******************************************************************************/ + +/***************************PIPE_CONTROL***********************************/ + +void dce80_hw_sequencer_construct(struct dc *dc) +{ + dce110_hw_sequencer_construct(dc); + + dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating; + dc->hwss.pipe_control_lock = dce_pipe_control_lock; + dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; + dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; +} + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.h new file mode 100644 index 000000000000..e43af832d00c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.h @@ -0,0 +1,37 @@ +/* +* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCE80_H__ +#define __DC_HWSS_DCE80_H__ + +#include "core_types.h" +#include "hw_sequencer_private.h" + +struct dc; + +void dce80_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_HWSS_DCE80_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c new file mode 100644 index 000000000000..2b8b8366538e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -0,0 +1,3898 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include +#include "dm_services.h" +#include "basics/dc_common.h" +#include "core_types.h" +#include "resource.h" +#include "custom_float.h" +#include "dcn10_hwseq.h" +#include "dcn10/dcn10_hw_sequencer_debug.h" +#include "dce/dce_hwseq.h" +#include "abm.h" +#include "dmcu.h" +#include "dcn10/dcn10_optc.h" +#include "dcn10/dcn10_dpp.h" +#include "dcn10/dcn10_mpc.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "reg_helper.h" +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_hubbub.h" +#include "dcn10/dcn10_cm_common.h" +#include "dccg.h" +#include "clk_mgr.h" +#include "link_hwss.h" +#include "dpcd_defs.h" +#include "dsc.h" +#include "dce/dmub_psr.h" +#include "dc_dmub_srv.h" +#include "dce/dmub_hw_lock_mgr.h" +#include "dc_trace.h" +#include "dce/dmub_outbox.h" +#include "link.h" + +#define DC_LOGGER \ + dc_logger +#define DC_LOGGER_INIT(logger) \ + struct dal_logger *dc_logger = logger + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +/*print is 17 wide, first two characters are spaces*/ +#define DTN_INFO_MICRO_SEC(ref_cycle) \ + print_microsec(dc_ctx, log_ctx, ref_cycle) + +#define GAMMA_HW_POINTS_NUM 256 + +#define PGFSM_POWER_ON 0 +#define PGFSM_POWER_OFF 2 + +static void print_microsec(struct dc_context *dc_ctx, + struct dc_log_buffer_ctx *log_ctx, + uint32_t ref_cycle) +{ + const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000; + static const unsigned int frac = 1000; + uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; + + DTN_INFO(" %11d.%03d", + us_x10 / frac, + us_x10 % frac); +} + +void dcn10_lock_all_pipes(struct dc *dc, + struct dc_state *context, + bool lock) +{ + struct pipe_ctx *pipe_ctx; + struct pipe_ctx *old_pipe_ctx; + struct timing_generator *tg; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + pipe_ctx = &context->res_ctx.pipe_ctx[i]; + tg = pipe_ctx->stream_res.tg; + + /* + * Only lock the top pipe's tg to prevent redundant + * (un)locking. Also skip if pipe is disabled. + */ + if (pipe_ctx->top_pipe || + !pipe_ctx->stream || + (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) || + !tg->funcs->is_tg_enabled(tg) || + pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) + continue; + + if (lock) + dc->hwss.pipe_control_lock(dc, pipe_ctx, true); + else + dc->hwss.pipe_control_lock(dc, pipe_ctx, false); + } +} + +static void log_mpc_crc(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx) +{ + struct dc_context *dc_ctx = dc->ctx; + struct dce_hwseq *hws = dc->hwseq; + + if (REG(MPC_CRC_RESULT_GB)) + DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n", + REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR)); + if (REG(DPP_TOP0_DPP_CRC_VAL_B_A)) + DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n", + REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G)); +} + +static void dcn10_log_hubbub_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx) +{ + struct dc_context *dc_ctx = dc->ctx; + struct dcn_hubbub_wm wm; + int i; + + memset(&wm, 0, sizeof(struct dcn_hubbub_wm)); + dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm); + + DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent" + " sr_enter sr_exit dram_clk_change\n"); + + for (i = 0; i < 4; i++) { + struct dcn_hubbub_wm_set *s; + + s = &wm.sets[i]; + DTN_INFO("WM_Set[%d]:", s->wm_set); + DTN_INFO_MICRO_SEC(s->data_urgent); + DTN_INFO_MICRO_SEC(s->pte_meta_urgent); + DTN_INFO_MICRO_SEC(s->sr_enter); + DTN_INFO_MICRO_SEC(s->sr_exit); + DTN_INFO_MICRO_SEC(s->dram_clk_change); + DTN_INFO("\n"); + } + + DTN_INFO("\n"); +} + +static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx) +{ + struct dc_context *dc_ctx = dc->ctx; + struct resource_pool *pool = dc->res_pool; + int i; + + DTN_INFO( + "HUBP: format addr_hi width height rot mir sw_mode dcc_en blank_en clock_en ttu_dis underflow min_ttu_vblank qos_low_wm qos_high_wm\n"); + for (i = 0; i < pool->pipe_count; i++) { + struct hubp *hubp = pool->hubps[i]; + struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); + + hubp->funcs->hubp_read_state(hubp); + + if (!s->blank_en) { + DTN_INFO("[%2d]: %5xh %6xh %5d %6d %2xh %2xh %6xh %6d %8d %8d %7d %8xh", + hubp->inst, + s->pixel_format, + s->inuse_addr_hi, + s->viewport_width, + s->viewport_height, + s->rotation_angle, + s->h_mirror_en, + s->sw_mode, + s->dcc_en, + s->blank_en, + s->clock_en, + s->ttu_disable, + s->underflow_status); + DTN_INFO_MICRO_SEC(s->min_ttu_vblank); + DTN_INFO_MICRO_SEC(s->qos_level_low_wm); + DTN_INFO_MICRO_SEC(s->qos_level_high_wm); + DTN_INFO("\n"); + } + } + + DTN_INFO("\n=========RQ========\n"); + DTN_INFO("HUBP: drq_exp_m prq_exp_m mrq_exp_m crq_exp_m plane1_ba L:chunk_s min_chu_s meta_ch_s" + " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s" + " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n"); + for (i = 0; i < pool->pipe_count; i++) { + struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); + struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; + + if (!s->blank_en) + DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", + pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode, + rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size, + rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size, + rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size, + rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height, + rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size, + rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size, + rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size, + rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear); + } + + DTN_INFO("========DLG========\n"); + DTN_INFO("HUBP: rc_hbe dlg_vbe min_d_y_n rc_per_ht rc_x_a_s " + " dst_y_a_s dst_y_pf dst_y_vvb dst_y_rvb dst_y_vfl dst_y_rfl rf_pix_fq" + " vratio_pf vrat_pf_c rc_pg_vbl rc_pg_vbc rc_mc_vbl rc_mc_vbc rc_pg_fll" + " rc_pg_flc rc_mc_fll rc_mc_flc pr_nom_l pr_nom_c rc_pg_nl rc_pg_nc " + " mr_nom_l mr_nom_c rc_mc_nl rc_mc_nc rc_ld_pl rc_ld_pc rc_ld_l " + " rc_ld_c cha_cur0 ofst_cur1 cha_cur1 vr_af_vc0 ddrq_limt x_rt_dlay" + " x_rp_dlay x_rr_sfl\n"); + for (i = 0; i < pool->pipe_count; i++) { + struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); + struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr; + + if (!s->blank_en) + DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" + " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh" + " %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", + pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start, + dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler, + dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank, + dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq, + dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l, + dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l, + dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l, + dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l, + dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l, + dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l, + dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l, + dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l, + dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l, + dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l, + dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1, + dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit, + dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay, + dlg_regs->xfc_reg_remote_surface_flip_latency); + } + + DTN_INFO("========TTU========\n"); + DTN_INFO("HUBP: qos_ll_wm qos_lh_wm mn_ttu_vb qos_l_flp rc_rd_p_l rc_rd_l rc_rd_p_c" + " rc_rd_c rc_rd_c0 rc_rd_pc0 rc_rd_c1 rc_rd_pc1 qos_lf_l qos_rds_l" + " qos_lf_c qos_rds_c qos_lf_c0 qos_rds_c0 qos_lf_c1 qos_rds_c1\n"); + for (i = 0; i < pool->pipe_count; i++) { + struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); + struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr; + + if (!s->blank_en) + DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", + pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank, + ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l, + ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0, + ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1, + ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l, + ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0, + ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1); + } + DTN_INFO("\n"); +} + +void dcn10_log_hw_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx) +{ + struct dc_context *dc_ctx = dc->ctx; + struct resource_pool *pool = dc->res_pool; + int i; + + DTN_INFO_BEGIN(); + + dcn10_log_hubbub_state(dc, log_ctx); + + dcn10_log_hubp_states(dc, log_ctx); + + DTN_INFO("DPP: IGAM format IGAM mode DGAM mode RGAM mode" + " GAMUT mode C11 C12 C13 C14 C21 C22 C23 C24 " + "C31 C32 C33 C34\n"); + for (i = 0; i < pool->pipe_count; i++) { + struct dpp *dpp = pool->dpps[i]; + struct dcn_dpp_state s = {0}; + + dpp->funcs->dpp_read_state(dpp, &s); + + if (!s.is_enabled) + continue; + + DTN_INFO("[%2d]: %11xh %-11s %-11s %-11s" + "%8x %08xh %08xh %08xh %08xh %08xh %08xh", + dpp->inst, + s.igam_input_format, + (s.igam_lut_mode == 0) ? "BypassFixed" : + ((s.igam_lut_mode == 1) ? "BypassFloat" : + ((s.igam_lut_mode == 2) ? "RAM" : + ((s.igam_lut_mode == 3) ? "RAM" : + "Unknown"))), + (s.dgam_lut_mode == 0) ? "Bypass" : + ((s.dgam_lut_mode == 1) ? "sRGB" : + ((s.dgam_lut_mode == 2) ? "Ycc" : + ((s.dgam_lut_mode == 3) ? "RAM" : + ((s.dgam_lut_mode == 4) ? "RAM" : + "Unknown")))), + (s.rgam_lut_mode == 0) ? "Bypass" : + ((s.rgam_lut_mode == 1) ? "sRGB" : + ((s.rgam_lut_mode == 2) ? "Ycc" : + ((s.rgam_lut_mode == 3) ? "RAM" : + ((s.rgam_lut_mode == 4) ? "RAM" : + "Unknown")))), + s.gamut_remap_mode, + s.gamut_remap_c11_c12, + s.gamut_remap_c13_c14, + s.gamut_remap_c21_c22, + s.gamut_remap_c23_c24, + s.gamut_remap_c31_c32, + s.gamut_remap_c33_c34); + DTN_INFO("\n"); + } + DTN_INFO("\n"); + + DTN_INFO("MPCC: OPP DPP MPCCBOT MODE ALPHA_MODE PREMULT OVERLAP_ONLY IDLE\n"); + for (i = 0; i < pool->pipe_count; i++) { + struct mpcc_state s = {0}; + + pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s); + if (s.opp_id != 0xf) + DTN_INFO("[%2d]: %2xh %2xh %6xh %4d %10d %7d %12d %4d\n", + i, s.opp_id, s.dpp_id, s.bot_mpcc_id, + s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only, + s.idle); + } + DTN_INFO("\n"); + + DTN_INFO("OTG: v_bs v_be v_ss v_se vpol vmax vmin vmax_sel vmin_sel h_bs h_be h_ss h_se hpol htot vtot underflow blank_en\n"); + + for (i = 0; i < pool->timing_generator_count; i++) { + struct timing_generator *tg = pool->timing_generators[i]; + struct dcn_otg_state s = {0}; + /* Read shared OTG state registers for all DCNx */ + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + + /* + * For DCN2 and greater, a register on the OPP is used to + * determine if the CRTC is blanked instead of the OTG. So use + * dpg_is_blanked() if exists, otherwise fallback on otg. + * + * TODO: Implement DCN-specific read_otg_state hooks. + */ + if (pool->opps[i]->funcs->dpg_is_blanked) + s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]); + else + s.blank_enabled = tg->funcs->is_blanked(tg); + + //only print if OTG master is enabled + if ((s.otg_enabled & 1) == 0) + continue; + + DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d %9d %8d\n", + tg->inst, + s.v_blank_start, + s.v_blank_end, + s.v_sync_a_start, + s.v_sync_a_end, + s.v_sync_a_pol, + s.v_total_max, + s.v_total_min, + s.v_total_max_sel, + s.v_total_min_sel, + s.h_blank_start, + s.h_blank_end, + s.h_sync_a_start, + s.h_sync_a_end, + s.h_sync_a_pol, + s.h_total, + s.v_total, + s.underflow_occurred_status, + s.blank_enabled); + + // Clear underflow for debug purposes + // We want to keep underflow sticky bit on for the longevity tests outside of test environment. + // This function is called only from Windows or Diags test environment, hence it's safe to clear + // it from here without affecting the original intent. + tg->funcs->clear_optc_underflow(tg); + } + DTN_INFO("\n"); + + // dcn_dsc_state struct field bytes_per_pixel was renamed to bits_per_pixel + // TODO: Update golden log header to reflect this name change + DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); + for (i = 0; i < pool->res_cap->num_dsc; i++) { + struct display_stream_compressor *dsc = pool->dscs[i]; + struct dcn_dsc_state s = {0}; + + dsc->funcs->dsc_read_state(dsc, &s); + DTN_INFO("[%d]: %-9d %-12d %-10d\n", + dsc->inst, + s.dsc_clock_en, + s.dsc_slice_width, + s.dsc_bits_per_pixel); + DTN_INFO("\n"); + } + DTN_INFO("\n"); + + DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM" + " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n"); + for (i = 0; i < pool->stream_enc_count; i++) { + struct stream_encoder *enc = pool->stream_enc[i]; + struct enc_state s = {0}; + + if (enc->funcs->enc_read_state) { + enc->funcs->enc_read_state(enc, &s); + DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n", + enc->id, + s.dsc_mode, + s.sec_gsp_pps_line_num, + s.vbid6_line_reference, + s.vbid6_line_num, + s.sec_gsp_pps_enable, + s.sec_stream_enable); + DTN_INFO("\n"); + } + } + DTN_INFO("\n"); + + DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS DP_LINK_TRAINING_COMPLETE\n"); + for (i = 0; i < dc->link_count; i++) { + struct link_encoder *lenc = dc->links[i]->link_enc; + + struct link_enc_state s = {0}; + + if (lenc && lenc->funcs->read_state) { + lenc->funcs->read_state(lenc, &s); + DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n", + i, + s.dphy_fec_en, + s.dphy_fec_ready_shadow, + s.dphy_fec_active_status, + s.dp_link_training_complete); + DTN_INFO("\n"); + } + } + DTN_INFO("\n"); + + DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" + "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", + dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz, + dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz, + dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz, + dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz, + dc->current_state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz, + dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz, + dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz); + + log_mpc_crc(dc, log_ctx); + + { + if (pool->hpo_dp_stream_enc_count > 0) { + DTN_INFO("DP HPO S_ENC: Enabled OTG Format Depth Vid SDP Compressed Link\n"); + for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { + struct hpo_dp_stream_encoder_state hpo_dp_se_state = {0}; + struct hpo_dp_stream_encoder *hpo_dp_stream_enc = pool->hpo_dp_stream_enc[i]; + + if (hpo_dp_stream_enc && hpo_dp_stream_enc->funcs->read_state) { + hpo_dp_stream_enc->funcs->read_state(hpo_dp_stream_enc, &hpo_dp_se_state); + + DTN_INFO("[%d]: %d %d %6s %d %d %d %d %d\n", + hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0, + hpo_dp_se_state.stream_enc_enabled, + hpo_dp_se_state.otg_inst, + (hpo_dp_se_state.pixel_encoding == 0) ? "4:4:4" : + ((hpo_dp_se_state.pixel_encoding == 1) ? "4:2:2" : + (hpo_dp_se_state.pixel_encoding == 2) ? "4:2:0" : "Y-Only"), + (hpo_dp_se_state.component_depth == 0) ? 6 : + ((hpo_dp_se_state.component_depth == 1) ? 8 : + (hpo_dp_se_state.component_depth == 2) ? 10 : 12), + hpo_dp_se_state.vid_stream_enabled, + hpo_dp_se_state.sdp_enabled, + hpo_dp_se_state.compressed_format, + hpo_dp_se_state.mapped_to_link_enc); + } + } + + DTN_INFO("\n"); + } + + /* log DP HPO L_ENC section if any hpo_dp_link_enc exists */ + if (pool->hpo_dp_link_enc_count) { + DTN_INFO("DP HPO L_ENC: Enabled Mode Lanes Stream Slots VC Rate X VC Rate Y\n"); + + for (i = 0; i < pool->hpo_dp_link_enc_count; i++) { + struct hpo_dp_link_encoder *hpo_dp_link_enc = pool->hpo_dp_link_enc[i]; + struct hpo_dp_link_enc_state hpo_dp_le_state = {0}; + + if (hpo_dp_link_enc->funcs->read_state) { + hpo_dp_link_enc->funcs->read_state(hpo_dp_link_enc, &hpo_dp_le_state); + DTN_INFO("[%d]: %d %6s %d %d %d %d %d\n", + hpo_dp_link_enc->inst, + hpo_dp_le_state.link_enc_enabled, + (hpo_dp_le_state.link_mode == 0) ? "TPS1" : + (hpo_dp_le_state.link_mode == 1) ? "TPS2" : + (hpo_dp_le_state.link_mode == 2) ? "ACTIVE" : "TEST", + hpo_dp_le_state.lane_count, + hpo_dp_le_state.stream_src[0], + hpo_dp_le_state.slot_count[0], + hpo_dp_le_state.vc_rate_x[0], + hpo_dp_le_state.vc_rate_y[0]); + DTN_INFO("\n"); + } + } + + DTN_INFO("\n"); + } + } + + DTN_INFO_END(); +} + +bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + + if (tg->funcs->is_optc_underflow_occurred(tg)) { + tg->funcs->clear_optc_underflow(tg); + return true; + } + + if (hubp->funcs->hubp_get_underflow_status(hubp)) { + hubp->funcs->hubp_clear_underflow(hubp); + return true; + } + return false; +} + +void dcn10_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable) +{ + bool force_on = true; /* disable power gating */ + + if (enable) + force_on = false; + + /* DCHUBP0/1/2/3 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); + + /* DPP0/1/2/3 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); +} + +void dcn10_disable_vga( + struct dce_hwseq *hws) +{ + unsigned int in_vga1_mode = 0; + unsigned int in_vga2_mode = 0; + unsigned int in_vga3_mode = 0; + unsigned int in_vga4_mode = 0; + + REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode); + REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode); + REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode); + REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode); + + if (in_vga1_mode == 0 && in_vga2_mode == 0 && + in_vga3_mode == 0 && in_vga4_mode == 0) + return; + + REG_WRITE(D1VGA_CONTROL, 0); + REG_WRITE(D2VGA_CONTROL, 0); + REG_WRITE(D3VGA_CONTROL, 0); + REG_WRITE(D4VGA_CONTROL, 0); + + /* HW Engineer's Notes: + * During switch from vga->extended, if we set the VGA_TEST_ENABLE and + * then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly. + * + * Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset + * VGA_TEST_ENABLE, to leave it in the same state as before. + */ + REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1); + REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); +} + +/** + * dcn10_dpp_pg_control - DPP power gate control. + * + * @hws: dce_hwseq reference. + * @dpp_inst: DPP instance reference. + * @power_on: true if we want to enable power gate, false otherwise. + * + * Enable or disable power gate in the specific DPP instance. + */ +void dcn10_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; + + if (hws->ctx->dc->debug.disable_dpp_power_gate) + return; + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; + + switch (dpp_inst) { + case 0: /* DPP0 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, + DOMAIN1_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN1_PG_STATUS, + DOMAIN1_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DPP1 */ + REG_UPDATE(DOMAIN3_PG_CONFIG, + DOMAIN3_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN3_PG_STATUS, + DOMAIN3_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DPP2 */ + REG_UPDATE(DOMAIN5_PG_CONFIG, + DOMAIN5_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN5_PG_STATUS, + DOMAIN5_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DPP3 */ + REG_UPDATE(DOMAIN7_PG_CONFIG, + DOMAIN7_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN7_PG_STATUS, + DOMAIN7_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +/** + * dcn10_hubp_pg_control - HUBP power gate control. + * + * @hws: dce_hwseq reference. + * @hubp_inst: DPP instance reference. + * @power_on: true if we want to enable power gate, false otherwise. + * + * Enable or disable power gate in the specific HUBP instance. + */ +void dcn10_hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; + + switch (hubp_inst) { + case 0: /* DCHUBP0 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, + DOMAIN0_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN0_PG_STATUS, + DOMAIN0_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DCHUBP1 */ + REG_UPDATE(DOMAIN2_PG_CONFIG, + DOMAIN2_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN2_PG_STATUS, + DOMAIN2_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DCHUBP2 */ + REG_UPDATE(DOMAIN4_PG_CONFIG, + DOMAIN4_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN4_PG_STATUS, + DOMAIN4_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DCHUBP3 */ + REG_UPDATE(DOMAIN6_PG_CONFIG, + DOMAIN6_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN6_PG_STATUS, + DOMAIN6_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +static void power_on_plane_resources( + struct dce_hwseq *hws, + int plane_id) +{ + DC_LOGGER_INIT(hws->ctx->logger); + + if (hws->funcs.dpp_root_clock_control) + hws->funcs.dpp_root_clock_control(hws, plane_id, true); + + if (REG(DC_IP_REQUEST_CNTL)) { + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + + if (hws->funcs.dpp_pg_control) + hws->funcs.dpp_pg_control(hws, plane_id, true); + + if (hws->funcs.hubp_pg_control) + hws->funcs.hubp_pg_control(hws, plane_id, true); + + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + DC_LOG_DEBUG( + "Un-gated front end for pipe %d\n", plane_id); + } +} + +static void undo_DEGVIDCN10_253_wa(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = dc->res_pool->hubps[0]; + + if (!hws->wa_state.DEGVIDCN10_253_applied) + return; + + hubp->funcs->set_blank(hubp, true); + + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + + hws->funcs.hubp_pg_control(hws, 0, false); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + + hws->wa_state.DEGVIDCN10_253_applied = false; +} + +static void apply_DEGVIDCN10_253_wa(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = dc->res_pool->hubps[0]; + int i; + + if (dc->debug.disable_stutter) + return; + + if (!hws->wa.DEGVIDCN10_253) + return; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (!dc->res_pool->hubps[i]->power_gated) + return; + } + + /* all pipe power gated, apply work around to enable stutter. */ + + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + + hws->funcs.hubp_pg_control(hws, 0, true); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + + hubp->funcs->set_hubp_blank_en(hubp, false); + hws->wa_state.DEGVIDCN10_253_applied = true; +} + +void dcn10_bios_golden_init(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *bp = dc->ctx->dc_bios; + int i; + bool allow_self_fresh_force_enable = true; + + if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc)) + return; + + if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) + allow_self_fresh_force_enable = + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); + + + /* WA for making DF sleep when idle after resume from S0i3. + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by + * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 + * before calling command table and it changed to 1 after, + * it should be set back to 0. + */ + + /* initialize dcn global */ + bp->funcs->enable_disp_power_gating(bp, + CONTROLLER_ID_D0, ASIC_PIPE_INIT); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + /* initialize dcn per pipe */ + bp->funcs->enable_disp_power_gating(bp, + CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); + } + + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + if (allow_self_fresh_force_enable == false && + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub)) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + +} + +static void false_optc_underflow_wa( + struct dc *dc, + const struct dc_stream_state *stream, + struct timing_generator *tg) +{ + int i; + bool underflow; + + if (!dc->hwseq->wa.false_optc_underflow) + return; + + underflow = tg->funcs->is_optc_underflow_occurred(tg); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (old_pipe_ctx->stream != stream) + continue; + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); + } + + if (tg->funcs->set_blank_data_double_buffer) + tg->funcs->set_blank_data_double_buffer(tg, true); + + if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) + tg->funcs->clear_optc_underflow(tg); +} + +static int calculate_vready_offset_for_group(struct pipe_ctx *pipe) +{ + struct pipe_ctx *other_pipe; + int vready_offset = pipe->pipe_dlg_param.vready_offset; + + /* Always use the largest vready_offset of all connected pipes */ + for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + + return vready_offset; +} + +enum dc_status dcn10_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + enum dc_color_space color_space; + struct tg_color black_color = {0}; + + /* by upper caller loop, pipe0 is parent pipe and be called first. + * back end is set up by for pipe0. Other children pipe share back end + * with pipe 0. No program is needed. + */ + if (pipe_ctx->top_pipe != NULL) + return DC_OK; + + /* TODO check if timing_changed, disable stream if timing changed */ + + /* HW program guide assume display already disable + * by unplug sequence. OTG assume stop. + */ + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); + + if (false == pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + if (dc_is_hdmi_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + else + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + } + + pipe_ctx->stream_res.tg->funcs->program_timing( + pipe_ctx->stream_res.tg, + &stream->timing, + calculate_vready_offset_for_group(pipe_ctx), + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width, + pipe_ctx->stream->signal, + true); + +#if 0 /* move to after enable_crtc */ + /* TODO: OPP FMT, ABM. etc. should be done here. */ + /* or FPGA now. instance 0 only. TODO: move to opp.c */ + + inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt; + + pipe_ctx->stream_res.opp->funcs->opp_program_fmt( + pipe_ctx->stream_res.opp, + &stream->bit_depth_params, + &stream->clamping); +#endif + /* program otg blank color */ + color_space = stream->output_color_space; + color_space_to_black_color(dc, color_space, &black_color); + + /* + * The way 420 is packed, 2 channels carry Y component, 1 channel + * alternate between Cb and Cr, so both channels need the pixel + * value for Y + */ + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + black_color.color_r_cr = black_color.color_g_y; + + if (pipe_ctx->stream_res.tg->funcs->set_blank_color) + pipe_ctx->stream_res.tg->funcs->set_blank_color( + pipe_ctx->stream_res.tg, + &black_color); + + if (pipe_ctx->stream_res.tg->funcs->is_blanked && + !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) { + pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); + hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); + false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg); + } + + /* VTG is within DCHUB command block. DCFCLK is always on */ + if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + /* TODO program crtc source select for non-virtual signal*/ + /* TODO program FMT */ + /* TODO setup link_enc */ + /* TODO set stream attributes */ + /* TODO program audio */ + /* TODO enable stream if timing changed */ + /* TODO unblank stream if DP */ + + return DC_OK; +} + +static void dcn10_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + int i; + struct dc_link *link; + DC_LOGGER_INIT(dc->ctx->logger); + if (pipe_ctx->stream_res.stream_enc == NULL) { + pipe_ctx->stream = NULL; + return; + } + + link = pipe_ctx->stream->link; + /* DPMS may already disable or */ + /* dpms_off status is incorrect due to fastboot + * feature. When system resume from S4 with second + * screen only, the dpms_off would be true but + * VBIOS lit up eDP, so check link status too. + */ + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) + dc->link_srv->set_dpms_off(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } + } + + /* by upper caller loop, parent pipe: pipe0, will be reset last. + * back end share by all pipes and will be disable only when disable + * parent pipe. + */ + if (pipe_ctx->top_pipe == NULL) { + + if (pipe_ctx->stream_res.abm) + dc->hwss.set_abm_immediate_disable(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); + pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) + break; + + if (i == dc->res_pool->pipe_count) + return; + + pipe_ctx->stream = NULL; + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", + pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); +} + +static bool dcn10_hw_wa_force_recovery(struct dc *dc) +{ + struct hubp *hubp ; + unsigned int i; + bool need_recover = true; + + if (!dc->debug.recovery_enabled) + return false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx != NULL) { + hubp = pipe_ctx->plane_res.hubp; + if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) { + if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) { + /* one pipe underflow, we will reset all the pipes*/ + need_recover = true; + } + } + } + } + if (!need_recover) + return false; + /* + DCHUBP_CNTL:HUBP_BLANK_EN=1 + DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1 + DCHUBP_CNTL:HUBP_DISABLE=1 + DCHUBP_CNTL:HUBP_DISABLE=0 + DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0 + DCSURF_PRIMARY_SURFACE_ADDRESS + DCHUBP_CNTL:HUBP_BLANK_EN=0 + */ + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx != NULL) { + hubp = pipe_ctx->plane_res.hubp; + /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/ + if (hubp != NULL && hubp->funcs->set_hubp_blank_en) + hubp->funcs->set_hubp_blank_en(hubp, true); + } + } + /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/ + hubbub1_soft_reset(dc->res_pool->hubbub, true); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx != NULL) { + hubp = pipe_ctx->plane_res.hubp; + /*DCHUBP_CNTL:HUBP_DISABLE=1*/ + if (hubp != NULL && hubp->funcs->hubp_disable_control) + hubp->funcs->hubp_disable_control(hubp, true); + } + } + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx != NULL) { + hubp = pipe_ctx->plane_res.hubp; + /*DCHUBP_CNTL:HUBP_DISABLE=0*/ + if (hubp != NULL && hubp->funcs->hubp_disable_control) + hubp->funcs->hubp_disable_control(hubp, true); + } + } + /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/ + hubbub1_soft_reset(dc->res_pool->hubbub, false); + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx != NULL) { + hubp = pipe_ctx->plane_res.hubp; + /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/ + if (hubp != NULL && hubp->funcs->set_hubp_blank_en) + hubp->funcs->set_hubp_blank_en(hubp, true); + } + } + return true; + +} + +void dcn10_verify_allow_pstate_change_high(struct dc *dc) +{ + struct hubbub *hubbub = dc->res_pool->hubbub; + static bool should_log_hw_state; /* prevent hw state log by default */ + + if (!hubbub->funcs->verify_allow_pstate_change_high) + return; + + if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) { + int i = 0; + + if (should_log_hw_state) + dcn10_log_hw_state(dc, NULL); + + TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES); + BREAK_TO_DEBUGGER(); + if (dcn10_hw_wa_force_recovery(dc)) { + /*check again*/ + if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) + BREAK_TO_DEBUGGER(); + } + } +} + +/* trigger HW to start disconnect plane from stream on the next vsync */ +void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + int dpp_id = pipe_ctx->plane_res.dpp->inst; + struct mpc *mpc = dc->res_pool->mpc; + struct mpc_tree *mpc_tree_params; + struct mpcc *mpcc_to_remove = NULL; + struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; + + mpc_tree_params = &(opp->mpc_tree_params); + mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); + + /*Already reset*/ + if (mpcc_to_remove == NULL) + return; + + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); + // Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle, + // so don't wait for MPCC_IDLE in the programming sequence + if (opp != NULL && !pipe_ctx->plane_state->is_phantom) + opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + + dc->optimized_required = true; + + if (hubp->funcs->hubp_disconnect) + hubp->funcs->hubp_disconnect(hubp); + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); +} + +/** + * dcn10_plane_atomic_power_down - Power down plane components. + * + * @dc: dc struct reference. used for grab hwseq. + * @dpp: dpp struct reference. + * @hubp: hubp struct reference. + * + * Keep in mind that this operation requires a power gate configuration; + * however, requests for switch power gate are precisely controlled to avoid + * problems. For this reason, power gate request is usually disabled. This + * function first needs to enable the power gate request before disabling DPP + * and HUBP. Finally, it disables the power gate request again. + */ +void dcn10_plane_atomic_power_down(struct dc *dc, + struct dpp *dpp, + struct hubp *hubp) +{ + struct dce_hwseq *hws = dc->hwseq; + DC_LOGGER_INIT(dc->ctx->logger); + + if (REG(DC_IP_REQUEST_CNTL)) { + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + + if (hws->funcs.dpp_pg_control) + hws->funcs.dpp_pg_control(hws, dpp->inst, false); + + if (hws->funcs.hubp_pg_control) + hws->funcs.hubp_pg_control(hws, hubp->inst, false); + + dpp->funcs->dpp_reset(dpp); + + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + DC_LOG_DEBUG( + "Power gated front end %d\n", hubp->inst); + } + + if (hws->funcs.dpp_root_clock_control) + hws->funcs.dpp_root_clock_control(hws, dpp->inst, false); +} + +/* disable HW used by plane. + * note: cannot disable until disconnect is complete + */ +void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + int opp_id = hubp->opp_id; + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); + + hubp->funcs->hubp_clk_cntl(hubp, false); + + dpp->funcs->dpp_dppclk_control(dpp, false, false); + + if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL) + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + false); + + hubp->power_gated = true; + dc->optimized_required = false; /* We're powering off, no need to optimize */ + + hws->funcs.plane_atomic_power_down(dc, + pipe_ctx->plane_res.dpp, + pipe_ctx->plane_res.hubp); + + pipe_ctx->stream = NULL; + memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); + memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->plane_state = NULL; +} + +void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + DC_LOGGER_INIT(dc->ctx->logger); + + if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) + return; + + hws->funcs.plane_atomic_disable(dc, pipe_ctx); + + apply_DEGVIDCN10_253_wa(dc); + + DC_LOG_DC("Power down front end %d\n", + pipe_ctx->pipe_idx); +} + +void dcn10_init_pipes(struct dc *dc, struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + struct hubbub *hubbub = dc->res_pool->hubbub; + bool can_apply_seamless_boot = false; + + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->apply_seamless_boot_optimization) { + can_apply_seamless_boot = true; + break; + } + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* There is assumption that pipe_ctx is not mapping irregularly + * to non-preferred front end. If pipe_ctx->stream is not NULL, + * we will use the pipe, so don't disable + */ + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) + continue; + + /* Blank controller using driver code instead of + * command table. + */ + if (tg->funcs->is_tg_enabled(tg)) { + if (hws->funcs.init_blank != NULL) { + hws->funcs.init_blank(dc, tg); + tg->funcs->lock(tg); + } else { + tg->funcs->lock(tg); + tg->funcs->set_blank(tg, true); + hwss_wait_for_blank_complete(tg); + } + } + } + + /* Reset det size */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = dc->res_pool->hubps[i]; + + /* Do not need to reset for seamless boot */ + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) + continue; + + if (hubbub && hubp) { + if (hubbub->funcs->program_det_size) + hubbub->funcs->program_det_size(hubbub, hubp->inst, 0); + } + } + + /* num_opp will be equal to number of mpcc */ + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* Cannot reset the MPC mux if seamless boot */ + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) + continue; + + dc->res_pool->mpc->funcs->mpc_init_single_inst( + dc->res_pool->mpc, i); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct hubp *hubp = dc->res_pool->hubps[i]; + struct dpp *dpp = dc->res_pool->dpps[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* There is assumption that pipe_ctx is not mapping irregularly + * to non-preferred front end. If pipe_ctx->stream is not NULL, + * we will use the pipe, so don't disable + */ + if (can_apply_seamless_boot && + pipe_ctx->stream != NULL && + pipe_ctx->stream_res.tg->funcs->is_tg_enabled( + pipe_ctx->stream_res.tg)) { + // Enable double buffering for OTG_BLANK no matter if + // seamless boot is enabled or not to suppress global sync + // signals when OTG blanked. This is to prevent pipe from + // requesting data while in PSR. + tg->funcs->tg_init(tg); + hubp->power_gated = true; + continue; + } + + /* Disable on the current state so the new one isn't cleared. */ + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + dpp->funcs->dpp_reset(dpp); + + pipe_ctx->stream_res.tg = tg; + pipe_ctx->pipe_idx = i; + + pipe_ctx->plane_res.hubp = hubp; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; + hubp->opp_id = OPP_ID_INVALID; + hubp->power_gated = false; + + dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; + dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; + + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->unlock(tg); + + dc->hwss.disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + + if (tg->funcs->is_tg_enabled(tg)) { + if (tg->funcs->init_odm) + tg->funcs->init_odm(tg); + } + + tg->funcs->tg_init(tg); + } + + /* Power gate DSCs */ + if (hws->funcs.dsc_pg_control != NULL) { + uint32_t num_opps = 0; + uint32_t opp_id_src0 = OPP_ID_INVALID; + uint32_t opp_id_src1 = OPP_ID_INVALID; + + // Step 1: To find out which OPTC is running & OPTC DSC is ON + // We can't use res_pool->res_cap->num_timing_generator to check + // Because it records display pipes default setting built in driver, + // not display pipes of the current chip. + // Some ASICs would be fused display pipes less than the default setting. + // In dcnxx_resource_construct function, driver would obatin real information. + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + uint32_t optc_dsc_state = 0; + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) { + if (tg->funcs->get_dsc_status) + tg->funcs->get_dsc_status(tg, &optc_dsc_state); + // Only one OPTC with DSC is ON, so if we got one result, we would exit this block. + // non-zero value is DSC enabled + if (optc_dsc_state != 0) { + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + break; + } + } + } + + // Step 2: To power down DSC but skip DSC of running OPTC + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { + struct dcn_dsc_state s = {0}; + + dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); + + if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && + s.dsc_clock_en && s.dsc_fw_en) + continue; + + hws->funcs.dsc_pg_control(hws, dc->res_pool->dscs[i]->inst, false); + } + } +} + +void dcn10_init_hw(struct dc *dc) +{ + int i; + struct abm *abm = dc->res_pool->abm; + struct dmcu *dmcu = dc->res_pool->dmcu; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + struct resource_pool *res_pool = dc->res_pool; + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + bool is_optimized_init_done = false; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + /* Align bw context with hw config when system resume. */ + if (dc->clk_mgr->clks.dispclk_khz != 0 && dc->clk_mgr->clks.dppclk_khz != 0) { + dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz = dc->clk_mgr->clks.dispclk_khz; + dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz = dc->clk_mgr->clks.dppclk_khz; + } + + // Initialize the dccg + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) + dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + if (!dcb->funcs->is_accelerated_mode(dcb)) + hws->funcs.disable_vga(dc->hwseq); + + if (!dc_dmub_srv_optimized_init_done(dc->ctx->dmub_srv)) + hws->funcs.bios_golden_init(dc); + + + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + + if (res_pool->dccg && res_pool->hubbub) { + + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } else + ASSERT_CRITICAL(false); + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + if (!is_optimized_init_done) + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) { + link->link_status.link_active = true; + if (link->link_enc->funcs->fec_is_active && + link->link_enc->funcs->fec_is_active(link->link_enc)) + link->fec_state = dc_link_fec_enabled; + } + } + + /* we want to turn off all dp displays before doing detection */ + dc->link_srv->blank_all_dp_displays(dc); + + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + + /* If taking control over from VBIOS, we may want to optimize our first + * mode set, so we need to skip powering down pipes until we know which + * pipes we want to use. + * Otherwise, if taking control is not possible, we need to power + * everything down. + */ + if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { + if (!is_optimized_init_done) { + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } + } + + if (!is_optimized_init_done) { + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } + + if (abm != NULL) + abm->funcs->abm_init(abm, backlight); + + if (dmcu != NULL && !dmcu->auto_load_dmcu) + dmcu->funcs->dmcu_init(dmcu); + } + + if (abm != NULL && dmcu != NULL) + abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + if (!is_optimized_init_done) + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + if (dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); +} + +/* In headless boot cases, DIG may be turned + * on which causes HW/SW discrepancies. + * To avoid this, power down hardware on boot + * if DIG is turned on + */ +void dcn10_power_down_on_boot(struct dc *dc) +{ + struct dc_link *edp_links[MAX_NUM_EDP]; + struct dc_link *edp_link = NULL; + int edp_num; + int i = 0; + + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num) + edp_link = edp_links[0]; + + if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + dc->hwseq->funcs.edp_backlight_control && + dc->hwss.power_down && + dc->hwss.edp_power_control) { + dc->hwseq->funcs.edp_backlight_control(edp_link, false); + dc->hwss.power_down(dc); + dc->hwss.edp_power_control(edp_link, false); + } else { + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->link_enc && link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc) && + dc->hwss.power_down) { + dc->hwss.power_down(dc); + break; + } + + } + } + + /* + * Call update_clocks with empty context + * to send DISPLAY_OFF + * Otherwise DISPLAY_OFF may not be asserted + */ + if (dc->clk_mgr->funcs->set_low_power_state) + dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr); +} + +void dcn10_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + + /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (pipe_ctx_old->top_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx_old); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } +} + +static bool patch_address_for_sbs_tb_stereo( + struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + bool sec_split = pipe_ctx->top_pipe && + pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; + if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && + (pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_SIDE_BY_SIDE || + pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { + *addr = plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.left_addr = + plane_state->address.grph_stereo.right_addr; + return true; + } else { + if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && + plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { + plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; + plane_state->address.grph_stereo.right_addr = + plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.right_meta_addr = + plane_state->address.grph_stereo.left_meta_addr; + } + } + return false; +} + +void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + bool addr_patched = false; + PHYSICAL_ADDRESS_LOC addr; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + + if (plane_state == NULL) + return; + + addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); + + pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( + pipe_ctx->plane_res.hubp, + &plane_state->address, + plane_state->flip_immediate); + + plane_state->status.requested_address = plane_state->address; + + if (plane_state->flip_immediate) + plane_state->status.current_address = plane_state->address; + + if (addr_patched) + pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; +} + +bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + const struct dc_transfer_func *tf = NULL; + bool result = true; + + if (dpp_base == NULL) + return false; + + if (plane_state->in_transfer_func) + tf = plane_state->in_transfer_func; + + if (plane_state->gamma_correction && + !dpp_base->ctx->dc->debug.always_use_regamma + && !plane_state->gamma_correction->is_identity + && dce_use_lut(plane_state->format)) + dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); + + if (tf == NULL) + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + else if (tf->type == TF_TYPE_PREDEFINED) { + switch (tf->tf) { + case TRANSFER_FUNCTION_SRGB: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB); + break; + case TRANSFER_FUNCTION_BT709: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC); + break; + case TRANSFER_FUNCTION_LINEAR: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + break; + case TRANSFER_FUNCTION_PQ: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); + cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); + result = true; + break; + default: + result = false; + break; + } + } else if (tf->type == TF_TYPE_BYPASS) { + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + } else { + cm_helper_translate_curve_to_degamma_hw_format(tf, + &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, + &dpp_base->degamma_params); + result = true; + } + + return result; +} + +#define MAX_NUM_HW_POINTS 0x200 + +static void log_tf(struct dc_context *ctx, + struct dc_transfer_func *tf, uint32_t hw_points_num) +{ + // DC_LOG_GAMMA is default logging of all hw points + // DC_LOG_ALL_GAMMA logs all points, not only hw points + // DC_LOG_ALL_TF_POINTS logs all channels of the tf + int i = 0; + + DC_LOG_GAMMA("Gamma Correction TF"); + DC_LOG_ALL_GAMMA("Logging all tf points..."); + DC_LOG_ALL_TF_CHANNELS("Logging all channels..."); + + for (i = 0; i < hw_points_num; i++) { + DC_LOG_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); + DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); + DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); + } + + for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) { + DC_LOG_ALL_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value); + DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value); + DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value); + } +} + +bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + struct dpp *dpp = pipe_ctx->plane_res.dpp; + + if (dpp == NULL) + return false; + + dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; + + if (stream->out_transfer_func && + stream->out_transfer_func->type == TF_TYPE_PREDEFINED && + stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) + dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB); + + /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full + * update. + */ + else if (cm_helper_translate_curve_to_hw_format(dc->ctx, + stream->out_transfer_func, + &dpp->regamma_params, false)) { + dpp->funcs->dpp_program_regamma_pwl( + dpp, + &dpp->regamma_params, OPP_REGAMMA_USER); + } else + dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); + + if (stream != NULL && stream->ctx != NULL && + stream->out_transfer_func != NULL) { + log_tf(stream->ctx, + stream->out_transfer_func, + dpp->regamma_params.hw_points_num); + } + + return true; +} + +void dcn10_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + struct dce_hwseq *hws = dc->hwseq; + + /* use TG master update lock to lock everything on the TG + * therefore only top pipe need to lock + */ + if (!pipe || pipe->top_pipe) + return; + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); + + if (lock) + pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); +} + +/** + * delay_cursor_until_vupdate() - Delay cursor update if too close to VUPDATE. + * + * Software keepout workaround to prevent cursor update locking from stalling + * out cursor updates indefinitely or from old values from being retained in + * the case where the viewport changes in the same frame as the cursor. + * + * The idea is to calculate the remaining time from VPOS to VUPDATE. If it's + * too close to VUPDATE, then stall out until VUPDATE finishes. + * + * TODO: Optimize cursor programming to be once per frame before VUPDATE + * to avoid the need for this workaround. + * + * @dc: Current DC state + * @pipe_ctx: Pipe_ctx pointer for delayed cursor update + * + * Return: void + */ +static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct crtc_position position; + uint32_t vupdate_start, vupdate_end; + unsigned int lines_to_vupdate, us_to_vupdate, vpos; + unsigned int us_per_line, us_vupdate; + + if (!dc->hwss.calc_vupdate_position || !dc->hwss.get_position) + return; + + if (!pipe_ctx->stream_res.stream_enc || !pipe_ctx->stream_res.tg) + return; + + dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start, + &vupdate_end); + + dc->hwss.get_position(&pipe_ctx, 1, &position); + vpos = position.vertical_count; + + /* Avoid wraparound calculation issues */ + vupdate_start += stream->timing.v_total; + vupdate_end += stream->timing.v_total; + vpos += stream->timing.v_total; + + if (vpos <= vupdate_start) { + /* VPOS is in VACTIVE or back porch. */ + lines_to_vupdate = vupdate_start - vpos; + } else if (vpos > vupdate_end) { + /* VPOS is in the front porch. */ + return; + } else { + /* VPOS is in VUPDATE. */ + lines_to_vupdate = 0; + } + + /* Calculate time until VUPDATE in microseconds. */ + us_per_line = + stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz; + us_to_vupdate = lines_to_vupdate * us_per_line; + + /* 70 us is a conservative estimate of cursor update time*/ + if (us_to_vupdate > 70) + return; + + /* Stall out until the cursor update completes. */ + if (vupdate_end < vupdate_start) + vupdate_end += stream->timing.v_total; + us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line; + udelay(us_to_vupdate + us_vupdate); +} + +void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock) +{ + /* cursor lock is per MPCC tree, so only need to lock one pipe per stream */ + if (!pipe || pipe->top_pipe) + return; + + /* Prevent cursor lock from stalling out cursor updates. */ + if (lock) + delay_cursor_until_vupdate(dc, pipe); + + if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) { + union dmub_hw_lock_flags hw_locks = { 0 }; + struct dmub_hw_lock_inst_flags inst_flags = { 0 }; + + hw_locks.bits.lock_cursor = 1; + inst_flags.opp_inst = pipe->stream_res.opp->inst; + + dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, + lock, + &hw_locks, + &inst_flags); + } else + dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc, + pipe->stream_res.opp->inst, lock); +} + +static bool wait_for_reset_trigger_to_occur( + struct dc_context *dc_ctx, + struct timing_generator *tg) +{ + bool rc = false; + + DC_LOGGER_INIT(dc_ctx->logger); + + /* To avoid endless loop we wait at most + * frames_to_wait_on_triggered_reset frames for the reset to occur. */ + const uint32_t frames_to_wait_on_triggered_reset = 10; + int i; + + for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { + + if (!tg->funcs->is_counter_moving(tg)) { + DC_ERROR("TG counter is not moving!\n"); + break; + } + + if (tg->funcs->did_triggered_reset_occur(tg)) { + rc = true; + /* usually occurs at i=1 */ + DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", + i); + break; + } + + /* Wait for one frame. */ + tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); + tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); + } + + if (false == rc) + DC_ERROR("GSL: Timeout on reset trigger!\n"); + + return rc; +} + +static uint64_t reduceSizeAndFraction(uint64_t *numerator, + uint64_t *denominator, + bool checkUint32Bounary) +{ + int i; + bool ret = checkUint32Bounary == false; + uint64_t max_int32 = 0xffffffff; + uint64_t num, denom; + static const uint16_t prime_numbers[] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, + 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, + 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, + 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, + 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, + 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, + 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, + 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, + 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, + 941, 947, 953, 967, 971, 977, 983, 991, 997}; + int count = ARRAY_SIZE(prime_numbers); + + num = *numerator; + denom = *denominator; + for (i = 0; i < count; i++) { + uint32_t num_remainder, denom_remainder; + uint64_t num_result, denom_result; + if (checkUint32Bounary && + num <= max_int32 && denom <= max_int32) { + ret = true; + break; + } + do { + num_result = div_u64_rem(num, prime_numbers[i], &num_remainder); + denom_result = div_u64_rem(denom, prime_numbers[i], &denom_remainder); + if (num_remainder == 0 && denom_remainder == 0) { + num = num_result; + denom = denom_result; + } + } while (num_remainder == 0 && denom_remainder == 0); + } + *numerator = num; + *denominator = denom; + return ret; +} + +static bool is_low_refresh_rate(struct pipe_ctx *pipe) +{ + uint32_t master_pipe_refresh_rate = + pipe->stream->timing.pix_clk_100hz * 100 / + pipe->stream->timing.h_total / + pipe->stream->timing.v_total; + return master_pipe_refresh_rate <= 30; +} + +static uint8_t get_clock_divider(struct pipe_ctx *pipe, + bool account_low_refresh_rate) +{ + uint32_t clock_divider = 1; + uint32_t numpipes = 1; + + if (account_low_refresh_rate && is_low_refresh_rate(pipe)) + clock_divider *= 2; + + if (pipe->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) + clock_divider *= 2; + + while (pipe->next_odm_pipe) { + pipe = pipe->next_odm_pipe; + numpipes++; + } + clock_divider *= numpipes; + + return clock_divider; +} + +static int dcn10_align_pixel_clocks(struct dc *dc, int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + int i, master = -1, embedded = -1; + struct dc_crtc_timing *hw_crtc_timing; + uint64_t phase[MAX_PIPES]; + uint64_t modulo[MAX_PIPES]; + unsigned int pclk; + + uint32_t embedded_pix_clk_100hz; + uint16_t embedded_h_total; + uint16_t embedded_v_total; + uint32_t dp_ref_clk_100hz = + dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10; + + DC_LOGGER_INIT(dc_ctx->logger); + + hw_crtc_timing = kcalloc(MAX_PIPES, sizeof(*hw_crtc_timing), GFP_KERNEL); + if (!hw_crtc_timing) + return master; + + if (dc->config.vblank_alignment_dto_params && + dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) { + embedded_h_total = + (dc->config.vblank_alignment_dto_params >> 32) & 0x7FFF; + embedded_v_total = + (dc->config.vblank_alignment_dto_params >> 48) & 0x7FFF; + embedded_pix_clk_100hz = + dc->config.vblank_alignment_dto_params & 0xFFFFFFFF; + + for (i = 0; i < group_size; i++) { + grouped_pipes[i]->stream_res.tg->funcs->get_hw_timing( + grouped_pipes[i]->stream_res.tg, + &hw_crtc_timing[i]); + dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( + dc->res_pool->dp_clock_source, + grouped_pipes[i]->stream_res.tg->inst, + &pclk); + hw_crtc_timing[i].pix_clk_100hz = pclk; + if (dc_is_embedded_signal( + grouped_pipes[i]->stream->signal)) { + embedded = i; + master = i; + phase[i] = embedded_pix_clk_100hz*100; + modulo[i] = dp_ref_clk_100hz*100; + } else { + + phase[i] = (uint64_t)embedded_pix_clk_100hz* + hw_crtc_timing[i].h_total* + hw_crtc_timing[i].v_total; + phase[i] = div_u64(phase[i], get_clock_divider(grouped_pipes[i], true)); + modulo[i] = (uint64_t)dp_ref_clk_100hz* + embedded_h_total* + embedded_v_total; + + if (reduceSizeAndFraction(&phase[i], + &modulo[i], true) == false) { + /* + * this will help to stop reporting + * this timing synchronizable + */ + DC_SYNC_INFO("Failed to reduce DTO parameters\n"); + grouped_pipes[i]->stream->has_non_synchronizable_pclk = true; + } + } + } + + for (i = 0; i < group_size; i++) { + if (i != embedded && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) { + dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk( + dc->res_pool->dp_clock_source, + grouped_pipes[i]->stream_res.tg->inst, + phase[i], modulo[i]); + dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( + dc->res_pool->dp_clock_source, + grouped_pipes[i]->stream_res.tg->inst, &pclk); + grouped_pipes[i]->stream->timing.pix_clk_100hz = + pclk*get_clock_divider(grouped_pipes[i], false); + if (master == -1) + master = i; + } + } + + } + + kfree(hw_crtc_timing); + return master; +} + +void dcn10_enable_vblanks_synchronization( + struct dc *dc, + int group_index, + int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + struct output_pixel_processor *opp; + struct timing_generator *tg; + int i, width, height, master; + + DC_LOGGER_INIT(dc_ctx->logger); + + for (i = 1; i < group_size; i++) { + opp = grouped_pipes[i]->stream_res.opp; + tg = grouped_pipes[i]->stream_res.tg; + tg->funcs->get_otg_active_size(tg, &width, &height); + + if (!tg->funcs->is_tg_enabled(tg)) { + DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); + return; + } + + if (opp->funcs->opp_program_dpg_dimensions) + opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); + } + + for (i = 0; i < group_size; i++) { + if (grouped_pipes[i]->stream == NULL) + continue; + grouped_pipes[i]->stream->vblank_synchronized = false; + grouped_pipes[i]->stream->has_non_synchronizable_pclk = false; + } + + DC_SYNC_INFO("Aligning DP DTOs\n"); + + master = dcn10_align_pixel_clocks(dc, group_size, grouped_pipes); + + DC_SYNC_INFO("Synchronizing VBlanks\n"); + + if (master >= 0) { + for (i = 0; i < group_size; i++) { + if (i != master && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) + grouped_pipes[i]->stream_res.tg->funcs->align_vblanks( + grouped_pipes[master]->stream_res.tg, + grouped_pipes[i]->stream_res.tg, + grouped_pipes[master]->stream->timing.pix_clk_100hz, + grouped_pipes[i]->stream->timing.pix_clk_100hz, + get_clock_divider(grouped_pipes[master], false), + get_clock_divider(grouped_pipes[i], false)); + grouped_pipes[i]->stream->vblank_synchronized = true; + } + grouped_pipes[master]->stream->vblank_synchronized = true; + DC_SYNC_INFO("Sync complete\n"); + } + + for (i = 1; i < group_size; i++) { + opp = grouped_pipes[i]->stream_res.opp; + tg = grouped_pipes[i]->stream_res.tg; + tg->funcs->get_otg_active_size(tg, &width, &height); + if (opp->funcs->opp_program_dpg_dimensions) + opp->funcs->opp_program_dpg_dimensions(opp, width, height); + } +} + +void dcn10_enable_timing_synchronization( + struct dc *dc, + int group_index, + int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + struct output_pixel_processor *opp; + struct timing_generator *tg; + int i, width, height; + + DC_LOGGER_INIT(dc_ctx->logger); + + DC_SYNC_INFO("Setting up OTG reset trigger\n"); + + for (i = 1; i < group_size; i++) { + if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + continue; + + opp = grouped_pipes[i]->stream_res.opp; + tg = grouped_pipes[i]->stream_res.tg; + tg->funcs->get_otg_active_size(tg, &width, &height); + + if (!tg->funcs->is_tg_enabled(tg)) { + DC_SYNC_INFO("Skipping timing sync on disabled OTG\n"); + return; + } + + if (opp->funcs->opp_program_dpg_dimensions) + opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1); + } + + for (i = 0; i < group_size; i++) { + if (grouped_pipes[i]->stream == NULL) + continue; + + if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + continue; + + grouped_pipes[i]->stream->vblank_synchronized = false; + } + + for (i = 1; i < group_size; i++) { + if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + continue; + + grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( + grouped_pipes[i]->stream_res.tg, + grouped_pipes[0]->stream_res.tg->inst); + } + + DC_SYNC_INFO("Waiting for trigger\n"); + + /* Need to get only check 1 pipe for having reset as all the others are + * synchronized. Look at last pipe programmed to reset. + */ + + if (grouped_pipes[1]->stream && grouped_pipes[1]->stream->mall_stream_config.type != SUBVP_PHANTOM) + wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg); + + for (i = 1; i < group_size; i++) { + if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + continue; + + grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( + grouped_pipes[i]->stream_res.tg); + } + + for (i = 1; i < group_size; i++) { + if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + continue; + + opp = grouped_pipes[i]->stream_res.opp; + tg = grouped_pipes[i]->stream_res.tg; + tg->funcs->get_otg_active_size(tg, &width, &height); + if (opp->funcs->opp_program_dpg_dimensions) + opp->funcs->opp_program_dpg_dimensions(opp, width, height); + } + + DC_SYNC_INFO("Sync complete\n"); +} + +void dcn10_enable_per_frame_crtc_position_reset( + struct dc *dc, + int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + int i; + + DC_LOGGER_INIT(dc_ctx->logger); + + DC_SYNC_INFO("Setting up\n"); + for (i = 0; i < group_size; i++) + if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) + grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( + grouped_pipes[i]->stream_res.tg, + 0, + &grouped_pipes[i]->stream->triggered_crtc_reset); + + DC_SYNC_INFO("Waiting for trigger\n"); + + for (i = 0; i < group_size; i++) + wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); + + DC_SYNC_INFO("Multi-display sync is complete\n"); +} + +static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1, + struct vm_system_aperture_param *apt, + struct dce_hwseq *hws) +{ + PHYSICAL_ADDRESS_LOC physical_page_number; + uint32_t logical_addr_low; + uint32_t logical_addr_high; + + REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, + PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part); + REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, + PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part); + + REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR, + LOGICAL_ADDR, &logical_addr_low); + + REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, + LOGICAL_ADDR, &logical_addr_high); + + apt->sys_default.quad_part = physical_page_number.quad_part << 12; + apt->sys_low.quad_part = (int64_t)logical_addr_low << 18; + apt->sys_high.quad_part = (int64_t)logical_addr_high << 18; +} + +/* Temporary read settings, future will get values from kmd directly */ +static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, + struct vm_context0_param *vm0, + struct dce_hwseq *hws) +{ + PHYSICAL_ADDRESS_LOC fb_base; + PHYSICAL_ADDRESS_LOC fb_offset; + uint32_t fb_base_value; + uint32_t fb_offset_value; + + REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value); + REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value); + + REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, + PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part); + REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, + PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part); + + REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, + LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part); + REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, + LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part); + + REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, + LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part); + REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, + LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part); + + REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, + PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part); + REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, + PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part); + + /* + * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space. + * Therefore we need to do + * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE + */ + fb_base.quad_part = (uint64_t)fb_base_value << 24; + fb_offset.quad_part = (uint64_t)fb_offset_value << 24; + vm0->pte_base.quad_part += fb_base.quad_part; + vm0->pte_base.quad_part -= fb_offset.quad_part; +} + + +static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + struct vm_system_aperture_param apt = {0}; + struct vm_context0_param vm0 = {0}; + + mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws); + mmhub_read_vm_context0_settings(hubp1, &vm0, hws); + + hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt); + hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0); +} + +static void dcn10_enable_plane( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + + if (dc->debug.sanity_checks) { + hws->funcs.verify_allow_pstate_change_high(dc); + } + + undo_DEGVIDCN10_253_wa(dc); + + power_on_plane_resources(dc->hwseq, + pipe_ctx->plane_res.hubp->inst); + + /* enable DCFCLK current DCHUB */ + pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); + + /* make sure OPP_PIPE_CLOCK_EN = 1 */ + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); + + if (dc->config.gpu_vm_support) + dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); + + if (dc->debug.sanity_checks) { + hws->funcs.verify_allow_pstate_change_high(dc); + } + + if (!pipe_ctx->top_pipe + && pipe_ctx->plane_state + && pipe_ctx->plane_state->flip_int_enabled + && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) + pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); + +} + +void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) +{ + int i = 0; + struct dpp_grph_csc_adjustment adjust; + memset(&adjust, 0, sizeof(adjust)); + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + + if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + } else if (pipe_ctx->plane_state && + pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + adjust.temperature_matrix[i] = + pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; + } + + pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); +} + + +static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace) +{ + if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) { + if (pipe_ctx->top_pipe) { + struct pipe_ctx *top = pipe_ctx->top_pipe; + + while (top->top_pipe) + top = top->top_pipe; // Traverse to top pipe_ctx + if (top->plane_state && top->plane_state->layer_index == 0) + return true; // Front MPO plane not hidden + } + } + return false; +} + +static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix) +{ + // Override rear plane RGB bias to fix MPO brightness + uint16_t rgb_bias = matrix[3]; + + matrix[3] = 0; + matrix[7] = 0; + matrix[11] = 0; + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); + matrix[3] = rgb_bias; + matrix[7] = rgb_bias; + matrix[11] = rgb_bias; +} + +void dcn10_program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id) +{ + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { + if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) { + + /* MPO is broken with RGB colorspaces when OCSC matrix + * brightness offset >= 0 on DCN1 due to OCSC before MPC + * Blending adds offsets from front + rear to rear plane + * + * Fix is to set RGB bias to 0 on rear plane, top plane + * black value pixels add offset instead of rear + front + */ + + int16_t rgb_bias = matrix[3]; + // matrix[3/7/11] are all the same offset value + + if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) { + dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix); + } else { + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); + } + } + } else { + if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); + } +} + +static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) +{ + struct dc_bias_and_scale bns_params = {0}; + + // program the input csc + dpp->funcs->dpp_setup(dpp, + plane_state->format, + EXPANSION_MODE_ZERO, + plane_state->input_csc_color_matrix, + plane_state->color_space, + NULL); + + //set scale and bias registers + build_prescale_params(&bns_params, plane_state); + if (dpp->funcs->dpp_program_bias_and_scale) + dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); +} + +void dcn10_update_visual_confirm_color(struct dc *dc, + struct pipe_ctx *pipe_ctx, + int mpcc_id) +{ + struct mpc *mpc = dc->res_pool->mpc; + + if (mpc->funcs->set_bg_color) { + memcpy(&pipe_ctx->plane_state->visual_confirm_color, &(pipe_ctx->visual_confirm_color), sizeof(struct tg_color)); + mpc->funcs->set_bg_color(mpc, &(pipe_ctx->visual_confirm_color), mpcc_id); + } +} + +void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct mpcc_blnd_cfg blnd_cfg = {0}; + bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; + int mpcc_id; + struct mpcc *new_mpcc; + struct mpc *mpc = dc->res_pool->mpc; + struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); + + blnd_cfg.overlap_only = false; + blnd_cfg.global_gain = 0xff; + + if (per_pixel_alpha) { + /* DCN1.0 has output CM before MPC which seems to screw with + * pre-multiplied alpha. + */ + blnd_cfg.pre_multiplied_alpha = (is_rgb_cspace( + pipe_ctx->stream->output_color_space) + && pipe_ctx->plane_state->pre_multiplied_alpha); + if (pipe_ctx->plane_state->global_alpha) { + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; + blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; + } else { + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; + } + } else { + blnd_cfg.pre_multiplied_alpha = false; + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; + } + + if (pipe_ctx->plane_state->global_alpha) + blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; + else + blnd_cfg.global_alpha = 0xff; + + /* + * TODO: remove hack + * Note: currently there is a bug in init_hw such that + * on resume from hibernate, BIOS sets up MPCC0, and + * we do mpcc_remove but the mpcc cannot go to idle + * after remove. This cause us to pick mpcc1 here, + * which causes a pstate hang for yet unknown reason. + */ + mpcc_id = hubp->inst; + + /* If there is no full update, don't need to touch MPC tree*/ + if (!pipe_ctx->plane_state->update_flags.bits.full_update) { + mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); + return; + } + + /* check if this MPCC is already being used */ + new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); + /* remove MPCC if being used */ + if (new_mpcc != NULL) + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); + else + if (dc->debug.sanity_checks) + mpc->funcs->assert_mpcc_idle_before_connect( + dc->res_pool->mpc, mpcc_id); + + /* Call MPC to insert new plane */ + new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, + mpc_tree_params, + &blnd_cfg, + NULL, + NULL, + hubp->inst, + mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); + + ASSERT(new_mpcc != NULL); + hubp->opp_id = pipe_ctx->stream_res.opp->inst; + hubp->mpcc_id = mpcc_id; +} + +static void update_scaler(struct pipe_ctx *pipe_ctx) +{ + bool per_pixel_alpha = + pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; + + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; + pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP; + /* scaler configuration */ + pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( + pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); +} + +static void dcn10_update_dchubp_dpp( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct plane_size size = plane_state->plane_size; + unsigned int compat_level = 0; + bool should_divided_by_2 = false; + + /* depends on DML calculation, DPP clock value may change dynamically */ + /* If request max dpp clk is lower than current dispclk, no need to + * divided by 2 + */ + if (plane_state->update_flags.bits.full_update) { + + /* new calculated dispclk, dppclk are stored in + * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current + * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz. + * dcn10_validate_bandwidth compute new dispclk, dppclk. + * dispclk will put in use after optimize_bandwidth when + * ramp_up_dispclk_with_dpp is called. + * there are two places for dppclk be put in use. One location + * is the same as the location as dispclk. Another is within + * update_dchubp_dpp which happens between pre_bandwidth and + * optimize_bandwidth. + * dppclk updated within update_dchubp_dpp will cause new + * clock values of dispclk and dppclk not be in use at the same + * time. when clocks are decreased, this may cause dppclk is + * lower than previous configuration and let pipe stuck. + * for example, eDP + external dp, change resolution of DP from + * 1920x1080x144hz to 1280x960x60hz. + * before change: dispclk = 337889 dppclk = 337889 + * change mode, dcn10_validate_bandwidth calculate + * dispclk = 143122 dppclk = 143122 + * update_dchubp_dpp be executed before dispclk be updated, + * dispclk = 337889, but dppclk use new value dispclk /2 = + * 168944. this will cause pipe pstate warning issue. + * solution: between pre_bandwidth and optimize_bandwidth, while + * dispclk is going to be decreased, keep dppclk = dispclk + **/ + if (context->bw_ctx.bw.dcn.clk.dispclk_khz < + dc->clk_mgr->clks.dispclk_khz) + should_divided_by_2 = false; + else + should_divided_by_2 = + context->bw_ctx.bw.dcn.clk.dppclk_khz <= + dc->clk_mgr->clks.dispclk_khz / 2; + + dpp->funcs->dpp_dppclk_control( + dpp, + should_divided_by_2, + true); + + if (dc->res_pool->dccg) + dc->res_pool->dccg->funcs->update_dpp_dto( + dc->res_pool->dccg, + dpp->inst, + pipe_ctx->plane_res.bw.dppclk_khz); + else + dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? + dc->clk_mgr->clks.dispclk_khz / 2 : + dc->clk_mgr->clks.dispclk_khz; + } + + /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG + * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. + * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG + */ + if (plane_state->update_flags.bits.full_update) { + hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); + + hubp->funcs->hubp_setup( + hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs, + &pipe_ctx->rq_regs, + &pipe_ctx->pipe_dlg_param); + hubp->funcs->hubp_setup_interdependent( + hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs); + } + + size.surface_size = pipe_ctx->plane_res.scl_data.viewport; + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.bpp_change) + dcn10_update_dpp(dpp, plane_state); + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.per_pixel_alpha_change || + plane_state->update_flags.bits.global_alpha_change) + hws->funcs.update_mpcc(dc, pipe_ctx); + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.per_pixel_alpha_change || + plane_state->update_flags.bits.global_alpha_change || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.position_change) { + update_scaler(pipe_ctx); + } + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.position_change) { + hubp->funcs->mem_program_viewport( + hubp, + &pipe_ctx->plane_res.scl_data.viewport, + &pipe_ctx->plane_res.scl_data.viewport_c); + } + + if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { + dc->hwss.set_cursor_position(pipe_ctx); + dc->hwss.set_cursor_attribute(pipe_ctx); + + if (dc->hwss.set_cursor_sdr_white_level) + dc->hwss.set_cursor_sdr_white_level(pipe_ctx); + } + + if (plane_state->update_flags.bits.full_update) { + /*gamut remap*/ + dc->hwss.program_gamut_remap(pipe_ctx); + + dc->hwss.program_output_csc(dc, + pipe_ctx, + pipe_ctx->stream->output_color_space, + pipe_ctx->stream->csc_color_matrix.matrix, + pipe_ctx->stream_res.opp->inst); + } + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.pixel_format_change || + plane_state->update_flags.bits.horizontal_mirror_change || + plane_state->update_flags.bits.rotation_change || + plane_state->update_flags.bits.swizzle_change || + plane_state->update_flags.bits.dcc_change || + plane_state->update_flags.bits.bpp_change || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.plane_size_change) { + hubp->funcs->hubp_program_surface_config( + hubp, + plane_state->format, + &plane_state->tiling_info, + &size, + plane_state->rotation, + &plane_state->dcc, + plane_state->horizontal_mirror, + compat_level); + } + + hubp->power_gated = false; + + hws->funcs.update_plane_addr(dc, pipe_ctx); + + if (is_pipe_tree_visible(pipe_ctx)) + hubp->funcs->set_blank(hubp, false); +} + +void dcn10_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank) +{ + enum dc_color_space color_space; + struct tg_color black_color = {0}; + struct stream_resource *stream_res = &pipe_ctx->stream_res; + struct dc_stream_state *stream = pipe_ctx->stream; + + /* program otg blank color */ + color_space = stream->output_color_space; + color_space_to_black_color(dc, color_space, &black_color); + + /* + * The way 420 is packed, 2 channels carry Y component, 1 channel + * alternate between Cb and Cr, so both channels need the pixel + * value for Y + */ + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + black_color.color_r_cr = black_color.color_g_y; + + + if (stream_res->tg->funcs->set_blank_color) + stream_res->tg->funcs->set_blank_color( + stream_res->tg, + &black_color); + + if (!blank) { + if (stream_res->tg->funcs->set_blank) + stream_res->tg->funcs->set_blank(stream_res->tg, blank); + if (stream_res->abm) { + dc->hwss.set_pipe(pipe_ctx); + stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); + } + } else { + dc->hwss.set_abm_immediate_disable(pipe_ctx); + if (stream_res->tg->funcs->set_blank) { + stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK); + stream_res->tg->funcs->set_blank(stream_res->tg, blank); + } + } +} + +void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx) +{ + struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult; + uint32_t hw_mult = 0x1f000; // 1.0 default multiplier + struct custom_float_format fmt; + + fmt.exponenta_bits = 6; + fmt.mantissa_bits = 12; + fmt.sign = true; + + + if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0 + convert_to_custom_float_format(multiplier, &fmt, &hw_mult); + + pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier( + pipe_ctx->plane_res.dpp, hw_mult); +} + +void dcn10_program_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + + if (pipe_ctx->top_pipe == NULL) { + bool blank = !is_pipe_tree_visible(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->program_global_sync( + pipe_ctx->stream_res.tg, + calculate_vready_offset_for_group(pipe_ctx), + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width); + + pipe_ctx->stream_res.tg->funcs->set_vtg_params( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); + + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); + + hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); + } + + if (pipe_ctx->plane_state->update_flags.bits.full_update) + dcn10_enable_plane(dc, pipe_ctx, context); + + dcn10_update_dchubp_dpp(dc, pipe_ctx, context); + + hws->funcs.set_hdr_multiplier(pipe_ctx); + + if (pipe_ctx->plane_state->update_flags.bits.full_update || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change) + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); + + /* dcn10_translate_regamma_to_hw_format takes 750us to finish + * only do gamma programming for full update. + * TODO: This can be further optimized/cleaned up + * Always call this for now since it does memcmp inside before + * doing heavy calculation and programming + */ + if (pipe_ctx->plane_state->update_flags.bits.full_update) + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); +} + +void dcn10_wait_for_pending_cleared(struct dc *dc, + struct dc_state *context) +{ + struct pipe_ctx *pipe_ctx; + struct timing_generator *tg; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe_ctx = &context->res_ctx.pipe_ctx[i]; + tg = pipe_ctx->stream_res.tg; + + /* + * Only wait for top pipe's tg penindg bit + * Also skip if pipe is disabled. + */ + if (pipe_ctx->top_pipe || + !pipe_ctx->stream || !pipe_ctx->plane_state || + !tg->funcs->is_tg_enabled(tg)) + continue; + + /* + * Wait for VBLANK then VACTIVE to ensure we get VUPDATE. + * For some reason waiting for OTG_UPDATE_PENDING cleared + * seems to not trigger the update right away, and if we + * lock again before VUPDATE then we don't get a separated + * operation. + */ + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); + } +} + +void dcn10_post_unlock_program_front_end( + struct dc *dc, + struct dc_state *context) +{ + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->top_pipe && + !pipe_ctx->prev_odm_pipe && + pipe_ctx->stream) { + struct timing_generator *tg = pipe_ctx->stream_res.tg; + + if (context->stream_status[i].plane_count == 0) + false_optc_underflow_wa(dc, pipe_ctx->stream, tg); + } + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) + dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) { + dc->hwss.optimize_bandwidth(dc, context); + break; + } + + if (dc->hwseq->wa.DEGVIDCN10_254) + hubbub1_wm_change_req_wa(dc->res_pool->hubbub); +} + +static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context) +{ + uint8_t i; + + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->timing.timing_3d_format + == TIMING_3D_FORMAT_HW_FRAME_PACKING) { + /* + * Disable stutter + */ + hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false); + break; + } + } +} + +void dcn10_prepare_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubbub *hubbub = dc->res_pool->hubbub; + int min_fclk_khz, min_dcfclk_khz, socclk_khz; + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); + + if (context->stream_count == 0) + context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + false); + + dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + true); + dcn10_stereo_hw_frame_pack_wa(dc, context); + + if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { + DC_FP_START(); + dcn_get_soc_clks( + dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); + DC_FP_END(); + dcn_bw_notify_pplib_of_wm_ranges( + dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); + } + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); +} + +void dcn10_optimize_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubbub *hubbub = dc->res_pool->hubbub; + int min_fclk_khz, min_dcfclk_khz, socclk_khz; + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); + + if (context->stream_count == 0) + context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + true); + + hubbub->funcs->program_watermarks(hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + true); + + dcn10_stereo_hw_frame_pack_wa(dc, context); + + if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { + DC_FP_START(); + dcn_get_soc_clks( + dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); + DC_FP_END(); + dcn_bw_notify_pplib_of_wm_ranges( + dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); + } + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); +} + +void dcn10_set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, struct dc_crtc_timing_adjust adjust) +{ + int i = 0; + struct drr_params params = {0}; + // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow + unsigned int event_triggers = 0x800; + // Note DRR trigger events are generated regardless of whether num frames met. + unsigned int num_frames = 2; + + params.vertical_total_max = adjust.v_total_max; + params.vertical_total_min = adjust.v_total_min; + params.vertical_total_mid = adjust.v_total_mid; + params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num; + /* TODO: If multiple pipes are to be supported, you need + * some GSL stuff. Static screen triggers may be programmed differently + * as well. + */ + for (i = 0; i < num_pipes; i++) { + if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) { + if (pipe_ctx[i]->stream_res.tg->funcs->set_drr) + pipe_ctx[i]->stream_res.tg->funcs->set_drr( + pipe_ctx[i]->stream_res.tg, ¶ms); + if (adjust.v_total_max != 0 && adjust.v_total_min != 0) + if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control) + pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( + pipe_ctx[i]->stream_res.tg, + event_triggers, num_frames); + } + } +} + +void dcn10_get_position(struct pipe_ctx **pipe_ctx, + int num_pipes, + struct crtc_position *position) +{ + int i = 0; + + /* TODO: handle pipes > 1 + */ + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); +} + +void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params) +{ + unsigned int i; + unsigned int triggers = 0; + + if (params->triggers.surface_update) + triggers |= 0x80; + if (params->triggers.cursor_update) + triggers |= 0x2; + if (params->triggers.force_trigger) + triggers |= 0x1; + + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs-> + set_static_screen_control(pipe_ctx[i]->stream_res.tg, + triggers, params->num_frames); +} + +static void dcn10_config_stereo_parameters( + struct dc_stream_state *stream, struct crtc_stereo_flags *flags) +{ + enum view_3d_format view_format = stream->view_format; + enum dc_timing_3d_format timing_3d_format =\ + stream->timing.timing_3d_format; + bool non_stereo_timing = false; + + if (timing_3d_format == TIMING_3D_FORMAT_NONE || + timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE || + timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM) + non_stereo_timing = true; + + if (non_stereo_timing == false && + view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) { + + flags->PROGRAM_STEREO = 1; + flags->PROGRAM_POLARITY = 1; + if (timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE || + timing_3d_format == TIMING_3D_FORMAT_INBAND_FA || + timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || + timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { + + if (stream->link && stream->link->ddc) { + enum display_dongle_type dongle = \ + stream->link->ddc->dongle_type; + + if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || + dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || + dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) + flags->DISABLE_STEREO_DP_SYNC = 1; + } + } + flags->RIGHT_EYE_POLARITY =\ + stream->timing.flags.RIGHT_EYE_3D_POLARITY; + if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) + flags->FRAME_PACKED = 1; + } + + return; +} + +void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) +{ + struct crtc_stereo_flags flags = { 0 }; + struct dc_stream_state *stream = pipe_ctx->stream; + + dcn10_config_stereo_parameters(stream, &flags); + + if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { + if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service)) + dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); + } else { + dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); + } + + pipe_ctx->stream_res.opp->funcs->opp_program_stereo( + pipe_ctx->stream_res.opp, + flags.PROGRAM_STEREO == 1, + &stream->timing); + + pipe_ctx->stream_res.tg->funcs->program_stereo( + pipe_ctx->stream_res.tg, + &stream->timing, + &flags); + + return; +} + +static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst) +{ + int i; + + for (i = 0; i < res_pool->pipe_count; i++) { + if (res_pool->hubps[i]->inst == mpcc_inst) + return res_pool->hubps[i]; + } + ASSERT(false); + return NULL; +} + +void dcn10_wait_for_mpcc_disconnect( + struct dc *dc, + struct resource_pool *res_pool, + struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + int mpcc_inst; + + if (dc->debug.sanity_checks) { + hws->funcs.verify_allow_pstate_change_high(dc); + } + + if (!pipe_ctx->stream_res.opp) + return; + + for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) { + if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) { + struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst); + + if (pipe_ctx->stream_res.tg && + pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) + res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); + pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; + hubp->funcs->set_blank(hubp, true); + } + } + + if (dc->debug.sanity_checks) { + hws->funcs.verify_allow_pstate_change_high(dc); + } + +} + +bool dcn10_dummy_display_power_gating( + struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating) +{ + return true; +} + +void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + bool flip_pending; + struct dc *dc = pipe_ctx->stream->ctx->dc; + + if (plane_state == NULL) + return; + + flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( + pipe_ctx->plane_res.hubp); + + plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending; + + if (!flip_pending) + plane_state->status.current_address = plane_state->status.requested_address; + + if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && + tg->funcs->is_stereo_left_eye) { + plane_state->status.is_right_eye = + !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); + } + + if (dc->hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied) { + struct dce_hwseq *hwseq = dc->hwseq; + struct timing_generator *tg = dc->res_pool->timing_generators[0]; + unsigned int cur_frame = tg->funcs->get_frame_count(tg); + + if (cur_frame != hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame) { + struct hubbub *hubbub = dc->res_pool->hubbub; + + hubbub->funcs->allow_self_refresh_control(hubbub, !dc->debug.disable_stutter); + hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = false; + } + } +} + +void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) +{ + struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; + + /* In DCN, this programming sequence is owned by the hubbub */ + hubbub->funcs->update_dchub(hubbub, dh_data); +} + +static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *test_pipe, *split_pipe; + const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data; + struct rect r1 = scl_data->recout, r2, r2_half; + int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b; + int cur_layer = pipe_ctx->plane_state->layer_index; + + /** + * Disable the cursor if there's another pipe above this with a + * plane that contains this pipe's viewport to prevent double cursor + * and incorrect scaling artifacts. + */ + for (test_pipe = pipe_ctx->top_pipe; test_pipe; + test_pipe = test_pipe->top_pipe) { + // Skip invisible layer and pipe-split plane on same layer + if (!test_pipe->plane_state || + !test_pipe->plane_state->visible || + test_pipe->plane_state->layer_index == cur_layer) + continue; + + r2 = test_pipe->plane_res.scl_data.recout; + r2_r = r2.x + r2.width; + r2_b = r2.y + r2.height; + split_pipe = test_pipe; + + /** + * There is another half plane on same layer because of + * pipe-split, merge together per same height. + */ + for (split_pipe = pipe_ctx->top_pipe; split_pipe; + split_pipe = split_pipe->top_pipe) + if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) { + r2_half = split_pipe->plane_res.scl_data.recout; + r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x; + r2.width = r2.width + r2_half.width; + r2_r = r2.x + r2.width; + break; + } + + if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b) + return true; + } + + return false; +} + +void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + struct dc_cursor_mi_param param = { + .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, + .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz, + .viewport = pipe_ctx->plane_res.scl_data.viewport, + .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, + .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, + .rotation = pipe_ctx->plane_state->rotation, + .mirror = pipe_ctx->plane_state->horizontal_mirror + }; + bool pipe_split_on = false; + bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) || + (pipe_ctx->prev_odm_pipe != NULL); + + int x_plane = pipe_ctx->plane_state->dst_rect.x; + int y_plane = pipe_ctx->plane_state->dst_rect.y; + int x_pos = pos_cpy.x; + int y_pos = pos_cpy.y; + + if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) { + if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) || + (pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) { + pipe_split_on = true; + } + } + + /** + * DC cursor is stream space, HW cursor is plane space and drawn + * as part of the framebuffer. + * + * Cursor position can't be negative, but hotspot can be used to + * shift cursor out of the plane bounds. Hotspot must be smaller + * than the cursor size. + */ + + /** + * Translate cursor from stream space to plane space. + * + * If the cursor is scaled then we need to scale the position + * to be in the approximately correct place. We can't do anything + * about the actual size being incorrect, that's a limitation of + * the hardware. + */ + if (param.rotation == ROTATION_ANGLE_90 || param.rotation == ROTATION_ANGLE_270) { + x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.height / + pipe_ctx->plane_state->dst_rect.width; + y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.width / + pipe_ctx->plane_state->dst_rect.height; + } else { + x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width / + pipe_ctx->plane_state->dst_rect.width; + y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height / + pipe_ctx->plane_state->dst_rect.height; + } + + /** + * If the cursor's source viewport is clipped then we need to + * translate the cursor to appear in the correct position on + * the screen. + * + * This translation isn't affected by scaling so it needs to be + * done *after* we adjust the position for the scale factor. + * + * This is only done by opt-in for now since there are still + * some usecases like tiled display that might enable the + * cursor on both streams while expecting dc to clip it. + */ + if (pos_cpy.translate_by_source) { + x_pos += pipe_ctx->plane_state->src_rect.x; + y_pos += pipe_ctx->plane_state->src_rect.y; + } + + /** + * If the position is negative then we need to add to the hotspot + * to shift the cursor outside the plane. + */ + + if (x_pos < 0) { + pos_cpy.x_hotspot -= x_pos; + x_pos = 0; + } + + if (y_pos < 0) { + pos_cpy.y_hotspot -= y_pos; + y_pos = 0; + } + + pos_cpy.x = (uint32_t)x_pos; + pos_cpy.y = (uint32_t)y_pos; + + if (pipe_ctx->plane_state->address.type + == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) + pos_cpy.enable = false; + + if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx)) + pos_cpy.enable = false; + + + if (param.rotation == ROTATION_ANGLE_0) { + int viewport_width = + pipe_ctx->plane_res.scl_data.viewport.width; + int viewport_x = + pipe_ctx->plane_res.scl_data.viewport.x; + + if (param.mirror) { + if (pipe_split_on || odm_combine_on) { + if (pos_cpy.x >= viewport_width + viewport_x) { + pos_cpy.x = 2 * viewport_width + - pos_cpy.x + 2 * viewport_x; + } else { + uint32_t temp_x = pos_cpy.x; + + pos_cpy.x = 2 * viewport_x - pos_cpy.x; + if (temp_x >= viewport_x + + (int)hubp->curs_attr.width || pos_cpy.x + <= (int)hubp->curs_attr.width + + pipe_ctx->plane_state->src_rect.x) { + pos_cpy.x = temp_x + viewport_width; + } + } + } else { + pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; + } + } + } + // Swap axis and mirror horizontally + else if (param.rotation == ROTATION_ANGLE_90) { + uint32_t temp_x = pos_cpy.x; + + pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width - + (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x; + pos_cpy.y = temp_x; + } + // Swap axis and mirror vertically + else if (param.rotation == ROTATION_ANGLE_270) { + uint32_t temp_y = pos_cpy.y; + int viewport_height = + pipe_ctx->plane_res.scl_data.viewport.height; + int viewport_y = + pipe_ctx->plane_res.scl_data.viewport.y; + + /** + * Display groups that are 1xnY, have pos_cpy.x > 2 * viewport.height + * For pipe split cases: + * - apply offset of viewport.y to normalize pos_cpy.x + * - calculate the pos_cpy.y as before + * - shift pos_cpy.y back by same offset to get final value + * - since we iterate through both pipes, use the lower + * viewport.y for offset + * For non pipe split cases, use the same calculation for + * pos_cpy.y as the 180 degree rotation case below, + * but use pos_cpy.x as our input because we are rotating + * 270 degrees + */ + if (pipe_split_on || odm_combine_on) { + int pos_cpy_x_offset; + int other_pipe_viewport_y; + + if (pipe_split_on) { + if (pipe_ctx->bottom_pipe) { + other_pipe_viewport_y = + pipe_ctx->bottom_pipe->plane_res.scl_data.viewport.y; + } else { + other_pipe_viewport_y = + pipe_ctx->top_pipe->plane_res.scl_data.viewport.y; + } + } else { + if (pipe_ctx->next_odm_pipe) { + other_pipe_viewport_y = + pipe_ctx->next_odm_pipe->plane_res.scl_data.viewport.y; + } else { + other_pipe_viewport_y = + pipe_ctx->prev_odm_pipe->plane_res.scl_data.viewport.y; + } + } + pos_cpy_x_offset = (viewport_y > other_pipe_viewport_y) ? + other_pipe_viewport_y : viewport_y; + pos_cpy.x -= pos_cpy_x_offset; + if (pos_cpy.x > viewport_height) { + pos_cpy.x = pos_cpy.x - viewport_height; + pos_cpy.y = viewport_height - pos_cpy.x; + } else { + pos_cpy.y = 2 * viewport_height - pos_cpy.x; + } + pos_cpy.y += pos_cpy_x_offset; + } else { + pos_cpy.y = (2 * viewport_y) + viewport_height - pos_cpy.x; + } + pos_cpy.x = temp_y; + } + // Mirror horizontally and vertically + else if (param.rotation == ROTATION_ANGLE_180) { + int viewport_width = + pipe_ctx->plane_res.scl_data.viewport.width; + int viewport_x = + pipe_ctx->plane_res.scl_data.viewport.x; + + if (!param.mirror) { + if (pipe_split_on || odm_combine_on) { + if (pos_cpy.x >= viewport_width + viewport_x) { + pos_cpy.x = 2 * viewport_width + - pos_cpy.x + 2 * viewport_x; + } else { + uint32_t temp_x = pos_cpy.x; + + pos_cpy.x = 2 * viewport_x - pos_cpy.x; + if (temp_x >= viewport_x + + (int)hubp->curs_attr.width || pos_cpy.x + <= (int)hubp->curs_attr.width + + pipe_ctx->plane_state->src_rect.x) { + pos_cpy.x = 2 * viewport_width - temp_x; + } + } + } else { + pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x; + } + } + + /** + * Display groups that are 1xnY, have pos_cpy.y > viewport.height + * Calculation: + * delta_from_bottom = viewport.y + viewport.height - pos_cpy.y + * pos_cpy.y_new = viewport.y + delta_from_bottom + * Simplify it as: + * pos_cpy.y = viewport.y * 2 + viewport.height - pos_cpy.y + */ + pos_cpy.y = (2 * pipe_ctx->plane_res.scl_data.viewport.y) + + pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; + } + + hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); + dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); +} + +void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; + + pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( + pipe_ctx->plane_res.hubp, attributes); + pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( + pipe_ctx->plane_res.dpp, attributes); +} + +void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) +{ + uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; + struct fixed31_32 multiplier; + struct dpp_cursor_attributes opt_attr = { 0 }; + uint32_t hw_scale = 0x3c00; // 1.0 default multiplier + struct custom_float_format fmt; + + if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes) + return; + + fmt.exponenta_bits = 5; + fmt.mantissa_bits = 10; + fmt.sign = true; + + if (sdr_white_level > 80) { + multiplier = dc_fixpt_from_fraction(sdr_white_level, 80); + convert_to_custom_float_format(multiplier, &fmt, &hw_scale); + } + + opt_attr.scale = hw_scale; + opt_attr.bias = 0; + + pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes( + pipe_ctx->plane_res.dpp, &opt_attr); +} + +/* + * apply_front_porch_workaround TODO FPGA still need? + * + * This is a workaround for a bug that has existed since R5xx and has not been + * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. + */ +static void apply_front_porch_workaround( + struct dc_crtc_timing *timing) +{ + if (timing->flags.INTERLACE == 1) { + if (timing->v_front_porch < 2) + timing->v_front_porch = 2; + } else { + if (timing->v_front_porch < 1) + timing->v_front_porch = 1; + } +} + +int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) +{ + const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; + struct dc_crtc_timing patched_crtc_timing; + int vesa_sync_start; + int asic_blank_end; + int interlace_factor; + + patched_crtc_timing = *dc_crtc_timing; + apply_front_porch_workaround(&patched_crtc_timing); + + interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; + + vesa_sync_start = patched_crtc_timing.v_addressable + + patched_crtc_timing.v_border_bottom + + patched_crtc_timing.v_front_porch; + + asic_blank_end = (patched_crtc_timing.v_total - + vesa_sync_start - + patched_crtc_timing.v_border_top) + * interlace_factor; + + return asic_blank_end - + pipe_ctx->pipe_dlg_param.vstartup_start + 1; +} + +void dcn10_calc_vupdate_position( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + uint32_t *start_line, + uint32_t *end_line) +{ + const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + int vupdate_pos = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); + + if (vupdate_pos >= 0) + *start_line = vupdate_pos - ((vupdate_pos / timing->v_total) * timing->v_total); + else + *start_line = vupdate_pos + ((-vupdate_pos / timing->v_total) + 1) * timing->v_total - 1; + *end_line = (*start_line + 2) % timing->v_total; +} + +static void dcn10_cal_vline_position( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + uint32_t *start_line, + uint32_t *end_line) +{ + const struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + int vline_pos = pipe_ctx->stream->periodic_interrupt.lines_offset; + + if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_UPDATE) { + if (vline_pos > 0) + vline_pos--; + else if (vline_pos < 0) + vline_pos++; + + vline_pos += dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); + if (vline_pos >= 0) + *start_line = vline_pos - ((vline_pos / timing->v_total) * timing->v_total); + else + *start_line = vline_pos + ((-vline_pos / timing->v_total) + 1) * timing->v_total - 1; + *end_line = (*start_line + 2) % timing->v_total; + } else if (pipe_ctx->stream->periodic_interrupt.ref_point == START_V_SYNC) { + // vsync is line 0 so start_line is just the requested line offset + *start_line = vline_pos; + *end_line = (*start_line + 2) % timing->v_total; + } else + ASSERT(0); +} + +void dcn10_setup_periodic_interrupt( + struct dc *dc, + struct pipe_ctx *pipe_ctx) +{ + struct timing_generator *tg = pipe_ctx->stream_res.tg; + uint32_t start_line = 0; + uint32_t end_line = 0; + + dcn10_cal_vline_position(dc, pipe_ctx, &start_line, &end_line); + + tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line); +} + +void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct timing_generator *tg = pipe_ctx->stream_res.tg; + int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); + + if (start_line < 0) { + ASSERT(0); + start_line = 0; + } + + if (tg->funcs->setup_vertical_interrupt2) + tg->funcs->setup_vertical_interrupt2(tg, start_line); +} + +void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings) +{ + struct encoder_unblank_param params = {0}; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; + + /* only 3 items below are used by unblank */ + params.timing = pipe_ctx->stream->timing; + + params.link_settings.link_rate = link_settings->link_rate; + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + params.timing.pix_clk_100hz /= 2; + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); + } + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + hws->funcs.edp_backlight_control(link, true); + } +} + +void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size) +{ + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message( + pipe_ctx->stream_res.stream_enc, + custom_sdp_message, + sdp_message_size); + } +} +enum dc_status dcn10_set_clock(struct dc *dc, + enum dc_clock_type clock_type, + uint32_t clk_khz, + uint32_t stepping) +{ + struct dc_state *context = dc->current_state; + struct dc_clock_config clock_cfg = {0}; + struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk; + + if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock) + return DC_FAIL_UNSUPPORTED_1; + + dc->clk_mgr->funcs->get_clock(dc->clk_mgr, + context, clock_type, &clock_cfg); + + if (clk_khz > clock_cfg.max_clock_khz) + return DC_FAIL_CLK_EXCEED_MAX; + + if (clk_khz < clock_cfg.min_clock_khz) + return DC_FAIL_CLK_BELOW_MIN; + + if (clk_khz < clock_cfg.bw_requirequired_clock_khz) + return DC_FAIL_CLK_BELOW_CFG_REQUIRED; + + /*update internal request clock for update clock use*/ + if (clock_type == DC_CLOCK_TYPE_DISPCLK) + current_clocks->dispclk_khz = clk_khz; + else if (clock_type == DC_CLOCK_TYPE_DPPCLK) + current_clocks->dppclk_khz = clk_khz; + else + return DC_ERROR_UNEXPECTED; + + if (dc->clk_mgr->funcs->update_clocks) + dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, + context, true); + return DC_OK; + +} + +void dcn10_get_clock(struct dc *dc, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg) +{ + struct dc_state *context = dc->current_state; + + if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock) + dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); + +} + +void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits) +{ + struct resource_pool *pool = dc->res_pool; + int i; + + for (i = 0; i < pool->pipe_count; i++) { + struct hubp *hubp = pool->hubps[i]; + struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); + + hubp->funcs->hubp_read_state(hubp); + + if (!s->blank_en) + dcc_en_bits[i] = s->dcc_en ? 1 : 0; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h new file mode 100644 index 000000000000..ef6d56da417c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h @@ -0,0 +1,207 @@ +/* +* Copyright 2016-2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN10_H__ +#define __DC_HWSS_DCN10_H__ + +#include "core_types.h" +#include "hw_sequencer_private.h" + +struct dc; + +void dcn10_hw_sequencer_construct(struct dc *dc); + +int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx); +void dcn10_calc_vupdate_position( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + uint32_t *start_line, + uint32_t *end_line); +void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); +enum dc_status dcn10_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); +void dcn10_optimize_bandwidth( + struct dc *dc, + struct dc_state *context); +void dcn10_prepare_bandwidth( + struct dc *dc, + struct dc_state *context); +void dcn10_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock); +void dcn10_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); +void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); +void dcn10_program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id); +bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); +bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); +void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context); +void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_lock_all_pipes( + struct dc *dc, + struct dc_state *context, + bool lock); +void dcn10_post_unlock_program_front_end( + struct dc *dc, + struct dc_state *context); +void dcn10_hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); +void dcn10_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); +void dcn10_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable); +void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_disable_vga( + struct dce_hwseq *hws); +void dcn10_program_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); +void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx); +void dcn10_init_hw(struct dc *dc); +void dcn10_init_pipes(struct dc *dc, struct dc_state *context); +void dcn10_power_down_on_boot(struct dc *dc); +enum dc_status dce110_apply_ctx_to_hw( + struct dc *dc, + struct dc_state *context); +void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data); +void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx); +void dce110_power_down(struct dc *dc); +void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); +void dcn10_enable_timing_synchronization( + struct dc *dc, + int group_index, + int group_size, + struct pipe_ctx *grouped_pipes[]); +void dcn10_enable_vblanks_synchronization( + struct dc *dc, + int group_index, + int group_size, + struct pipe_ctx *grouped_pipes[]); +void dcn10_enable_per_frame_crtc_position_reset( + struct dc *dc, + int group_size, + struct pipe_ctx *grouped_pipes[]); +void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); +void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size); +void dce110_blank_stream(struct pipe_ctx *pipe_ctx); +void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx); +bool dcn10_dummy_display_power_gating( + struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating); +void dcn10_set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, struct dc_crtc_timing_adjust adjust); +void dcn10_get_position(struct pipe_ctx **pipe_ctx, + int num_pipes, + struct crtc_position *position); +void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params); +void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc); +void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); +void dcn10_log_hw_state(struct dc *dc, + struct dc_log_buffer_ctx *log_ctx); +void dcn10_get_hw_state(struct dc *dc, + char *pBuf, + unsigned int bufSize, + unsigned int mask); +void dcn10_clear_status_bits(struct dc *dc, unsigned int mask); +void dcn10_wait_for_mpcc_disconnect( + struct dc *dc, + struct resource_pool *res_pool, + struct pipe_ctx *pipe_ctx); +void dce110_edp_backlight_control( + struct dc_link *link, + bool enable); +void dce110_edp_wait_for_T12( + struct dc_link *link); +void dce110_edp_power_control( + struct dc_link *link, + bool power_up); +void dce110_edp_wait_for_hpd_ready( + struct dc_link *link, + bool power_up); +void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx); +void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx); +void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx); +void dcn10_setup_periodic_interrupt( + struct dc *dc, + struct pipe_ctx *pipe_ctx); +enum dc_status dcn10_set_clock(struct dc *dc, + enum dc_clock_type clock_type, + uint32_t clk_khz, + uint32_t stepping); +void dcn10_get_clock(struct dc *dc, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg); +bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_bios_golden_init(struct dc *dc); +void dcn10_plane_atomic_power_down(struct dc *dc, + struct dpp *dpp, + struct hubp *hubp); +bool dcn10_disconnect_pipes( + struct dc *dc, + struct dc_state *context); + +void dcn10_wait_for_pending_cleared(struct dc *dc, + struct dc_state *context); +void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx); +void dcn10_verify_allow_pstate_change_high(struct dc *dc); + +void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits); + +void dcn10_update_visual_confirm_color( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + int mpcc_id); + +#endif /* __DC_HWSS_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c new file mode 100644 index 000000000000..d8c02f83b7d7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -0,0 +1,2941 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#include + +#include "dm_services.h" +#include "basics/dc_common.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dcn20/dcn20_resource.h" +#include "dcn20_hwseq.h" +#include "dce/dce_hwseq.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn20/dcn20_optc.h" +#include "abm.h" +#include "clk_mgr.h" +#include "dmcu.h" +#include "hubp.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "dchubbub.h" +#include "reg_helper.h" +#include "dcn10/dcn10_cm_common.h" +#include "vm_helper.h" +#include "dccg.h" +#include "dc_dmub_srv.h" +#include "dce/dmub_hw_lock_mgr.h" +#include "hw_sequencer.h" +#include "dpcd_defs.h" +#include "inc/link_enc_cfg.h" +#include "link_hwss.h" +#include "link.h" + +#define DC_LOGGER \ + dc_logger +#define DC_LOGGER_INIT(logger) \ + struct dal_logger *dc_logger = logger + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +static int find_free_gsl_group(const struct dc *dc) +{ + if (dc->res_pool->gsl_groups.gsl_0 == 0) + return 1; + if (dc->res_pool->gsl_groups.gsl_1 == 0) + return 2; + if (dc->res_pool->gsl_groups.gsl_2 == 0) + return 3; + + return 0; +} + +/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock) + * This is only used to lock pipes in pipe splitting case with immediate flip + * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate, + * so we get tearing with freesync since we cannot flip multiple pipes + * atomically. + * We use GSL for this: + * - immediate flip: find first available GSL group if not already assigned + * program gsl with that group, set current OTG as master + * and always us 0x4 = AND of flip_ready from all pipes + * - vsync flip: disable GSL if used + * + * Groups in stream_res are stored as +1 from HW registers, i.e. + * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1 + * Using a magic value like -1 would require tracking all inits/resets + */ + void dcn20_setup_gsl_group_as_lock( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable) +{ + struct gsl_params gsl; + int group_idx; + + memset(&gsl, 0, sizeof(struct gsl_params)); + + if (enable) { + /* return if group already assigned since GSL was set up + * for vsync flip, we would unassign so it can't be "left over" + */ + if (pipe_ctx->stream_res.gsl_group > 0) + return; + + group_idx = find_free_gsl_group(dc); + ASSERT(group_idx != 0); + pipe_ctx->stream_res.gsl_group = group_idx; + + /* set gsl group reg field and mark resource used */ + switch (group_idx) { + case 1: + gsl.gsl0_en = 1; + dc->res_pool->gsl_groups.gsl_0 = 1; + break; + case 2: + gsl.gsl1_en = 1; + dc->res_pool->gsl_groups.gsl_1 = 1; + break; + case 3: + gsl.gsl2_en = 1; + dc->res_pool->gsl_groups.gsl_2 = 1; + break; + default: + BREAK_TO_DEBUGGER(); + return; // invalid case + } + gsl.gsl_master_en = 1; + } else { + group_idx = pipe_ctx->stream_res.gsl_group; + if (group_idx == 0) + return; // if not in use, just return + + pipe_ctx->stream_res.gsl_group = 0; + + /* unset gsl group reg field and mark resource free */ + switch (group_idx) { + case 1: + gsl.gsl0_en = 0; + dc->res_pool->gsl_groups.gsl_0 = 0; + break; + case 2: + gsl.gsl1_en = 0; + dc->res_pool->gsl_groups.gsl_1 = 0; + break; + case 3: + gsl.gsl2_en = 0; + dc->res_pool->gsl_groups.gsl_2 = 0; + break; + default: + BREAK_TO_DEBUGGER(); + return; + } + gsl.gsl_master_en = 0; + } + + /* at this point we want to program whether it's to enable or disable */ + if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL && + pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) { + pipe_ctx->stream_res.tg->funcs->set_gsl( + pipe_ctx->stream_res.tg, + &gsl); + + pipe_ctx->stream_res.tg->funcs->set_gsl_source_select( + pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0); + } else + BREAK_TO_DEBUGGER(); +} + +void dcn20_set_flip_control_gsl( + struct pipe_ctx *pipe_ctx, + bool flip_immediate) +{ + if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl) + pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl( + pipe_ctx->plane_res.hubp, flip_immediate); + +} + +void dcn20_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable) +{ + bool force_on = true; /* disable power gating */ + uint32_t org_ip_request_cntl = 0; + + if (enable) + force_on = false; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + /* DCHUBP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); + if (REG(DOMAIN8_PG_CONFIG)) + REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); + if (REG(DOMAIN10_PG_CONFIG)) + REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); + + /* DPP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); + if (REG(DOMAIN9_PG_CONFIG)) + REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); + if (REG(DOMAIN11_PG_CONFIG)) + REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); + + /* DCS0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on); + if (REG(DOMAIN19_PG_CONFIG)) + REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on); + if (REG(DOMAIN20_PG_CONFIG)) + REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on); + if (REG(DOMAIN21_PG_CONFIG)) + REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on); + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); + +} + +void dcn20_dccg_init(struct dce_hwseq *hws) +{ + /* + * set MICROSECOND_TIME_BASE_DIV + * 100Mhz refclk -> 0x120264 + * 27Mhz refclk -> 0x12021b + * 48Mhz refclk -> 0x120230 + * + */ + REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264); + + /* + * set MILLISECOND_TIME_BASE_DIV + * 100Mhz refclk -> 0x1186a0 + * 27Mhz refclk -> 0x106978 + * 48Mhz refclk -> 0x10bb80 + * + */ + REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0); + + /* This value is dependent on the hardware pipeline delay so set once per SOC */ + REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c); +} + +void dcn20_disable_vga( + struct dce_hwseq *hws) +{ + REG_WRITE(D1VGA_CONTROL, 0); + REG_WRITE(D2VGA_CONTROL, 0); + REG_WRITE(D3VGA_CONTROL, 0); + REG_WRITE(D4VGA_CONTROL, 0); + REG_WRITE(D5VGA_CONTROL, 0); + REG_WRITE(D6VGA_CONTROL, 0); +} + +void dcn20_program_triple_buffer( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable_triple_buffer) +{ + if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) { + pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer( + pipe_ctx->plane_res.hubp, + enable_triple_buffer); + } +} + +/* Blank pixel data during initialization */ +void dcn20_init_blank( + struct dc *dc, + struct timing_generator *tg) +{ + struct dce_hwseq *hws = dc->hwseq; + enum dc_color_space color_space; + struct tg_color black_color = {0}; + struct output_pixel_processor *opp = NULL; + struct output_pixel_processor *bottom_opp = NULL; + uint32_t num_opps, opp_id_src0, opp_id_src1; + uint32_t otg_active_width, otg_active_height; + + /* program opp dpg blank color */ + color_space = COLOR_SPACE_SRGB; + color_space_to_black_color(dc, color_space, &black_color); + + /* get the OTG active size */ + tg->funcs->get_otg_active_size(tg, + &otg_active_width, + &otg_active_height); + + /* get the OPTC source */ + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + + if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) { + ASSERT(false); + return; + } + opp = dc->res_pool->opps[opp_id_src0]; + + /* don't override the blank pattern if already enabled with the correct one. */ + if (opp->funcs->dpg_is_blanked && opp->funcs->dpg_is_blanked(opp)) + return; + + if (num_opps == 2) { + otg_active_width = otg_active_width / 2; + + if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) { + ASSERT(false); + return; + } + bottom_opp = dc->res_pool->opps[opp_id_src1]; + } + + opp->funcs->opp_set_disp_pattern_generator( + opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height, + 0); + + if (num_opps == 2) { + bottom_opp->funcs->opp_set_disp_pattern_generator( + bottom_opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height, + 0); + } + + hws->funcs.wait_for_blank_complete(opp); +} + +void dcn20_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + + if (REG(DOMAIN16_PG_CONFIG) == 0) + return; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN16_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN16_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN17_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN17_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN18_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN18_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DSC3 */ + REG_UPDATE(DOMAIN19_PG_CONFIG, + DOMAIN19_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN19_PG_STATUS, + DOMAIN19_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DSC4 */ + REG_UPDATE(DOMAIN20_PG_CONFIG, + DOMAIN20_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN20_PG_STATUS, + DOMAIN20_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 5: /* DSC5 */ + REG_UPDATE(DOMAIN21_PG_CONFIG, + DOMAIN21_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN21_PG_STATUS, + DOMAIN21_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + +void dcn20_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_dpp_power_gate) + return; + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; + + switch (dpp_inst) { + case 0: /* DPP0 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, + DOMAIN1_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN1_PG_STATUS, + DOMAIN1_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DPP1 */ + REG_UPDATE(DOMAIN3_PG_CONFIG, + DOMAIN3_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN3_PG_STATUS, + DOMAIN3_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DPP2 */ + REG_UPDATE(DOMAIN5_PG_CONFIG, + DOMAIN5_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN5_PG_STATUS, + DOMAIN5_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DPP3 */ + REG_UPDATE(DOMAIN7_PG_CONFIG, + DOMAIN7_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN7_PG_STATUS, + DOMAIN7_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DPP4 */ + REG_UPDATE(DOMAIN9_PG_CONFIG, + DOMAIN9_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN9_PG_STATUS, + DOMAIN9_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 5: /* DPP5 */ + /* + * Do not power gate DPP5, should be left at HW default, power on permanently. + * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard + * reset. + * REG_UPDATE(DOMAIN11_PG_CONFIG, + * DOMAIN11_POWER_GATE, power_gate); + * + * REG_WAIT(DOMAIN11_PG_STATUS, + * DOMAIN11_PGFSM_PWR_STATUS, pwr_status, + * 1, 1000); + */ + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + + +void dcn20_hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; + + switch (hubp_inst) { + case 0: /* DCHUBP0 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, + DOMAIN0_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN0_PG_STATUS, + DOMAIN0_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DCHUBP1 */ + REG_UPDATE(DOMAIN2_PG_CONFIG, + DOMAIN2_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN2_PG_STATUS, + DOMAIN2_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DCHUBP2 */ + REG_UPDATE(DOMAIN4_PG_CONFIG, + DOMAIN4_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN4_PG_STATUS, + DOMAIN4_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DCHUBP3 */ + REG_UPDATE(DOMAIN6_PG_CONFIG, + DOMAIN6_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN6_PG_STATUS, + DOMAIN6_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DCHUBP4 */ + REG_UPDATE(DOMAIN8_PG_CONFIG, + DOMAIN8_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN8_PG_STATUS, + DOMAIN8_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 5: /* DCHUBP5 */ + /* + * Do not power gate DCHUB5, should be left at HW default, power on permanently. + * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard + * reset. + * REG_UPDATE(DOMAIN10_PG_CONFIG, + * DOMAIN10_POWER_GATE, power_gate); + * + * REG_WAIT(DOMAIN10_PG_STATUS, + * DOMAIN10_PGFSM_PWR_STATUS, pwr_status, + * 1, 1000); + */ + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + + +/* disable HW used by plane. + * note: cannot disable until disconnect is complete + */ +void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); + + /* In flip immediate with pipe splitting case GSL is used for + * synchronization so we must disable it when the plane is disabled. + */ + if (pipe_ctx->stream_res.gsl_group != 0) + dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false); + + if (hubp->funcs->hubp_update_mall_sel) + hubp->funcs->hubp_update_mall_sel(hubp, 0, false); + + dc->hwss.set_flip_control_gsl(pipe_ctx, false); + + hubp->funcs->hubp_clk_cntl(hubp, false); + + dpp->funcs->dpp_dppclk_control(dpp, false, false); + + hubp->power_gated = true; + + hws->funcs.plane_atomic_power_down(dc, + pipe_ctx->plane_res.dpp, + pipe_ctx->plane_res.hubp); + + pipe_ctx->stream = NULL; + memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); + memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->prev_odm_pipe = NULL; + pipe_ctx->next_odm_pipe = NULL; + pipe_ctx->plane_state = NULL; +} + + +void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom; + struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) + return; + + dcn20_plane_atomic_disable(dc, pipe_ctx); + + /* Turn back off the phantom OTG after the phantom plane is fully disabled + */ + if (is_phantom) + if (tg && tg->funcs->disable_phantom_crtc) + tg->funcs->disable_phantom_crtc(tg); + + DC_LOG_DC("Power down front end %d\n", + pipe_ctx->pipe_idx); +} + +void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank) +{ + dcn20_blank_pixel_data(dc, pipe_ctx, blank); +} + +static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, + int opp_cnt) +{ + bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); + int flow_ctrl_cnt; + + if (opp_cnt >= 2) + hblank_halved = true; + + flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - + stream->timing.h_border_left - + stream->timing.h_border_right; + + if (hblank_halved) + flow_ctrl_cnt /= 2; + + /* ODM combine 4:1 case */ + if (opp_cnt == 4) + flow_ctrl_cnt /= 2; + + return flow_ctrl_cnt; +} + +static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link) +{ + switch (link->link_enc->transmitter) { + case TRANSMITTER_UNIPHY_A: + return PHYD32CLKA; + case TRANSMITTER_UNIPHY_B: + return PHYD32CLKB; + case TRANSMITTER_UNIPHY_C: + return PHYD32CLKC; + case TRANSMITTER_UNIPHY_D: + return PHYD32CLKD; + case TRANSMITTER_UNIPHY_E: + return PHYD32CLKE; + default: + return PHYD32CLKA; + } +} + +static int get_odm_segment_count(struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + int count = 1; + + while (odm_pipe != NULL) { + count++; + odm_pipe = odm_pipe->next_odm_pipe; + } + + return count; +} + +enum dc_status dcn20_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + struct dc_stream_state *stream = pipe_ctx->stream; + struct drr_params params = {0}; + unsigned int event_triggers = 0; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; + bool interlace = stream->timing.flags.INTERLACE; + int i; + struct mpc_dwb_flow_control flow_control; + struct mpc *mpc = dc->res_pool->mpc; + bool rate_control_2x_pclk = (interlace || optc2_is_two_pixels_per_containter(&stream->timing)); + unsigned int k1_div = PIXEL_RATE_DIV_NA; + unsigned int k2_div = PIXEL_RATE_DIV_NA; + + if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { + hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); + + dc->res_pool->dccg->funcs->set_pixel_rate_div( + dc->res_pool->dccg, + pipe_ctx->stream_res.tg->inst, + k1_div, k2_div); + } + /* by upper caller loop, pipe0 is parent pipe and be called first. + * back end is set up by for pipe0. Other children pipe share back end + * with pipe 0. No program is needed. + */ + if (pipe_ctx->top_pipe != NULL) + return DC_OK; + + /* TODO check if timing_changed, disable stream if timing changed */ + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; + opp_cnt++; + } + + if (opp_cnt > 1) + pipe_ctx->stream_res.tg->funcs->set_odm_combine( + pipe_ctx->stream_res.tg, + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); + + /* HW program guide assume display already disable + * by unplug sequence. OTG assume stop. + */ + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); + + if (false == pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + if (dc_is_hdmi_tmds_signal(stream->signal)) { + stream->link->phy_state.symclk_ref_cnts.otg = 1; + if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF) + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + else + stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + } + + if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal))) + dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->program_timing( + pipe_ctx->stream_res.tg, + &stream->timing, + pipe_ctx->pipe_dlg_param.vready_offset, + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width, + pipe_ctx->stream->signal, + true); + + rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; + flow_control.flow_ctrl_mode = 0; + flow_control.flow_ctrl_cnt0 = 0x80; + flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt); + if (mpc->funcs->set_out_rate_control) { + for (i = 0; i < opp_cnt; ++i) { + mpc->funcs->set_out_rate_control( + mpc, opp_inst[i], + true, + rate_control_2x_pclk, + &flow_control); + } + } + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( + odm_pipe->stream_res.opp, + true); + + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); + + hws->funcs.blank_pixel_data(dc, pipe_ctx, true); + + /* VTG is within DCHUB command block. DCFCLK is always on */ + if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp); + + params.vertical_total_min = stream->adjust.v_total_min; + params.vertical_total_max = stream->adjust.v_total_max; + params.vertical_total_mid = stream->adjust.v_total_mid; + params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num; + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, ¶ms); + + // DRR should set trigger event to monitor surface update event + if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) + event_triggers = 0x80; + /* Event triggers and num frames initialized for DRR, but can be + * later updated for PSR use. Note DRR trigger events are generated + * regardless of whether num frames met. + */ + if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) + pipe_ctx->stream_res.tg->funcs->set_static_screen_control( + pipe_ctx->stream_res.tg, event_triggers, 2); + + /* TODO program crtc source select for non-virtual signal*/ + /* TODO program FMT */ + /* TODO setup link_enc */ + /* TODO set stream attributes */ + /* TODO program audio */ + /* TODO enable stream if timing changed */ + /* TODO unblank stream if DP */ + + if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (pipe_ctx->stream_res.tg && pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable) + pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg); + } + + if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + struct dccg *dccg = dc->res_pool->dccg; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + struct dtbclk_dto_params dto_params = {0}; + + if (dccg->funcs->set_dtbclk_p_src) + dccg->funcs->set_dtbclk_p_src(dccg, DTBCLK0, tg->inst); + + dto_params.otg_inst = tg->inst; + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; + dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); + dto_params.timing = &pipe_ctx->stream->timing; + dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + } + + return DC_OK; +} + +void dcn20_program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id) +{ + struct mpc *mpc = dc->res_pool->mpc; + enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + + if (mpc->funcs->power_on_mpc_mem_pwr) + mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); + + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { + if (mpc->funcs->set_output_csc != NULL) + mpc->funcs->set_output_csc(mpc, + opp_id, + matrix, + ocsc_mode); + } else { + if (mpc->funcs->set_ocsc_default != NULL) + mpc->funcs->set_ocsc_default(mpc, + opp_id, + colorspace, + ocsc_mode); + } +} + +bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + struct pwl_params *params = NULL; + /* + * program OGAM only for the top pipe + * if there is a pipe split then fix diagnostic is required: + * how to pass OGAM parameter for stream. + * if programming for all pipes is required then remove condition + * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic. + */ + if (mpc->funcs->power_on_mpc_mem_pwr) + mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); + if (pipe_ctx->top_pipe == NULL + && mpc->funcs->set_output_gamma && stream->out_transfer_func) { + if (stream->out_transfer_func->type == TF_TYPE_HWPWL) + params = &stream->out_transfer_func->pwl; + else if (pipe_ctx->stream->out_transfer_func->type == + TF_TYPE_DISTRIBUTED_POINTS && + cm_helper_translate_curve_to_hw_format(dc->ctx, + stream->out_transfer_func, + &mpc->blender_params, false)) + params = &mpc->blender_params; + /* + * there is no ROM + */ + if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) + BREAK_TO_DEBUGGER(); + } + /* + * if above if is not executed then 'params' equal to 0 and set in bypass + */ + mpc->funcs->set_output_gamma(mpc, mpcc_id, params); + + return true; +} + +bool dcn20_set_blend_lut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + bool result = true; + struct pwl_params *blend_lut = NULL; + + if (plane_state->blend_tf) { + if (plane_state->blend_tf->type == TF_TYPE_HWPWL) + blend_lut = &plane_state->blend_tf->pwl; + else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_hw_format(plane_state->ctx, + plane_state->blend_tf, + &dpp_base->regamma_params, false); + blend_lut = &dpp_base->regamma_params; + } + } + result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut); + + return result; +} + +bool dcn20_set_shaper_3dlut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + bool result = true; + struct pwl_params *shaper_lut = NULL; + + if (plane_state->in_shaper_func) { + if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL) + shaper_lut = &plane_state->in_shaper_func->pwl; + else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_hw_format(plane_state->ctx, + plane_state->in_shaper_func, + &dpp_base->shaper_params, true); + shaper_lut = &dpp_base->shaper_params; + } + } + + result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); + if (plane_state->lut3d_func && + plane_state->lut3d_func->state.bits.initialized == 1) + result = dpp_base->funcs->dpp_program_3dlut(dpp_base, + &plane_state->lut3d_func->lut_3d); + else + result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL); + + return result; +} + +bool dcn20_set_input_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) +{ + struct dce_hwseq *hws = dc->hwseq; + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + const struct dc_transfer_func *tf = NULL; + bool result = true; + bool use_degamma_ram = false; + + if (dpp_base == NULL || plane_state == NULL) + return false; + + hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state); + hws->funcs.set_blend_lut(pipe_ctx, plane_state); + + if (plane_state->in_transfer_func) + tf = plane_state->in_transfer_func; + + + if (tf == NULL) { + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + return true; + } + + if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS) + use_degamma_ram = true; + + if (use_degamma_ram == true) { + if (tf->type == TF_TYPE_HWPWL) + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, + &tf->pwl); + else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_degamma_hw_format(tf, + &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, + &dpp_base->degamma_params); + } + return true; + } + /* handle here the optimized cases when de-gamma ROM could be used. + * + */ + if (tf->type == TF_TYPE_PREDEFINED) { + switch (tf->tf) { + case TRANSFER_FUNCTION_SRGB: + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_HW_sRGB); + break; + case TRANSFER_FUNCTION_BT709: + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_HW_xvYCC); + break; + case TRANSFER_FUNCTION_LINEAR: + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + break; + case TRANSFER_FUNCTION_PQ: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL); + cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params); + result = true; + break; + default: + result = false; + break; + } + } else if (tf->type == TF_TYPE_BYPASS) + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + else { + /* + * if we are here, we did not handle correctly. + * fix is required for this use case + */ + BREAK_TO_DEBUGGER(); + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + } + + return result; +} + +void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; + opp_cnt++; + } + + if (opp_cnt > 1) + pipe_ctx->stream_res.tg->funcs->set_odm_combine( + pipe_ctx->stream_res.tg, + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); + else + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); +} + +void dcn20_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank) +{ + struct tg_color black_color = {0}; + struct stream_resource *stream_res = &pipe_ctx->stream_res; + struct dc_stream_state *stream = pipe_ctx->stream; + enum dc_color_space color_space = stream->output_color_space; + enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; + enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; + struct pipe_ctx *odm_pipe; + int odm_cnt = 1; + int h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; + int v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; + int odm_slice_width, last_odm_slice_width, offset = 0; + + if (stream->link->test_pattern_enabled) + return; + + /* get opp dpg blank color */ + color_space_to_black_color(dc, color_space, &black_color); + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + odm_cnt++; + odm_slice_width = h_active / odm_cnt; + last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1); + + if (blank) { + dc->hwss.set_abm_immediate_disable(pipe_ctx); + + if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { + test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; + test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; + } + } else { + test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; + } + + odm_pipe = pipe_ctx; + + while (odm_pipe->next_odm_pipe) { + dc->hwss.set_disp_pattern_generator(dc, + odm_pipe, + test_pattern, + test_pattern_color_space, + stream->timing.display_color_depth, + &black_color, + odm_slice_width, + v_active, + offset); + offset += odm_slice_width; + odm_pipe = odm_pipe->next_odm_pipe; + } + + dc->hwss.set_disp_pattern_generator(dc, + odm_pipe, + test_pattern, + test_pattern_color_space, + stream->timing.display_color_depth, + &black_color, + last_odm_slice_width, + v_active, + offset); + + if (!blank) + if (stream_res->abm) { + dc->hwss.set_pipe(pipe_ctx); + stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); + } +} + + +static void dcn20_power_on_plane_resources( + struct dce_hwseq *hws, + struct pipe_ctx *pipe_ctx) +{ + DC_LOGGER_INIT(hws->ctx->logger); + + if (hws->funcs.dpp_root_clock_control) + hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true); + + if (REG(DC_IP_REQUEST_CNTL)) { + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + + if (hws->funcs.dpp_pg_control) + hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true); + + if (hws->funcs.hubp_pg_control) + hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true); + + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + DC_LOG_DEBUG( + "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst); + } +} + +static void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + //if (dc->debug.sanity_checks) { + // dcn10_verify_allow_pstate_change_high(dc); + //} + dcn20_power_on_plane_resources(dc->hwseq, pipe_ctx); + + /* enable DCFCLK current DCHUB */ + pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); + + /* initialize HUBP on power up */ + pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp); + + /* make sure OPP_PIPE_CLOCK_EN = 1 */ + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); + +/* TODO: enable/disable in dm as per update type. + if (plane_state) { + DC_LOG_DC(dc->ctx->logger, + "Pipe:%d 0x%x: addr hi:0x%x, " + "addr low:0x%x, " + "src: %d, %d, %d," + " %d; dst: %d, %d, %d, %d;\n", + pipe_ctx->pipe_idx, + plane_state, + plane_state->address.grph.addr.high_part, + plane_state->address.grph.addr.low_part, + plane_state->src_rect.x, + plane_state->src_rect.y, + plane_state->src_rect.width, + plane_state->src_rect.height, + plane_state->dst_rect.x, + plane_state->dst_rect.y, + plane_state->dst_rect.width, + plane_state->dst_rect.height); + + DC_LOG_DC(dc->ctx->logger, + "Pipe %d: width, height, x, y format:%d\n" + "viewport:%d, %d, %d, %d\n" + "recout: %d, %d, %d, %d\n", + pipe_ctx->pipe_idx, + plane_state->format, + pipe_ctx->plane_res.scl_data.viewport.width, + pipe_ctx->plane_res.scl_data.viewport.height, + pipe_ctx->plane_res.scl_data.viewport.x, + pipe_ctx->plane_res.scl_data.viewport.y, + pipe_ctx->plane_res.scl_data.recout.width, + pipe_ctx->plane_res.scl_data.recout.height, + pipe_ctx->plane_res.scl_data.recout.x, + pipe_ctx->plane_res.scl_data.recout.y); + print_rq_dlg_ttu(dc, pipe_ctx); + } +*/ + if (dc->vm_pa_config.valid) { + struct vm_system_aperture_param apt; + + apt.sys_default.quad_part = 0; + + apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr; + apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr; + + // Program system aperture settings + pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); + } + + if (!pipe_ctx->top_pipe + && pipe_ctx->plane_state + && pipe_ctx->plane_state->flip_int_enabled + && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) + pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); + +// if (dc->debug.sanity_checks) { +// dcn10_verify_allow_pstate_change_high(dc); +// } +} + +void dcn20_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + struct pipe_ctx *temp_pipe; + bool flip_immediate = false; + + /* use TG master update lock to lock everything on the TG + * therefore only top pipe need to lock + */ + if (!pipe || pipe->top_pipe) + return; + + if (pipe->plane_state != NULL) + flip_immediate = pipe->plane_state->flip_immediate; + + if (pipe->stream_res.gsl_group > 0) { + temp_pipe = pipe->bottom_pipe; + while (!flip_immediate && temp_pipe) { + if (temp_pipe->plane_state != NULL) + flip_immediate = temp_pipe->plane_state->flip_immediate; + temp_pipe = temp_pipe->bottom_pipe; + } + } + + if (flip_immediate && lock) { + const int TIMEOUT_FOR_FLIP_PENDING_US = 100000; + unsigned int polling_interval_us = 1; + int i; + + temp_pipe = pipe; + while (temp_pipe) { + if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) { + for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING_US / polling_interval_us; ++i) { + if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp)) + break; + udelay(polling_interval_us); + } + + /* no reason it should take this long for immediate flips */ + ASSERT(i != TIMEOUT_FOR_FLIP_PENDING_US); + } + temp_pipe = temp_pipe->bottom_pipe; + } + } + + /* In flip immediate and pipe splitting case, we need to use GSL + * for synchronization. Only do setup on locking and on flip type change. + */ + if (lock && (pipe->bottom_pipe != NULL || !flip_immediate)) + if ((flip_immediate && pipe->stream_res.gsl_group == 0) || + (!flip_immediate && pipe->stream_res.gsl_group > 0)) + dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate); + + if (pipe->plane_state != NULL) + flip_immediate = pipe->plane_state->flip_immediate; + + temp_pipe = pipe->bottom_pipe; + while (flip_immediate && temp_pipe) { + if (temp_pipe->plane_state != NULL) + flip_immediate = temp_pipe->plane_state->flip_immediate; + temp_pipe = temp_pipe->bottom_pipe; + } + + if (!lock && pipe->stream_res.gsl_group > 0 && pipe->plane_state && + !flip_immediate) + dcn20_setup_gsl_group_as_lock(dc, pipe, false); + + if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) { + union dmub_hw_lock_flags hw_locks = { 0 }; + struct dmub_hw_lock_inst_flags inst_flags = { 0 }; + + hw_locks.bits.lock_pipe = 1; + inst_flags.otg_inst = pipe->stream_res.tg->inst; + + if (pipe->plane_state != NULL) + hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips; + + dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv, + lock, + &hw_locks, + &inst_flags); + } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { + if (lock) + pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg); + } else { + if (lock) + pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + } +} + +static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx *new_pipe) +{ + new_pipe->update_flags.raw = 0; + + /* If non-phantom pipe is being transitioned to a phantom pipe, + * set disable and return immediately. This is because the pipe + * that was previously in use must be fully disabled before we + * can "enable" it as a phantom pipe (since the OTG will certainly + * be different). The post_unlock sequence will set the correct + * update flags to enable the phantom pipe. + */ + if (old_pipe->plane_state && !old_pipe->plane_state->is_phantom && + new_pipe->plane_state && new_pipe->plane_state->is_phantom) { + new_pipe->update_flags.bits.disable = 1; + return; + } + + /* Exit on unchanged, unused pipe */ + if (!old_pipe->plane_state && !new_pipe->plane_state) + return; + /* Detect pipe enable/disable */ + if (!old_pipe->plane_state && new_pipe->plane_state) { + new_pipe->update_flags.bits.enable = 1; + new_pipe->update_flags.bits.mpcc = 1; + new_pipe->update_flags.bits.dppclk = 1; + new_pipe->update_flags.bits.hubp_interdependent = 1; + new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; + new_pipe->update_flags.bits.unbounded_req = 1; + new_pipe->update_flags.bits.gamut_remap = 1; + new_pipe->update_flags.bits.scaler = 1; + new_pipe->update_flags.bits.viewport = 1; + new_pipe->update_flags.bits.det_size = 1; + if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) { + new_pipe->update_flags.bits.odm = 1; + new_pipe->update_flags.bits.global_sync = 1; + } + return; + } + + /* For SubVP we need to unconditionally enable because any phantom pipes are + * always removed then newly added for every full updates whenever SubVP is in use. + * The remove-add sequence of the phantom pipe always results in the pipe + * being blanked in enable_stream_timing (DPG). + */ + if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) + new_pipe->update_flags.bits.enable = 1; + + /* Phantom pipes are effectively disabled, if the pipe was previously phantom + * we have to enable + */ + if (old_pipe->plane_state && old_pipe->plane_state->is_phantom && + new_pipe->plane_state && !new_pipe->plane_state->is_phantom) + new_pipe->update_flags.bits.enable = 1; + + if (old_pipe->plane_state && !new_pipe->plane_state) { + new_pipe->update_flags.bits.disable = 1; + return; + } + + /* Detect plane change */ + if (old_pipe->plane_state != new_pipe->plane_state) { + new_pipe->update_flags.bits.plane_changed = true; + } + + /* Detect top pipe only changes */ + if (resource_is_pipe_type(new_pipe, OTG_MASTER)) { + /* Detect odm changes */ + if (resource_is_odm_topology_changed(new_pipe, old_pipe)) + new_pipe->update_flags.bits.odm = 1; + + /* Detect global sync changes */ + if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset + || old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start + || old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset + || old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width) + new_pipe->update_flags.bits.global_sync = 1; + } + + if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb) + new_pipe->update_flags.bits.det_size = 1; + + /* + * Detect opp / tg change, only set on change, not on enable + * Assume mpcc inst = pipe index, if not this code needs to be updated + * since mpcc is what is affected by these. In fact all of our sequence + * makes this assumption at the moment with how hubp reset is matched to + * same index mpcc reset. + */ + if (old_pipe->stream_res.opp != new_pipe->stream_res.opp) + new_pipe->update_flags.bits.opp_changed = 1; + if (old_pipe->stream_res.tg != new_pipe->stream_res.tg) + new_pipe->update_flags.bits.tg_changed = 1; + + /* + * Detect mpcc blending changes, only dpp inst and opp matter here, + * mpccs getting removed/inserted update connected ones during their own + * programming + */ + if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp + || old_pipe->stream_res.opp != new_pipe->stream_res.opp) + new_pipe->update_flags.bits.mpcc = 1; + + /* Detect dppclk change */ + if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz) + new_pipe->update_flags.bits.dppclk = 1; + + /* Check for scl update */ + if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data))) + new_pipe->update_flags.bits.scaler = 1; + /* Check for vp update */ + if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect)) + || memcmp(&old_pipe->plane_res.scl_data.viewport_c, + &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect))) + new_pipe->update_flags.bits.viewport = 1; + + /* Detect dlg/ttu/rq updates */ + { + struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs; + struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs; + struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs; + struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs; + + /* Detect pipe interdependent updates */ + if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch || + old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch || + old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c || + old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank || + old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank || + old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip || + old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip || + old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l || + old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c || + old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l || + old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l || + old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c || + old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l || + old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c || + old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 || + old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 || + old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank || + old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) { + old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch; + old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch; + old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c; + old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank; + old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank; + old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip; + old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip; + old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l; + old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c; + old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l; + old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l; + old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c; + old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l; + old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c; + old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0; + old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1; + old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank; + old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip; + new_pipe->update_flags.bits.hubp_interdependent = 1; + } + /* Detect any other updates to ttu/rq/dlg */ + if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) || + memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) || + memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs))) + new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; + } + + if (old_pipe->unbounded_req != new_pipe->unbounded_req) + new_pipe->update_flags.bits.unbounded_req = 1; +} + +static void dcn20_update_dchubp_dpp( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct dccg *dccg = dc->res_pool->dccg; + bool viewport_changed = false; + + if (pipe_ctx->update_flags.bits.dppclk) + dpp->funcs->dpp_dppclk_control(dpp, false, true); + + if (pipe_ctx->update_flags.bits.enable) + dccg->funcs->update_dpp_dto(dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz); + + /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG + * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. + * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG + */ + if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) { + hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); + + hubp->funcs->hubp_setup( + hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs, + &pipe_ctx->rq_regs, + &pipe_ctx->pipe_dlg_param); + } + + if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting) + hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req); + + if (pipe_ctx->update_flags.bits.hubp_interdependent) + hubp->funcs->hubp_setup_interdependent( + hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs); + + if (pipe_ctx->update_flags.bits.enable || + pipe_ctx->update_flags.bits.plane_changed || + plane_state->update_flags.bits.bpp_change || + plane_state->update_flags.bits.input_csc_change || + plane_state->update_flags.bits.color_space_change || + plane_state->update_flags.bits.coeff_reduction_change) { + struct dc_bias_and_scale bns_params = {0}; + + // program the input csc + dpp->funcs->dpp_setup(dpp, + plane_state->format, + EXPANSION_MODE_ZERO, + plane_state->input_csc_color_matrix, + plane_state->color_space, + NULL); + + if (dpp->funcs->dpp_program_bias_and_scale) { + //TODO :for CNVC set scale and bias registers if necessary + build_prescale_params(&bns_params, plane_state); + dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); + } + } + + if (pipe_ctx->update_flags.bits.mpcc + || pipe_ctx->update_flags.bits.plane_changed + || plane_state->update_flags.bits.global_alpha_change + || plane_state->update_flags.bits.per_pixel_alpha_change) { + // MPCC inst is equal to pipe index in practice + hws->funcs.update_mpcc(dc, pipe_ctx); + } + + if (pipe_ctx->update_flags.bits.scaler || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.position_change || + plane_state->update_flags.bits.per_pixel_alpha_change || + pipe_ctx->stream->update_flags.bits.scaling) { + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; + ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP); + /* scaler configuration */ + pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( + pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); + } + + if (pipe_ctx->update_flags.bits.viewport || + (context == dc->current_state && plane_state->update_flags.bits.position_change) || + (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || + (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { + + hubp->funcs->mem_program_viewport( + hubp, + &pipe_ctx->plane_res.scl_data.viewport, + &pipe_ctx->plane_res.scl_data.viewport_c); + viewport_changed = true; + } + + /* Any updates are handled in dc interface, just need to apply existing for plane enable */ + if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || + pipe_ctx->update_flags.bits.scaler || viewport_changed == true) && + pipe_ctx->stream->cursor_attributes.address.quad_part != 0) { + dc->hwss.set_cursor_position(pipe_ctx); + dc->hwss.set_cursor_attribute(pipe_ctx); + + if (dc->hwss.set_cursor_sdr_white_level) + dc->hwss.set_cursor_sdr_white_level(pipe_ctx); + } + + /* Any updates are handled in dc interface, just need + * to apply existing for plane enable / opp change */ + if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed + || pipe_ctx->update_flags.bits.plane_changed + || pipe_ctx->stream->update_flags.bits.gamut_remap + || plane_state->update_flags.bits.gamut_remap_change + || pipe_ctx->stream->update_flags.bits.out_csc) { + /* dpp/cm gamut remap*/ + dc->hwss.program_gamut_remap(pipe_ctx); + + /*call the dcn2 method which uses mpc csc*/ + dc->hwss.program_output_csc(dc, + pipe_ctx, + pipe_ctx->stream->output_color_space, + pipe_ctx->stream->csc_color_matrix.matrix, + hubp->opp_id); + } + + if (pipe_ctx->update_flags.bits.enable || + pipe_ctx->update_flags.bits.plane_changed || + pipe_ctx->update_flags.bits.opp_changed || + plane_state->update_flags.bits.pixel_format_change || + plane_state->update_flags.bits.horizontal_mirror_change || + plane_state->update_flags.bits.rotation_change || + plane_state->update_flags.bits.swizzle_change || + plane_state->update_flags.bits.dcc_change || + plane_state->update_flags.bits.bpp_change || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.plane_size_change) { + struct plane_size size = plane_state->plane_size; + + size.surface_size = pipe_ctx->plane_res.scl_data.viewport; + hubp->funcs->hubp_program_surface_config( + hubp, + plane_state->format, + &plane_state->tiling_info, + &size, + plane_state->rotation, + &plane_state->dcc, + plane_state->horizontal_mirror, + 0); + hubp->power_gated = false; + } + + if (pipe_ctx->update_flags.bits.enable || + pipe_ctx->update_flags.bits.plane_changed || + plane_state->update_flags.bits.addr_update) { + if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && + pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { + union block_sequence_params params; + + params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv; + params.subvp_save_surf_addr.addr = &pipe_ctx->plane_state->address; + params.subvp_save_surf_addr.subvp_index = pipe_ctx->subvp_index; + hwss_subvp_save_surf_addr(¶ms); + } + hws->funcs.update_plane_addr(dc, pipe_ctx); + } + + if (pipe_ctx->update_flags.bits.enable) + hubp->funcs->set_blank(hubp, false); + /* If the stream paired with this plane is phantom, the plane is also phantom */ + if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM + && hubp->funcs->phantom_hubp_post_enable) + hubp->funcs->phantom_hubp_post_enable(hubp); +} + +static int calculate_vready_offset_for_group(struct pipe_ctx *pipe) +{ + struct pipe_ctx *other_pipe; + int vready_offset = pipe->pipe_dlg_param.vready_offset; + + /* Always use the largest vready_offset of all connected pipes */ + for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) { + if (other_pipe->pipe_dlg_param.vready_offset > vready_offset) + vready_offset = other_pipe->pipe_dlg_param.vready_offset; + } + + return vready_offset; +} + +static void dcn20_program_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + + /* Only need to unblank on top pipe */ + if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) { + if (pipe_ctx->update_flags.bits.enable || + pipe_ctx->update_flags.bits.odm || + pipe_ctx->stream->update_flags.bits.abm_level) + hws->funcs.blank_pixel_data(dc, pipe_ctx, + !pipe_ctx->plane_state || + !pipe_ctx->plane_state->visible); + } + + /* Only update TG on top pipe */ + if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe + && !pipe_ctx->prev_odm_pipe) { + pipe_ctx->stream_res.tg->funcs->program_global_sync( + pipe_ctx->stream_res.tg, + calculate_vready_offset_for_group(pipe_ctx), + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width); + + if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); + + pipe_ctx->stream_res.tg->funcs->set_vtg_params( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true); + + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); + } + + if (pipe_ctx->update_flags.bits.odm) + hws->funcs.update_odm(dc, context, pipe_ctx); + + if (pipe_ctx->update_flags.bits.enable) { + if (hws->funcs.enable_plane) + hws->funcs.enable_plane(dc, pipe_ctx, context); + else + dcn20_enable_plane(dc, pipe_ctx, context); + + if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes) + dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub); + } + + if (dc->res_pool->hubbub->funcs->program_det_size && pipe_ctx->update_flags.bits.det_size) + dc->res_pool->hubbub->funcs->program_det_size( + dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb); + + if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw) + dcn20_update_dchubp_dpp(dc, pipe_ctx, context); + + if (pipe_ctx->update_flags.bits.enable + || pipe_ctx->plane_state->update_flags.bits.hdr_mult) + hws->funcs.set_hdr_multiplier(pipe_ctx); + + if (pipe_ctx->update_flags.bits.enable || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change || + pipe_ctx->plane_state->update_flags.bits.lut_3d) + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); + + /* dcn10_translate_regamma_to_hw_format takes 750us to finish + * only do gamma programming for powering on, internal memcmp to avoid + * updating on slave planes + */ + if (pipe_ctx->update_flags.bits.enable || + pipe_ctx->update_flags.bits.plane_changed || + pipe_ctx->stream->update_flags.bits.out_tf || + pipe_ctx->plane_state->update_flags.bits.output_tf_change) + hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); + + /* If the pipe has been enabled or has a different opp, we + * should reprogram the fmt. This deals with cases where + * interation between mpc and odm combine on different streams + * causes a different pipe to be chosen to odm combine with. + */ + if (pipe_ctx->update_flags.bits.enable + || pipe_ctx->update_flags.bits.opp_changed) { + + pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion( + pipe_ctx->stream_res.opp, + COLOR_SPACE_YCBCR601, + pipe_ctx->stream->timing.display_color_depth, + pipe_ctx->stream->signal); + + pipe_ctx->stream_res.opp->funcs->opp_program_fmt( + pipe_ctx->stream_res.opp, + &pipe_ctx->stream->bit_depth_params, + &pipe_ctx->stream->clamping); + } + + /* Set ABM pipe after other pipe configurations done */ + if (pipe_ctx->plane_state->visible) { + if (pipe_ctx->stream_res.abm) { + dc->hwss.set_pipe(pipe_ctx); + pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm, + pipe_ctx->stream->abm_level); + } + } +} + +void dcn20_program_front_end_for_ctx( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + DC_LOGGER_INIT(dc->ctx->logger); + + if (resource_is_pipe_topology_changed(dc->current_state, context)) + resource_log_pipe_topology_update(dc, context); + + if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->plane_state) { + ASSERT(!pipe_ctx->plane_state->triplebuffer_flips); + /*turn off triple buffer for full update*/ + dc->hwss.program_triplebuffer( + dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); + } + } + } + + /* Set pipe update flags and lock pipes */ + for (i = 0; i < dc->res_pool->pipe_count; i++) + dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i], + &context->res_ctx.pipe_ctx[i]); + + /* When disabling phantom pipes, turn on phantom OTG first (so we can get double + * buffer updates properly) + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream; + + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream && + dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { + struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; + + if (tg->funcs->enable_crtc) { + if (dc->hwss.blank_phantom) { + int main_pipe_width, main_pipe_height; + + main_pipe_width = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.width; + main_pipe_height = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.height; + dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); + } + tg->funcs->enable_crtc(tg); + } + } + } + /* OTG blank before disabling all front ends */ + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable + && !context->res_ctx.pipe_ctx[i].top_pipe + && !context->res_ctx.pipe_ctx[i].prev_odm_pipe + && context->res_ctx.pipe_ctx[i].stream) + hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true); + + + /* Disconnect mpcc */ + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable + || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { + struct hubbub *hubbub = dc->res_pool->hubbub; + + /* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom + * then we want to do the programming here (effectively it's being disabled). If we do + * the programming later the DET won't be updated until the OTG for the phantom pipe is + * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with + * DET allocation. + */ + if (hubbub->funcs->program_det_size && (context->res_ctx.pipe_ctx[i].update_flags.bits.disable || + (context->res_ctx.pipe_ctx[i].plane_state && context->res_ctx.pipe_ctx[i].plane_state->is_phantom))) + hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); + hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); + } + + /* + * Program all updated pipes, order matters for mpcc setup. Start with + * top pipe and program all pipes that follow in order + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->plane_state && !pipe->top_pipe) { + while (pipe) { + if (hws->funcs.program_pipe) + hws->funcs.program_pipe(dc, pipe, context); + else { + /* Don't program phantom pipes in the regular front end programming sequence. + * There is an MPO transition case where a pipe being used by a video plane is + * transitioned directly to be a phantom pipe when closing the MPO video. However + * the phantom pipe will program a new HUBP_VTG_SEL (update takes place right away), + * but the MPO still exists until the double buffered update of the main pipe so we + * will get a frame of underflow if the phantom pipe is programmed here. + */ + if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) + dcn20_program_pipe(dc, pipe, context); + } + + pipe = pipe->bottom_pipe; + } + } + /* Program secondary blending tree and writeback pipes */ + pipe = &context->res_ctx.pipe_ctx[i]; + if (!pipe->top_pipe && !pipe->prev_odm_pipe + && pipe->stream && pipe->stream->num_wb_info > 0 + && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw) + || pipe->stream->update_flags.raw) + && hws->funcs.program_all_writeback_pipes_in_tree) + hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); + + /* Avoid underflow by check of pipe line read when adding 2nd plane. */ + if (hws->wa.wait_hubpret_read_start_during_mpo_transition && + !pipe->top_pipe && + pipe->stream && + pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start && + dc->current_state->stream_status[0].plane_count == 1 && + context->stream_status[0].plane_count > 1) { + pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp); + } + + /* when dynamic ODM is active, pipes must be reconfigured when all planes are + * disabled, as some transitions will leave software and hardware state + * mismatched. + */ + if (dc->debug.enable_single_display_2to1_odm_policy && + pipe->stream && + pipe->update_flags.bits.disable && + !pipe->prev_odm_pipe && + hws->funcs.update_odm) + hws->funcs.update_odm(dc, context, pipe); + } +} + +void dcn20_post_unlock_program_front_end( + struct dc *dc, + struct dc_state *context) +{ + int i; + const unsigned int TIMEOUT_FOR_PIPE_ENABLE_US = 100000; + unsigned int polling_interval_us = 1; + struct dce_hwseq *hwseq = dc->hwseq; + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) + dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + + /* + * If we are enabling a pipe, we need to wait for pending clear as this is a critical + * part of the enable operation otherwise, DM may request an immediate flip which + * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which + * is unsupported on DCN. + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + // Don't check flip pending on phantom pipes + if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable && + pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { + struct hubp *hubp = pipe->plane_res.hubp; + int j = 0; + for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_US / polling_interval_us + && hubp->funcs->hubp_is_flip_pending(hubp); j++) + udelay(polling_interval_us); + } + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->plane_state && !pipe->top_pipe) { + /* Program phantom pipe here to prevent a frame of underflow in the MPO transition + * case (if a pipe being used for a video plane transitions to a phantom pipe, it + * can underflow due to HUBP_VTG_SEL programming if done in the regular front end + * programming sequence). + */ + while (pipe) { + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + /* When turning on the phantom pipe we want to run through the + * entire enable sequence, so apply all the "enable" flags. + */ + if (dc->hwss.apply_update_flags_for_phantom) + dc->hwss.apply_update_flags_for_phantom(pipe); + if (dc->hwss.update_phantom_vp_position) + dc->hwss.update_phantom_vp_position(dc, context, pipe); + dcn20_program_pipe(dc, pipe, context); + } + pipe = pipe->bottom_pipe; + } + } + } + + /* P-State support transitions: + * Natural -> FPO: P-State disabled in prepare, force disallow anytime is safe + * FPO -> Natural: Unforce anytime after FW disable is safe (P-State will assert naturally) + * Unsupported -> FPO: P-State enabled in optimize, force disallow anytime is safe + * FPO -> Unsupported: P-State disabled in prepare, unforce disallow anytime is safe + * FPO <-> SubVP: Force disallow is maintained on the FPO / SubVP pipes + */ + if (hwseq && hwseq->funcs.update_force_pstate) + dc->hwseq->funcs.update_force_pstate(dc, context); + + /* Only program the MALL registers after all the main and phantom pipes + * are done programming. + */ + if (hwseq->funcs.program_mall_pipe_config) + hwseq->funcs.program_mall_pipe_config(dc, context); + + /* WA to apply WM setting*/ + if (hwseq->wa.DEGVIDCN21) + dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub); + + + /* WA for stutter underflow during MPO transitions when adding 2nd plane */ + if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) { + + if (dc->current_state->stream_status[0].plane_count == 1 && + context->stream_status[0].plane_count > 1) { + + struct timing_generator *tg = dc->res_pool->timing_generators[0]; + + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false); + + hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true; + hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame = tg->funcs->get_frame_count(tg); + } + } +} + +void dcn20_prepare_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct hubbub *hubbub = dc->res_pool->hubbub; + unsigned int compbuf_size_kb = 0; + unsigned int cache_wm_a = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns; + unsigned int i; + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + false); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + // At optimize don't restore the original watermark value + if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; + break; + } + } + + /* program dchubbub watermarks: + * For assigning wm_optimized_required, use |= operator since we don't want + * to clear the value if the optimize has not happened yet + */ + dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + false); + + // Restore the real watermark so we can commit the value to DMCUB + // DMCUB uses the "original" watermark value in SubVP MCLK switch + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = cache_wm_a; + + /* decrease compbuf size */ + if (hubbub->funcs->program_compbuf_size) { + if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes) { + compbuf_size_kb = context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes; + dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.dml.ip.min_comp_buffer_size_kbytes); + } else { + compbuf_size_kb = context->bw_ctx.bw.dcn.compbuf_size_kb; + dc->wm_optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.bw.dcn.compbuf_size_kb); + } + + hubbub->funcs->program_compbuf_size(hubbub, compbuf_size_kb, false); + } +} + +void dcn20_optimize_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct hubbub *hubbub = dc->res_pool->hubbub; + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + // At optimize don't need to restore the original watermark value + if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; + break; + } + } + + /* program dchubbub watermarks */ + hubbub->funcs->program_watermarks(hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + true); + + if (dc->clk_mgr->dc_mode_softmax_enabled) + if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && + context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) + dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk); + + /* increase compbuf size */ + if (hubbub->funcs->program_compbuf_size) + hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true); + + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { + dc_dmub_srv_p_state_delegate(dc, + true, context); + context->bw_ctx.bw.dcn.clk.p_state_change_support = true; + dc->clk_mgr->clks.fw_based_mclk_switching = true; + } else { + dc->clk_mgr->clks.fw_based_mclk_switching = false; + } + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + true); + if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) { + for (i = 0; i < dc->res_pool->pipe_count; ++i) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank + && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max + && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total) + pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp, + pipe_ctx->dlg_regs.min_dst_y_next_start); + } + } +} + +bool dcn20_update_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + + /* recalculate DML parameters */ + if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) + return false; + + /* apply updated bandwidth parameters */ + dc->hwss.prepare_bandwidth(dc, context); + + /* update hubp configs for all pipes */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->plane_state == NULL) + continue; + + if (pipe_ctx->top_pipe == NULL) { + bool blank = !is_pipe_tree_visible(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->program_global_sync( + pipe_ctx->stream_res.tg, + calculate_vready_offset_for_group(pipe_ctx), + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width); + + pipe_ctx->stream_res.tg->funcs->set_vtg_params( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false); + + if (pipe_ctx->prev_odm_pipe == NULL) + hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); + + if (hws->funcs.setup_vupdate_interrupt) + hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx); + } + + pipe_ctx->plane_res.hubp->funcs->hubp_setup( + pipe_ctx->plane_res.hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs, + &pipe_ctx->rq_regs, + &pipe_ctx->pipe_dlg_param); + } + + return true; +} + +void dcn20_enable_writeback( + struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context) +{ + struct dwbc *dwb; + struct mcif_wb *mcif_wb; + struct timing_generator *optc; + + ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES); + ASSERT(wb_info->wb_enabled); + dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; + + /* set the OPTC source mux */ + optc = dc->res_pool->timing_generators[dwb->otg_inst]; + optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst); + /* set MCIF_WB buffer and arbitration configuration */ + mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height); + mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); + /* Enable MCIF_WB */ + mcif_wb->funcs->enable_mcif(mcif_wb); + /* Enable DWB */ + dwb->funcs->enable(dwb, &wb_info->dwb_params); + /* TODO: add sequence to enable/disable warmup */ +} + +void dcn20_disable_writeback( + struct dc *dc, + unsigned int dwb_pipe_inst) +{ + struct dwbc *dwb; + struct mcif_wb *mcif_wb; + + ASSERT(dwb_pipe_inst < MAX_DWB_PIPES); + dwb = dc->res_pool->dwbc[dwb_pipe_inst]; + mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst]; + + dwb->funcs->disable(dwb); + mcif_wb->funcs->disable_mcif(mcif_wb); +} + +bool dcn20_wait_for_blank_complete( + struct output_pixel_processor *opp) +{ + int counter; + + for (counter = 0; counter < 1000; counter++) { + if (opp->funcs->dpg_is_blanked(opp)) + break; + + udelay(100); + } + + if (counter == 1000) { + dm_error("DC: failed to blank crtc!\n"); + return false; + } + + return true; +} + +bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + + if (!hubp) + return false; + return hubp->funcs->dmdata_status_done(hubp); +} + +void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + + if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + + hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true); + while (odm_pipe) { + hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true); + odm_pipe = odm_pipe->next_odm_pipe; + } + } +} + +void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + + if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + + hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false); + while (odm_pipe) { + hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false); + odm_pipe = odm_pipe->next_odm_pipe; + } + } +} + +void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) +{ + struct dc_dmdata_attributes attr = { 0 }; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + + attr.dmdata_mode = DMDATA_HW_MODE; + attr.dmdata_size = + dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36; + attr.address.quad_part = + pipe_ctx->stream->dmdata_address.quad_part; + attr.dmdata_dl_delta = 0; + attr.dmdata_qos_mode = 0; + attr.dmdata_qos_level = 0; + attr.dmdata_repeat = 1; /* always repeat */ + attr.dmdata_updated = 1; + attr.dmdata_sw_data = NULL; + + hubp->funcs->dmdata_set_attributes(hubp, &attr); +} + +void dcn20_init_vm_ctx( + struct dce_hwseq *hws, + struct dc *dc, + struct dc_virtual_addr_space_config *va_config, + int vmid) +{ + struct dcn_hubbub_virt_addr_config config; + + if (vmid == 0) { + ASSERT(0); /* VMID cannot be 0 for vm context */ + return; + } + + config.page_table_start_addr = va_config->page_table_start_addr; + config.page_table_end_addr = va_config->page_table_end_addr; + config.page_table_block_size = va_config->page_table_block_size_in_bytes; + config.page_table_depth = va_config->page_table_depth; + config.page_table_base_addr = va_config->page_table_base_addr; + + dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid); +} + +int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) +{ + struct dcn_hubbub_phys_addr_config config; + + config.system_aperture.fb_top = pa_config->system_aperture.fb_top; + config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; + config.system_aperture.fb_base = pa_config->system_aperture.fb_base; + config.system_aperture.agp_top = pa_config->system_aperture.agp_top; + config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; + config.system_aperture.agp_base = pa_config->system_aperture.agp_base; + config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; + config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; + config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; + config.page_table_default_page_addr = pa_config->page_table_default_page_addr; + + return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); +} + +static bool patch_address_for_sbs_tb_stereo( + struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + bool sec_split = pipe_ctx->top_pipe && + pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; + if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && + (pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_SIDE_BY_SIDE || + pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { + *addr = plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.left_addr = + plane_state->address.grph_stereo.right_addr; + return true; + } + + if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && + plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { + plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; + plane_state->address.grph_stereo.right_addr = + plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.right_meta_addr = + plane_state->address.grph_stereo.left_meta_addr; + } + return false; +} + +void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + bool addr_patched = false; + PHYSICAL_ADDRESS_LOC addr; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + + if (plane_state == NULL) + return; + + addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); + + // Call Helper to track VMID use + vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst); + + pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( + pipe_ctx->plane_res.hubp, + &plane_state->address, + plane_state->flip_immediate); + + plane_state->status.requested_address = plane_state->address; + + if (plane_state->flip_immediate) + plane_state->status.current_address = plane_state->address; + + if (addr_patched) + pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; +} + +void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings) +{ + struct encoder_unblank_param params = {0}; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; + struct pipe_ctx *odm_pipe; + + params.opp_cnt = 1; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + params.opp_cnt++; + } + /* only 3 items below are used by unblank */ + params.timing = pipe_ctx->stream->timing; + + params.link_settings.link_rate = link_settings->link_rate; + + if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( + pipe_ctx->stream_res.hpo_dp_stream_enc, + pipe_ctx->stream_res.tg->inst); + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1) + params.timing.pix_clk_100hz /= 2; + pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( + pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1); + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); + } + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + hws->funcs.edp_backlight_control(link, true); + } +} + +void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct timing_generator *tg = pipe_ctx->stream_res.tg; + int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx); + + if (start_line < 0) + start_line = 0; + + if (tg->funcs->setup_vertical_interrupt2) + tg->funcs->setup_vertical_interrupt2(tg, start_line); +} + +static void dcn20_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + int i; + struct dc_link *link = pipe_ctx->stream->link; + const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + + DC_LOGGER_INIT(dc->ctx->logger); + if (pipe_ctx->stream_res.stream_enc == NULL) { + pipe_ctx->stream = NULL; + return; + } + + /* DPMS may already disable or */ + /* dpms_off status is incorrect due to fastboot + * feature. When system resume from S4 with second + * screen only, the dpms_off would be true but + * VBIOS lit up eDP, so check link status too. + */ + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) + dc->link_srv->set_dpms_off(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + /* free acquired resources */ + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } + } + + /* by upper caller loop, parent pipe: pipe0, will be reset last. + * back end share by all pipes and will be disable only when disable + * parent pipe. + */ + if (pipe_ctx->top_pipe == NULL) { + + dc->hwss.set_abm_immediate_disable(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); + if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); + /* TODO - convert symclk_ref_cnts for otg to a bit map to solve + * the case where the same symclk is shared across multiple otg + * instances + */ + link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, + &pipe_ctx->link_res, pipe_ctx->stream->signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + } + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) + break; + + if (i == dc->res_pool->pipe_count) + return; + + pipe_ctx->stream = NULL; + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", + pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); +} + +void dcn20_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + + /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx_old); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } +} + +void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct mpcc_blnd_cfg blnd_cfg = {0}; + bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; + int mpcc_id; + struct mpcc *new_mpcc; + struct mpc *mpc = dc->res_pool->mpc; + struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); + + blnd_cfg.overlap_only = false; + blnd_cfg.global_gain = 0xff; + + if (per_pixel_alpha) { + blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha; + if (pipe_ctx->plane_state->global_alpha) { + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN; + blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value; + } else { + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; + } + } else { + blnd_cfg.pre_multiplied_alpha = false; + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; + } + + if (pipe_ctx->plane_state->global_alpha) + blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; + else + blnd_cfg.global_alpha = 0xff; + + blnd_cfg.background_color_bpc = 4; + blnd_cfg.bottom_gain_mode = 0; + blnd_cfg.top_gain = 0x1f000; + blnd_cfg.bottom_inside_gain = 0x1f000; + blnd_cfg.bottom_outside_gain = 0x1f000; + + if (pipe_ctx->plane_state->format + == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA) + blnd_cfg.pre_multiplied_alpha = false; + + /* + * TODO: remove hack + * Note: currently there is a bug in init_hw such that + * on resume from hibernate, BIOS sets up MPCC0, and + * we do mpcc_remove but the mpcc cannot go to idle + * after remove. This cause us to pick mpcc1 here, + * which causes a pstate hang for yet unknown reason. + */ + mpcc_id = hubp->inst; + + /* If there is no full update, don't need to touch MPC tree*/ + if (!pipe_ctx->plane_state->update_flags.bits.full_update && + !pipe_ctx->update_flags.bits.mpcc) { + mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); + return; + } + + /* check if this MPCC is already being used */ + new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); + /* remove MPCC if being used */ + if (new_mpcc != NULL) + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); + else + if (dc->debug.sanity_checks) + mpc->funcs->assert_mpcc_idle_before_connect( + dc->res_pool->mpc, mpcc_id); + + /* Call MPC to insert new plane */ + new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, + mpc_tree_params, + &blnd_cfg, + NULL, + NULL, + hubp->inst, + mpcc_id); + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); + + ASSERT(new_mpcc != NULL); + hubp->opp_id = pipe_ctx->stream_res.opp->inst; + hubp->mpcc_id = mpcc_id; +} + +void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) +{ + enum dc_lane_count lane_count = + pipe_ctx->stream->link->cur_link_settings.lane_count; + + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + struct dc_link *link = pipe_ctx->stream->link; + + uint32_t active_total_with_borders; + uint32_t early_control = 0; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + struct dc *dc = pipe_ctx->stream->ctx->dc; + struct dtbclk_dto_params dto_params = {0}; + struct dccg *dccg = dc->res_pool->dccg; + enum phyd32clk_clock_source phyd32clk; + int dp_hpo_inst; + struct dce_hwseq *hws = dc->hwseq; + unsigned int k1_div = PIXEL_RATE_DIV_NA; + unsigned int k2_div = PIXEL_RATE_DIV_NA; + + if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + if (dc->hwseq->funcs.setup_hpo_hw_control) + dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, true); + } + + if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; + dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst); + + phyd32clk = get_phyd32clk_src(link); + dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); + + dto_params.otg_inst = tg->inst; + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; + dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx); + dto_params.timing = &pipe_ctx->stream->timing; + dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + } + if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { + hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); + + dc->res_pool->dccg->funcs->set_pixel_rate_div( + dc->res_pool->dccg, + pipe_ctx->stream_res.tg->inst, + k1_div, k2_div); + } + + link_hwss->setup_stream_encoder(pipe_ctx); + + if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) { + if (dc->hwss.program_dmdata_engine) + dc->hwss.program_dmdata_engine(pipe_ctx); + } + + dc->hwss.update_info_frame(pipe_ctx); + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME); + + /* enable early control to avoid corruption on DP monitor*/ + active_total_with_borders = + timing->h_addressable + + timing->h_border_left + + timing->h_border_right; + + if (lane_count != 0) + early_control = active_total_with_borders % lane_count; + + if (early_control == 0) + early_control = lane_count; + + tg->funcs->set_early_control(tg, early_control); + + if (dc->hwseq->funcs.set_pixels_per_cycle) + dc->hwseq->funcs.set_pixels_per_cycle(pipe_ctx); +} + +void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + bool enable = false; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) + ? dmdata_dp + : dmdata_hdmi; + + /* if using dynamic meta, don't set up generic infopackets */ + if (pipe_ctx->stream->dmdata_address.quad_part != 0) { + pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; + enable = true; + } + + if (!hubp) + return; + + if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) + return; + + stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, + hubp->inst, mode); +} + +void dcn20_fpga_init_hw(struct dc *dc) +{ + int i, j; + struct dce_hwseq *hws = dc->hwseq; + struct resource_pool *res_pool = dc->res_pool; + struct dc_state *context = dc->current_state; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + //Enable ability to power gate / don't force power on permanently + hws->funcs.enable_power_gating_plane(hws, true); + + // Specific to FPGA dccg and registers + REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); + REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); + + hws->funcs.dccg_init(hws); + + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + if (REG(REFCLK_CNTL)) + REG_WRITE(REFCLK_CNTL, 0); + // + + + /* Blank pixel data with OPP DPG */ + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + dcn20_init_blank(dc, tg); + } + + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->lock(tg); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct dpp *dpp = res_pool->dpps[i]; + + dpp->funcs->dpp_reset(dpp); + } + + /* Reset all MPCC muxes */ + res_pool->mpc->funcs->mpc_init(res_pool->mpc); + + /* initialize OPP mpc_tree parameter */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; + res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + for (j = 0; j < MAX_PIPES; j++) + res_pool->opps[i]->mpcc_disconnect_pending[j] = false; + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = dc->res_pool->hubps[i]; + struct dpp *dpp = dc->res_pool->dpps[i]; + + pipe_ctx->stream_res.tg = tg; + pipe_ctx->pipe_idx = i; + + pipe_ctx->plane_res.hubp = hubp; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; + hubp->opp_id = OPP_ID_INVALID; + hubp->power_gated = false; + pipe_ctx->stream_res.opp = NULL; + + hubp->funcs->hubp_init(hubp); + + //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; + //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; + /*to do*/ + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + } + + /* initialize DWB pointer to MCIF_WB */ + for (i = 0; i < res_pool->res_cap->num_dwb; i++) + res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->unlock(tg); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dc->hwss.disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + } + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + tg->funcs->tg_init(tg); + } + + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); +} + +void dcn20_set_disp_pattern_generator(const struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, int height, int offset) +{ + pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern, + color_space, color_depth, solid_color, width, height, offset); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h new file mode 100644 index 000000000000..ab02e4e9c8c2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h @@ -0,0 +1,153 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN20_H__ +#define __DC_HWSS_DCN20_H__ + +#include "hw_sequencer_private.h" + +bool dcn20_set_blend_lut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); +bool dcn20_set_shaper_3dlut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state); +void dcn20_program_front_end_for_ctx( + struct dc *dc, + struct dc_state *context); +void dcn20_post_unlock_program_front_end( + struct dc *dc, + struct dc_state *context); +void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); +bool dcn20_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); +bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); +void dcn20_program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id); +void dcn20_enable_stream(struct pipe_ctx *pipe_ctx); +void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); +void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_disable_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); +void dcn20_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); +void dcn20_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +void dcn20_prepare_bandwidth( + struct dc *dc, + struct dc_state *context); +void dcn20_optimize_bandwidth( + struct dc *dc, + struct dc_state *context); +bool dcn20_update_bandwidth( + struct dc *dc, + struct dc_state *context); +void dcn20_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context); +enum dc_status dcn20_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); +void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_init_blank( + struct dc *dc, + struct timing_generator *tg); +void dcn20_disable_vga( + struct dce_hwseq *hws); +void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable); +void dcn20_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); +void dcn20_hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); +void dcn20_program_triple_buffer( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable_triple_buffer); +void dcn20_enable_writeback( + struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context); +void dcn20_disable_writeback( + struct dc *dc, + unsigned int dwb_pipe_inst); +void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); +bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx); +void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx); +void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx); +void dcn20_init_vm_ctx( + struct dce_hwseq *hws, + struct dc *dc, + struct dc_virtual_addr_space_config *va_config, + int vmid); +void dcn20_set_flip_control_gsl( + struct pipe_ctx *pipe_ctx, + bool flip_immediate); +void dcn20_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); +void dcn20_fpga_init_hw(struct dc *dc); +bool dcn20_wait_for_blank_complete( + struct output_pixel_processor *opp); +void dcn20_dccg_init(struct dce_hwseq *hws); +int dcn20_init_sys_ctx(struct dce_hwseq *hws, + struct dc *dc, + struct dc_phy_addr_space_config *pa_config); + +void dcn20_set_disp_pattern_generator(const struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, int height, int offset); + +void dcn20_setup_gsl_group_as_lock( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable); + +#endif /* __DC_HWSS_DCN20_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c new file mode 100644 index 000000000000..d3fe6092f50e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c @@ -0,0 +1,611 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "basics/dc_common.h" +#include "core_types.h" +#include "resource.h" +#include "dcn201_hwseq.h" +#include "dcn201/dcn201_optc.h" +#include "dce/dce_hwseq.h" +#include "hubp.h" +#include "dchubbub.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "dccg.h" +#include "clk_mgr.h" +#include "reg_helper.h" + +#define CTX \ + hws->ctx + +#define REG(reg)\ + hws->regs->reg + +#define DC_LOGGER \ + dc->ctx->logger + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +static bool patch_address_for_sbs_tb_stereo( + struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + bool sec_split = pipe_ctx->top_pipe && + pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; + + if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && + (pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_SIDE_BY_SIDE || + pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { + *addr = plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.left_addr = + plane_state->address.grph_stereo.right_addr; + return true; + } else { + if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && + plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { + plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; + plane_state->address.grph_stereo.right_addr = + plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.right_meta_addr = + plane_state->address.grph_stereo.left_meta_addr; + } + } + return false; +} + +static bool gpu_addr_to_uma(struct dce_hwseq *hwseq, + PHYSICAL_ADDRESS_LOC *addr) +{ + bool is_in_uma; + + if (hwseq->fb_base.quad_part <= addr->quad_part && + addr->quad_part < hwseq->fb_top.quad_part) { + addr->quad_part -= hwseq->fb_base.quad_part; + addr->quad_part += hwseq->fb_offset.quad_part; + is_in_uma = true; + } else if (hwseq->fb_offset.quad_part <= addr->quad_part && + addr->quad_part <= hwseq->uma_top.quad_part) { + is_in_uma = true; + } else { + is_in_uma = false; + } + return is_in_uma; +} + +static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq, + struct dc_plane_address *addr) +{ + switch (addr->type) { + case PLN_ADDR_TYPE_GRAPHICS: + gpu_addr_to_uma(hwseq, &addr->grph.addr); + gpu_addr_to_uma(hwseq, &addr->grph.meta_addr); + break; + case PLN_ADDR_TYPE_GRPH_STEREO: + gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr); + gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr); + gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr); + gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr); + break; + case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE: + gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr); + gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr); + gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr); + gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + bool addr_patched = false; + PHYSICAL_ADDRESS_LOC addr; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct dce_hwseq *hws = dc->hwseq; + struct dc_plane_address uma; + + if (plane_state == NULL) + return; + + uma = plane_state->address; + addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); + + plane_address_in_gpu_space_to_uma(hws, &uma); + + pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( + pipe_ctx->plane_res.hubp, + &uma, + plane_state->flip_immediate); + + plane_state->status.requested_address = plane_state->address; + + if (plane_state->flip_immediate) + plane_state->status.current_address = plane_state->address; + + if (addr_patched) + pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; +} + +/* Blank pixel data during initialization */ +void dcn201_init_blank( + struct dc *dc, + struct timing_generator *tg) +{ + struct dce_hwseq *hws = dc->hwseq; + enum dc_color_space color_space; + struct tg_color black_color = {0}; + struct output_pixel_processor *opp = NULL; + uint32_t num_opps, opp_id_src0, opp_id_src1; + uint32_t otg_active_width, otg_active_height; + + /* program opp dpg blank color */ + color_space = COLOR_SPACE_SRGB; + color_space_to_black_color(dc, color_space, &black_color); + + /* get the OTG active size */ + tg->funcs->get_otg_active_size(tg, + &otg_active_width, + &otg_active_height); + + /* get the OPTC source */ + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); + opp = dc->res_pool->opps[opp_id_src0]; + + opp->funcs->opp_set_disp_pattern_generator( + opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height, + 0); + + hws->funcs.wait_for_blank_complete(opp); +} + +static void read_mmhub_vm_setup(struct dce_hwseq *hws) +{ + uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE); + uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP); + uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET); + + /* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */ + fb_top++; + + /* bit 23:0 in register map to bit 47:24 in address */ + hws->fb_base.low_part = fb_base; + hws->fb_base.quad_part <<= 24; + + hws->fb_top.low_part = fb_top; + hws->fb_top.quad_part <<= 24; + hws->fb_offset.low_part = fb_offset; + hws->fb_offset.quad_part <<= 24; + + hws->uma_top.quad_part = hws->fb_top.quad_part + - hws->fb_base.quad_part + hws->fb_offset.quad_part; +} + +void dcn201_init_hw(struct dc *dc) +{ + int i, j; + struct dce_hwseq *hws = dc->hwseq; + struct resource_pool *res_pool = dc->res_pool; + struct dc_state *context = dc->current_state; + + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + hws->funcs.bios_golden_init(dc); + + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + + if (res_pool->dccg && res_pool->hubbub) { + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } else + ASSERT_CRITICAL(false); + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + link->link_enc->funcs->hw_init(link->link_enc); + } + if (hws->fb_offset.quad_part == 0) + read_mmhub_vm_setup(hws); + + /* Blank pixel data with OPP DPG */ + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) { + dcn201_init_blank(dc, tg); + } + } + + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->lock(tg); + } + + for (i = 0; i < res_pool->pipe_count; i++) { + struct dpp *dpp = res_pool->dpps[i]; + + dpp->funcs->dpp_reset(dpp); + } + + /* Reset all MPCC muxes */ + res_pool->mpc->funcs->mpc_init(res_pool->mpc); + + /* initialize OPP mpc_tree parameter */ + for (i = 0; i < res_pool->res_cap->num_opp; i++) { + res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; + res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + for (j = 0; j < MAX_PIPES; j++) + res_pool->opps[i]->mpcc_disconnect_pending[j] = false; + } + + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = res_pool->timing_generators[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = res_pool->hubps[i]; + struct dpp *dpp = res_pool->dpps[i]; + + pipe_ctx->stream_res.tg = tg; + pipe_ctx->pipe_idx = i; + + pipe_ctx->plane_res.hubp = hubp; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; + hubp->opp_id = OPP_ID_INVALID; + hubp->power_gated = false; + pipe_ctx->stream_res.opp = NULL; + + hubp->funcs->hubp_init(hubp); + + res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + pipe_ctx->stream_res.opp = res_pool->opps[i]; + /*To do: number of MPCC != number of opp*/ + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + } + + /* initialize DWB pointer to MCIF_WB */ + for (i = 0; i < res_pool->res_cap->num_dwb; i++) + res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; + + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->unlock(tg); + } + + for (i = 0; i < res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dc->hwss.disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + } + + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = res_pool->timing_generators[i]; + + tg->funcs->tg_init(tg); + } + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } +} + +/* trigger HW to start disconnect plane from stream on the next vsync */ +void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + int dpp_id = pipe_ctx->plane_res.dpp->inst; + struct mpc *mpc = dc->res_pool->mpc; + struct mpc_tree *mpc_tree_params; + struct mpcc *mpcc_to_remove = NULL; + struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; + bool mpcc_removed = false; + + mpc_tree_params = &(opp->mpc_tree_params); + + /* check if this plane is being used by an MPCC in the secondary blending chain */ + if (mpc->funcs->get_mpcc_for_dpp_from_secondary) + mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id); + + /* remove MPCC from secondary if being used */ + if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) { + mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove); + mpcc_removed = true; + } + + /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */ + mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); + if (mpcc_to_remove != NULL) { + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); + mpcc_removed = true; + } + + /*Already reset*/ + if (mpcc_removed == false) + return; + + if (opp != NULL) + opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + + dc->optimized_required = true; + + if (hubp->funcs->hubp_disconnect) + hubp->funcs->hubp_disconnect(hubp); + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); +} + +void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct mpcc_blnd_cfg blnd_cfg; + bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; + int mpcc_id, dpp_id; + struct mpcc *new_mpcc; + struct mpcc *remove_mpcc = NULL; + struct mpc *mpc = dc->res_pool->mpc; + struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); + + if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { + get_hdr_visual_confirm_color( + pipe_ctx, &blnd_cfg.black_color); + } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { + get_surface_visual_confirm_color( + pipe_ctx, &blnd_cfg.black_color); + } else { + color_space_to_black_color( + dc, pipe_ctx->stream->output_color_space, + &blnd_cfg.black_color); + } + + if (per_pixel_alpha) + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; + else + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; + + blnd_cfg.overlap_only = false; + + if (pipe_ctx->plane_state->global_alpha_value) + blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; + else + blnd_cfg.global_alpha = 0xff; + + blnd_cfg.global_gain = 0xff; + blnd_cfg.background_color_bpc = 4; + blnd_cfg.bottom_gain_mode = 0; + blnd_cfg.top_gain = 0x1f000; + blnd_cfg.bottom_inside_gain = 0x1f000; + blnd_cfg.bottom_outside_gain = 0x1f000; + /*the input to MPCC is RGB*/ + blnd_cfg.black_color.color_b_cb = 0; + blnd_cfg.black_color.color_g_y = 0; + blnd_cfg.black_color.color_r_cr = 0; + + /* DCN1.0 has output CM before MPC which seems to screw with + * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2. + */ + blnd_cfg.pre_multiplied_alpha = per_pixel_alpha; + + /* + * TODO: remove hack + * Note: currently there is a bug in init_hw such that + * on resume from hibernate, BIOS sets up MPCC0, and + * we do mpcc_remove but the mpcc cannot go to idle + * after remove. This cause us to pick mpcc1 here, + * which causes a pstate hang for yet unknown reason. + */ + dpp_id = hubp->inst; + mpcc_id = dpp_id; + + /* If there is no full update, don't need to touch MPC tree*/ + if (!pipe_ctx->plane_state->update_flags.bits.full_update) { + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); + mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); + return; + } + + /* check if this plane is being used by an MPCC in the secondary blending chain */ + if (mpc->funcs->get_mpcc_for_dpp_from_secondary) + remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id); + + /* remove MPCC from secondary if being used */ + if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary) + mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc); + + /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */ + remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); + /* remove MPCC if being used */ + + if (remove_mpcc != NULL) + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc); + else + if (dc->debug.sanity_checks) + mpc->funcs->assert_mpcc_idle_before_connect( + dc->res_pool->mpc, mpcc_id); + + /* Call MPC to insert new plane */ + dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); + new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, + mpc_tree_params, + &blnd_cfg, + NULL, + NULL, + dpp_id, + mpcc_id); + + ASSERT(new_mpcc != NULL); + hubp->opp_id = pipe_ctx->stream_res.opp->inst; + hubp->mpcc_id = mpcc_id; +} + +void dcn201_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + struct dce_hwseq *hws = dc->hwseq; + /* use TG master update lock to lock everything on the TG + * therefore only top pipe need to lock + */ + if (pipe->top_pipe) + return; + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); + + if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { + if (lock) + pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg); + } else { + if (lock) + pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + } + + if (dc->debug.sanity_checks) + hws->funcs.verify_allow_pstate_change_high(dc); +} + +void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx) +{ + struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; + + gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address); + + pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( + pipe_ctx->plane_res.hubp, attributes); + pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( + pipe_ctx->plane_res.dpp, attributes); +} + +void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) +{ + struct dc_dmdata_attributes attr = { 0 }; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + + gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, + &pipe_ctx->stream->dmdata_address); + + attr.dmdata_mode = DMDATA_HW_MODE; + attr.dmdata_size = + dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36; + attr.address.quad_part = + pipe_ctx->stream->dmdata_address.quad_part; + attr.dmdata_dl_delta = 0; + attr.dmdata_qos_mode = 0; + attr.dmdata_qos_level = 0; + attr.dmdata_repeat = 1; /* always repeat */ + attr.dmdata_updated = 1; + attr.dmdata_sw_data = NULL; + + hubp->funcs->dmdata_set_attributes(hubp, &attr); +} + +void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings) +{ + struct encoder_unblank_param params = { { 0 } }; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; + + /* only 3 items below are used by unblank */ + params.timing = pipe_ctx->stream->timing; + + params.link_settings.link_rate = link_settings->link_rate; + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + /*check whether it is half the rate*/ + if (optc201_is_two_pixels_per_containter(&stream->timing)) + params.timing.pix_clk_100hz /= 2; + + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); + } + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + hws->funcs.edp_backlight_control(link, true); + } +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h new file mode 100644 index 000000000000..26cd62be6418 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h @@ -0,0 +1,46 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN201_H__ +#define __DC_HWSS_DCN201_H__ + +#include "hw_sequencer_private.h" + +void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx); +void dcn201_init_hw(struct dc *dc); +void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); +void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx); +void dcn201_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +void dcn201_init_blank( + struct dc *dc, + struct timing_generator *tg); +#endif /* __DC_HWSS_DCN201_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c new file mode 100644 index 000000000000..467812cf3368 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c @@ -0,0 +1,270 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dce/dce_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn21_hwseq.h" +#include "vmid.h" +#include "reg_helper.h" +#include "hw/clk_mgr.h" +#include "dc_dmub_srv.h" +#include "abm.h" +#include "link.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +/* Temporary read settings, future will get values from kmd directly */ +static void mmhub_update_page_table_config(struct dcn_hubbub_phys_addr_config *config, + struct dce_hwseq *hws) +{ + uint32_t page_table_base_hi; + uint32_t page_table_base_lo; + + REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, + PAGE_DIRECTORY_ENTRY_HI32, &page_table_base_hi); + REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, + PAGE_DIRECTORY_ENTRY_LO32, &page_table_base_lo); + + config->gart_config.page_table_base_addr = ((uint64_t)page_table_base_hi << 32) | page_table_base_lo; + +} + +int dcn21_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) +{ + struct dcn_hubbub_phys_addr_config config; + + config.system_aperture.fb_top = pa_config->system_aperture.fb_top; + config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; + config.system_aperture.fb_base = pa_config->system_aperture.fb_base; + config.system_aperture.agp_top = pa_config->system_aperture.agp_top; + config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; + config.system_aperture.agp_base = pa_config->system_aperture.agp_base; + config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; + config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; + config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; + + mmhub_update_page_table_config(&config, hws); + + return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); +} + +// work around for Renoir s0i3, if register is programmed, bypass golden init. + +bool dcn21_s0i3_golden_init_wa(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + uint32_t value = 0; + + value = REG_READ(MICROSECOND_TIME_BASE_DIV); + + return value != 0x00120464; +} + +void dcn21_exit_optimized_pwr_state( + const struct dc *dc, + struct dc_state *context) +{ + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + false); +} + +void dcn21_optimize_pwr_state( + const struct dc *dc, + struct dc_state *context) +{ + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + true); +} + +/* If user hotplug a HDMI monitor while in monitor off, + * OS will do a mode set (with output timing) but keep output off. + * In this case DAL will ask vbios to power up the pll in the PHY. + * If user unplug the monitor (while we are on monitor off) or + * system attempt to enter modern standby (which we will disable PLL), + * PHY will hang on the next mode set attempt. + * if enable PLL follow by disable PLL (without executing lane enable/disable), + * RDPCS_PHY_DP_MPLLB_STATE remains 1, + * which indicate that PLL disable attempt actually didn't go through. + * As a workaround, insert PHY lane enable/disable before PLL disable. + */ +void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx) +{ + if (!pipe_ctx->stream->dpms_off) + return; + + pipe_ctx->stream->dpms_off = false; + pipe_ctx->stream->ctx->dc->link_srv->set_dpms_on(context, pipe_ctx); + pipe_ctx->stream->ctx->dc->link_srv->set_dpms_off(pipe_ctx); + pipe_ctx->stream->dpms_off = true; +} + +static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) +{ + union dmub_rb_cmd cmd; + struct dc_context *dc = abm->ctx; + uint32_t ramping_boundary = 0xFFFF; + + memset(&cmd, 0, sizeof(cmd)); + cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; + cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; + cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; + cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; + cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; + cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; + cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data); + + dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + + return true; +} + +static void dmub_abm_set_backlight(struct dc_context *dc, uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp, uint32_t panel_inst) +{ + union dmub_rb_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.abm_set_backlight.header.type = DMUB_CMD__ABM; + cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT; + cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = frame_ramp; + cmd.abm_set_backlight.abm_set_backlight_data.backlight_user_level = backlight_pwm_u16_16; + cmd.abm_set_backlight.abm_set_backlight_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1; + cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst); + cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); + + dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +} + +void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) +{ + struct abm *abm = pipe_ctx->stream_res.abm; + uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + + struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; + + if (dmcu) { + dce110_set_abm_immediate_disable(pipe_ctx); + return; + } + + if (abm && panel_cntl) { + if (abm->funcs && abm->funcs->set_pipe_ex) { + abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, + panel_cntl->inst); + } else { + dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, panel_cntl->inst); + } + panel_cntl->funcs->store_backlight_level(panel_cntl); + } +} + +void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) +{ + struct abm *abm = pipe_ctx->stream_res.abm; + uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; + + if (dmcu) { + dce110_set_pipe(pipe_ctx); + return; + } + + if (abm && panel_cntl) { + if (abm->funcs && abm->funcs->set_pipe_ex) { + abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + } else { + dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + } + } +} + +bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, + uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp) +{ + struct dc_context *dc = pipe_ctx->stream->ctx; + struct abm *abm = pipe_ctx->stream_res.abm; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + + if (dc->dc->res_pool->dmcu) { + dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp); + return true; + } + + if (abm != NULL) { + uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; + + if (abm && panel_cntl) { + if (abm->funcs && abm->funcs->set_pipe_ex) { + abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + } else { + dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + } + } + } + + if (abm && abm->funcs && abm->funcs->set_backlight_level_pwm) + abm->funcs->set_backlight_level_pwm(abm, backlight_pwm_u16_16, + frame_ramp, 0, panel_cntl->inst); + else + dmub_abm_set_backlight(dc, backlight_pwm_u16_16, frame_ramp, panel_cntl->inst); + + return true; +} + +bool dcn21_is_abm_supported(struct dc *dc, + struct dc_state *context, struct dc_stream_state *stream) +{ + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == stream && + (pipe_ctx->prev_odm_pipe == NULL && pipe_ctx->next_odm_pipe == NULL)) + return true; + } + return false; +} + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h new file mode 100644 index 000000000000..9cee9bdb8de9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h @@ -0,0 +1,58 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN21_H__ +#define __DC_HWSS_DCN21_H__ + +#include "hw_sequencer_private.h" + +struct dc; + +int dcn21_init_sys_ctx(struct dce_hwseq *hws, + struct dc *dc, + struct dc_phy_addr_space_config *pa_config); + +bool dcn21_s0i3_golden_init_wa(struct dc *dc); + +void dcn21_exit_optimized_pwr_state( + const struct dc *dc, + struct dc_state *context); + +void dcn21_optimize_pwr_state( + const struct dc *dc, + struct dc_state *context); + +void dcn21_PLAT_58856_wa(struct dc_state *context, + struct pipe_ctx *pipe_ctx); + +void dcn21_set_pipe(struct pipe_ctx *pipe_ctx); +void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx); +bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, + uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp); +bool dcn21_is_abm_supported(struct dc *dc, + struct dc_state *context, struct dc_stream_state *stream); + +#endif /* __DC_HWSS_DCN21_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c new file mode 100644 index 000000000000..9247a8ed5570 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -0,0 +1,1047 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dcn30_hwseq.h" +#include "dccg.h" +#include "dce/dce_hwseq.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn10/dcn10_cm_common.h" +#include "dcn30/dcn30_cm_common.h" +#include "reg_helper.h" +#include "abm.h" +#include "clk_mgr.h" +#include "hubp.h" +#include "dchubbub.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "dc_dmub_srv.h" +#include "link_hwss.h" +#include "dpcd_defs.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_resource.h" +#include "link.h" + + + + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg +#define DC_LOGGER \ + dc->ctx->logger + + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +bool dcn30_set_blend_lut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + bool result = true; + struct pwl_params *blend_lut = NULL; + + if (plane_state->blend_tf) { + if (plane_state->blend_tf->type == TF_TYPE_HWPWL) + blend_lut = &plane_state->blend_tf->pwl; + else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm3_helper_translate_curve_to_hw_format( + plane_state->blend_tf, &dpp_base->regamma_params, false); + blend_lut = &dpp_base->regamma_params; + } + } + result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut); + + return result; +} + +static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + bool result = false; + int acquired_rmu = 0; + int mpcc_id_projected = 0; + + const struct pwl_params *shaper_lut = NULL; + //get the shaper lut params + if (stream->func_shaper) { + if (stream->func_shaper->type == TF_TYPE_HWPWL) { + shaper_lut = &stream->func_shaper->pwl; + } else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_hw_format(stream->ctx, stream->func_shaper, + &dpp_base->shaper_params, true); + shaper_lut = &dpp_base->shaper_params; + } + } + + if (stream->lut3d_func && + stream->lut3d_func->state.bits.initialized == 1 && + stream->lut3d_func->state.bits.rmu_idx_valid == 1) { + if (stream->lut3d_func->state.bits.rmu_mux_num == 0) + mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux; + else if (stream->lut3d_func->state.bits.rmu_mux_num == 1) + mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu1_mux; + else if (stream->lut3d_func->state.bits.rmu_mux_num == 2) + mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux; + if (mpcc_id_projected != mpcc_id) + BREAK_TO_DEBUGGER(); + /* find the reason why logical layer assigned a different + * mpcc_id into acquire_post_bldn_3dlut + */ + acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id, + stream->lut3d_func->state.bits.rmu_mux_num); + if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num) + BREAK_TO_DEBUGGER(); + + result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d, + stream->lut3d_func->state.bits.rmu_mux_num); + result = mpc->funcs->program_shaper(mpc, shaper_lut, + stream->lut3d_func->state.bits.rmu_mux_num); + } else { + // loop through the available mux and release the requested mpcc_id + mpc->funcs->release_rmu(mpc, mpcc_id); + } + + return result; +} + +bool dcn30_set_input_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) +{ + struct dce_hwseq *hws = dc->hwseq; + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + enum dc_transfer_func_predefined tf; + bool result = true; + struct pwl_params *params = NULL; + + if (dpp_base == NULL || plane_state == NULL) + return false; + + tf = TRANSFER_FUNCTION_UNITY; + + if (plane_state->in_transfer_func && + plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED) + tf = plane_state->in_transfer_func->tf; + + dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf); + + if (plane_state->in_transfer_func) { + if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL) + params = &plane_state->in_transfer_func->pwl; + else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS && + cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func, + &dpp_base->degamma_params, false)) + params = &dpp_base->degamma_params; + } + + result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); + + if (pipe_ctx->stream_res.opp && pipe_ctx->stream_res.opp->ctx) { + if (dpp_base->funcs->dpp_program_blnd_lut) + hws->funcs.set_blend_lut(pipe_ctx, plane_state); + if (dpp_base->funcs->dpp_program_shaper_lut && + dpp_base->funcs->dpp_program_3dlut) + hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state); + } + + return result; +} + +void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx) +{ + int i = 0; + struct dpp_grph_csc_adjustment dpp_adjust; + struct mpc_grph_gamut_adjustment mpc_adjust; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + + memset(&dpp_adjust, 0, sizeof(dpp_adjust)); + dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + if (pipe_ctx->plane_state && + pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) { + dpp_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + dpp_adjust.temperature_matrix[i] = + pipe_ctx->plane_state->gamut_remap_matrix.matrix[i]; + } + + pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, + &dpp_adjust); + + memset(&mpc_adjust, 0, sizeof(mpc_adjust)); + mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + if (pipe_ctx->top_pipe == NULL) { + if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { + mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++) + mpc_adjust.temperature_matrix[i] = + pipe_ctx->stream->gamut_remap_matrix.matrix[i]; + } + } + + mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust); +} + +bool dcn30_set_output_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + struct pwl_params *params = NULL; + bool ret = false; + + /* program OGAM or 3DLUT only for the top pipe*/ + if (pipe_ctx->top_pipe == NULL) { + /*program rmu shaper and 3dlut in MPC*/ + ret = dcn30_set_mpc_shaper_3dlut(pipe_ctx, stream); + if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) { + if (stream->out_transfer_func->type == TF_TYPE_HWPWL) + params = &stream->out_transfer_func->pwl; + else if (pipe_ctx->stream->out_transfer_func->type == + TF_TYPE_DISTRIBUTED_POINTS && + cm3_helper_translate_curve_to_hw_format( + stream->out_transfer_func, + &mpc->blender_params, false)) + params = &mpc->blender_params; + /* there are no ROM LUTs in OUTGAM */ + if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) + BREAK_TO_DEBUGGER(); + } + } + + mpc->funcs->set_output_gamma(mpc, mpcc_id, params); + return ret; +} + +static void dcn30_set_writeback( + struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context) +{ + struct mcif_wb *mcif_wb; + struct mcif_buf_params *mcif_buf_params; + + ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES); + ASSERT(wb_info->wb_enabled); + ASSERT(wb_info->mpcc_inst >= 0); + ASSERT(wb_info->mpcc_inst < dc->res_pool->mpcc_count); + mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; + mcif_buf_params = &wb_info->mcif_buf_params; + + /* set DWB MPC mux */ + dc->res_pool->mpc->funcs->set_dwb_mux(dc->res_pool->mpc, + wb_info->dwb_pipe_inst, wb_info->mpcc_inst); + /* set MCIF_WB buffer and arbitration configuration */ + mcif_wb->funcs->config_mcif_buf(mcif_wb, mcif_buf_params, wb_info->dwb_params.dest_height); + mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); +} + +void dcn30_update_writeback( + struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context) +{ + struct dwbc *dwb; + dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ + __func__, wb_info->dwb_pipe_inst,\ + wb_info->mpcc_inst); + + dcn30_set_writeback(dc, wb_info, context); + + /* update DWB */ + dwb->funcs->update(dwb, &wb_info->dwb_params); +} + +bool dcn30_mmhubbub_warmup( + struct dc *dc, + unsigned int num_dwb, + struct dc_writeback_info *wb_info) +{ + struct dwbc *dwb; + struct mcif_wb *mcif_wb; + struct mcif_warmup_params warmup_params = {0}; + unsigned int i, i_buf; + /*make sure there is no active DWB eanbled */ + for (i = 0; i < num_dwb; i++) { + dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst]; + if (dwb->dwb_is_efc_transition || dwb->dwb_is_drc) { + /*can not do warmup while any dwb enabled*/ + return false; + } + } + + if (wb_info->mcif_warmup_params.p_vmid == 0) + return false; + + /*check whether this is new interface: warmup big buffer once*/ + if (wb_info->mcif_warmup_params.start_address.quad_part != 0 && + wb_info->mcif_warmup_params.region_size != 0) { + /*mmhubbub is shared, so it does not matter which MCIF*/ + mcif_wb = dc->res_pool->mcif_wb[0]; + /*warmup a big chunk of VM buffer at once*/ + warmup_params.start_address.quad_part = wb_info->mcif_warmup_params.start_address.quad_part; + warmup_params.address_increment = wb_info->mcif_warmup_params.region_size; + warmup_params.region_size = wb_info->mcif_warmup_params.region_size; + warmup_params.p_vmid = wb_info->mcif_warmup_params.p_vmid; + + if (warmup_params.address_increment == 0) + warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes; + + mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params); + return true; + } + /*following is the original: warmup each DWB's mcif buffer*/ + for (i = 0; i < num_dwb; i++) { + dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst]; + mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst]; + /*warmup is for VM mode only*/ + if (wb_info[i].mcif_buf_params.p_vmid == 0) + return false; + + /* Warmup MCIF_WB */ + for (i_buf = 0; i_buf < MCIF_BUF_COUNT; i_buf++) { + warmup_params.start_address.quad_part = wb_info[i].mcif_buf_params.luma_address[i_buf]; + warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes; + warmup_params.region_size = wb_info[i].mcif_buf_params.luma_pitch * wb_info[i].dwb_params.dest_height; + warmup_params.p_vmid = wb_info[i].mcif_buf_params.p_vmid; + mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params); + } + } + return true; +} + +void dcn30_enable_writeback( + struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context) +{ + struct dwbc *dwb; + struct mcif_wb *mcif_wb; + + dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; + + DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ + __func__, wb_info->dwb_pipe_inst,\ + wb_info->mpcc_inst); + + /* Warmup interface */ + dcn30_mmhubbub_warmup(dc, 1, wb_info); + + /* Update writeback pipe */ + dcn30_set_writeback(dc, wb_info, context); + + /* Enable MCIF_WB */ + mcif_wb->funcs->enable_mcif(mcif_wb); + /* Enable DWB */ + dwb->funcs->enable(dwb, &wb_info->dwb_params); +} + +void dcn30_disable_writeback( + struct dc *dc, + unsigned int dwb_pipe_inst) +{ + struct dwbc *dwb; + struct mcif_wb *mcif_wb; + + ASSERT(dwb_pipe_inst < MAX_DWB_PIPES); + dwb = dc->res_pool->dwbc[dwb_pipe_inst]; + mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst]; + DC_LOG_DWB("%s dwb_pipe_inst = %d",\ + __func__, dwb_pipe_inst); + + /* disable DWB */ + dwb->funcs->disable(dwb); + /* disable MCIF */ + mcif_wb->funcs->disable_mcif(mcif_wb); + /* disable MPC DWB mux */ + dc->res_pool->mpc->funcs->disable_dwb_mux(dc->res_pool->mpc, dwb_pipe_inst); +} + +void dcn30_program_all_writeback_pipes_in_tree( + struct dc *dc, + const struct dc_stream_state *stream, + struct dc_state *context) +{ + struct dc_writeback_info wb_info; + struct dwbc *dwb; + struct dc_stream_status *stream_status = NULL; + int i_wb, i_pipe, i_stream; + DC_LOG_DWB("%s", __func__); + + ASSERT(stream); + for (i_stream = 0; i_stream < context->stream_count; i_stream++) { + if (context->streams[i_stream] == stream) { + stream_status = &context->stream_status[i_stream]; + break; + } + } + ASSERT(stream_status); + + ASSERT(stream->num_wb_info <= dc->res_pool->res_cap->num_dwb); + /* For each writeback pipe */ + for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) { + + /* copy writeback info to local non-const so mpcc_inst can be set */ + wb_info = stream->writeback_info[i_wb]; + if (wb_info.wb_enabled) { + + /* get the MPCC instance for writeback_source_plane */ + wb_info.mpcc_inst = -1; + for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe]; + + if (!pipe_ctx->plane_state) + continue; + + if (pipe_ctx->plane_state == wb_info.writeback_source_plane) { + wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst; + break; + } + } + + if (wb_info.mpcc_inst == -1) { + /* Disable writeback pipe and disconnect from MPCC + * if source plane has been removed + */ + dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst); + continue; + } + + ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb); + dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst]; + if (dwb->funcs->is_enabled(dwb)) { + /* writeback pipe already enabled, only need to update */ + dc->hwss.update_writeback(dc, &wb_info, context); + } else { + /* Enable writeback pipe and connect to MPCC */ + dc->hwss.enable_writeback(dc, &wb_info, context); + } + } else { + /* Disable writeback pipe and disconnect from MPCC */ + dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst); + } + } +} + +void dcn30_init_hw(struct dc *dc) +{ + struct abm **abms = dc->res_pool->multiple_abms; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + struct resource_pool *res_pool = dc->res_pool; + int i; + int edp_num; + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + hws->funcs.bios_golden_init(dc); + hws->funcs.disable_vga(dc->hwseq); + } + + if (dc->debug.enable_mem_low_power.bits.dmcu) { + // Force ERAM to shutdown if DMCU is not enabled + if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { + REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); + } + } + + // Set default OPTC memory power states + if (dc->debug.enable_mem_low_power.bits.optc) { + // Shutdown when unassigned and light sleep in VBLANK + REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); + } + + if (dc->debug.enable_mem_low_power.bits.vga) { + // Power down VGA memory + REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); + } + + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + + if (res_pool->dccg && res_pool->hubbub) { + + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } else + ASSERT_CRITICAL(false); + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) { + link->link_status.link_active = true; + if (link->link_enc->funcs->fec_is_active && + link->link_enc->funcs->fec_is_active(link->link_enc)) + link->fec_state = dc_link_fec_enabled; + } + } + + /* we want to turn off all dp displays before doing detection */ + dc->link_srv->blank_all_dp_displays(dc); + + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + + /* If taking control over from VBIOS, we may want to optimize our first + * mode set, so we need to skip powering down pipes until we know which + * pipes we want to use. + * Otherwise, if taking control is not possible, we need to power + * everything down. + */ + if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } + + /* In headless boot cases, DIG may be turned + * on which causes HW/SW discrepancies. + * To avoid this, power down hardware on boot + * if DIG is turned on and seamless boot not enabled + */ + if (!dc->config.seamless_boot_edp_requested) { + struct dc_link *edp_links[MAX_NUM_EDP]; + struct dc_link *edp_link = NULL; + + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num) + edp_link = edp_links[0]; + if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + dc->hwss.edp_backlight_control && + dc->hwss.power_down && + dc->hwss.edp_power_control) { + dc->hwss.edp_backlight_control(edp_link, false); + dc->hwss.power_down(dc); + dc->hwss.edp_power_control(edp_link, false); + } else { + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc) && + dc->hwss.power_down) { + dc->hwss.power_down(dc); + break; + } + + } + } + } + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (abms[i] != NULL) + abms[i]->funcs->abm_init(abms[i], backlight); + } + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) + dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); + + if (dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); + + //if softmax is enabled then hardmax will be set by a different call + if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); + + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, false, false); + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); + + // Get DMCUB capabilities + dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); + dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; + dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; +} + +void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) +{ + if (pipe_ctx == NULL) + return; + + if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) + pipe_ctx->stream_res.stream_enc->funcs->set_avmute( + pipe_ctx->stream_res.stream_enc, + enable); +} + +void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx) +{ + bool is_hdmi_tmds; + bool is_dp; + + ASSERT(pipe_ctx->stream); + + if (pipe_ctx->stream_res.stream_enc == NULL) + return; /* this is not root pipe */ + + is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); + is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); + + if (!is_hdmi_tmds && !is_dp) + return; + + if (is_hdmi_tmds) + pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + else { + if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num) + pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + + pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + } +} + +void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + bool enable = false; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) + ? dmdata_dp + : dmdata_hdmi; + + /* if using dynamic meta, don't set up generic infopackets */ + if (pipe_ctx->stream->dmdata_address.quad_part != 0) { + pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; + enable = true; + } + + if (!hubp) + return; + + if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) + return; + + stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, + hubp->inst, mode); +} + +bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable) +{ + union dmub_rb_cmd cmd; + uint32_t tmr_delay = 0, tmr_scale = 0; + struct dc_cursor_attributes cursor_attr; + bool cursor_cache_enable = false; + struct dc_stream_state *stream = NULL; + struct dc_plane_state *plane = NULL; + + if (!dc->ctx->dmub_srv) + return false; + + if (enable) { + if (dc->current_state) { + int i; + + /* First, check no-memory-requests case */ + for (i = 0; i < dc->current_state->stream_count; i++) { + if (dc->current_state->stream_status[i].plane_count) + /* Fail eligibility on a visible stream */ + break; + } + + if (i == dc->current_state->stream_count) { + /* Enable no-memory-requests case */ + memset(&cmd, 0, sizeof(cmd)); + cmd.mall.header.type = DMUB_CMD__MALL; + cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ; + cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + + return true; + } + + stream = dc->current_state->streams[0]; + plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL); + + if (stream && plane) { + cursor_cache_enable = stream->cursor_position.enable && + plane->address.grph.cursor_cache_addr.quad_part; + cursor_attr = stream->cursor_attributes; + } + + /* + * Second, check MALL eligibility + * + * single display only, single surface only, 8 and 16 bit formats only, no VM, + * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW + * + * TODO: When we implement multi-display, PSR displays will be allowed if there is + * a non-PSR display present, since in that case we can't do D0i3.2 + */ + if (dc->current_state->stream_count == 1 && + stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && + dc->current_state->stream_status[0].plane_count == 1 && + plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F && + plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 && + plane->address.page_table_base.quad_part == 0 && + dc->hwss.does_plane_fit_in_mall && + dc->hwss.does_plane_fit_in_mall(dc, plane, + cursor_cache_enable ? &cursor_attr : NULL)) { + unsigned int v_total = stream->adjust.v_total_max ? + stream->adjust.v_total_max : stream->timing.v_total; + unsigned int refresh_hz = div_u64((unsigned long long) stream->timing.pix_clk_100hz * + 100LL, (v_total * stream->timing.h_total)); + + /* + * one frame time in microsec: + * Delay_Us = 1000000 / refresh + * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period + * + * one frame time modified by 'additional timer percent' (p): + * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100 + * = dynamic_delay_us * (1 + p / 100) + * = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100 + * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) + * + * formula for timer duration based on parameters, from regspec: + * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale + * + * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale + * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly + * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64 + * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64 + * = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64 + * + * need to round up the result of the division before the subtraction + */ + unsigned int denom = refresh_hz * 6528; + unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us; + + tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) * + (100LL + dc->debug.mall_additional_timer_percent) + denom - 1), + denom) - 64LL; + + /* In some cases the stutter period is really big (tiny modes) in these + * cases MALL cant be enabled, So skip these cases to avoid a ASSERT() + * + * We can check if stutter_period is more than 1/10th the frame time to + * consider if we can actually meet the range of hysteresis timer + */ + if (stutter_period > 100000/refresh_hz) + return false; + + /* scale should be increased until it fits into 6 bits */ + while (tmr_delay & ~0x3F) { + tmr_scale++; + + if (tmr_scale > 3) { + /* Delay exceeds range of hysteresis timer */ + ASSERT(false); + return false; + } + + denom *= 2; + tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) * + (100LL + dc->debug.mall_additional_timer_percent) + denom - 1), + denom) - 64LL; + } + + /* Copy HW cursor */ + if (cursor_cache_enable) { + memset(&cmd, 0, sizeof(cmd)); + cmd.mall.header.type = DMUB_CMD__MALL; + cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR; + cmd.mall.header.payload_bytes = + sizeof(cmd.mall) - sizeof(cmd.mall.header); + + switch (cursor_attr.color_format) { + case CURSOR_MODE_MONO: + cmd.mall.cursor_bpp = 2; + break; + case CURSOR_MODE_COLOR_1BIT_AND: + case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: + case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: + cmd.mall.cursor_bpp = 32; + break; + + case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: + case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: + cmd.mall.cursor_bpp = 64; + break; + } + + cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part; + cmd.mall.cursor_copy_dst.quad_part = + (plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047; + cmd.mall.cursor_width = cursor_attr.width; + cmd.mall.cursor_height = cursor_attr.height; + cmd.mall.cursor_pitch = cursor_attr.pitch; + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + + /* Use copied cursor, and it's okay to not switch back */ + cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part; + dc_stream_set_cursor_attributes(stream, &cursor_attr); + } + + /* Enable MALL */ + memset(&cmd, 0, sizeof(cmd)); + cmd.mall.header.type = DMUB_CMD__MALL; + cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW; + cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); + cmd.mall.tmr_delay = tmr_delay; + cmd.mall.tmr_scale = tmr_scale; + cmd.mall.debug_bits = dc->debug.mall_error_as_fatal; + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + + return true; + } + } + + /* No applicable optimizations */ + return false; + } + + /* Disable MALL */ + memset(&cmd, 0, sizeof(cmd)); + cmd.mall.header.type = DMUB_CMD__MALL; + cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW; + cmd.mall.header.payload_bytes = + sizeof(cmd.mall) - sizeof(cmd.mall.header); + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + + return true; +} + +bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, struct dc_cursor_attributes *cursor_attr) +{ + // add meta size? + unsigned int surface_size = plane->plane_size.surface_pitch * plane->plane_size.surface_size.height * + (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4); + unsigned int mall_size = dc->caps.mall_size_total; + unsigned int cursor_size = 0; + + if (dc->debug.mall_size_override) + mall_size = 1024 * 1024 * dc->debug.mall_size_override; + + if (cursor_attr) { + cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size; + + switch (cursor_attr->color_format) { + case CURSOR_MODE_MONO: + cursor_size /= 2; + break; + case CURSOR_MODE_COLOR_1BIT_AND: + case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: + case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: + cursor_size *= 4; + break; + + case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: + case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: + cursor_size *= 8; + break; + } + } + + return (surface_size + cursor_size) < mall_size; +} + +void dcn30_hardware_release(struct dc *dc) +{ + bool subvp_in_use = false; + uint32_t i; + + dc_dmub_srv_p_state_delegate(dc, false, NULL); + dc_dmub_setup_subvp_dmub_command(dc, dc->current_state, false); + + /* SubVP treated the same way as FPO. If driver disable and + * we are using a SubVP config, disable and force on DCN side + * to prevent P-State hang on driver enable. + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe->stream) + continue; + + if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + subvp_in_use = true; + break; + } + } + /* If pstate unsupported, or still supported + * by firmware, force it supported by dcn + */ + if (dc->current_state) + if ((!dc->clk_mgr->clks.p_state_change_support || subvp_in_use || + dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) && + dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, true, true); +} + +void dcn30_set_disp_pattern_generator(const struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, int height, int offset) +{ + pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern, + color_space, color_depth, solid_color, width, height, offset); +} + +void dcn30_prepare_bandwidth(struct dc *dc, + struct dc_state *context) +{ + bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support; + /* Any transition into an FPO config should disable MCLK switching first to avoid + * driver and FW P-State synchronization issues. + */ + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) { + dc->optimized_required = true; + context->bw_ctx.bw.dcn.clk.p_state_change_support = false; + } + + if (dc->clk_mgr->dc_mode_softmax_enabled) + if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && + context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) + 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); + + dcn20_prepare_bandwidth(dc, context); + /* + * enabled -> enabled: do not disable + * enabled -> disabled: disable + * disabled -> enabled: don't care + * disabled -> disabled: don't care + */ + if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) + dc_dmub_srv_p_state_delegate(dc, false, context); + + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) { + /* After disabling P-State, restore the original value to ensure we get the correct P-State + * on the next optimize. */ + context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support; + } +} + +void dcn30_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params) +{ + unsigned int i; + unsigned int triggers = 0; + + if (params->triggers.surface_update) + triggers |= 0x100; + if (params->triggers.cursor_update) + triggers |= 0x8; + if (params->triggers.force_trigger) + triggers |= 0x1; + + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(pipe_ctx[i]->stream_res.tg, + triggers, params->num_frames); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h new file mode 100644 index 000000000000..e557e2b98618 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h @@ -0,0 +1,96 @@ +/* +* Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN30_H__ +#define __DC_HWSS_DCN30_H__ + +#include "hw_sequencer_private.h" +#include "dcn20/dcn20_hwseq.h" +struct dc; + +void dcn30_init_hw(struct dc *dc); +void dcn30_program_all_writeback_pipes_in_tree( + struct dc *dc, + const struct dc_stream_state *stream, + struct dc_state *context); +void dcn30_update_writeback( + struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context); +void dcn30_enable_writeback( + struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context); +void dcn30_disable_writeback( + struct dc *dc, + unsigned int dwb_pipe_inst); + +bool dcn30_mmhubbub_warmup( + struct dc *dc, + unsigned int num_dwb, + struct dc_writeback_info *wb_info); + +bool dcn30_set_blend_lut(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + +bool dcn30_set_input_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + +void dcn30_program_gamut_remap(struct pipe_ctx *pipe_ctx); + +bool dcn30_set_output_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); +void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); +void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx); +void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx); + +bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, + struct dc_cursor_attributes *cursor_attr); + +bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable); + +void dcn30_hardware_release(struct dc *dc); + +void dcn30_set_disp_pattern_generator(const struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, int height, int offset); + +void dcn30_set_hubp_blank(const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank_enable); + +void dcn30_prepare_bandwidth(struct dc *dc, + struct dc_state *context); + +void dcn30_set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_params *params); + +#endif /* __DC_HWSS_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_hwseq.c new file mode 100644 index 000000000000..10bedb2ea62a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_hwseq.c @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "core_types.h" +#include "dce/dce_hwseq.h" +#include "dcn301_hwseq.h" +#include "reg_helper.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + + diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_hwseq.h new file mode 100644 index 000000000000..aa3df3f77108 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_hwseq.h @@ -0,0 +1,32 @@ +/* +* Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN301_H__ +#define __DC_HWSS_DCN301_H__ + +#include "hw_sequencer_private.h" + + +#endif /* __DC_HWSS_DCN301_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_hwseq.c new file mode 100644 index 000000000000..0a6d58dd8f6d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_hwseq.c @@ -0,0 +1,223 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dcn302_hwseq.h" + +#include "dce/dce_hwseq.h" + +#include "reg_helper.h" +#include "dc.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + + +void dcn302_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_dpp_power_gate) + return; + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; + + switch (dpp_inst) { + case 0: /* DPP0 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, + DOMAIN1_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN1_PG_STATUS, + DOMAIN1_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DPP1 */ + REG_UPDATE(DOMAIN3_PG_CONFIG, + DOMAIN3_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN3_PG_STATUS, + DOMAIN3_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DPP2 */ + REG_UPDATE(DOMAIN5_PG_CONFIG, + DOMAIN5_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN5_PG_STATUS, + DOMAIN5_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DPP3 */ + REG_UPDATE(DOMAIN7_PG_CONFIG, + DOMAIN7_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN7_PG_STATUS, + DOMAIN7_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DPP4 */ + REG_UPDATE(DOMAIN9_PG_CONFIG, + DOMAIN9_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN9_PG_STATUS, + DOMAIN9_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +void dcn302_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; + + switch (hubp_inst) { + case 0: /* DCHUBP0 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, + DOMAIN0_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN0_PG_STATUS, + DOMAIN0_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DCHUBP1 */ + REG_UPDATE(DOMAIN2_PG_CONFIG, + DOMAIN2_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN2_PG_STATUS, + DOMAIN2_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DCHUBP2 */ + REG_UPDATE(DOMAIN4_PG_CONFIG, + DOMAIN4_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN4_PG_STATUS, + DOMAIN4_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DCHUBP3 */ + REG_UPDATE(DOMAIN6_PG_CONFIG, + DOMAIN6_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN6_PG_STATUS, + DOMAIN6_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DCHUBP4 */ + REG_UPDATE(DOMAIN8_PG_CONFIG, + DOMAIN8_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN8_PG_STATUS, + DOMAIN8_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +void dcn302_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + + if (REG(DOMAIN16_PG_CONFIG) == 0) + return; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN16_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN16_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN17_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN17_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN18_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN18_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DSC3 */ + REG_UPDATE(DOMAIN19_PG_CONFIG, + DOMAIN19_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN19_PG_STATUS, + DOMAIN19_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DSC4 */ + REG_UPDATE(DOMAIN20_PG_CONFIG, + DOMAIN20_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN20_PG_STATUS, + DOMAIN20_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_hwseq.h new file mode 100644 index 000000000000..1e5126a0e695 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_hwseq.h @@ -0,0 +1,35 @@ +/* + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN302_H__ +#define __DC_HWSS_DCN302_H__ + +#include "hw_sequencer_private.h" + +void dcn302_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on); +void dcn302_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); +void dcn302_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); + +#endif /* __DC_HWSS_DCN302_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.c new file mode 100644 index 000000000000..b48b732aa647 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2021 Advanced Micro Devices, Inc. + * + * Authors: AMD + */ + +#include "dcn303_hwseq.h" + +#include "dce/dce_hwseq.h" + +#include "reg_helper.h" +#include "dc.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + + +void dcn303_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) +{ + /*DCN303 removes PG registers*/ +} + +void dcn303_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) +{ + /*DCN303 removes PG registers*/ +} + +void dcn303_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on) +{ + /*DCN303 removes PG registers*/ +} + +void dcn303_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) +{ + /*DCN303 removes PG registers*/ +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.h new file mode 100644 index 000000000000..8b69a3b76c11 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_hwseq.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 2021 Advanced Micro Devices, Inc. + * + * Authors: AMD + */ + +#ifndef __DC_HWSS_DCN303_H__ +#define __DC_HWSS_DCN303_H__ + +#include "hw_sequencer_private.h" + +void dcn303_dpp_pg_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on); +void dcn303_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); +void dcn303_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); +void dcn303_enable_power_gating_plane(struct dce_hwseq *hws, bool enable); + +#endif /* __DC_HWSS_DCN303_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c new file mode 100644 index 000000000000..c339f756b8e7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -0,0 +1,604 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dccg.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "reg_helper.h" +#include "abm.h" +#include "hubp.h" +#include "dchubbub.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "dc_dmub_srv.h" +#include "dcn31_hwseq.h" +#include "link_hwss.h" +#include "dpcd_defs.h" +#include "dce/dmub_outbox.h" +#include "link.h" +#include "dcn10/dcn10_hwseq.h" +#include "inc/link_enc_cfg.h" +#include "dcn30/dcn30_vpg.h" +#include "dce/dce_i2c_hw.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg +#define DC_LOGGER \ + dc->ctx->logger + + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +static void enable_memory_low_power(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + int i; + + if (dc->debug.enable_mem_low_power.bits.dmcu) { + // Force ERAM to shutdown if DMCU is not enabled + if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { + REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); + } + } + + // Set default OPTC memory power states + if (dc->debug.enable_mem_low_power.bits.optc) { + // Shutdown when unassigned and light sleep in VBLANK + REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); + } + + if (dc->debug.enable_mem_low_power.bits.vga) { + // Power down VGA memory + REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); + } + + if (dc->debug.enable_mem_low_power.bits.mpc && + dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode) + dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc); + + + if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) { + // Power down VPGs + for (i = 0; i < dc->res_pool->stream_enc_count; i++) + if (dc->res_pool->stream_enc[i]->vpg) + dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); +#if defined(CONFIG_DRM_AMD_DC_FP) + for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) + dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); +#endif + } + +} + +void dcn31_init_hw(struct dc *dc) +{ + struct abm **abms = dc->res_pool->multiple_abms; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + struct resource_pool *res_pool = dc->res_pool; + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + int i; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + hws->funcs.bios_golden_init(dc); + if (hws->funcs.disable_vga) + hws->funcs.disable_vga(dc->hwseq); + } + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + enable_memory_low_power(dc); + + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + + if (res_pool->dccg && res_pool->hubbub) { + + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } else + ASSERT_CRITICAL(false); + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + if (link->ep_type != DISPLAY_ENDPOINT_PHY) + continue; + + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) { + link->link_status.link_active = true; + if (link->link_enc->funcs->fec_is_active && + link->link_enc->funcs->fec_is_active(link->link_enc)) + link->fec_state = dc_link_fec_enabled; + } + } + + /* we want to turn off all dp displays before doing detection */ + dc->link_srv->blank_all_dp_displays(dc); + + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + + /* If taking control over from VBIOS, we may want to optimize our first + * mode set, so we need to skip powering down pipes until we know which + * pipes we want to use. + * Otherwise, if taking control is not possible, we need to power + * everything down. + */ + if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { + + // we want to turn off edp displays if odm is enabled and no seamless boot + if (!dc->caps.seamless_odm) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + uint32_t num_opps, opp_id_src0, opp_id_src1; + + num_opps = 1; + if (tg) { + if (tg->funcs->is_tg_enabled(tg) && tg->funcs->get_optc_source) { + tg->funcs->get_optc_source(tg, &num_opps, + &opp_id_src0, &opp_id_src1); + } + } + + if (num_opps > 1) { + dc->link_srv->blank_all_edp_displays(dc); + break; + } + } + } + + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (abms[i] != NULL) + abms[i]->funcs->abm_init(abms[i], backlight); + } + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + // Set i2c to light sleep until engine is setup + if (dc->debug.enable_mem_low_power.bits.i2c) + REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1); + + if (hws->funcs.setup_hpo_hw_control) + hws->funcs.setup_hpo_hw_control(hws, false); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) + dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); + + if (dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); + + if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); + + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, false, false); +#if defined(CONFIG_DRM_AMD_DC_FP) + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); +#endif + + // Get DMCUB capabilities + dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); + dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; + dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; +} + +void dcn31_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + + if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc && + hws->ctx->dc->res_pool->dccg->funcs->enable_dsc && + power_on) + hws->ctx->dc->res_pool->dccg->funcs->enable_dsc( + hws->ctx->dc->res_pool->dccg, dsc_inst); + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); + + if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc) { + if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) + hws->ctx->dc->res_pool->dccg->funcs->disable_dsc( + hws->ctx->dc->res_pool->dccg, dsc_inst); + } + +} + + +void dcn31_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable) +{ + bool force_on = true; /* disable power gating */ + uint32_t org_ip_request_cntl = 0; + + if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate) + force_on = false; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + /* DCHUBP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + /* DPP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + force_on = true; /* disable power gating */ + if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) + force_on = false; + + /* DCS0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + +void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx) +{ + bool is_hdmi_tmds; + bool is_dp; + + ASSERT(pipe_ctx->stream); + + if (pipe_ctx->stream_res.stream_enc == NULL) + return; /* this is not root pipe */ + + is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal); + is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); + + if (!is_hdmi_tmds && !is_dp) + return; + + if (is_hdmi_tmds) + pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + else if (pipe_ctx->stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets( + pipe_ctx->stream_res.hpo_dp_stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + return; + } else { + if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num) + pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + + pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( + pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream_res.encoder_info_frame); + } +} +void dcn31_z10_save_init(struct dc *dc) +{ + union dmub_rb_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; + cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT; + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +} + +void dcn31_z10_restore(const struct dc *dc) +{ + union dmub_rb_cmd cmd; + + /* + * DMUB notifies whether restore is required. + * Optimization to avoid sending commands when not required. + */ + if (!dc_dmub_srv_is_restore_required(dc->ctx->dmub_srv)) + return; + + memset(&cmd, 0, sizeof(cmd)); + cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; + cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_RESTORE; + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +} + +void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl; + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (hubp_inst) { + case 0: + REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 1: + REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 2: + REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 3: + REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + +int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) +{ + struct dcn_hubbub_phys_addr_config config; + + config.system_aperture.fb_top = pa_config->system_aperture.fb_top; + config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; + config.system_aperture.fb_base = pa_config->system_aperture.fb_base; + config.system_aperture.agp_top = pa_config->system_aperture.agp_top; + config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; + config.system_aperture.agp_base = pa_config->system_aperture.agp_base; + config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; + config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; + + if (pa_config->gart_config.base_addr_is_mc_addr) { + /* Convert from MC address to offset into FB */ + config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr - + pa_config->system_aperture.fb_base + + pa_config->system_aperture.fb_offset; + } else + config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; + + return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); +} + +static void dcn31_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dc_link *link; + + DC_LOGGER_INIT(dc->ctx->logger); + if (pipe_ctx->stream_res.stream_enc == NULL) { + pipe_ctx->stream = NULL; + return; + } + ASSERT(!pipe_ctx->top_pipe); + + dc->hwss.set_abm_immediate_disable(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, + OPTC_DSC_DISABLED, 0, 0); + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); + if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; + + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); + + link = pipe_ctx->stream->link; + /* DPMS may already disable or */ + /* dpms_off status is incorrect due to fastboot + * feature. When system resume from S4 with second + * screen only, the dpms_off would be true but + * VBIOS lit up eDP, so check link status too. + */ + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) + dc->link_srv->set_dpms_off(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + /* free acquired resources */ + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } + } + + pipe_ctx->stream = NULL; + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", + pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); +} + +void dcn31_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + + /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + dcn31_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx_old); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } + + /* New dc_state in the process of being applied to hardware. */ + link_enc_cfg_set_transient_mode(dc, dc->current_state, context); +} + +void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) +{ + if (hws->ctx->dc->debug.hpo_optimization) + REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h new file mode 100644 index 000000000000..edfc01d6ad73 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h @@ -0,0 +1,59 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN31_H__ +#define __DC_HWSS_DCN31_H__ + +#include "hw_sequencer_private.h" + +struct dc; + +void dcn31_init_hw(struct dc *dc); + +void dcn31_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + +void dcn31_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable); + +void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx); + +void dcn31_z10_restore(const struct dc *dc); +void dcn31_z10_save_init(struct dc *dc); + +void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); +int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config); +void dcn31_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context); +bool dcn31_is_abm_supported(struct dc *dc, + struct dc_state *context, struct dc_stream_state *stream); +void dcn31_init_pipes(struct dc *dc, struct dc_state *context); +void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); + +#endif /* __DC_HWSS_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c new file mode 100644 index 000000000000..3a9cc8ac0c07 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dccg.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "reg_helper.h" +#include "abm.h" +#include "hubp.h" +#include "dchubbub.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "dc_dmub_srv.h" +#include "dcn314_hwseq.h" +#include "link_hwss.h" +#include "dpcd_defs.h" +#include "dce/dmub_outbox.h" +#include "link.h" +#include "dcn10/dcn10_hwseq.h" +#include "inc/link_enc_cfg.h" +#include "dcn30/dcn30_vpg.h" +#include "dce/dce_i2c_hw.h" +#include "dsc.h" +#include "dcn20/dcn20_optc.h" +#include "dcn30/dcn30_cm_common.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg +#define DC_LOGGER \ + stream->ctx->logger + + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, + int opp_cnt) +{ + bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); + int flow_ctrl_cnt; + + if (opp_cnt >= 2) + hblank_halved = true; + + flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - + stream->timing.h_border_left - + stream->timing.h_border_right; + + if (hblank_halved) + flow_ctrl_cnt /= 2; + + /* ODM combine 4:1 case */ + if (opp_cnt == 4) + flow_ctrl_cnt /= 2; + + return flow_ctrl_cnt; +} + +static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) +{ + struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct dc_stream_state *stream = pipe_ctx->stream; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + ASSERT(dsc); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; + + if (enable) { + struct dsc_config dsc_cfg; + struct dsc_optc_config dsc_optc_cfg; + enum optc_dsc_mode optc_dsc_mode; + + /* Enable DSC hw block */ + dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; + dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; + dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; + dsc_cfg.color_depth = stream->timing.display_color_depth; + dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; + dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; + + dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); + dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; + + ASSERT(odm_dsc); + odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); + odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); + } + dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; + dsc_cfg.pic_width *= opp_cnt; + + optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; + + /* Enable DSC in OPTC */ + DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); + pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, + optc_dsc_mode, + dsc_optc_cfg.bytes_per_pixel, + dsc_optc_cfg.slice_width); + } else { + /* disable DSC in OPTC */ + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, + OPTC_DSC_DISABLED, 0, 0); + + /* disable DSC block */ + dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + ASSERT(odm_pipe->stream_res.dsc); + odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); + } + } +} + +// Given any pipe_ctx, return the total ODM combine factor, and optionally return +// the OPPids which are used +static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) +{ + unsigned int opp_count = 1; + struct pipe_ctx *odm_pipe; + + // First get to the top pipe + for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) + ; + + // First pipe is always used + if (opp_instances) + opp_instances[0] = odm_pipe->stream_res.opp->inst; + + // Find and count odm pipes, if any + for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + if (opp_instances) + opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; + opp_count++; + } + + return opp_count; +} + +void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *odm_pipe; + int opp_cnt = 0; + int opp_inst[MAX_PIPES] = {0}; + bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); + struct mpc_dwb_flow_control flow_control; + struct mpc *mpc = dc->res_pool->mpc; + int i; + + opp_cnt = get_odm_config(pipe_ctx, opp_inst); + + if (opp_cnt > 1) + pipe_ctx->stream_res.tg->funcs->set_odm_combine( + pipe_ctx->stream_res.tg, + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); + else + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; + flow_control.flow_ctrl_mode = 0; + flow_control.flow_ctrl_cnt0 = 0x80; + flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt); + if (mpc->funcs->set_out_rate_control) { + for (i = 0; i < opp_cnt; ++i) { + mpc->funcs->set_out_rate_control( + mpc, opp_inst[i], + true, + rate_control_2x_pclk, + &flow_control); + } + } + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( + odm_pipe->stream_res.opp, + true); + } + + if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; + + update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); + + /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ + if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && + current_pipe_ctx->next_odm_pipe->stream_res.dsc) { + struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; + /* disconnect DSC block from stream */ + dsc->funcs->dsc_disconnect(dsc); + } + } +} + +void dcn314_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + + if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc && + hws->ctx->dc->res_pool->dccg->funcs->enable_dsc && + power_on) + hws->ctx->dc->res_pool->dccg->funcs->enable_dsc( + hws->ctx->dc->res_pool->dccg, dsc_inst); + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DSC3 */ + REG_UPDATE(DOMAIN19_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN19_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); + + if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc) { + if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) + hws->ctx->dc->res_pool->dccg->funcs->disable_dsc( + hws->ctx->dc->res_pool->dccg, dsc_inst); + } + +} + +void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) +{ + bool force_on = true; /* disable power gating */ + uint32_t org_ip_request_cntl = 0; + + if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate) + force_on = false; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + /* DCHUBP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + /* DPP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + force_on = true; /* disable power gating */ + if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) + force_on = false; + + /* DCS0/1/2/3/4 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + +unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + unsigned int odm_combine_factor = 0; + bool two_pix_per_container = false; + + two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); + odm_combine_factor = get_odm_config(pipe_ctx, NULL); + + if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + *k1_div = PIXEL_RATE_DIV_BY_1; + *k2_div = PIXEL_RATE_DIV_BY_1; + } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) { + *k1_div = PIXEL_RATE_DIV_BY_1; + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + *k2_div = PIXEL_RATE_DIV_BY_2; + else + *k2_div = PIXEL_RATE_DIV_BY_4; + } else if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) { + if (two_pix_per_container) { + *k1_div = PIXEL_RATE_DIV_BY_1; + *k2_div = PIXEL_RATE_DIV_BY_2; + } else { + *k1_div = PIXEL_RATE_DIV_BY_1; + *k2_div = PIXEL_RATE_DIV_BY_4; + if (odm_combine_factor == 2) + *k2_div = PIXEL_RATE_DIV_BY_2; + } + } + + if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA)) + ASSERT(false); + + return odm_combine_factor; +} + +void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) +{ + uint32_t pix_per_cycle = 1; + uint32_t odm_combine_factor = 1; + + if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc) + return; + + odm_combine_factor = get_odm_config(pipe_ctx, NULL); + if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1) + pix_per_cycle = 2; + + if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) + pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, + pix_per_cycle); +} + +void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context) +{ + unsigned int i; + struct pipe_ctx *pipe = NULL; + bool otg_disabled[MAX_PIPES] = {false}; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (pipe->top_pipe || pipe->prev_odm_pipe) + continue; + + if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { + pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg); + reset_sync_context_for_pipe(dc, context, i); + otg_disabled[i] = true; + } + } + + hws->ctx->dc->res_pool->dccg->funcs->trigger_dio_fifo_resync(hws->ctx->dc->res_pool->dccg); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (otg_disabled[i]) + pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); + } +} + +void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on) +{ + if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp) + return; + + if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control) + hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control( + hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on); +} + +static void apply_symclk_on_tx_off_wa(struct dc_link *link) +{ + /* There are use cases where SYMCLK is referenced by OTG. For instance + * for TMDS signal, OTG relies SYMCLK even if TX video output is off. + * However current link interface will power off PHY when disabling link + * output. This will turn off SYMCLK generated by PHY. The workaround is + * to identify such case where SYMCLK is still in use by OTG when we + * power off PHY. When this is detected, we will temporarily power PHY + * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling + * program_pix_clk interface. When OTG is disabled, we will then power + * off PHY by calling disable link output again. + * + * In future dcn generations, we plan to rework transmitter control + * interface so that we could have an option to set SYMCLK ON TX OFF + * state in one step without this workaround + */ + + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + if (link->phy_state.symclk_ref_cnts.otg > 0) { + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) { + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format( + &pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + break; + } + } + } +} + +void dcn314_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control && + !link->skip_implict_edp_power_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + /* + * Add the logic to extract BOTH power up and power down sequences + * from enable/disable link output and only call edp panel control + * in enable_link_dp and disable_link_dp once. + */ + if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->unlock_phy(dmcu); + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); + + apply_symclk_on_tx_off_wa(link); +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h new file mode 100644 index 000000000000..eafcc4ea6d24 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN314_H__ +#define __DC_HWSS_DCN314_H__ + +#include "hw_sequencer_private.h" + +struct dc; + +void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); + +void dcn314_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); + +void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable); + +unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div); + +void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx); + +void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context); + +void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on); + +void dcn314_disable_link_output(struct dc_link *link, const struct link_resource *link_res, enum signal_type signal); + +#endif /* __DC_HWSS_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c new file mode 100644 index 000000000000..68dc99034eba --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -0,0 +1,1678 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dccg.h" +#include "dce/dce_hwseq.h" +#include "dcn30/dcn30_cm_common.h" +#include "reg_helper.h" +#include "abm.h" +#include "hubp.h" +#include "dchubbub.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "dc_dmub_srv.h" +#include "link_hwss.h" +#include "dpcd_defs.h" +#include "dcn32_hwseq.h" +#include "clk_mgr.h" +#include "dsc.h" +#include "dcn20/dcn20_optc.h" +#include "dce/dmub_hw_lock_mgr.h" +#include "dcn32/dcn32_resource.h" +#include "link.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg +#define DC_LOGGER \ + stream->ctx->logger + + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +void dcn32_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + + if (!hws->ctx->dc->debug.enable_double_buffered_dsc_pg_support) + return; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DSC3 */ + REG_UPDATE(DOMAIN19_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN19_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + + +void dcn32_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable) +{ + bool force_on = true; /* disable power gating */ + uint32_t org_ip_request_cntl = 0; + + if (enable) + force_on = false; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + /* DCHUBP0/1/2/3 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + /* DCS0/1/2/3 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + +void dcn32_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; + + switch (hubp_inst) { + case 0: + REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 1: + REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 2: + REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + case 3: + REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate); + REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +static bool dcn32_check_no_memory_request_for_cab(struct dc *dc) +{ + int i; + + /* First, check no-memory-request case */ + for (i = 0; i < dc->current_state->stream_count; i++) { + if ((dc->current_state->stream_status[i].plane_count) && + (dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)) + /* Fail eligibility on a visible stream */ + break; + } + + if (i == dc->current_state->stream_count) + return true; + + return false; +} + + +/* This function loops through every surface that needs to be cached in CAB for SS, + * and calculates the total number of ways required to store all surfaces (primary, + * meta, cursor). + */ +static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx) +{ + int i; + uint8_t num_ways = 0; + uint32_t mall_ss_size_bytes = 0; + + mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes; + // TODO add additional logic for PSR active stream exclusion optimization + // mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes; + + // Include cursor size for CAB allocation + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i]; + + if (!pipe->stream || !pipe->plane_state) + continue; + + mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false); + } + + // Convert number of cache lines required to number of ways + if (dc->debug.force_mall_ss_num_ways > 0) { + num_ways = dc->debug.force_mall_ss_num_ways; + } else { + num_ways = dcn32_helper_mall_bytes_to_ways(dc, mall_ss_size_bytes); + } + + return num_ways; +} + +bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) +{ + union dmub_rb_cmd cmd; + uint8_t ways, i; + int j; + bool mall_ss_unsupported = false; + struct dc_plane_state *plane = NULL; + + if (!dc->ctx->dmub_srv) + return false; + + for (i = 0; i < dc->current_state->stream_count; i++) { + /* MALL SS messaging is not supported with PSR at this time */ + if (dc->current_state->streams[i] != NULL && + dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) + return false; + } + + if (enable) { + if (dc->current_state) { + + /* 1. Check no memory request case for CAB. + * If no memory request case, send CAB_ACTION NO_DF_REQ DMUB message + */ + if (dcn32_check_no_memory_request_for_cab(dc)) { + /* Enable no-memory-requests case */ + memset(&cmd, 0, sizeof(cmd)); + cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; + cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ; + cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + + return true; + } + + /* 2. Check if all surfaces can fit in CAB. + * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message + * and configure HUBP's to fetch from MALL + */ + ways = dcn32_calculate_cab_allocation(dc, dc->current_state); + + /* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo, + * or TMZ surface, don't try to enter MALL. + */ + for (i = 0; i < dc->current_state->stream_count; i++) { + for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) { + plane = dc->current_state->stream_status[i].plane_states[j]; + + if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO || + plane->address.tmz_surface) { + mall_ss_unsupported = true; + break; + } + } + if (mall_ss_unsupported) + break; + } + if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) { + memset(&cmd, 0, sizeof(cmd)); + cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; + cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB; + cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); + cmd.cab.cab_alloc_ways = ways; + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + + return true; + } + + } + return false; + } + + /* Disable CAB */ + memset(&cmd, 0, sizeof(cmd)); + cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; + cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION; + cmd.cab.header.payload_bytes = + sizeof(cmd.cab) - sizeof(cmd.cab.header); + + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + + return true; +} + +/* Send DMCUB message with SubVP pipe info + * - For each pipe in context, populate payload with required SubVP information + * if the pipe is using SubVP for MCLK switch + * - This function must be called while the DMUB HW lock is acquired by driver + */ +void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context) +{ + int i; + bool enable_subvp = false; + + if (!dc->ctx || !dc->ctx->dmub_srv) + return; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.paired_stream && + pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { + // There is at least 1 SubVP pipe, so enable SubVP + enable_subvp = true; + break; + } + } + dc_dmub_setup_subvp_dmub_command(dc, context, enable_subvp); +} + +/* Sub-Viewport DMUB lock needs to be acquired by driver whenever SubVP is active and: + * 1. Any full update for any SubVP main pipe + * 2. Any immediate flip for any SubVP pipe + * 3. Any flip for DRR pipe + * 4. If SubVP was previously in use (i.e. in old context) + */ +void dcn32_subvp_pipe_control_lock(struct dc *dc, + struct dc_state *context, + bool lock, + bool should_lock_all_pipes, + struct pipe_ctx *top_pipe_to_program, + bool subvp_prev_use) +{ + unsigned int i = 0; + bool subvp_immediate_flip = false; + bool subvp_in_use = false; + struct pipe_ctx *pipe; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + subvp_in_use = true; + break; + } + } + + if (top_pipe_to_program && top_pipe_to_program->stream && top_pipe_to_program->plane_state) { + if (top_pipe_to_program->stream->mall_stream_config.type == SUBVP_MAIN && + top_pipe_to_program->plane_state->flip_immediate) + subvp_immediate_flip = true; + } + + // Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared. + if ((subvp_in_use && (should_lock_all_pipes || subvp_immediate_flip)) || (!subvp_in_use && subvp_prev_use)) { + union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; + + if (!lock) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &context->res_ctx.pipe_ctx[i]; + if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN && + should_lock_all_pipes) + pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK); + } + } + + hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; + hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; + hw_lock_cmd.bits.lock = lock; + hw_lock_cmd.bits.should_release = !lock; + dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); + } +} + +void dcn32_subvp_pipe_control_lock_fast(union block_sequence_params *params) +{ + struct dc *dc = params->subvp_pipe_control_lock_fast_params.dc; + bool lock = params->subvp_pipe_control_lock_fast_params.lock; + struct pipe_ctx *pipe_ctx = params->subvp_pipe_control_lock_fast_params.pipe_ctx; + bool subvp_immediate_flip = false; + + if (pipe_ctx && pipe_ctx->stream && pipe_ctx->plane_state) { + if (pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN && + pipe_ctx->plane_state->flip_immediate) + subvp_immediate_flip = true; + } + + // Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared. + if (subvp_immediate_flip) { + union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; + + hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; + hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; + hw_lock_cmd.bits.lock = lock; + hw_lock_cmd.bits.should_release = !lock; + dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); + } +} + +bool dcn32_set_mpc_shaper_3dlut( + struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + bool result = false; + + const struct pwl_params *shaper_lut = NULL; + //get the shaper lut params + if (stream->func_shaper) { + if (stream->func_shaper->type == TF_TYPE_HWPWL) + shaper_lut = &stream->func_shaper->pwl; + else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_hw_format(stream->ctx, + stream->func_shaper, + &dpp_base->shaper_params, true); + shaper_lut = &dpp_base->shaper_params; + } + } + + if (stream->lut3d_func && + stream->lut3d_func->state.bits.initialized == 1) { + + result = mpc->funcs->program_3dlut(mpc, + &stream->lut3d_func->lut_3d, + mpcc_id); + + result = mpc->funcs->program_shaper(mpc, + shaper_lut, + mpcc_id); + } + + return result; +} + +bool dcn32_set_mcm_luts( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + bool result = true; + struct pwl_params *lut_params = NULL; + + // 1D LUT + if (plane_state->blend_tf) { + if (plane_state->blend_tf->type == TF_TYPE_HWPWL) + lut_params = &plane_state->blend_tf->pwl; + else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_hw_format(plane_state->ctx, + plane_state->blend_tf, + &dpp_base->regamma_params, false); + lut_params = &dpp_base->regamma_params; + } + } + result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id); + + // Shaper + if (plane_state->in_shaper_func) { + if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL) + lut_params = &plane_state->in_shaper_func->pwl; + else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { + // TODO: dpp_base replace + ASSERT(false); + cm_helper_translate_curve_to_hw_format(plane_state->ctx, + plane_state->in_shaper_func, + &dpp_base->shaper_params, true); + lut_params = &dpp_base->shaper_params; + } + } + + result = mpc->funcs->program_shaper(mpc, lut_params, mpcc_id); + + // 3D + if (plane_state->lut3d_func && plane_state->lut3d_func->state.bits.initialized == 1) + result = mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func->lut_3d, mpcc_id); + else + result = mpc->funcs->program_3dlut(mpc, NULL, mpcc_id); + + return result; +} + +bool dcn32_set_input_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) +{ + struct dce_hwseq *hws = dc->hwseq; + struct mpc *mpc = dc->res_pool->mpc; + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + + enum dc_transfer_func_predefined tf; + bool result = true; + struct pwl_params *params = NULL; + + if (mpc == NULL || plane_state == NULL) + return false; + + tf = TRANSFER_FUNCTION_UNITY; + + if (plane_state->in_transfer_func && + plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED) + tf = plane_state->in_transfer_func->tf; + + dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf); + + if (plane_state->in_transfer_func) { + if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL) + params = &plane_state->in_transfer_func->pwl; + else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS && + cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func, + &dpp_base->degamma_params, false)) + params = &dpp_base->degamma_params; + } + + dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); + + if (pipe_ctx->stream_res.opp && + pipe_ctx->stream_res.opp->ctx && + hws->funcs.set_mcm_luts) + result = hws->funcs.set_mcm_luts(pipe_ctx, plane_state); + + return result; +} + +bool dcn32_set_output_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + struct pwl_params *params = NULL; + bool ret = false; + + /* program OGAM or 3DLUT only for the top pipe*/ + if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) { + /*program shaper and 3dlut in MPC*/ + ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream); + if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) { + if (stream->out_transfer_func->type == TF_TYPE_HWPWL) + params = &stream->out_transfer_func->pwl; + else if (pipe_ctx->stream->out_transfer_func->type == + TF_TYPE_DISTRIBUTED_POINTS && + cm3_helper_translate_curve_to_hw_format( + stream->out_transfer_func, + &mpc->blender_params, false)) + params = &mpc->blender_params; + /* there are no ROM LUTs in OUTGAM */ + if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) + BREAK_TO_DEBUGGER(); + } + } + + mpc->funcs->set_output_gamma(mpc, mpcc_id, params); + return ret; +} + +/* Program P-State force value according to if pipe is using SubVP / FPO or not: + * 1. Reset P-State force on all pipes first + * 2. For each main pipe, force P-State disallow (P-State allow moderated by DMUB) + */ +void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context) +{ + int i; + + /* Unforce p-state for each pipe if it is not FPO or SubVP. + * For FPO and SubVP, if it's already forced disallow, leave + * it as disallow. + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = pipe->plane_res.hubp; + + if (!pipe->stream || !(pipe->stream->mall_stream_config.type == SUBVP_MAIN || + pipe->stream->fpo_in_use)) { + if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) + hubp->funcs->hubp_update_force_pstate_disallow(hubp, false); + } + + /* Today only FPO uses cursor P-State force. Only clear cursor P-State force + * if it's not FPO. + */ + if (!pipe->stream || !pipe->stream->fpo_in_use) { + if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow) + hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, false); + } + } + + /* Loop through each pipe -- for each subvp main pipe force p-state allow equal to false. + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = pipe->plane_res.hubp; + + if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) + hubp->funcs->hubp_update_force_pstate_disallow(hubp, true); + } + + if (pipe->stream && pipe->stream->fpo_in_use) { + if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) + hubp->funcs->hubp_update_force_pstate_disallow(hubp, true); + /* For now only force cursor p-state disallow for FPO + * Needs to be added for subvp once FW side gets updated + */ + if (hubp && hubp->funcs->hubp_update_force_cursor_pstate_disallow) + hubp->funcs->hubp_update_force_cursor_pstate_disallow(hubp, true); + } + } +} + +/* Update MALL_SEL register based on if pipe / plane + * is a phantom pipe, main pipe, and if using MALL + * for SS. + */ +void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context) +{ + int i; + unsigned int num_ways = dcn32_calculate_cab_allocation(dc, context); + bool cache_cursor = false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = pipe->plane_res.hubp; + + if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) { + int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; + + switch (hubp->curs_attr.color_format) { + case CURSOR_MODE_MONO: + cursor_size /= 2; + break; + case CURSOR_MODE_COLOR_1BIT_AND: + case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: + case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: + cursor_size *= 4; + break; + + case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: + case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: + default: + cursor_size *= 8; + break; + } + + if (cursor_size > 16384) + cache_cursor = true; + + if (pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + hubp->funcs->hubp_update_mall_sel(hubp, 1, false); + } else { + // MALL not supported with Stereo3D + hubp->funcs->hubp_update_mall_sel(hubp, + num_ways <= dc->caps.cache_num_ways && + pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && + pipe->plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO && + !pipe->plane_state->address.tmz_surface ? 2 : 0, + cache_cursor); + } + } + } +} + +/* Program the sub-viewport pipe configuration after the main / phantom pipes + * have been programmed in hardware. + * 1. Update force P-State for all the main pipes (disallow P-state) + * 2. Update MALL_SEL register + * 3. Program FORCE_ONE_ROW_FOR_FRAME for main subvp pipes + */ +void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + + // Don't force p-state disallow -- can't block dummy p-state + + // Update MALL_SEL register for each pipe + if (hws && hws->funcs.update_mall_sel) + hws->funcs.update_mall_sel(dc, context); + + // Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = pipe->plane_res.hubp; + + if (pipe->stream && hubp && hubp->funcs->hubp_prepare_subvp_buffering) { + /* TODO - remove setting CURSOR_REQ_MODE to 0 for legacy cases + * - need to investigate single pipe MPO + SubVP case to + * see if CURSOR_REQ_MODE will be back to 1 for SubVP + * when it should be 0 for MPO + */ + if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + hubp->funcs->hubp_prepare_subvp_buffering(hubp, true); + } + } + } +} + +static void dcn32_initialize_min_clocks(struct dc *dc) +{ + struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk; + + clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ; + clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000; + clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000; + clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000; + clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000; + clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; + clocks->fclk_p_state_change_support = true; + clocks->p_state_change_support = true; + if (dc->debug.disable_boot_optimizations) { + clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000; + } else { + /* Even though DPG_EN = 1 for the connected display, it still requires the + * correct timing so we cannot set DISPCLK to min freq or it could cause + * audio corruption. Read current DISPCLK from DENTIST and request the same + * freq to ensure that the timing is valid and unchanged. + */ + clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr); + } + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + dc->current_state, + true); +} + +void dcn32_init_hw(struct dc *dc) +{ + struct abm **abms = dc->res_pool->multiple_abms; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + struct resource_pool *res_pool = dc->res_pool; + int i; + int edp_num; + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + hws->funcs.bios_golden_init(dc); + hws->funcs.disable_vga(dc->hwseq); + } + + // Set default OPTC memory power states + if (dc->debug.enable_mem_low_power.bits.optc) { + // Shutdown when unassigned and light sleep in VBLANK + REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); + } + + if (dc->debug.enable_mem_low_power.bits.vga) { + // Power down VGA memory + REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); + } + + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + + if (res_pool->dccg && res_pool->hubbub) { + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } else + ASSERT_CRITICAL(false); + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) { + link->link_status.link_active = true; + link->phy_state.symclk_state = SYMCLK_ON_TX_ON; + if (link->link_enc->funcs->fec_is_active && + link->link_enc->funcs->fec_is_active(link->link_enc)) + link->fec_state = dc_link_fec_enabled; + } + } + + /* enable_power_gating_plane before dsc_pg_control because + * FORCEON = 1 with hw default value on bootup, resume from s3 + */ + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + + /* we want to turn off all dp displays before doing detection */ + dc->link_srv->blank_all_dp_displays(dc); + + /* If taking control over from VBIOS, we may want to optimize our first + * mode set, so we need to skip powering down pipes until we know which + * pipes we want to use. + * Otherwise, if taking control is not possible, we need to power + * everything down. + */ + if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { + /* Disable boot optimizations means power down everything including PHY, DIG, + * and OTG (i.e. the boot is not optimized because we do a full power down). + */ + if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations) + dc->hwss.enable_accelerated_mode(dc, dc->current_state); + else + hws->funcs.init_pipes(dc, dc->current_state); + + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + + dcn32_initialize_min_clocks(dc); + + /* On HW init, allow idle optimizations after pipes have been turned off. + * + * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state + * is reset (i.e. not in idle at the time hw init is called), but software state + * still has idle_optimizations = true, so we must disable idle optimizations first + * (i.e. set false), then re-enable (set true). + */ + dc_allow_idle_optimizations(dc, false); + dc_allow_idle_optimizations(dc, true); + } + + /* In headless boot cases, DIG may be turned + * on which causes HW/SW discrepancies. + * To avoid this, power down hardware on boot + * if DIG is turned on and seamless boot not enabled + */ + if (!dc->config.seamless_boot_edp_requested) { + struct dc_link *edp_links[MAX_NUM_EDP]; + struct dc_link *edp_link; + + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num) { + for (i = 0; i < edp_num; i++) { + edp_link = edp_links[i]; + if (edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + dc->hwss.edp_backlight_control && + dc->hwss.power_down && + dc->hwss.edp_power_control) { + dc->hwss.edp_backlight_control(edp_link, false); + dc->hwss.power_down(dc); + dc->hwss.edp_power_control(edp_link, false); + } + } + } else { + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc) && + dc->hwss.power_down) { + dc->hwss.power_down(dc); + break; + } + + } + } + } + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (abms[i] != NULL && abms[i]->funcs != NULL) + abms[i]->funcs->abm_init(abms[i], backlight); + } + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) + dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); + + if (dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); + + if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); + + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, false, false); + + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); + + if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0) + 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); + + // Get DMCUB capabilities + if (dc->ctx->dmub_srv) { + dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); + dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; + dc->caps.dmub_caps.subvp_psr = dc->ctx->dmub_srv->dmub->feature_caps.subvp_psr_support; + dc->caps.dmub_caps.gecc_enable = dc->ctx->dmub_srv->dmub->feature_caps.gecc_enable; + dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; + } +} + +static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, + int opp_cnt) +{ + bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); + int flow_ctrl_cnt; + + if (opp_cnt >= 2) + hblank_halved = true; + + flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - + stream->timing.h_border_left - + stream->timing.h_border_right; + + if (hblank_halved) + flow_ctrl_cnt /= 2; + + /* ODM combine 4:1 case */ + if (opp_cnt == 4) + flow_ctrl_cnt /= 2; + + return flow_ctrl_cnt; +} + +static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) +{ + struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct dc_stream_state *stream = pipe_ctx->stream; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + ASSERT(dsc); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; + + if (enable) { + struct dsc_config dsc_cfg; + struct dsc_optc_config dsc_optc_cfg; + enum optc_dsc_mode optc_dsc_mode; + + /* Enable DSC hw block */ + dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; + dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; + dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; + dsc_cfg.color_depth = stream->timing.display_color_depth; + dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; + dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; + + dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); + dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; + + ASSERT(odm_dsc); + odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); + odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); + } + dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; + dsc_cfg.pic_width *= opp_cnt; + + optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; + + /* Enable DSC in OPTC */ + DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); + pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, + optc_dsc_mode, + dsc_optc_cfg.bytes_per_pixel, + dsc_optc_cfg.slice_width); + } else { + /* disable DSC in OPTC */ + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, + OPTC_DSC_DISABLED, 0, 0); + + /* disable DSC block */ + dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + ASSERT(odm_pipe->stream_res.dsc); + odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); + } + } +} + +/* +* Given any pipe_ctx, return the total ODM combine factor, and optionally return +* the OPPids which are used +* */ +static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) +{ + unsigned int opp_count = 1; + struct pipe_ctx *odm_pipe; + + /* First get to the top pipe */ + for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) + ; + + /* First pipe is always used */ + if (opp_instances) + opp_instances[0] = odm_pipe->stream_res.opp->inst; + + /* Find and count odm pipes, if any */ + for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + if (opp_instances) + opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; + opp_count++; + } + + return opp_count; +} + +void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *odm_pipe; + int opp_cnt = 0; + int opp_inst[MAX_PIPES] = {0}; + bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); + struct mpc_dwb_flow_control flow_control; + struct mpc *mpc = dc->res_pool->mpc; + int i; + + opp_cnt = get_odm_config(pipe_ctx, opp_inst); + + if (opp_cnt > 1) + pipe_ctx->stream_res.tg->funcs->set_odm_combine( + pipe_ctx->stream_res.tg, + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); + else + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; + flow_control.flow_ctrl_mode = 0; + flow_control.flow_ctrl_cnt0 = 0x80; + flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt); + if (mpc->funcs->set_out_rate_control) { + for (i = 0; i < opp_cnt; ++i) { + mpc->funcs->set_out_rate_control( + mpc, opp_inst[i], + true, + rate_control_2x_pclk, + &flow_control); + } + } + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( + odm_pipe->stream_res.opp, + true); + } + + if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; + + update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); + + /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ + if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && + current_pipe_ctx->next_odm_pipe->stream_res.dsc) { + struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; + /* disconnect DSC block from stream */ + dsc->funcs->dsc_disconnect(dsc); + } + } +} + +unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + unsigned int odm_combine_factor = 0; + bool two_pix_per_container = false; + + two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); + odm_combine_factor = get_odm_config(pipe_ctx, NULL); + + if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + *k1_div = PIXEL_RATE_DIV_BY_1; + *k2_div = PIXEL_RATE_DIV_BY_1; + } else if (dc_is_hdmi_tmds_signal(stream->signal) || dc_is_dvi_signal(stream->signal)) { + *k1_div = PIXEL_RATE_DIV_BY_1; + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + *k2_div = PIXEL_RATE_DIV_BY_2; + else + *k2_div = PIXEL_RATE_DIV_BY_4; + } else if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) { + if (two_pix_per_container) { + *k1_div = PIXEL_RATE_DIV_BY_1; + *k2_div = PIXEL_RATE_DIV_BY_2; + } else { + *k1_div = PIXEL_RATE_DIV_BY_1; + *k2_div = PIXEL_RATE_DIV_BY_4; + if ((odm_combine_factor == 2) || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) + *k2_div = PIXEL_RATE_DIV_BY_2; + } + } + + if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA)) + ASSERT(false); + + return odm_combine_factor; +} + +void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) +{ + uint32_t pix_per_cycle = 1; + uint32_t odm_combine_factor = 1; + + if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc) + return; + + odm_combine_factor = get_odm_config(pipe_ctx, NULL); + if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1 + || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) + pix_per_cycle = 2; + + if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) + pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, + pix_per_cycle); +} + +void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context) +{ + unsigned int i; + struct pipe_ctx *pipe = NULL; + bool otg_disabled[MAX_PIPES] = {false}; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!resource_is_pipe_type(pipe, OTG_MASTER)) + continue; + + if ((pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal)) + && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { + pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg); + reset_sync_context_for_pipe(dc, context, i); + otg_disabled[i] = true; + } + } + + hws->ctx->dc->res_pool->dccg->funcs->trigger_dio_fifo_resync(hws->ctx->dc->res_pool->dccg); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (otg_disabled[i]) + pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); + } +} + +void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings) +{ + struct encoder_unblank_param params = {0}; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + struct dce_hwseq *hws = link->dc->hwseq; + struct pipe_ctx *odm_pipe; + uint32_t pix_per_cycle = 1; + + params.opp_cnt = 1; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + params.opp_cnt++; + + /* only 3 items below are used by unblank */ + params.timing = pipe_ctx->stream->timing; + + params.link_settings.link_rate = link_settings->link_rate; + + if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { + /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ + pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( + pipe_ctx->stream_res.hpo_dp_stream_enc, + pipe_ctx->stream_res.tg->inst); + } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1 + || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) { + params.timing.pix_clk_100hz /= 2; + pix_per_cycle = 2; + } + pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( + pipe_ctx->stream_res.stream_enc, pix_per_cycle > 1); + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); + } + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) + hws->funcs.edp_backlight_control(link, true); +} + +bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx) +{ + struct dc *dc = pipe_ctx->stream->ctx->dc; + + if (!is_h_timing_divisible_by_2(pipe_ctx->stream)) + return false; + + if (dc_is_dp_signal(pipe_ctx->stream->signal) && !dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) && + dc->debug.enable_dp_dig_pixel_rate_div_policy) + return true; + return false; +} + +static void apply_symclk_on_tx_off_wa(struct dc_link *link) +{ + /* There are use cases where SYMCLK is referenced by OTG. For instance + * for TMDS signal, OTG relies SYMCLK even if TX video output is off. + * However current link interface will power off PHY when disabling link + * output. This will turn off SYMCLK generated by PHY. The workaround is + * to identify such case where SYMCLK is still in use by OTG when we + * power off PHY. When this is detected, we will temporarily power PHY + * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling + * program_pix_clk interface. When OTG is disabled, we will then power + * off PHY by calling disable link output again. + * + * In future dcn generations, we plan to rework transmitter control + * interface so that we could have an option to set SYMCLK ON TX OFF + * state in one step without this workaround + */ + + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + if (link->phy_state.symclk_ref_cnts.otg > 0) { + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) && pipe_ctx->stream->link == link) { + pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + dc->link_srv->dp_get_encoding_format( + &pipe_ctx->link_config.dp_link_settings), + &pipe_ctx->pll_settings); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + break; + } + } + } +} + +void dcn32_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) +{ + struct dc *dc = link->ctx->dc; + const struct link_hwss *link_hwss = get_link_hwss(link, link_res); + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control && + !link->skip_implict_edp_power_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + link_hwss->disable_link_output(link, link_res, signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + + if (signal == SIGNAL_TYPE_EDP && + link->dc->hwss.edp_backlight_control && + !link->skip_implict_edp_power_control) + link->dc->hwss.edp_power_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->unlock_phy(dmcu); + + dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); + + apply_symclk_on_tx_off_wa(link); +} + +/* For SubVP the main pipe can have a viewport position change + * without a full update. In this case we must also update the + * viewport positions for the phantom pipe accordingly. + */ +void dcn32_update_phantom_vp_position(struct dc *dc, + struct dc_state *context, + struct pipe_ctx *phantom_pipe) +{ + uint32_t i; + struct dc_plane_state *phantom_plane = phantom_pipe->plane_state; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN && + pipe->stream->mall_stream_config.paired_stream == phantom_pipe->stream) { + if (pipe->plane_state && pipe->plane_state->update_flags.bits.position_change) { + + phantom_plane->src_rect.x = pipe->plane_state->src_rect.x; + phantom_plane->src_rect.y = pipe->plane_state->src_rect.y; + phantom_plane->clip_rect.x = pipe->plane_state->clip_rect.x; + phantom_plane->dst_rect.x = pipe->plane_state->dst_rect.x; + phantom_plane->dst_rect.y = pipe->plane_state->dst_rect.y; + + phantom_pipe->plane_state->update_flags.bits.position_change = 1; + resource_build_scaling_params(phantom_pipe); + return; + } + } + } +} + +/* Treat the phantom pipe as if it needs to be fully enabled. + * If the pipe was previously in use but not phantom, it would + * have been disabled earlier in the sequence so we need to run + * the full enable sequence. + */ +void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe) +{ + phantom_pipe->update_flags.raw = 0; + if (phantom_pipe->stream && phantom_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) { + phantom_pipe->update_flags.bits.enable = 1; + phantom_pipe->update_flags.bits.mpcc = 1; + phantom_pipe->update_flags.bits.dppclk = 1; + phantom_pipe->update_flags.bits.hubp_interdependent = 1; + phantom_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; + phantom_pipe->update_flags.bits.gamut_remap = 1; + phantom_pipe->update_flags.bits.scaler = 1; + phantom_pipe->update_flags.bits.viewport = 1; + phantom_pipe->update_flags.bits.det_size = 1; + if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) { + phantom_pipe->update_flags.bits.odm = 1; + phantom_pipe->update_flags.bits.global_sync = 1; + } + } + } +} + +bool dcn32_dsc_pg_status( + struct dce_hwseq *hws, + unsigned int dsc_inst) +{ + uint32_t pwr_status = 0; + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_GET(DOMAIN16_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + case 1: /* DSC1 */ + + REG_GET(DOMAIN17_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + case 2: /* DSC2 */ + REG_GET(DOMAIN18_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + case 3: /* DSC3 */ + REG_GET(DOMAIN19_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, &pwr_status); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + return pwr_status == 0; +} + +void dcn32_update_dsc_pg(struct dc *dc, + struct dc_state *context, + bool safe_to_disable) +{ + struct dce_hwseq *hws = dc->hwseq; + int i; + + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { + struct display_stream_compressor *dsc = dc->res_pool->dscs[i]; + bool is_dsc_ungated = hws->funcs.dsc_pg_status(hws, dsc->inst); + + if (context->res_ctx.is_dsc_acquired[i]) { + if (!is_dsc_ungated) { + hws->funcs.dsc_pg_control(hws, dsc->inst, true); + } + } else if (safe_to_disable) { + if (is_dsc_ungated) { + hws->funcs.dsc_pg_control(hws, dsc->inst, false); + } + } + } +} + +void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context) +{ + unsigned int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + /* If an active, non-phantom pipe is being transitioned into a phantom + * pipe, wait for the double buffer update to complete first before we do + * ANY phantom pipe programming. + */ + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM && + old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { + old_pipe->stream_res.tg->funcs->wait_for_state( + old_pipe->stream_res.tg, + CRTC_STATE_VBLANK); + old_pipe->stream_res.tg->funcs->wait_for_state( + old_pipe->stream_res.tg, + CRTC_STATE_VACTIVE); + } + } + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; + + if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + // If old context or new context has phantom pipes, apply + // the phantom timings now. We can't change the phantom + // pipe configuration safely without driver acquiring + // the DMCUB lock first. + dc->hwss.apply_ctx_to_hw(dc, context); + break; + } + } +} + +/* Blank pixel data during initialization */ +void dcn32_init_blank( + struct dc *dc, + struct timing_generator *tg) +{ + struct dce_hwseq *hws = dc->hwseq; + enum dc_color_space color_space; + struct tg_color black_color = {0}; + struct output_pixel_processor *opp = NULL; + struct output_pixel_processor *bottom_opp = NULL; + uint32_t num_opps, opp_id_src0, opp_id_src1; + uint32_t otg_active_width, otg_active_height; + uint32_t i; + + /* program opp dpg blank color */ + color_space = COLOR_SPACE_SRGB; + color_space_to_black_color(dc, color_space, &black_color); + + /* get the OTG active size */ + tg->funcs->get_otg_active_size(tg, + &otg_active_width, + &otg_active_height); + + /* get the OPTC source */ + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + + if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) { + ASSERT(false); + return; + } + + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { + if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) { + opp = dc->res_pool->opps[i]; + break; + } + } + + if (num_opps == 2) { + otg_active_width = otg_active_width / 2; + + if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) { + ASSERT(false); + return; + } + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { + if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src1) { + bottom_opp = dc->res_pool->opps[i]; + break; + } + } + } + + if (opp && opp->funcs->opp_set_disp_pattern_generator) + opp->funcs->opp_set_disp_pattern_generator( + opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height, + 0); + + if (num_opps == 2) { + if (bottom_opp && bottom_opp->funcs->opp_set_disp_pattern_generator) { + bottom_opp->funcs->opp_set_disp_pattern_generator( + bottom_opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height, + 0); + hws->funcs.wait_for_blank_complete(bottom_opp); + } + } + + if (opp) + hws->funcs.wait_for_blank_complete(opp); +} + +void dcn32_blank_phantom(struct dc *dc, + struct timing_generator *tg, + int width, + int height) +{ + struct dce_hwseq *hws = dc->hwseq; + enum dc_color_space color_space; + struct tg_color black_color = {0}; + struct output_pixel_processor *opp = NULL; + uint32_t num_opps, opp_id_src0, opp_id_src1; + uint32_t otg_active_width, otg_active_height; + uint32_t i; + + /* program opp dpg blank color */ + color_space = COLOR_SPACE_SRGB; + color_space_to_black_color(dc, color_space, &black_color); + + otg_active_width = width; + otg_active_height = height; + + /* get the OPTC source */ + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); + + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { + if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) { + opp = dc->res_pool->opps[i]; + break; + } + } + + if (opp && opp->funcs->opp_set_disp_pattern_generator) + opp->funcs->opp_set_disp_pattern_generator( + opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height, + 0); + + if (tg->funcs->is_tg_enabled(tg)) + hws->funcs.wait_for_blank_complete(opp); +} + +bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc, + const struct dc_state *cur_ctx, + const struct dc_state *new_ctx) +{ + int i; + const struct pipe_ctx *cur_pipe, *new_pipe; + bool is_seamless = true; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + cur_pipe = &cur_ctx->res_ctx.pipe_ctx[i]; + new_pipe = &new_ctx->res_ctx.pipe_ctx[i]; + + if (resource_is_pipe_type(cur_pipe, FREE_PIPE) || + resource_is_pipe_type(new_pipe, FREE_PIPE)) + /* adding or removing free pipes is always seamless */ + continue; + else if (resource_is_pipe_type(cur_pipe, OTG_MASTER)) { + if (resource_is_pipe_type(new_pipe, OTG_MASTER)) + if (cur_pipe->stream->stream_id == new_pipe->stream->stream_id) + /* OTG master with the same stream is seamless */ + continue; + } else if (resource_is_pipe_type(cur_pipe, OPP_HEAD)) { + if (resource_is_pipe_type(new_pipe, OPP_HEAD)) { + if (cur_pipe->stream_res.tg == new_pipe->stream_res.tg) + /* + * OPP heads sharing the same timing + * generator is seamless + */ + continue; + } + } else if (resource_is_pipe_type(cur_pipe, DPP_PIPE)) { + if (resource_is_pipe_type(new_pipe, DPP_PIPE)) { + if (cur_pipe->stream_res.opp == new_pipe->stream_res.opp) + /* + * DPP pipes sharing the same OPP head is + * seamless + */ + continue; + } + } + + /* + * This pipe's transition doesn't fall under any seamless + * conditions + */ + is_seamless = false; + break; + } + + return is_seamless; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h new file mode 100644 index 000000000000..9992e40acd21 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h @@ -0,0 +1,127 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN32_H__ +#define __DC_HWSS_DCN32_H__ + +#include "hw_sequencer_private.h" + +struct dc; + +void dcn32_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + +void dcn32_enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable); + +void dcn32_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); + +bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable); + +void dcn32_cab_for_ss_control(struct dc *dc, bool enable); + +void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context); + +bool dcn32_set_mcm_luts(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + +bool dcn32_set_input_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + +bool dcn32_set_mpc_shaper_3dlut( + struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream); + +bool dcn32_set_output_transfer_func(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); + +void dcn32_init_hw(struct dc *dc); + +void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context); + +void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context); + +void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context); + +void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); + +unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div); + +void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx); + +void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context); + +void dcn32_subvp_pipe_control_lock(struct dc *dc, + struct dc_state *context, + bool lock, + bool should_lock_all_pipes, + struct pipe_ctx *top_pipe_to_program, + bool subvp_prev_use); + +void dcn32_subvp_pipe_control_lock_fast(union block_sequence_params *params); + +void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); + +bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx); + +void dcn32_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); + +void dcn32_update_phantom_vp_position(struct dc *dc, + struct dc_state *context, + struct pipe_ctx *phantom_pipe); + +void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe); + +bool dcn32_dsc_pg_status( + struct dce_hwseq *hws, + unsigned int dsc_inst); + +void dcn32_update_dsc_pg(struct dc *dc, + struct dc_state *context, + bool safe_to_disable); + +void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context); + +void dcn32_init_blank( + struct dc *dc, + struct timing_generator *tg); + +void dcn32_blank_phantom(struct dc *dc, + struct timing_generator *tg, + int width, + int height); + +bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc, + const struct dc_state *cur_ctx, + const struct dc_state *new_ctx); + +#endif /* __DC_HWSS_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c new file mode 100644 index 000000000000..0e218f9e2a86 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -0,0 +1,1205 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dccg.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "reg_helper.h" +#include "abm.h" +#include "hubp.h" +#include "dchubbub.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "dc_dmub_srv.h" +#include "dcn35_hwseq.h" +#include "dcn35/dcn35_dccg.h" +#include "link_hwss.h" +#include "dpcd_defs.h" +#include "dce/dmub_outbox.h" +#include "link.h" +#include "dcn10/dcn10_hwseq.h" +#include "inc/link_enc_cfg.h" +#include "dcn30/dcn30_vpg.h" +#include "dce/dce_i2c_hw.h" +#include "dsc.h" +#include "dcn20/dcn20_optc.h" +#include "dcn30/dcn30_cm_common.h" +#include "dcn31/dcn31_hwseq.h" +#include "dcn20/dcn20_hwseq.h" + +#define DC_LOGGER_INIT(logger) \ + struct dal_logger *dc_logger = logger + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg +#define DC_LOGGER \ + dc_logger + + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name +#if 0 +static void enable_memory_low_power(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + int i; + + if (dc->debug.enable_mem_low_power.bits.dmcu) { + // Force ERAM to shutdown if DMCU is not enabled + if (dc->debug.disable_dmcu || dc->config.disable_dmcu) { + REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3); + } + } + /*dcn35 has default MEM_PWR enabled, make sure wake them up*/ + // Set default OPTC memory power states + if (dc->debug.enable_mem_low_power.bits.optc) { + // Shutdown when unassigned and light sleep in VBLANK + REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1); + } + + if (dc->debug.enable_mem_low_power.bits.vga) { + // Power down VGA memory + REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1); + } + + if (dc->debug.enable_mem_low_power.bits.mpc && + dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode) + dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc); + + if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) { + // Power down VPGs + for (i = 0; i < dc->res_pool->stream_enc_count; i++) + dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); +#if defined(CONFIG_DRM_AMD_DC_DP2_0) + for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) + dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); +#endif + } + +} +#endif + +void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable) +{ + REG_UPDATE_3(DMU_CLK_CNTL, + RBBMIF_FGCG_REP_DIS, !enable, + IHC_FGCG_REP_DIS, !enable, + LONO_FGCG_REP_DIS, !enable + ); +} + +void dcn35_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable) +{ + REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable); +} + +void dcn35_init_hw(struct dc *dc) +{ + struct abm **abms = dc->res_pool->multiple_abms; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + struct resource_pool *res_pool = dc->res_pool; + uint32_t backlight = MAX_BACKLIGHT_LEVEL; + int i; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0x3F000000); + REG_WRITE(DCCG_GATE_DISABLE_CNTL5, 0x1f7c3fcf); + + //dcn35_set_dmu_fgcg(hws, dc->debug.enable_fine_grain_clock_gating.bits.dmu); + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + /*this calls into dmubfw to do the init*/ + hws->funcs.bios_golden_init(dc); + } + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + //enable_memory_low_power(dc); + + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; + + if (res_pool->dccg && res_pool->hubbub) { + + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } else + ASSERT_CRITICAL(false); + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + if (link->ep_type != DISPLAY_ENDPOINT_PHY) + continue; + + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) { + link->link_status.link_active = true; + if (link->link_enc->funcs->fec_is_active && + link->link_enc->funcs->fec_is_active(link->link_enc)) + link->fec_state = dc_link_fec_enabled; + } + } + + /* we want to turn off all dp displays before doing detection */ + dc->link_srv->blank_all_dp_displays(dc); +/* + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); +*/ + if (res_pool->hubbub->funcs->dchubbub_init) + res_pool->hubbub->funcs->dchubbub_init(dc->res_pool->hubbub); + /* If taking control over from VBIOS, we may want to optimize our first + * mode set, so we need to skip powering down pipes until we know which + * pipes we want to use. + * Otherwise, if taking control is not possible, we need to power + * everything down. + */ + if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { + + // we want to turn off edp displays if odm is enabled and no seamless boot + if (!dc->caps.seamless_odm) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + uint32_t num_opps, opp_id_src0, opp_id_src1; + + num_opps = 1; + if (tg) { + if (tg->funcs->is_tg_enabled(tg) && tg->funcs->get_optc_source) { + tg->funcs->get_optc_source(tg, &num_opps, + &opp_id_src0, &opp_id_src1); + } + } + + if (num_opps > 1) { + dc->link_srv->blank_all_edp_displays(dc); + break; + } + } + } + + hws->funcs.init_pipes(dc, dc->current_state); + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, + !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); + } + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->panel_cntl) + backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + } + if (dc->ctx->dmub_srv) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (abms[i] != NULL && abms[i]->funcs != NULL) + abms[i]->funcs->abm_init(abms[i], backlight); + } + } + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + // Set i2c to light sleep until engine is setup + if (dc->debug.enable_mem_low_power.bits.i2c) + REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0); + + if (hws->funcs.setup_hpo_hw_control) + hws->funcs.setup_hpo_hw_control(hws, false); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + if (dc->debug.disable_mem_low_power) { + REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 1); + } + if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) + dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); + + if (dc->clk_mgr->funcs->notify_wm_ranges) + dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); + + if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) + dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); + + + + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, false, false); + + if (dc->res_pool->hubbub->funcs->init_crb) + dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); + + if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0) + 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); + // Get DMCUB capabilities + if (dc->ctx->dmub_srv) { + dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); + dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; + dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; + } + + if (dc->res_pool->pg_cntl) { + if (dc->res_pool->pg_cntl->funcs->init_pg_status) + dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl); + } +} + +static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, + int opp_cnt) +{ + bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); + int flow_ctrl_cnt; + + if (opp_cnt >= 2) + hblank_halved = true; + + flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - + stream->timing.h_border_left - + stream->timing.h_border_right; + + if (hblank_halved) + flow_ctrl_cnt /= 2; + + /* ODM combine 4:1 case */ + if (opp_cnt == 4) + flow_ctrl_cnt /= 2; + + return flow_ctrl_cnt; +} + +static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) +{ + struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct dc_stream_state *stream = pipe_ctx->stream; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + DC_LOGGER_INIT(stream->ctx->logger); + + ASSERT(dsc); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; + + if (enable) { + struct dsc_config dsc_cfg; + struct dsc_optc_config dsc_optc_cfg; + enum optc_dsc_mode optc_dsc_mode; + + /* Enable DSC hw block */ + dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; + dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; + dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; + dsc_cfg.color_depth = stream->timing.display_color_depth; + dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false; + dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; + + dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); + dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; + + ASSERT(odm_dsc); + odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); + odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); + } + dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; + dsc_cfg.pic_width *= opp_cnt; + + optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; + + /* Enable DSC in OPTC */ + DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); + pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, + optc_dsc_mode, + dsc_optc_cfg.bytes_per_pixel, + dsc_optc_cfg.slice_width); + } else { + /* disable DSC in OPTC */ + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, + OPTC_DSC_DISABLED, 0, 0); + + /* disable DSC block */ + dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + ASSERT(odm_pipe->stream_res.dsc); + odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); + } + } +} + +// Given any pipe_ctx, return the total ODM combine factor, and optionally return +// the OPPids which are used +static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) +{ + unsigned int opp_count = 1; + struct pipe_ctx *odm_pipe; + + // First get to the top pipe + for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) + ; + + // First pipe is always used + if (opp_instances) + opp_instances[0] = odm_pipe->stream_res.opp->inst; + + // Find and count odm pipes, if any + for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + if (opp_instances) + opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; + opp_count++; + } + + return opp_count; +} + +void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *odm_pipe; + int opp_cnt = 0; + int opp_inst[MAX_PIPES] = {0}; + bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); + struct mpc_dwb_flow_control flow_control; + struct mpc *mpc = dc->res_pool->mpc; + int i; + + opp_cnt = get_odm_config(pipe_ctx, opp_inst); + + if (opp_cnt > 1) + pipe_ctx->stream_res.tg->funcs->set_odm_combine( + pipe_ctx->stream_res.tg, + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); + else + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; + flow_control.flow_ctrl_mode = 0; + flow_control.flow_ctrl_cnt0 = 0x80; + flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt); + if (mpc->funcs->set_out_rate_control) { + for (i = 0; i < opp_cnt; ++i) { + mpc->funcs->set_out_rate_control( + mpc, opp_inst[i], + true, + rate_control_2x_pclk, + &flow_control); + } + } + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( + odm_pipe->stream_res.opp, + true); + } + + if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; + + update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); + + /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ + if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && + current_pipe_ctx->next_odm_pipe->stream_res.dsc) { + struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; + /* disconnect DSC block from stream */ + dsc->funcs->dsc_disconnect(dsc); + } + } +} + +void dcn35_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on) +{ + if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp) + return; + + if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control) { + hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control( + hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on); + } +} + +void dcn35_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + if (hws->ctx->dc->debug.ignore_pg) + return; + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DSC3 */ + REG_UPDATE(DOMAIN19_PG_CONFIG, + DOMAIN_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN19_PG_STATUS, + DOMAIN_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} + +void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable) +{ + bool force_on = true; /* disable power gating */ + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + if (hws->ctx->dc->debug.ignore_pg) + return; + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + /* DCHUBP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + /* DPP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + force_on = true; /* disable power gating */ + if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) + force_on = false; + + /* DCS0/1/2/3/4 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); + + +} + +/* In headless boot cases, DIG may be turned + * on which causes HW/SW discrepancies. + * To avoid this, power down hardware on boot + * if DIG is turned on + */ +void dcn35_power_down_on_boot(struct dc *dc) +{ + struct dc_link *edp_links[MAX_NUM_EDP]; + struct dc_link *edp_link = NULL; + int edp_num; + int i = 0; + + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num) + edp_link = edp_links[0]; + + if (edp_link && edp_link->link_enc->funcs->is_dig_enabled && + edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && + dc->hwseq->funcs.edp_backlight_control && + dc->hwss.power_down && + dc->hwss.edp_power_control) { + dc->hwseq->funcs.edp_backlight_control(edp_link, false); + dc->hwss.power_down(dc); + dc->hwss.edp_power_control(edp_link, false); + } else { + for (i = 0; i < dc->link_count; i++) { + struct dc_link *link = dc->links[i]; + + if (link->link_enc && link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc) && + dc->hwss.power_down) { + dc->hwss.power_down(dc); + break; + } + + } + } + + /* + * Call update_clocks with empty context + * to send DISPLAY_OFF + * Otherwise DISPLAY_OFF may not be asserted + */ + if (dc->clk_mgr->funcs->set_low_power_state) + dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr); + + if (dc->clk_mgr->clks.pwr_state == DCN_PWR_STATE_LOW_POWER) { + if (!dc->idle_optimizations_allowed) { + dc_dmub_srv_notify_idle(dc, true); + dc->idle_optimizations_allowed = true; + } + } +} + +bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) +{ + struct dc_link *edp_links[MAX_NUM_EDP]; + int edp_num; + if (dc->debug.dmcub_emulation) + return true; + + if (enable) { + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num == 0 || edp_num > 1) + return false; + } + + // TODO: review other cases when idle optimization is allowed + + if (!enable) + dc_dmub_srv_exit_low_power_state(dc); + else + dc_dmub_srv_notify_idle(dc, enable); + + return true; +} + +void dcn35_z10_restore(const struct dc *dc) +{ + if (dc->debug.disable_z10) + return; + + dc_dmub_srv_exit_low_power_state(dc); + + dcn31_z10_restore(dc); +} + +void dcn35_init_pipes(struct dc *dc, struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + struct hubbub *hubbub = dc->res_pool->hubbub; + struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; + bool can_apply_seamless_boot = false; + + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->apply_seamless_boot_optimization) { + can_apply_seamless_boot = true; + break; + } + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* There is assumption that pipe_ctx is not mapping irregularly + * to non-preferred front end. If pipe_ctx->stream is not NULL, + * we will use the pipe, so don't disable + */ + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) + continue; + + /* Blank controller using driver code instead of + * command table. + */ + if (tg->funcs->is_tg_enabled(tg)) { + if (hws->funcs.init_blank != NULL) { + hws->funcs.init_blank(dc, tg); + tg->funcs->lock(tg); + } else { + tg->funcs->lock(tg); + tg->funcs->set_blank(tg, true); + hwss_wait_for_blank_complete(tg); + } + } + } + + /* Reset det size */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = dc->res_pool->hubps[i]; + + /* Do not need to reset for seamless boot */ + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) + continue; + + if (hubbub && hubp) { + if (hubbub->funcs->program_det_size) + hubbub->funcs->program_det_size(hubbub, hubp->inst, 0); + } + } + + /* num_opp will be equal to number of mpcc */ + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* Cannot reset the MPC mux if seamless boot */ + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) + continue; + + dc->res_pool->mpc->funcs->mpc_init_single_inst( + dc->res_pool->mpc, i); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct hubp *hubp = dc->res_pool->hubps[i]; + struct dpp *dpp = dc->res_pool->dpps[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* There is assumption that pipe_ctx is not mapping irregularly + * to non-preferred front end. If pipe_ctx->stream is not NULL, + * we will use the pipe, so don't disable + */ + if (can_apply_seamless_boot && + pipe_ctx->stream != NULL && + pipe_ctx->stream_res.tg->funcs->is_tg_enabled( + pipe_ctx->stream_res.tg)) { + // Enable double buffering for OTG_BLANK no matter if + // seamless boot is enabled or not to suppress global sync + // signals when OTG blanked. This is to prevent pipe from + // requesting data while in PSR. + tg->funcs->tg_init(tg); + hubp->power_gated = true; + continue; + } + + /* Disable on the current state so the new one isn't cleared. */ + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + dpp->funcs->dpp_reset(dpp); + + pipe_ctx->stream_res.tg = tg; + pipe_ctx->pipe_idx = i; + + pipe_ctx->plane_res.hubp = hubp; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; + hubp->opp_id = OPP_ID_INVALID; + hubp->power_gated = false; + + dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; + dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; + + hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->unlock(tg); + + dc->hwss.disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + + if (tg->funcs->is_tg_enabled(tg)) { + if (tg->funcs->init_odm) + tg->funcs->init_odm(tg); + } + + tg->funcs->tg_init(tg); + } + + if (pg_cntl != NULL) { + if (pg_cntl->funcs->dsc_pg_control != NULL) { + uint32_t num_opps = 0; + uint32_t opp_id_src0 = OPP_ID_INVALID; + uint32_t opp_id_src1 = OPP_ID_INVALID; + + // Step 1: To find out which OPTC is running & OPTC DSC is ON + // We can't use res_pool->res_cap->num_timing_generator to check + // Because it records display pipes default setting built in driver, + // not display pipes of the current chip. + // Some ASICs would be fused display pipes less than the default setting. + // In dcnxx_resource_construct function, driver would obatin real information. + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + uint32_t optc_dsc_state = 0; + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) { + if (tg->funcs->get_dsc_status) + tg->funcs->get_dsc_status(tg, &optc_dsc_state); + // Only one OPTC with DSC is ON, so if we got one result, + // we would exit this block. non-zero value is DSC enabled + if (optc_dsc_state != 0) { + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + break; + } + } + } + + // Step 2: To power down DSC but skip DSC of running OPTC + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { + struct dcn_dsc_state s = {0}; + + dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); + + if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && + s.dsc_clock_en && s.dsc_fw_en) + continue; + + pg_cntl->funcs->dsc_pg_control(pg_cntl, dc->res_pool->dscs[i]->inst, false); + } + } + } +} + +void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + /* enable DCFCLK current DCHUB */ + pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); + + /* initialize HUBP on power up */ + pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp); + + /* make sure OPP_PIPE_CLOCK_EN = 1 */ + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); + /*to do: insert PG here*/ + if (dc->vm_pa_config.valid) { + struct vm_system_aperture_param apt; + + apt.sys_default.quad_part = 0; + + apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr; + apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr; + + // Program system aperture settings + pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); + } + + if (!pipe_ctx->top_pipe + && pipe_ctx->plane_state + && pipe_ctx->plane_state->flip_int_enabled + && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) + pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp); +} + +/* disable HW used by plane. + * note: cannot disable until disconnect is complete + */ +void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); + + /* In flip immediate with pipe splitting case GSL is used for + * synchronization so we must disable it when the plane is disabled. + */ + if (pipe_ctx->stream_res.gsl_group != 0) + dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false); +/* + if (hubp->funcs->hubp_update_mall_sel) + hubp->funcs->hubp_update_mall_sel(hubp, 0, false); +*/ + dc->hwss.set_flip_control_gsl(pipe_ctx, false); + + hubp->funcs->hubp_clk_cntl(hubp, false); + + dpp->funcs->dpp_dppclk_control(dpp, false, false); +/*to do, need to support both case*/ + hubp->power_gated = true; + + dpp->funcs->dpp_reset(dpp); + + pipe_ctx->stream = NULL; + memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); + memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->plane_state = NULL; +} + +void dcn35_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom; + struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) + return; + + if (hws->funcs.plane_atomic_disable) + hws->funcs.plane_atomic_disable(dc, pipe_ctx); + + /* Turn back off the phantom OTG after the phantom plane is fully disabled + */ + if (is_phantom) + if (tg && tg->funcs->disable_phantom_crtc) + tg->funcs->disable_phantom_crtc(tg); + + DC_LOG_DC("Power down front end %d\n", + pipe_ctx->pipe_idx); +} + +void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, + struct pg_block_update *update_state) +{ + bool hpo_frl_stream_enc_acquired = false; + bool hpo_dp_stream_enc_acquired = false; + int i = 0, j = 0; + + memset(update_state, 0, sizeof(struct pg_block_update)); + + for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) { + if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] && + dc->res_pool->hpo_dp_stream_enc[i]) { + hpo_dp_stream_enc_acquired = true; + break; + } + } + + if (!hpo_frl_stream_enc_acquired && !hpo_dp_stream_enc_acquired) + update_state->pg_res_update[PG_HPO] = true; + + update_state->pg_res_update[PG_DWB] = true; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) + update_state->pg_pipe_res_update[j][i] = true; + + if (!pipe_ctx) + continue; + + if (pipe_ctx->plane_res.hubp) + update_state->pg_pipe_res_update[PG_HUBP][pipe_ctx->plane_res.hubp->inst] = false; + + if (pipe_ctx->plane_res.dpp) + update_state->pg_pipe_res_update[PG_DPP][pipe_ctx->plane_res.hubp->inst] = false; + + if ((pipe_ctx->plane_res.dpp || pipe_ctx->stream_res.opp) && + pipe_ctx->plane_res.mpcc_inst >= 0) + update_state->pg_pipe_res_update[PG_MPCC][pipe_ctx->plane_res.mpcc_inst] = false; + + if (pipe_ctx->stream_res.dsc) + update_state->pg_pipe_res_update[PG_DSC][pipe_ctx->stream_res.dsc->inst] = false; + + if (pipe_ctx->stream_res.opp) + update_state->pg_pipe_res_update[PG_OPP][pipe_ctx->stream_res.opp->inst] = false; + + if (pipe_ctx->stream_res.tg) + update_state->pg_pipe_res_update[PG_OPTC][pipe_ctx->stream_res.tg->inst] = false; + } +} + +void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, + struct pg_block_update *update_state) +{ + bool hpo_frl_stream_enc_acquired = false; + bool hpo_dp_stream_enc_acquired = false; + int i = 0, j = 0; + + memset(update_state, 0, sizeof(struct pg_block_update)); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *cur_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; + + if (cur_pipe == NULL || new_pipe == NULL) + continue; + + if ((!cur_pipe->plane_state && new_pipe->plane_state) || + (!cur_pipe->stream && new_pipe->stream)) { + // New pipe addition + for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) { + if (j == PG_HUBP && new_pipe->plane_res.hubp) + update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true; + + if (j == PG_DPP && new_pipe->plane_res.dpp) + update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true; + + if (j == PG_MPCC && new_pipe->plane_res.dpp) + update_state->pg_pipe_res_update[j][new_pipe->plane_res.mpcc_inst] = true; + + if (j == PG_DSC && new_pipe->stream_res.dsc) + update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true; + + if (j == PG_OPP && new_pipe->stream_res.opp) + update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true; + + if (j == PG_OPTC && new_pipe->stream_res.tg) + update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true; + } + } else if (cur_pipe->plane_state == new_pipe->plane_state || + cur_pipe == new_pipe) { + //unchanged pipes + for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) { + if (j == PG_HUBP && + cur_pipe->plane_res.hubp != new_pipe->plane_res.hubp && + new_pipe->plane_res.hubp) + update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true; + + if (j == PG_DPP && + cur_pipe->plane_res.dpp != new_pipe->plane_res.dpp && + new_pipe->plane_res.dpp) + update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true; + + if (j == PG_OPP && + cur_pipe->stream_res.opp != new_pipe->stream_res.opp && + new_pipe->stream_res.opp) + update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true; + + if (j == PG_DSC && + cur_pipe->stream_res.dsc != new_pipe->stream_res.dsc && + new_pipe->stream_res.dsc) + update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true; + + if (j == PG_OPTC && + cur_pipe->stream_res.tg != new_pipe->stream_res.tg && + new_pipe->stream_res.tg) + update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true; + } + } + } + + for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) { + if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] && + dc->res_pool->hpo_dp_stream_enc[i]) { + hpo_dp_stream_enc_acquired = true; + break; + } + } + + if (hpo_frl_stream_enc_acquired || hpo_dp_stream_enc_acquired) + update_state->pg_res_update[PG_HPO] = true; + +} + +void dcn35_block_power_control(struct dc *dc, + struct pg_block_update *update_state, bool power_on) +{ + int i = 0; + struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; + + if (!pg_cntl) + return; + if (dc->debug.ignore_pg) + return; + if (update_state->pg_res_update[PG_HPO]) { + if (pg_cntl->funcs->hpo_pg_control) + pg_cntl->funcs->hpo_pg_control(pg_cntl, power_on); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (update_state->pg_pipe_res_update[PG_HUBP][i] && + update_state->pg_pipe_res_update[PG_DPP][i]) { + if (pg_cntl->funcs->hubp_dpp_pg_control) + pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, power_on); + } + + if (update_state->pg_pipe_res_update[PG_DSC][i]) { + if (pg_cntl->funcs->dsc_pg_control) + pg_cntl->funcs->dsc_pg_control(pg_cntl, i, power_on); + } + + if (update_state->pg_pipe_res_update[PG_MPCC][i]) { + if (pg_cntl->funcs->mpcc_pg_control) + pg_cntl->funcs->mpcc_pg_control(pg_cntl, i, power_on); + } + + if (update_state->pg_pipe_res_update[PG_OPP][i]) { + if (pg_cntl->funcs->opp_pg_control) + pg_cntl->funcs->opp_pg_control(pg_cntl, i, power_on); + } + + if (update_state->pg_pipe_res_update[PG_OPTC][i]) { + if (pg_cntl->funcs->optc_pg_control) + pg_cntl->funcs->optc_pg_control(pg_cntl, i, power_on); + } + } + + if (update_state->pg_res_update[PG_DWB]) { + if (pg_cntl->funcs->dwb_pg_control) + pg_cntl->funcs->dwb_pg_control(pg_cntl, power_on); + } + + if (pg_cntl->funcs->plane_otg_pg_control) + pg_cntl->funcs->plane_otg_pg_control(pg_cntl, power_on); +} + +void dcn35_root_clock_control(struct dc *dc, + struct pg_block_update *update_state, bool power_on) +{ + int i = 0; + struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; + + if (!pg_cntl) + return; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (update_state->pg_pipe_res_update[PG_HUBP][i] && + update_state->pg_pipe_res_update[PG_DPP][i]) { + if (dc->hwseq->funcs.dpp_root_clock_control) + dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on); + } + + if (update_state->pg_pipe_res_update[PG_DSC][i]) { + if (power_on) { + if (dc->res_pool->dccg->funcs->enable_dsc) + dc->res_pool->dccg->funcs->enable_dsc(dc->res_pool->dccg, i); + } else { + if (dc->res_pool->dccg->funcs->disable_dsc) + dc->res_pool->dccg->funcs->disable_dsc(dc->res_pool->dccg, i); + } + } + } +} + +void dcn35_prepare_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct pg_block_update pg_update_state; + + if (dc->hwss.calc_blocks_to_ungate) { + dc->hwss.calc_blocks_to_ungate(dc, context, &pg_update_state); + + if (dc->hwss.root_clock_control) + dc->hwss.root_clock_control(dc, &pg_update_state, true); + + if (dc->hwss.block_power_control) + dc->hwss.block_power_control(dc, &pg_update_state, true); + } + + dcn20_prepare_bandwidth(dc, context); +} + +void dcn35_optimize_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct pg_block_update pg_update_state; + + dcn20_optimize_bandwidth(dc, context); + + if (dc->hwss.calc_blocks_to_gate) { + dc->hwss.calc_blocks_to_gate(dc, context, &pg_update_state); + + if (dc->hwss.block_power_control) + dc->hwss.block_power_control(dc, &pg_update_state, false); + + if (dc->hwss.root_clock_control) + dc->hwss.root_clock_control(dc, &pg_update_state, false); + } +} + +void dcn35_set_idle_state(const struct dc *dc, bool allow_idle) +{ + // TODO: Find a more suitable communcation + if (dc->clk_mgr->funcs->set_idle_state) + dc->clk_mgr->funcs->set_idle_state(dc->clk_mgr, allow_idle); +} + +uint32_t dcn35_get_idle_state(const struct dc *dc) +{ + // TODO: Find a more suitable communcation + if (dc->clk_mgr->funcs->get_idle_state) + return dc->clk_mgr->funcs->get_idle_state(dc->clk_mgr); + + return 0; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h new file mode 100644 index 000000000000..14bbdb0fa634 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __DC_HWSS_DCN35_H__ +#define __DC_HWSS_DCN35_H__ + +#include "hw_sequencer_private.h" + +struct dc; + +void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); + +void dcn35_dsc_pg_control(struct dce_hwseq *hws, unsigned int dsc_inst, bool power_on); + +void dcn35_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on); + +void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable); + +void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable); + +void dcn35_init_hw(struct dc *dc); + +void dcn35_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); + +void dcn35_power_down_on_boot(struct dc *dc); + +bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable); + +void dcn35_z10_restore(const struct dc *dc); + +void dcn35_init_pipes(struct dc *dc, struct dc_state *context); +void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, + struct dc_state *context); +void dcn35_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); + +void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, + struct pg_block_update *update_state); +void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, + struct pg_block_update *update_state); +void dcn35_block_power_control(struct dc *dc, + struct pg_block_update *update_state, bool power_on); +void dcn35_root_clock_control(struct dc *dc, + struct pg_block_update *update_state, bool power_on); + +void dcn35_prepare_bandwidth( + struct dc *dc, + struct dc_state *context); + +void dcn35_optimize_bandwidth( + struct dc *dc, + struct dc_state *context); + +void dcn35_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); +void dcn35_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + +void dcn35_set_idle_state(const struct dc *dc, bool allow_idle); +uint32_t dcn35_get_idle_state(const struct dc *dc); +#endif /* __DC_HWSS_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h new file mode 100644 index 000000000000..452680fe9aab --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -0,0 +1,493 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HW_SEQUENCER_H__ +#define __DC_HW_SEQUENCER_H__ +#include "dc_types.h" +#include "inc/clock_source.h" +#include "inc/hw/timing_generator.h" +#include "inc/hw/opp.h" +#include "inc/hw/link_encoder.h" +#include "inc/core_status.h" + +struct pipe_ctx; +struct dc_state; +struct dc_stream_status; +struct dc_writeback_info; +struct dchub_init_data; +struct dc_static_screen_params; +struct resource_pool; +struct dc_phy_addr_space_config; +struct dc_virtual_addr_space_config; +struct dpp; +struct dce_hwseq; +struct link_resource; +struct dc_dmub_cmd; +struct pg_block_update; + +struct subvp_pipe_control_lock_fast_params { + struct dc *dc; + bool lock; + struct pipe_ctx *pipe_ctx; +}; + +struct pipe_control_lock_params { + struct dc *dc; + struct pipe_ctx *pipe_ctx; + bool lock; +}; + +struct set_flip_control_gsl_params { + struct pipe_ctx *pipe_ctx; + bool flip_immediate; +}; + +struct program_triplebuffer_params { + const struct dc *dc; + struct pipe_ctx *pipe_ctx; + bool enableTripleBuffer; +}; + +struct update_plane_addr_params { + struct dc *dc; + struct pipe_ctx *pipe_ctx; +}; + +struct set_input_transfer_func_params { + struct dc *dc; + struct pipe_ctx *pipe_ctx; + struct dc_plane_state *plane_state; +}; + +struct program_gamut_remap_params { + struct pipe_ctx *pipe_ctx; +}; + +struct program_manual_trigger_params { + struct pipe_ctx *pipe_ctx; +}; + +struct send_dmcub_cmd_params { + struct dc_context *ctx; + union dmub_rb_cmd *cmd; + enum dm_dmub_wait_type wait_type; +}; + +struct setup_dpp_params { + struct pipe_ctx *pipe_ctx; +}; + +struct program_bias_and_scale_params { + struct pipe_ctx *pipe_ctx; +}; + +struct set_output_transfer_func_params { + struct dc *dc; + struct pipe_ctx *pipe_ctx; + const struct dc_stream_state *stream; +}; + +struct update_visual_confirm_params { + struct dc *dc; + struct pipe_ctx *pipe_ctx; + int mpcc_id; +}; + +struct power_on_mpc_mem_pwr_params { + struct mpc *mpc; + int mpcc_id; + bool power_on; +}; + +struct set_output_csc_params { + struct mpc *mpc; + int opp_id; + const uint16_t *regval; + enum mpc_output_csc_mode ocsc_mode; +}; + +struct set_ocsc_default_params { + struct mpc *mpc; + int opp_id; + enum dc_color_space color_space; + enum mpc_output_csc_mode ocsc_mode; +}; + +struct subvp_save_surf_addr { + struct dc_dmub_srv *dc_dmub_srv; + const struct dc_plane_address *addr; + uint8_t subvp_index; +}; + +union block_sequence_params { + struct update_plane_addr_params update_plane_addr_params; + struct subvp_pipe_control_lock_fast_params subvp_pipe_control_lock_fast_params; + struct pipe_control_lock_params pipe_control_lock_params; + struct set_flip_control_gsl_params set_flip_control_gsl_params; + struct program_triplebuffer_params program_triplebuffer_params; + struct set_input_transfer_func_params set_input_transfer_func_params; + struct program_gamut_remap_params program_gamut_remap_params; + struct program_manual_trigger_params program_manual_trigger_params; + struct send_dmcub_cmd_params send_dmcub_cmd_params; + struct setup_dpp_params setup_dpp_params; + struct program_bias_and_scale_params program_bias_and_scale_params; + struct set_output_transfer_func_params set_output_transfer_func_params; + struct update_visual_confirm_params update_visual_confirm_params; + struct power_on_mpc_mem_pwr_params power_on_mpc_mem_pwr_params; + struct set_output_csc_params set_output_csc_params; + struct set_ocsc_default_params set_ocsc_default_params; + struct subvp_save_surf_addr subvp_save_surf_addr; +}; + +enum block_sequence_func { + DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST = 0, + OPTC_PIPE_CONTROL_LOCK, + HUBP_SET_FLIP_CONTROL_GSL, + HUBP_PROGRAM_TRIPLEBUFFER, + HUBP_UPDATE_PLANE_ADDR, + DPP_SET_INPUT_TRANSFER_FUNC, + DPP_PROGRAM_GAMUT_REMAP, + OPTC_PROGRAM_MANUAL_TRIGGER, + DMUB_SEND_DMCUB_CMD, + DPP_SETUP_DPP, + DPP_PROGRAM_BIAS_AND_SCALE, + DPP_SET_OUTPUT_TRANSFER_FUNC, + MPC_UPDATE_VISUAL_CONFIRM, + MPC_POWER_ON_MPC_MEM_PWR, + MPC_SET_OUTPUT_CSC, + MPC_SET_OCSC_DEFAULT, + DMUB_SUBVP_SAVE_SURF_ADDR, +}; + +struct block_sequence { + union block_sequence_params params; + enum block_sequence_func func; +}; + +struct hw_sequencer_funcs { + void (*hardware_release)(struct dc *dc); + /* Embedded Display Related */ + void (*edp_power_control)(struct dc_link *link, bool enable); + void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); + void (*edp_wait_for_T12)(struct dc_link *link); + + /* Pipe Programming Related */ + void (*init_hw)(struct dc *dc); + void (*power_down_on_boot)(struct dc *dc); + void (*enable_accelerated_mode)(struct dc *dc, + struct dc_state *context); + enum dc_status (*apply_ctx_to_hw)(struct dc *dc, + struct dc_state *context); + void (*disable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*disable_pixel_data)(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank); + void (*apply_ctx_for_surface)(struct dc *dc, + const struct dc_stream_state *stream, + int num_planes, struct dc_state *context); + void (*program_front_end_for_ctx)(struct dc *dc, + struct dc_state *context); + void (*wait_for_pending_cleared)(struct dc *dc, + struct dc_state *context); + void (*post_unlock_program_front_end)(struct dc *dc, + struct dc_state *context); + void (*update_plane_addr)(const struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*update_dchub)(struct dce_hwseq *hws, + struct dchub_init_data *dh_data); + void (*wait_for_mpcc_disconnect)(struct dc *dc, + struct resource_pool *res_pool, + struct pipe_ctx *pipe_ctx); + void (*edp_backlight_control)( + struct dc_link *link, + bool enable); + void (*program_triplebuffer)(const struct dc *dc, + struct pipe_ctx *pipe_ctx, bool enableTripleBuffer); + void (*update_pending_status)(struct pipe_ctx *pipe_ctx); + void (*power_down)(struct dc *dc); + void (*update_dsc_pg)(struct dc *dc, struct dc_state *context, bool safe_to_disable); + + /* Pipe Lock Related */ + void (*pipe_control_lock)(struct dc *dc, + struct pipe_ctx *pipe, bool lock); + void (*interdependent_update_lock)(struct dc *dc, + struct dc_state *context, bool lock); + void (*set_flip_control_gsl)(struct pipe_ctx *pipe_ctx, + bool flip_immediate); + void (*cursor_lock)(struct dc *dc, struct pipe_ctx *pipe, bool lock); + + /* Timing Related */ + void (*get_position)(struct pipe_ctx **pipe_ctx, int num_pipes, + struct crtc_position *position); + int (*get_vupdate_offset_from_vsync)(struct pipe_ctx *pipe_ctx); + void (*calc_vupdate_position)( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + uint32_t *start_line, + uint32_t *end_line); + void (*enable_per_frame_crtc_position_reset)(struct dc *dc, + int group_size, struct pipe_ctx *grouped_pipes[]); + void (*enable_timing_synchronization)(struct dc *dc, + int group_index, int group_size, + struct pipe_ctx *grouped_pipes[]); + void (*enable_vblanks_synchronization)(struct dc *dc, + int group_index, int group_size, + struct pipe_ctx *grouped_pipes[]); + void (*setup_periodic_interrupt)(struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, + struct dc_crtc_timing_adjust adjust); + void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx, + int num_pipes, + const struct dc_static_screen_params *events); + + /* Stream Related */ + void (*enable_stream)(struct pipe_ctx *pipe_ctx); + void (*disable_stream)(struct pipe_ctx *pipe_ctx); + void (*blank_stream)(struct pipe_ctx *pipe_ctx); + void (*unblank_stream)(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings); + + /* Bandwidth Related */ + void (*prepare_bandwidth)(struct dc *dc, struct dc_state *context); + bool (*update_bandwidth)(struct dc *dc, struct dc_state *context); + void (*optimize_bandwidth)(struct dc *dc, struct dc_state *context); + + /* Infopacket Related */ + void (*set_avmute)(struct pipe_ctx *pipe_ctx, bool enable); + void (*send_immediate_sdp_message)( + struct pipe_ctx *pipe_ctx, + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size); + void (*update_info_frame)(struct pipe_ctx *pipe_ctx); + void (*set_dmdata_attributes)(struct pipe_ctx *pipe); + void (*program_dmdata_engine)(struct pipe_ctx *pipe_ctx); + bool (*dmdata_status_done)(struct pipe_ctx *pipe_ctx); + + /* Cursor Related */ + void (*set_cursor_position)(struct pipe_ctx *pipe); + void (*set_cursor_attribute)(struct pipe_ctx *pipe); + void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe); + + /* Colour Related */ + void (*program_gamut_remap)(struct pipe_ctx *pipe_ctx); + void (*program_output_csc)(struct dc *dc, struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, int opp_id); + + /* VM Related */ + int (*init_sys_ctx)(struct dce_hwseq *hws, + struct dc *dc, + struct dc_phy_addr_space_config *pa_config); + void (*init_vm_ctx)(struct dce_hwseq *hws, + struct dc *dc, + struct dc_virtual_addr_space_config *va_config, + int vmid); + + /* Writeback Related */ + void (*update_writeback)(struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context); + void (*enable_writeback)(struct dc *dc, + struct dc_writeback_info *wb_info, + struct dc_state *context); + void (*disable_writeback)(struct dc *dc, + unsigned int dwb_pipe_inst); + + bool (*mmhubbub_warmup)(struct dc *dc, + unsigned int num_dwb, + struct dc_writeback_info *wb_info); + + /* Clock Related */ + enum dc_status (*set_clock)(struct dc *dc, + enum dc_clock_type clock_type, + uint32_t clk_khz, uint32_t stepping); + void (*get_clock)(struct dc *dc, enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg); + void (*optimize_pwr_state)(const struct dc *dc, + struct dc_state *context); + void (*exit_optimized_pwr_state)(const struct dc *dc, + struct dc_state *context); + + /* Audio Related */ + void (*enable_audio_stream)(struct pipe_ctx *pipe_ctx); + void (*disable_audio_stream)(struct pipe_ctx *pipe_ctx); + + /* Stereo 3D Related */ + void (*setup_stereo)(struct pipe_ctx *pipe_ctx, struct dc *dc); + + /* HW State Logging Related */ + void (*log_hw_state)(struct dc *dc, struct dc_log_buffer_ctx *log_ctx); + void (*get_hw_state)(struct dc *dc, char *pBuf, + unsigned int bufSize, unsigned int mask); + void (*clear_status_bits)(struct dc *dc, unsigned int mask); + + bool (*set_backlight_level)(struct pipe_ctx *pipe_ctx, + uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp); + + void (*set_abm_immediate_disable)(struct pipe_ctx *pipe_ctx); + + void (*set_pipe)(struct pipe_ctx *pipe_ctx); + + void (*enable_dp_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + const struct dc_link_settings *link_settings); + void (*enable_tmds_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal, + enum clock_source_id clock_source, + enum dc_color_depth color_depth, + uint32_t pixel_clock); + void (*enable_lvds_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum clock_source_id clock_source, + uint32_t pixel_clock); + void (*disable_link_output)(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); + + void (*get_dcc_en_bits)(struct dc *dc, int *dcc_en_bits); + + /* Idle Optimization Related */ + bool (*apply_idle_power_optimizations)(struct dc *dc, bool enable); + + bool (*does_plane_fit_in_mall)(struct dc *dc, struct dc_plane_state *plane, + struct dc_cursor_attributes *cursor_attr); + void (*commit_subvp_config)(struct dc *dc, struct dc_state *context); + void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context); + void (*subvp_pipe_control_lock)(struct dc *dc, + struct dc_state *context, + bool lock, + bool should_lock_all_pipes, + struct pipe_ctx *top_pipe_to_program, + bool subvp_prev_use); + void (*subvp_pipe_control_lock_fast)(union block_sequence_params *params); + + void (*z10_restore)(const struct dc *dc); + void (*z10_save_init)(struct dc *dc); + bool (*is_abm_supported)(struct dc *dc, + struct dc_state *context, struct dc_stream_state *stream); + + void (*set_disp_pattern_generator)(const struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum controller_dp_test_pattern test_pattern, + enum controller_dp_color_space color_space, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, int height, int offset); + void (*blank_phantom)(struct dc *dc, + struct timing_generator *tg, + int width, + int height); + void (*update_visual_confirm_color)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + int mpcc_id); + void (*update_phantom_vp_position)(struct dc *dc, + struct dc_state *context, + struct pipe_ctx *phantom_pipe); + void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe); + + void (*calc_blocks_to_gate)(struct dc *dc, struct dc_state *context, + struct pg_block_update *update_state); + void (*calc_blocks_to_ungate)(struct dc *dc, struct dc_state *context, + struct pg_block_update *update_state); + void (*block_power_control)(struct dc *dc, + struct pg_block_update *update_state, bool power_on); + void (*root_clock_control)(struct dc *dc, + struct pg_block_update *update_state, bool power_on); + void (*set_idle_state)(const struct dc *dc, bool allow_idle); + uint32_t (*get_idle_state)(const struct dc *dc); + bool (*is_pipe_topology_transition_seamless)(struct dc *dc, + const struct dc_state *cur_ctx, + const struct dc_state *new_ctx); +}; + +void color_space_to_black_color( + const struct dc *dc, + enum dc_color_space colorspace, + struct tg_color *black_color); + +bool hwss_wait_for_blank_complete( + struct timing_generator *tg); + +const uint16_t *find_color_matrix( + enum dc_color_space color_space, + uint32_t *array_size); + +void get_surface_tile_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); +void get_surface_visual_confirm_color( + const struct pipe_ctx *pipe_ctx, + struct tg_color *color); + +void get_hdr_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); +void get_mpctree_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); + +void get_subvp_visual_confirm_color( + struct dc *dc, + struct dc_state *context, + struct pipe_ctx *pipe_ctx, + struct tg_color *color); + +void get_mclk_switch_visual_confirm_color( + struct dc *dc, + struct dc_state *context, + struct pipe_ctx *pipe_ctx, + struct tg_color *color); + +void hwss_execute_sequence(struct dc *dc, + struct block_sequence block_sequence[], + int num_steps); + +void hwss_build_fast_sequence(struct dc *dc, + struct dc_dmub_cmd *dc_dmub_cmd, + unsigned int dmub_cmd_count, + struct block_sequence block_sequence[], + int *num_steps, + struct pipe_ctx *pipe_ctx); + +void hwss_send_dmcub_cmd(union block_sequence_params *params); + +void hwss_program_manual_trigger(union block_sequence_params *params); + +void hwss_setup_dpp(union block_sequence_params *params); + +void hwss_program_bias_and_scale(union block_sequence_params *params); + +void hwss_power_on_mpc_mem_pwr(union block_sequence_params *params); + +void hwss_set_output_csc(union block_sequence_params *params); + +void hwss_set_ocsc_default(union block_sequence_params *params); + +void hwss_subvp_save_surf_addr(union block_sequence_params *params); + +#endif /* __DC_HW_SEQUENCER_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h new file mode 100644 index 000000000000..82c592166875 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -0,0 +1,186 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HW_SEQUENCER_PRIVATE_H__ +#define __DC_HW_SEQUENCER_PRIVATE_H__ + +#include "dc_types.h" + +enum pipe_gating_control { + PIPE_GATING_CONTROL_DISABLE = 0, + PIPE_GATING_CONTROL_ENABLE, + PIPE_GATING_CONTROL_INIT +}; + +struct dce_hwseq_wa { + bool blnd_crtc_trigger; + bool DEGVIDCN10_253; + bool false_optc_underflow; + bool DEGVIDCN10_254; + bool DEGVIDCN21; + bool disallow_self_refresh_during_multi_plane_transition; + bool dp_hpo_and_otg_sequence; + bool wait_hubpret_read_start_during_mpo_transition; +}; + +struct hwseq_wa_state { + bool DEGVIDCN10_253_applied; + bool disallow_self_refresh_during_multi_plane_transition_applied; + unsigned int disallow_self_refresh_during_multi_plane_transition_applied_on_frame; +}; + +struct pipe_ctx; +struct dc_state; +struct dc_stream_status; +struct dc_writeback_info; +struct dchub_init_data; +struct dc_static_screen_params; +struct resource_pool; +struct resource_context; +struct stream_resource; +struct dc_phy_addr_space_config; +struct dc_virtual_addr_space_config; +struct hubp; +struct dpp; +struct dce_hwseq; +struct timing_generator; +struct tg_color; +struct output_pixel_processor; +struct mpcc_blnd_cfg; + +struct hwseq_private_funcs { + + void (*disable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*enable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*init_pipes)(struct dc *dc, struct dc_state *context); + void (*reset_hw_ctx_wrap)(struct dc *dc, struct dc_state *context); + void (*update_plane_addr)(const struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*plane_atomic_disconnect)(struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*update_mpcc)(struct dc *dc, struct pipe_ctx *pipe_ctx); + bool (*set_input_transfer_func)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + bool (*set_output_transfer_func)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); + void (*power_down)(struct dc *dc); + void (*enable_display_pipe_clock_gating)(struct dc_context *ctx, + bool clock_gating); + bool (*enable_display_power_gating)(struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating); + void (*blank_pixel_data)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); + enum dc_status (*enable_stream_timing)( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); + void (*edp_backlight_control)(struct dc_link *link, + bool enable); + void (*setup_vupdate_interrupt)(struct dc *dc, + struct pipe_ctx *pipe_ctx); + bool (*did_underflow_occur)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*init_blank)(struct dc *dc, struct timing_generator *tg); + void (*disable_vga)(struct dce_hwseq *hws); + void (*bios_golden_init)(struct dc *dc); + void (*plane_atomic_power_down)(struct dc *dc, + struct dpp *dpp, + struct hubp *hubp); + void (*plane_atomic_disable)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*enable_power_gating_plane)(struct dce_hwseq *hws, + bool enable); + void (*dpp_root_clock_control)( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool clock_on); + void (*dpp_pg_control)(struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); + void (*hubp_pg_control)(struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); + void (*dsc_pg_control)(struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + bool (*dsc_pg_status)(struct dce_hwseq *hws, + unsigned int dsc_inst); + void (*update_odm)(struct dc *dc, struct dc_state *context, + struct pipe_ctx *pipe_ctx); + void (*program_all_writeback_pipes_in_tree)(struct dc *dc, + const struct dc_stream_state *stream, + struct dc_state *context); + bool (*s0i3_golden_init_wa)(struct dc *dc); + void (*set_hdr_multiplier)(struct pipe_ctx *pipe_ctx); + void (*verify_allow_pstate_change_high)(struct dc *dc); + void (*program_pipe)(struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); + bool (*wait_for_blank_complete)(struct output_pixel_processor *opp); + void (*dccg_init)(struct dce_hwseq *hws); + bool (*set_blend_lut)(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + bool (*set_shaper_3dlut)(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + bool (*set_mcm_luts)(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + void (*PLAT_58856_wa)(struct dc_state *context, + struct pipe_ctx *pipe_ctx); + void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable); + void (*enable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx, + struct dc_state *context); +#ifdef CONFIG_DRM_AMD_DC_FP + void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context); + void (*update_force_pstate)(struct dc *dc, struct dc_state *context); + void (*update_mall_sel)(struct dc *dc, struct dc_state *context); + unsigned int (*calculate_dccg_k1_k2_values)(struct pipe_ctx *pipe_ctx, + unsigned int *k1_div, + unsigned int *k2_div); + void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx); + void (*resync_fifo_dccg_dio)(struct dce_hwseq *hws, struct dc *dc, + struct dc_state *context); + bool (*is_dp_dig_pixel_rate_div_policy)(struct pipe_ctx *pipe_ctx); +#endif +}; + +struct dce_hwseq { + struct dc_context *ctx; + const struct dce_hwseq_registers *regs; + const struct dce_hwseq_shift *shifts; + const struct dce_hwseq_mask *masks; + struct dce_hwseq_wa wa; + struct hwseq_wa_state wa_state; + struct hwseq_private_funcs funcs; + + PHYSICAL_ADDRESS_LOC fb_base; + PHYSICAL_ADDRESS_LOC fb_top; + PHYSICAL_ADDRESS_LOC fb_offset; + PHYSICAL_ADDRESS_LOC uma_top; +}; + +#endif /* __DC_HW_SEQUENCER_PRIVATE_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h deleted file mode 100644 index 844ad5eb8e35..000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HW_SEQUENCER_H__ -#define __DC_HW_SEQUENCER_H__ -#include "dc_types.h" -#include "clock_source.h" -#include "inc/hw/timing_generator.h" -#include "inc/hw/opp.h" -#include "inc/hw/link_encoder.h" -#include "core_status.h" - -struct pipe_ctx; -struct dc_state; -struct dc_stream_status; -struct dc_writeback_info; -struct dchub_init_data; -struct dc_static_screen_params; -struct resource_pool; -struct dc_phy_addr_space_config; -struct dc_virtual_addr_space_config; -struct dpp; -struct dce_hwseq; -struct link_resource; -struct dc_dmub_cmd; -struct pg_block_update; - -struct subvp_pipe_control_lock_fast_params { - struct dc *dc; - bool lock; - struct pipe_ctx *pipe_ctx; -}; - -struct pipe_control_lock_params { - struct dc *dc; - struct pipe_ctx *pipe_ctx; - bool lock; -}; - -struct set_flip_control_gsl_params { - struct pipe_ctx *pipe_ctx; - bool flip_immediate; -}; - -struct program_triplebuffer_params { - const struct dc *dc; - struct pipe_ctx *pipe_ctx; - bool enableTripleBuffer; -}; - -struct update_plane_addr_params { - struct dc *dc; - struct pipe_ctx *pipe_ctx; -}; - -struct set_input_transfer_func_params { - struct dc *dc; - struct pipe_ctx *pipe_ctx; - struct dc_plane_state *plane_state; -}; - -struct program_gamut_remap_params { - struct pipe_ctx *pipe_ctx; -}; - -struct program_manual_trigger_params { - struct pipe_ctx *pipe_ctx; -}; - -struct send_dmcub_cmd_params { - struct dc_context *ctx; - union dmub_rb_cmd *cmd; - enum dm_dmub_wait_type wait_type; -}; - -struct setup_dpp_params { - struct pipe_ctx *pipe_ctx; -}; - -struct program_bias_and_scale_params { - struct pipe_ctx *pipe_ctx; -}; - -struct set_output_transfer_func_params { - struct dc *dc; - struct pipe_ctx *pipe_ctx; - const struct dc_stream_state *stream; -}; - -struct update_visual_confirm_params { - struct dc *dc; - struct pipe_ctx *pipe_ctx; - int mpcc_id; -}; - -struct power_on_mpc_mem_pwr_params { - struct mpc *mpc; - int mpcc_id; - bool power_on; -}; - -struct set_output_csc_params { - struct mpc *mpc; - int opp_id; - const uint16_t *regval; - enum mpc_output_csc_mode ocsc_mode; -}; - -struct set_ocsc_default_params { - struct mpc *mpc; - int opp_id; - enum dc_color_space color_space; - enum mpc_output_csc_mode ocsc_mode; -}; - -struct subvp_save_surf_addr { - struct dc_dmub_srv *dc_dmub_srv; - const struct dc_plane_address *addr; - uint8_t subvp_index; -}; - -union block_sequence_params { - struct update_plane_addr_params update_plane_addr_params; - struct subvp_pipe_control_lock_fast_params subvp_pipe_control_lock_fast_params; - struct pipe_control_lock_params pipe_control_lock_params; - struct set_flip_control_gsl_params set_flip_control_gsl_params; - struct program_triplebuffer_params program_triplebuffer_params; - struct set_input_transfer_func_params set_input_transfer_func_params; - struct program_gamut_remap_params program_gamut_remap_params; - struct program_manual_trigger_params program_manual_trigger_params; - struct send_dmcub_cmd_params send_dmcub_cmd_params; - struct setup_dpp_params setup_dpp_params; - struct program_bias_and_scale_params program_bias_and_scale_params; - struct set_output_transfer_func_params set_output_transfer_func_params; - struct update_visual_confirm_params update_visual_confirm_params; - struct power_on_mpc_mem_pwr_params power_on_mpc_mem_pwr_params; - struct set_output_csc_params set_output_csc_params; - struct set_ocsc_default_params set_ocsc_default_params; - struct subvp_save_surf_addr subvp_save_surf_addr; -}; - -enum block_sequence_func { - DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST = 0, - OPTC_PIPE_CONTROL_LOCK, - HUBP_SET_FLIP_CONTROL_GSL, - HUBP_PROGRAM_TRIPLEBUFFER, - HUBP_UPDATE_PLANE_ADDR, - DPP_SET_INPUT_TRANSFER_FUNC, - DPP_PROGRAM_GAMUT_REMAP, - OPTC_PROGRAM_MANUAL_TRIGGER, - DMUB_SEND_DMCUB_CMD, - DPP_SETUP_DPP, - DPP_PROGRAM_BIAS_AND_SCALE, - DPP_SET_OUTPUT_TRANSFER_FUNC, - MPC_UPDATE_VISUAL_CONFIRM, - MPC_POWER_ON_MPC_MEM_PWR, - MPC_SET_OUTPUT_CSC, - MPC_SET_OCSC_DEFAULT, - DMUB_SUBVP_SAVE_SURF_ADDR, -}; - -struct block_sequence { - union block_sequence_params params; - enum block_sequence_func func; -}; - -struct hw_sequencer_funcs { - void (*hardware_release)(struct dc *dc); - /* Embedded Display Related */ - void (*edp_power_control)(struct dc_link *link, bool enable); - void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up); - void (*edp_wait_for_T12)(struct dc_link *link); - - /* Pipe Programming Related */ - void (*init_hw)(struct dc *dc); - void (*power_down_on_boot)(struct dc *dc); - void (*enable_accelerated_mode)(struct dc *dc, - struct dc_state *context); - enum dc_status (*apply_ctx_to_hw)(struct dc *dc, - struct dc_state *context); - void (*disable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx); - void (*disable_pixel_data)(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank); - void (*apply_ctx_for_surface)(struct dc *dc, - const struct dc_stream_state *stream, - int num_planes, struct dc_state *context); - void (*program_front_end_for_ctx)(struct dc *dc, - struct dc_state *context); - void (*wait_for_pending_cleared)(struct dc *dc, - struct dc_state *context); - void (*post_unlock_program_front_end)(struct dc *dc, - struct dc_state *context); - void (*update_plane_addr)(const struct dc *dc, - struct pipe_ctx *pipe_ctx); - void (*update_dchub)(struct dce_hwseq *hws, - struct dchub_init_data *dh_data); - void (*wait_for_mpcc_disconnect)(struct dc *dc, - struct resource_pool *res_pool, - struct pipe_ctx *pipe_ctx); - void (*edp_backlight_control)( - struct dc_link *link, - bool enable); - void (*program_triplebuffer)(const struct dc *dc, - struct pipe_ctx *pipe_ctx, bool enableTripleBuffer); - void (*update_pending_status)(struct pipe_ctx *pipe_ctx); - void (*power_down)(struct dc *dc); - void (*update_dsc_pg)(struct dc *dc, struct dc_state *context, bool safe_to_disable); - - /* Pipe Lock Related */ - void (*pipe_control_lock)(struct dc *dc, - struct pipe_ctx *pipe, bool lock); - void (*interdependent_update_lock)(struct dc *dc, - struct dc_state *context, bool lock); - void (*set_flip_control_gsl)(struct pipe_ctx *pipe_ctx, - bool flip_immediate); - void (*cursor_lock)(struct dc *dc, struct pipe_ctx *pipe, bool lock); - - /* Timing Related */ - void (*get_position)(struct pipe_ctx **pipe_ctx, int num_pipes, - struct crtc_position *position); - int (*get_vupdate_offset_from_vsync)(struct pipe_ctx *pipe_ctx); - void (*calc_vupdate_position)( - struct dc *dc, - struct pipe_ctx *pipe_ctx, - uint32_t *start_line, - uint32_t *end_line); - void (*enable_per_frame_crtc_position_reset)(struct dc *dc, - int group_size, struct pipe_ctx *grouped_pipes[]); - void (*enable_timing_synchronization)(struct dc *dc, - int group_index, int group_size, - struct pipe_ctx *grouped_pipes[]); - void (*enable_vblanks_synchronization)(struct dc *dc, - int group_index, int group_size, - struct pipe_ctx *grouped_pipes[]); - void (*setup_periodic_interrupt)(struct dc *dc, - struct pipe_ctx *pipe_ctx); - void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, - struct dc_crtc_timing_adjust adjust); - void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx, - int num_pipes, - const struct dc_static_screen_params *events); - - /* Stream Related */ - void (*enable_stream)(struct pipe_ctx *pipe_ctx); - void (*disable_stream)(struct pipe_ctx *pipe_ctx); - void (*blank_stream)(struct pipe_ctx *pipe_ctx); - void (*unblank_stream)(struct pipe_ctx *pipe_ctx, - struct dc_link_settings *link_settings); - - /* Bandwidth Related */ - void (*prepare_bandwidth)(struct dc *dc, struct dc_state *context); - bool (*update_bandwidth)(struct dc *dc, struct dc_state *context); - void (*optimize_bandwidth)(struct dc *dc, struct dc_state *context); - - /* Infopacket Related */ - void (*set_avmute)(struct pipe_ctx *pipe_ctx, bool enable); - void (*send_immediate_sdp_message)( - struct pipe_ctx *pipe_ctx, - const uint8_t *custom_sdp_message, - unsigned int sdp_message_size); - void (*update_info_frame)(struct pipe_ctx *pipe_ctx); - void (*set_dmdata_attributes)(struct pipe_ctx *pipe); - void (*program_dmdata_engine)(struct pipe_ctx *pipe_ctx); - bool (*dmdata_status_done)(struct pipe_ctx *pipe_ctx); - - /* Cursor Related */ - void (*set_cursor_position)(struct pipe_ctx *pipe); - void (*set_cursor_attribute)(struct pipe_ctx *pipe); - void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe); - - /* Colour Related */ - void (*program_gamut_remap)(struct pipe_ctx *pipe_ctx); - void (*program_output_csc)(struct dc *dc, struct pipe_ctx *pipe_ctx, - enum dc_color_space colorspace, - uint16_t *matrix, int opp_id); - - /* VM Related */ - int (*init_sys_ctx)(struct dce_hwseq *hws, - struct dc *dc, - struct dc_phy_addr_space_config *pa_config); - void (*init_vm_ctx)(struct dce_hwseq *hws, - struct dc *dc, - struct dc_virtual_addr_space_config *va_config, - int vmid); - - /* Writeback Related */ - void (*update_writeback)(struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context); - void (*enable_writeback)(struct dc *dc, - struct dc_writeback_info *wb_info, - struct dc_state *context); - void (*disable_writeback)(struct dc *dc, - unsigned int dwb_pipe_inst); - - bool (*mmhubbub_warmup)(struct dc *dc, - unsigned int num_dwb, - struct dc_writeback_info *wb_info); - - /* Clock Related */ - enum dc_status (*set_clock)(struct dc *dc, - enum dc_clock_type clock_type, - uint32_t clk_khz, uint32_t stepping); - void (*get_clock)(struct dc *dc, enum dc_clock_type clock_type, - struct dc_clock_config *clock_cfg); - void (*optimize_pwr_state)(const struct dc *dc, - struct dc_state *context); - void (*exit_optimized_pwr_state)(const struct dc *dc, - struct dc_state *context); - - /* Audio Related */ - void (*enable_audio_stream)(struct pipe_ctx *pipe_ctx); - void (*disable_audio_stream)(struct pipe_ctx *pipe_ctx); - - /* Stereo 3D Related */ - void (*setup_stereo)(struct pipe_ctx *pipe_ctx, struct dc *dc); - - /* HW State Logging Related */ - void (*log_hw_state)(struct dc *dc, struct dc_log_buffer_ctx *log_ctx); - void (*get_hw_state)(struct dc *dc, char *pBuf, - unsigned int bufSize, unsigned int mask); - void (*clear_status_bits)(struct dc *dc, unsigned int mask); - - bool (*set_backlight_level)(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); - - void (*set_abm_immediate_disable)(struct pipe_ctx *pipe_ctx); - - void (*set_pipe)(struct pipe_ctx *pipe_ctx); - - void (*enable_dp_link_output)(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - const struct dc_link_settings *link_settings); - void (*enable_tmds_link_output)(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal, - enum clock_source_id clock_source, - enum dc_color_depth color_depth, - uint32_t pixel_clock); - void (*enable_lvds_link_output)(struct dc_link *link, - const struct link_resource *link_res, - enum clock_source_id clock_source, - uint32_t pixel_clock); - void (*disable_link_output)(struct dc_link *link, - const struct link_resource *link_res, - enum signal_type signal); - - void (*get_dcc_en_bits)(struct dc *dc, int *dcc_en_bits); - - /* Idle Optimization Related */ - bool (*apply_idle_power_optimizations)(struct dc *dc, bool enable); - - bool (*does_plane_fit_in_mall)(struct dc *dc, struct dc_plane_state *plane, - struct dc_cursor_attributes *cursor_attr); - void (*commit_subvp_config)(struct dc *dc, struct dc_state *context); - void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context); - void (*subvp_pipe_control_lock)(struct dc *dc, - struct dc_state *context, - bool lock, - bool should_lock_all_pipes, - struct pipe_ctx *top_pipe_to_program, - bool subvp_prev_use); - void (*subvp_pipe_control_lock_fast)(union block_sequence_params *params); - - void (*z10_restore)(const struct dc *dc); - void (*z10_save_init)(struct dc *dc); - bool (*is_abm_supported)(struct dc *dc, - struct dc_state *context, struct dc_stream_state *stream); - - void (*set_disp_pattern_generator)(const struct dc *dc, - struct pipe_ctx *pipe_ctx, - enum controller_dp_test_pattern test_pattern, - enum controller_dp_color_space color_space, - enum dc_color_depth color_depth, - const struct tg_color *solid_color, - int width, int height, int offset); - void (*blank_phantom)(struct dc *dc, - struct timing_generator *tg, - int width, - int height); - void (*update_visual_confirm_color)(struct dc *dc, - struct pipe_ctx *pipe_ctx, - int mpcc_id); - void (*update_phantom_vp_position)(struct dc *dc, - struct dc_state *context, - struct pipe_ctx *phantom_pipe); - void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe); - - void (*calc_blocks_to_gate)(struct dc *dc, struct dc_state *context, - struct pg_block_update *update_state); - void (*calc_blocks_to_ungate)(struct dc *dc, struct dc_state *context, - struct pg_block_update *update_state); - void (*block_power_control)(struct dc *dc, - struct pg_block_update *update_state, bool power_on); - void (*root_clock_control)(struct dc *dc, - struct pg_block_update *update_state, bool power_on); - void (*set_idle_state)(const struct dc *dc, bool allow_idle); - uint32_t (*get_idle_state)(const struct dc *dc); - bool (*is_pipe_topology_transition_seamless)(struct dc *dc, - const struct dc_state *cur_ctx, - const struct dc_state *new_ctx); -}; - -void color_space_to_black_color( - const struct dc *dc, - enum dc_color_space colorspace, - struct tg_color *black_color); - -bool hwss_wait_for_blank_complete( - struct timing_generator *tg); - -const uint16_t *find_color_matrix( - enum dc_color_space color_space, - uint32_t *array_size); - -void get_surface_tile_visual_confirm_color( - struct pipe_ctx *pipe_ctx, - struct tg_color *color); -void get_surface_visual_confirm_color( - const struct pipe_ctx *pipe_ctx, - struct tg_color *color); - -void get_hdr_visual_confirm_color( - struct pipe_ctx *pipe_ctx, - struct tg_color *color); -void get_mpctree_visual_confirm_color( - struct pipe_ctx *pipe_ctx, - struct tg_color *color); - -void get_subvp_visual_confirm_color( - struct dc *dc, - struct dc_state *context, - struct pipe_ctx *pipe_ctx, - struct tg_color *color); - -void get_mclk_switch_visual_confirm_color( - struct dc *dc, - struct dc_state *context, - struct pipe_ctx *pipe_ctx, - struct tg_color *color); - -void hwss_execute_sequence(struct dc *dc, - struct block_sequence block_sequence[], - int num_steps); - -void hwss_build_fast_sequence(struct dc *dc, - struct dc_dmub_cmd *dc_dmub_cmd, - unsigned int dmub_cmd_count, - struct block_sequence block_sequence[], - int *num_steps, - struct pipe_ctx *pipe_ctx); - -void hwss_send_dmcub_cmd(union block_sequence_params *params); - -void hwss_program_manual_trigger(union block_sequence_params *params); - -void hwss_setup_dpp(union block_sequence_params *params); - -void hwss_program_bias_and_scale(union block_sequence_params *params); - -void hwss_power_on_mpc_mem_pwr(union block_sequence_params *params); - -void hwss_set_output_csc(union block_sequence_params *params); - -void hwss_set_ocsc_default(union block_sequence_params *params); - -void hwss_subvp_save_surf_addr(union block_sequence_params *params); - -#endif /* __DC_HW_SEQUENCER_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h deleted file mode 100644 index 82c592166875..000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DC_HW_SEQUENCER_PRIVATE_H__ -#define __DC_HW_SEQUENCER_PRIVATE_H__ - -#include "dc_types.h" - -enum pipe_gating_control { - PIPE_GATING_CONTROL_DISABLE = 0, - PIPE_GATING_CONTROL_ENABLE, - PIPE_GATING_CONTROL_INIT -}; - -struct dce_hwseq_wa { - bool blnd_crtc_trigger; - bool DEGVIDCN10_253; - bool false_optc_underflow; - bool DEGVIDCN10_254; - bool DEGVIDCN21; - bool disallow_self_refresh_during_multi_plane_transition; - bool dp_hpo_and_otg_sequence; - bool wait_hubpret_read_start_during_mpo_transition; -}; - -struct hwseq_wa_state { - bool DEGVIDCN10_253_applied; - bool disallow_self_refresh_during_multi_plane_transition_applied; - unsigned int disallow_self_refresh_during_multi_plane_transition_applied_on_frame; -}; - -struct pipe_ctx; -struct dc_state; -struct dc_stream_status; -struct dc_writeback_info; -struct dchub_init_data; -struct dc_static_screen_params; -struct resource_pool; -struct resource_context; -struct stream_resource; -struct dc_phy_addr_space_config; -struct dc_virtual_addr_space_config; -struct hubp; -struct dpp; -struct dce_hwseq; -struct timing_generator; -struct tg_color; -struct output_pixel_processor; -struct mpcc_blnd_cfg; - -struct hwseq_private_funcs { - - void (*disable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); - void (*enable_stream_gating)(struct dc *dc, struct pipe_ctx *pipe_ctx); - void (*init_pipes)(struct dc *dc, struct dc_state *context); - void (*reset_hw_ctx_wrap)(struct dc *dc, struct dc_state *context); - void (*update_plane_addr)(const struct dc *dc, - struct pipe_ctx *pipe_ctx); - void (*plane_atomic_disconnect)(struct dc *dc, - struct pipe_ctx *pipe_ctx); - void (*update_mpcc)(struct dc *dc, struct pipe_ctx *pipe_ctx); - bool (*set_input_transfer_func)(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - bool (*set_output_transfer_func)(struct dc *dc, - struct pipe_ctx *pipe_ctx, - const struct dc_stream_state *stream); - void (*power_down)(struct dc *dc); - void (*enable_display_pipe_clock_gating)(struct dc_context *ctx, - bool clock_gating); - bool (*enable_display_power_gating)(struct dc *dc, - uint8_t controller_id, - struct dc_bios *dcb, - enum pipe_gating_control power_gating); - void (*blank_pixel_data)(struct dc *dc, - struct pipe_ctx *pipe_ctx, - bool blank); - enum dc_status (*enable_stream_timing)( - struct pipe_ctx *pipe_ctx, - struct dc_state *context, - struct dc *dc); - void (*edp_backlight_control)(struct dc_link *link, - bool enable); - void (*setup_vupdate_interrupt)(struct dc *dc, - struct pipe_ctx *pipe_ctx); - bool (*did_underflow_occur)(struct dc *dc, struct pipe_ctx *pipe_ctx); - void (*init_blank)(struct dc *dc, struct timing_generator *tg); - void (*disable_vga)(struct dce_hwseq *hws); - void (*bios_golden_init)(struct dc *dc); - void (*plane_atomic_power_down)(struct dc *dc, - struct dpp *dpp, - struct hubp *hubp); - void (*plane_atomic_disable)(struct dc *dc, struct pipe_ctx *pipe_ctx); - void (*enable_power_gating_plane)(struct dce_hwseq *hws, - bool enable); - void (*dpp_root_clock_control)( - struct dce_hwseq *hws, - unsigned int dpp_inst, - bool clock_on); - void (*dpp_pg_control)(struct dce_hwseq *hws, - unsigned int dpp_inst, - bool power_on); - void (*hubp_pg_control)(struct dce_hwseq *hws, - unsigned int hubp_inst, - bool power_on); - void (*dsc_pg_control)(struct dce_hwseq *hws, - unsigned int dsc_inst, - bool power_on); - bool (*dsc_pg_status)(struct dce_hwseq *hws, - unsigned int dsc_inst); - void (*update_odm)(struct dc *dc, struct dc_state *context, - struct pipe_ctx *pipe_ctx); - void (*program_all_writeback_pipes_in_tree)(struct dc *dc, - const struct dc_stream_state *stream, - struct dc_state *context); - bool (*s0i3_golden_init_wa)(struct dc *dc); - void (*set_hdr_multiplier)(struct pipe_ctx *pipe_ctx); - void (*verify_allow_pstate_change_high)(struct dc *dc); - void (*program_pipe)(struct dc *dc, - struct pipe_ctx *pipe_ctx, - struct dc_state *context); - bool (*wait_for_blank_complete)(struct output_pixel_processor *opp); - void (*dccg_init)(struct dce_hwseq *hws); - bool (*set_blend_lut)(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - bool (*set_shaper_3dlut)(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - bool (*set_mcm_luts)(struct pipe_ctx *pipe_ctx, - const struct dc_plane_state *plane_state); - void (*PLAT_58856_wa)(struct dc_state *context, - struct pipe_ctx *pipe_ctx); - void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable); - void (*enable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_state *context); -#ifdef CONFIG_DRM_AMD_DC_FP - void (*program_mall_pipe_config)(struct dc *dc, struct dc_state *context); - void (*update_force_pstate)(struct dc *dc, struct dc_state *context); - void (*update_mall_sel)(struct dc *dc, struct dc_state *context); - unsigned int (*calculate_dccg_k1_k2_values)(struct pipe_ctx *pipe_ctx, - unsigned int *k1_div, - unsigned int *k2_div); - void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx); - void (*resync_fifo_dccg_dio)(struct dce_hwseq *hws, struct dc *dc, - struct dc_state *context); - bool (*is_dp_dig_pixel_rate_div_policy)(struct pipe_ctx *pipe_ctx); -#endif -}; - -struct dce_hwseq { - struct dc_context *ctx; - const struct dce_hwseq_registers *regs; - const struct dce_hwseq_shift *shifts; - const struct dce_hwseq_mask *masks; - struct dce_hwseq_wa wa; - struct hwseq_wa_state wa_state; - struct hwseq_private_funcs funcs; - - PHYSICAL_ADDRESS_LOC fb_base; - PHYSICAL_ADDRESS_LOC fb_top; - PHYSICAL_ADDRESS_LOC fb_offset; - PHYSICAL_ADDRESS_LOC uma_top; -}; - -#endif /* __DC_HW_SEQUENCER_PRIVATE_H__ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 50686fef97f5..bc907ae2052d 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -2306,7 +2306,7 @@ struct dmub_cmd_psr_copy_settings_data { */ uint8_t relock_delay_frame_cnt; /** - * Explicit padding to 2 byte boundary. + * Explicit padding to 4 byte boundary. */ uint8_t pad3; /** @@ -3139,6 +3139,7 @@ enum hw_lock_client { * PSR SU is the client of HW Lock Manager. */ HW_LOCK_CLIENT_PSR_SU = 1, + HW_LOCK_CLIENT_SUBVP = 3, /** * Replay is the client of HW Lock Manager. */