[PATCH] drm/amd/display: Fix p-state allow debug index on dcn31
[Why] It changed since dcn30 but the hubbub31 constructor hasn't been modified to reflect this. [How] Update the value in the constructor to 0x6 so we're checking the right bits for p-state allow. It worked before by accident, but can falsely assert 0 depending on HW state transitions. The most frequent of which appears to be when all pipes turn off during IGT tests. Cc: Harry Wentland Fixes: d158560fc0e1 ("drm/amd/display: Add pstate verification and recovery for DCN31") Signed-off-by: Nicholas Kazlauskas Reviewed-by: Eric Yang --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c index 3e6d6ebd199e..51c5f3685470 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c @@ -1042,5 +1042,7 @@ void hubbub31_construct(struct dcn20_hubbub *hubbub31, hubbub31->detile_buf_size = det_size_kb * 1024; hubbub31->pixel_chunk_size = pixel_chunk_size_kb * 1024; hubbub31->crb_size_segs = config_return_buffer_size_kb / DCN31_CRB_SEGMENT_SIZE_KB; + + hubbub31->debug_test_index_pstate = 0x6; } -- 2.25.1
[PATCH] drm/amd/display: Add pstate verification and recovery for DCN31
[Why] To debug when p-state is being blocked and avoid PMFW hangs when it does occur. [How] Re-use the DCN10 hardware sequencer by adding a new interface for verifying p-state high on the hubbub. The interface is mostly the same as the DCN10 interface, but the bit definitions have changed for the debug bus. Signed-off-by: Nicholas Kazlauskas Reviewed-by: Eric Yang --- .../drm/amd/display/dc/dcn10/dcn10_hubbub.c | 1 + .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 10 +++- .../drm/amd/display/dc/dcn30/dcn30_hubbub.c | 1 + .../drm/amd/display/dc/dcn301/dcn301_hubbub.c | 1 + .../drm/amd/display/dc/dcn31/dcn31_hubbub.c | 60 +++ .../drm/amd/display/dc/dcn31/dcn31_resource.c | 2 +- .../gpu/drm/amd/display/dc/inc/hw/dchubbub.h | 2 + 7 files changed, 73 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index f4f423d0b8c3..80595d7f060c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -940,6 +940,7 @@ static const struct hubbub_funcs hubbub1_funcs = { .program_watermarks = hubbub1_program_watermarks, .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, .allow_self_refresh_control = hubbub1_allow_self_refresh_control, + .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high, }; void hubbub1_construct(struct hubbub *hubbub, 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 index bc9dd48258e3..c3e141c19a77 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1112,9 +1112,13 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc) 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 (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) { + 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) @@ -1123,8 +1127,8 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc) TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES); BREAK_TO_DEBUGGER(); if (dcn10_hw_wa_force_recovery(dc)) { - /*check again*/ - if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) + /*check again*/ + if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) BREAK_TO_DEBUGGER(); } } diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c index f4414de96acc..152c9c5733f1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c @@ -448,6 +448,7 @@ static const struct hubbub_funcs hubbub30_funcs = { .program_watermarks = hubbub3_program_watermarks, .allow_self_refresh_control = hubbub1_allow_self_refresh_control, .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, + .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high, .force_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes, .force_pstate_change_control = hubbub3_force_pstate_change_control, .init_watermarks = hubbub3_init_watermarks, diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c index 1e3bd2e9cdcc..a046664e2031 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c @@ -60,6 +60,7 @@ static const struct hubbub_funcs hubbub301_funcs = { .program_watermarks = hubbub3_program_watermarks, .allow_self_refresh_control = hubbub1_allow_self_refresh_control, .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, + .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high, .force_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes, .force_pstate_change_control = hubbub3_force_pstate_change_control, .hubbub_read_state = hubbub2_read_state, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c index 5e3bcaf12cac..3e6d6ebd199e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbu
[PATCH] drm/amd/display: Call dc_stream_release for remove link enc assignment
[Why] A porting error resulted in the stream assignment for the link being retained without being released - a memory leak. [How] Fix the porting error by adding back the dc_stream_release() intended as part of the original patch. Fixes: 2e45b19dd882 ("drm/amd/display: retain/release at proper places in link_enc assignment") Cc: Qingqing Zhuo Cc: Aurabindo Pillai Cc: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c index a55944da8d53..00f72f66a7ef 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c @@ -122,6 +122,7 @@ static void remove_link_enc_assignment( stream->link_enc = NULL; state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].eng_id = ENGINE_ID_UNKNOWN; state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].stream = NULL; + dc_stream_release(stream); break; } } -- 2.25.1
[PATCH] drm/amd/display: Fix out of bounds access on DNC31 stream encoder regs
[Why] During dcn31_stream_encoder_create, if PHYC/D get remapped to F/G on B0 then we'll index 5 or 6 into a array of length 5 - leading to an access violation on some configs during device creation. [How] Software won't be touching PHYF/PHYG directly, so just extend the array to cover all possible engine IDs. Even if it does by try to access one of these registers by accident the offset will be 0 and we'll get a warning during the access. Fixes: 2fe9a0e1173f ("drm/amd/display: Fix DCN3 B0 DP Alt Mapping") Cc: Mario Limonciello Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 ec5b4cec0ef2..04b52c9d18da 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -485,7 +485,8 @@ static const struct dcn31_apg_mask apg_mask = { SE_DCN3_REG_LIST(id)\ } -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { +/* Some encoders won't be initialized here - but they're logical, not physical. */ +static const struct dcn10_stream_enc_registers stream_enc_regs[ENGINE_ID_COUNT] = { stream_enc_regs(0), stream_enc_regs(1), stream_enc_regs(2), -- 2.25.1
[PATCH] drm/amdgpu/display: Only set vblank_disable_immediate when PSR is not enabled
[Why] PSR currently relies on the kernel's delayed vblank on/off mechanism as an implicit bufferring mechanism to prevent excessive entry/exit. Without this delay the user experience is impacted since it can take a few frames to enter/exit. [How] Only allow vblank disable immediate for DC when psr is not supported. Leave a TODO indicating that this support should be extended in the future to delay independent of the vblank interrupt. Fixes: 3d1508b73ff1 ("drm/amdgpu/display: set vblank_disable_immediate for DC") Cc: Harry Wentland Cc: Alex Deucher Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0747dc7922c2..d582d44c02ad 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1599,9 +1599,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) adev_to_drm(adev)->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size; adev_to_drm(adev)->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size; - /* Disable vblank IRQs aggressively for power-saving */ - adev_to_drm(adev)->vblank_disable_immediate = true; - if (drm_vblank_init(adev_to_drm(adev), adev->dm.display_indexes_num)) { DRM_ERROR( "amdgpu: failed to initialize sw for display support.\n"); @@ -4264,6 +4261,14 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } + /* +* Disable vblank IRQs aggressively for power-saving. +* +* TODO: Fix vblank control helpers to delay PSR entry to allow this when PSR +* is also supported. +*/ + adev_to_drm(adev)->vblank_disable_immediate = !psr_feature_enabled; + /* Software is initialized. Now we can register interrupt handlers. */ switch (adev->asic_type) { #if defined(CONFIG_DRM_AMD_DC_SI) -- 2.25.1
[PATCH 5/5] drm/amd/display: Enable dpia in dmub only for DCN31 B0
From: Jude Shih [Why] DMUB binary is common for both A0 and B0. Hence, driver should notify FW about the support for DPIA in B0. [How] Added dpia_supported bit in dmub_fw_boot_options and will be set only for B0. Assign dpia_supported to true before dm_dmub_hw_init in B0 case. Signed-off-by: Jude Shih Reviewed-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 1 + drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 1 + 3 files changed, 14 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0ad6d0e2a2d8..139a7707f317 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1017,6 +1017,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) const unsigned char *fw_inst_const, *fw_bss_data; uint32_t i, fw_inst_const_size, fw_bss_data_size; bool has_hw_support; + struct dc *dc = adev->dm.dc; if (!dmub_srv) /* DMUB isn't supported on the ASIC. */ @@ -1103,6 +1104,17 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) for (i = 0; i < fb_info->num_fb; ++i) hw_params.fb[i] = _info->fb[i]; + switch (adev->asic_type) { + case CHIP_YELLOW_CARP: + if (dc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_A0) { + hw_params.dpia_supported = true; + hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia; + } + break; + default: + break; + } + status = dmub_srv_hw_init(dmub_srv, _params); if (status != DMUB_STATUS_OK) { DRM_ERROR("Error initializing DMUB HW: %d\n", status); diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index 6c4f0ada163f..717c0e572d2f 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -238,6 +238,7 @@ struct dmub_srv_hw_params { bool load_inst_const; bool skip_panel_power_sequence; bool disable_z10; + bool dpia_supported; bool disable_dpia; }; diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c index 5df990277dd4..10ebf20eaa41 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -338,6 +338,7 @@ void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmu union dmub_fw_boot_options boot_options = {0}; boot_options.bits.z10_disable = params->disable_z10; + boot_options.bits.dpia_supported = params->dpia_supported; boot_options.bits.enable_dpia = params->disable_dpia ? 0 : 1; boot_options.bits.sel_mux_phy_c_d_phy_f_g = (dmub->asic == DMUB_ASIC_DCN31B) ? 1 : 0; -- 2.25.1
[PATCH 3/5] drm/amd/display: Fix USB4 hot plug crash issue
From: Jude Shih [Why] Notify data from outbox corrupt, the notify type should be 2 (HPD) instead of 0 (No data). We copied the address instead of the value. The memory might be freed in the end of outbox IRQ [How] We should allocate the memory of notify and copy the whole content from outbox to hpd handle function Fixes: 5cecad78ea53 ("drm/amd/display: Support for SET_CONFIG processing with DMUB") Signed-off-by: Jude Shih Reviewed-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 +-- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 4cd64529b180..0ad6d0e2a2d8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -730,6 +730,8 @@ static void dm_handle_hpd_work(struct work_struct *work) dmub_hpd_wrk->adev->dm.dmub_callback[dmub_hpd_wrk->dmub_notify->type](dmub_hpd_wrk->adev, dmub_hpd_wrk->dmub_notify); } + + kfree(dmub_hpd_wrk->dmub_notify); kfree(dmub_hpd_wrk); } @@ -755,12 +757,6 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) if (dc_enable_dmub_notifications(adev->dm.dc) && irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) { - dmub_hpd_wrk = kzalloc(sizeof(*dmub_hpd_wrk), GFP_ATOMIC); - if (!dmub_hpd_wrk) { - DRM_ERROR("Failed to allocate dmub_hpd_wrk"); - return; - } - INIT_WORK(_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); do { dc_stat_get_dmub_notification(adev->dm.dc, ); @@ -769,7 +765,20 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params) continue; } if (dm->dmub_thread_offload[notify.type] == true) { - dmub_hpd_wrk->dmub_notify = + dmub_hpd_wrk = kzalloc(sizeof(*dmub_hpd_wrk), GFP_ATOMIC); + if (!dmub_hpd_wrk) { + DRM_ERROR("Failed to allocate dmub_hpd_wrk"); + return; + } + dmub_hpd_wrk->dmub_notify = kzalloc(sizeof(struct dmub_notification), GFP_ATOMIC); + if (!dmub_hpd_wrk->dmub_notify) { + kfree(dmub_hpd_wrk); + DRM_ERROR("Failed to allocate dmub_hpd_wrk->dmub_notify"); + return; + } + INIT_WORK(_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); + if (dmub_hpd_wrk->dmub_notify) + memcpy(dmub_hpd_wrk->dmub_notify, , sizeof(struct dmub_notification)); dmub_hpd_wrk->adev = adev; if (notify.type == DMUB_NOTIFICATION_HPD) { plink = adev->dm.dc->links[notify.link_index]; -- 2.25.1
[PATCH 1/5] drm/amd/display: Fallback to clocks which meet requested voltage on DCN31
From: Michael Strauss [WHY] On certain configs, SMU clock table voltages don't match which cause parser to behave incorrectly by leaving dcfclk and socclk table entries unpopulated. [HOW] Currently the function that finds the corresponding clock for a given voltage only checks for exact voltage level matches. In the case that no match gets found, parser now falls back to searching for the max clock which meets the requested voltage (i.e. its corresponding voltage is below requested). Signed-off-by: Michael Strauss Reviewed-by: Nicholas Kazlauskas --- .../amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c| 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index 0088dff441da..f4c9a458ace8 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -523,14 +523,21 @@ static unsigned int find_clk_for_voltage( unsigned int voltage) { int i; + int max_voltage = 0; + int clock = 0; for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) { - if (clock_table->SocVoltage[i] == voltage) + if (clock_table->SocVoltage[i] == voltage) { return clocks[i]; + } else if (clock_table->SocVoltage[i] >= max_voltage && + clock_table->SocVoltage[i] < voltage) { + max_voltage = clock_table->SocVoltage[i]; + clock = clocks[i]; + } } - ASSERT(0); - return 0; + ASSERT(clock); + return clock; } void dcn31_clk_mgr_helper_populate_bw_params( -- 2.25.1
[PATCH 4/5] drm/amd/display: MST support for DPIA
From: Meenakshikumar Somasundaram [Why] - DPIA MST slot registers are not programmed during payload allocation and hence MST does not work with DPIA. - HPD RX interrupts are not handled for DPIA. [How] - Added inbox command to program the MST slots whenever payload allocation happens for DPIA links. - Added support for handling HPD RX interrupts Signed-off-by: Meenakshikumar Somasundaram Reviewed-by: Jun Lei Acked-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/core/dc.c | 54 +++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 28 ++ drivers/gpu/drm/amd/display/dc/dc.h | 6 +++ .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 23 4 files changed, 111 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 9d33b00b7e27..12e5470fa567 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3750,6 +3750,60 @@ bool dc_process_dmub_set_config_async(struct dc *dc, return is_cmd_complete; } +/** + * + * Function: dc_process_dmub_set_mst_slots + * + * @brief + * Submits mst slot allocation command to dmub via inbox message + * + * @param + * [in] dc: dc structure + * [in] link_index: link index + * [in] mst_alloc_slots: mst slots to be allotted + * [out] mst_slots_in_use: mst slots in use returned in failure case + * + * @return + * DC_OK if successful, DC_ERROR if failure + * + */ +enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, + uint32_t link_index, + uint8_t mst_alloc_slots, + uint8_t *mst_slots_in_use) +{ + union dmub_rb_cmd cmd = {0}; + struct dc_dmub_srv *dmub_srv = dc->ctx->dmub_srv; + + /* prepare MST_ALLOC_SLOTS command */ + cmd.set_mst_alloc_slots.header.type = DMUB_CMD__DPIA; + cmd.set_mst_alloc_slots.header.sub_type = DMUB_CMD__DPIA_MST_ALLOC_SLOTS; + + cmd.set_mst_alloc_slots.mst_slots_control.instance = dc->links[link_index]->ddc_hw_inst; + cmd.set_mst_alloc_slots.mst_slots_control.mst_alloc_slots = mst_alloc_slots; + + if (!dc_dmub_srv_cmd_with_reply_data(dmub_srv, )) + /* command is not processed by dmub */ + return DC_ERROR_UNEXPECTED; + + /* command processed by dmub, if ret_status is 1 */ + if (cmd.set_config_access.header.ret_status != 1) + /* command processing error */ + return DC_ERROR_UNEXPECTED; + + /* command processed and we have a status of 2, mst not enabled in dpia */ + if (cmd.set_mst_alloc_slots.mst_slots_control.immed_status == 2) + return DC_FAIL_UNSUPPORTED_1; + + /* previously configured mst alloc and used slots did not match */ + if (cmd.set_mst_alloc_slots.mst_slots_control.immed_status == 3) { + *mst_slots_in_use = cmd.set_mst_alloc_slots.mst_slots_control.mst_slots_in_use; + return DC_NOT_SUPPORTED; + } + + return DC_OK; +} + /** * dc_disable_accelerated_mode - disable accelerated mode * @dc: dc structure diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 27b9ff98a569..2796bdd17de1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3499,6 +3499,20 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) ASSERT(proposed_table.stream_count > 0); + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + static enum dc_status status; + uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF; + + for (i = 0; i < link->mst_stream_alloc_table.stream_count; i++) + mst_alloc_slots += link->mst_stream_alloc_table.stream_allocations[i].slot_count; + + status = dc_process_dmub_set_mst_slots(link->dc, link->link_index, + mst_alloc_slots, _mst_slots_in_use); + ASSERT(status == DC_OK); + DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n", + status, mst_alloc_slots, prev_mst_slots_in_use); + } + /* program DP source TX for payload */ #if defined(CONFIG_DRM_AMD_DC_DCN) switch (dp_get_link_encoding_format(>cur_link_settings)) { @@ -3842,6 +3856,20 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) #endif } + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + enum dc_status status; + uint8_t
[PATCH 2/5] drm/amd/display: Fix deadlock when falling back to v2 from v3
[Why] A deadlock in the kernel occurs when we fallback from the V3 to V2 add_topology_to_display or remove_topology_to_display because they both try to acquire the dtm_mutex but recursive locking isn't supported on mutex_lock(). [How] Make the mutex_lock/unlock more fine grained and move them up such that they're only required for the psp invocation itself. Fixes: bf62221e9d0e ("drm/amd/display: Add DCN3.1 HDCP support") Signed-off-by: Nicholas Kazlauskas Reviewed-by: Aric Cyr --- drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index e9bd84ec027d..be61975f1470 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -105,6 +105,7 @@ static enum mod_hdcp_status remove_display_from_topology_v3( dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE; psp_dtm_invoke(psp, dtm_cmd->cmd_id); + mutex_unlock(>dtm_context.mutex); if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) { status = remove_display_from_topology_v2(hdcp, index); @@ -115,8 +116,6 @@ static enum mod_hdcp_status remove_display_from_topology_v3( HDCP_TOP_REMOVE_DISPLAY_TRACE(hdcp, display->index); } - mutex_unlock(>dtm_context.mutex); - return status; } @@ -205,6 +204,7 @@ static enum mod_hdcp_status add_display_to_topology_v3( dtm_cmd->dtm_in_message.topology_update_v3.link_hdcp_cap = link->hdcp_supported_informational; psp_dtm_invoke(psp, dtm_cmd->cmd_id); + mutex_unlock(>dtm_context.mutex); if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) { status = add_display_to_topology_v2(hdcp, display); @@ -214,8 +214,6 @@ static enum mod_hdcp_status add_display_to_topology_v3( HDCP_TOP_ADD_DISPLAY_TRACE(hdcp, display->index); } - mutex_unlock(>dtm_context.mutex); - return status; } -- 2.25.1
[PATCH 0/5] Fix USBC lightup on DCN31B
This patchset is a mini-promotion to fix USBC lightup on DCN31B for both SST and MST displays. There are five issues at play here: 1. Invalid clock table causing mode validation to fail 2. HDCP downgrade to v2 causes deadlock 3. MST payload allocation not being propagated 4. PHY mux selection not being properly indicated to DMCUB 5. Hang occuring during HPD on PHYF/G. Jude Shih (2): drm/amd/display: Fix USB4 hot plug crash issue drm/amd/display: Enable dpia in dmub only for DCN31 B0 Meenakshikumar Somasundaram (1): drm/amd/display: MST support for DPIA Michael Strauss (1): drm/amd/display: Fallback to clocks which meet requested voltage on DCN31 Nicholas Kazlauskas (1): drm/amd/display: Fix deadlock when falling back to v2 from v3 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 35 +--- .../display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c | 13 +++-- drivers/gpu/drm/amd/display/dc/core/dc.c | 54 +++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 28 ++ drivers/gpu/drm/amd/display/dc/dc.h | 6 +++ drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 1 + .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 23 .../gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 1 + .../drm/amd/display/modules/hdcp/hdcp_psp.c | 6 +-- 9 files changed, 153 insertions(+), 14 deletions(-) -- 2.25.1
[PATCH] drm/amd/display: Fix surface optimization regression on Carrizo
[Why] DCE legacy optimization path isn't well tested under new DC optimization flow which can result in underflow occuring when initializing X11 on Carrizo. [How] Retain the legacy optimization flow for DCE and keep the new one for DCN to satisfy optimizations being correctly applied for ASIC that can support it. Fixes: ab37c6527bb1 ("drm/amd/display: Optimize bandwidth on following fast update") Cc: Bhawanpreet Lakha Cc: Mikita Lipski Reported-by: Tom St Denis Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/core/dc.c | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index da942e9f5142..f9876e429f26 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3118,8 +3118,13 @@ void dc_commit_updates_for_stream(struct dc *dc, if (new_pipe->plane_state && new_pipe->plane_state != old_pipe->plane_state) new_pipe->plane_state->force_full_update = true; } - } else if (update_type == UPDATE_TYPE_FAST) { - /* Previous frame finished and HW is ready for optimization. */ + } else if (update_type == UPDATE_TYPE_FAST && dc_ctx->dce_version >= DCE_VERSION_MAX) { + /* +* Previous frame finished and HW is ready for optimization. +* +* Only relevant for DCN behavior where we can guarantee the optimization +* is safe to apply - retain the legacy behavior for DCE. +*/ dc_post_update_surfaces_to_stream(dc); } @@ -3178,6 +3183,12 @@ void dc_commit_updates_for_stream(struct dc *dc, } } + /* Legacy optimization path for DCE. */ + if (update_type >= UPDATE_TYPE_FULL && dc_ctx->dce_version < DCE_VERSION_MAX) { + dc_post_update_surfaces_to_stream(dc); + TRACE_DCE_CLOCK_STATE(>bw_ctx.bw.dce); + } + return; } -- 2.25.1
[PATCH] drm/amd/display: Enable PSR by default on DCN3.1
[Why] New idle optimizations for DCN3.1 require PSR for optimal power savings on panels that support it. This was previously left disabled by default because of issues with compositors that do not pageflip and scan out directly to the frontbuffer. For these compositors we now have detection methods that wait for x number of pageflips after a full update - triggered by a buffer or format change typically. This may introduce bugs or new cases not tested by users so this is only currently targeting DCN31. [How] Add code in DM to set PSR state by default for DCN3.1 while falling back to the feature mask for older DCN. Add a global debug flag that can be set to disable it for either. Cc: Harry Wentland Cc: Roman Li Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 - drivers/gpu/drm/amd/include/amd_shared.h| 5 +++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index dc595ecec595..ff545503a6ed 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4031,6 +4031,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) int32_t primary_planes; enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; + bool psr_feature_enabled = false; dm->display_indexes_num = dm->dc->caps.max_streams; /* Update the actual used number of crtc */ @@ -4113,6 +4114,19 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) DRM_DEBUG_KMS("Unsupported DCN IP version for outbox: 0x%X\n", adev->ip_versions[DCE_HWIP][0]); } + + /* Determine whether to enable PSR support by default. */ + if (!(amdgpu_dc_debug_mask & DC_DISABLE_PSR)) { + switch (adev->ip_versions[DCE_HWIP][0]) { + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + psr_feature_enabled = true; + break; + default: + psr_feature_enabled = amdgpu_dc_feature_mask & DC_PSR_MASK; + break; + } + } #endif /* loops over all connectors on the board */ @@ -4156,7 +4170,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } else if (dc_link_detect(link, DETECT_REASON_BOOT)) { amdgpu_dm_update_connector_after_detect(aconnector); register_backlight_device(dm, link); - if (amdgpu_dc_feature_mask & DC_PSR_MASK) + + if (psr_feature_enabled) amdgpu_dm_set_psr_caps(link); } diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 257f280d3d53..f1a46d16f7ea 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -228,7 +228,7 @@ enum DC_FEATURE_MASK { DC_FBC_MASK = (1 << 0), //0x1, disabled by default DC_MULTI_MON_PP_MCLK_SWITCH_MASK = (1 << 1), //0x2, enabled by default DC_DISABLE_FRACTIONAL_PWM_MASK = (1 << 2), //0x4, disabled by default - DC_PSR_MASK = (1 << 3), //0x8, disabled by default + DC_PSR_MASK = (1 << 3), //0x8, disabled by default for dcn < 3.1 DC_EDP_NO_POWER_SEQUENCING = (1 << 4), //0x10, disabled by default }; @@ -236,7 +236,8 @@ enum DC_DEBUG_MASK { DC_DISABLE_PIPE_SPLIT = 0x1, DC_DISABLE_STUTTER = 0x2, DC_DISABLE_DSC = 0x4, - DC_DISABLE_CLOCK_GATING = 0x8 + DC_DISABLE_CLOCK_GATING = 0x8, + DC_DISABLE_PSR = 0x10, }; enum amd_dpm_forced_level; -- 2.25.1
[PATCH] drm/amd/display: Fix white screen page fault for gpuvm
[Why] The "base_addr_is_mc_addr" field was added for dcn3.1 support but pa_config was never updated to set it to false. Uninitialized memory causes it to be set to true which results in address mistranslation and white screen. [How] Use memset to ensure all fields are initialized to 0 by default. Cc: Aaron Liu Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 53363728dbb..b0426bb3f2e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1125,6 +1125,8 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ uint32_t agp_base, agp_bot, agp_top; PHYSICAL_ADDRESS_LOC page_table_start, page_table_end, page_table_base; + memset(pa_config, 0, sizeof(*pa_config)); + logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18; pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); -- 2.25.1
[PATCH] drm/amd/display: Add NULL checks for vblank workqueue
[Why] If we're running a headless config with 0 links then the vblank workqueue will be NULL - causing a NULL pointer exception during any commit. [How] Guard access to the workqueue if it's NULL and don't queue or flush work if it is. Cc: Roman Li Cc: Wayne Lin Cc: Harry Wentland Reported-by: Mike Lothian BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1700 Fixes: 91f86d4cce2 ("drm/amd/display: Use vblank control events for PSR enable/disable") Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 32 +++ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 8837259215d..46e08736f94 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6185,21 +6185,23 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) return 0; #if defined(CONFIG_DRM_AMD_DC_DCN) - work = kzalloc(sizeof(*work), GFP_ATOMIC); - if (!work) - return -ENOMEM; + if (dm->vblank_control_workqueue) { + work = kzalloc(sizeof(*work), GFP_ATOMIC); + if (!work) + return -ENOMEM; - INIT_WORK(>work, vblank_control_worker); - work->dm = dm; - work->acrtc = acrtc; - work->enable = enable; + INIT_WORK(>work, vblank_control_worker); + work->dm = dm; + work->acrtc = acrtc; + work->enable = enable; - if (acrtc_state->stream) { - dc_stream_retain(acrtc_state->stream); - work->stream = acrtc_state->stream; - } + if (acrtc_state->stream) { + dc_stream_retain(acrtc_state->stream); + work->stream = acrtc_state->stream; + } - queue_work(dm->vblank_control_workqueue, >work); + queue_work(dm->vblank_control_workqueue, >work); + } #endif return 0; @@ -8809,7 +8811,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, * If PSR or idle optimizations are enabled then flush out * any pending work before hardware programming. */ - flush_workqueue(dm->vblank_control_workqueue); + if (dm->vblank_control_workqueue) + flush_workqueue(dm->vblank_control_workqueue); #endif bundle->stream_update.stream = acrtc_state->stream; @@ -9144,7 +9147,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) /* if there mode set or reset, disable eDP PSR */ if (mode_set_reset_required) { #if defined(CONFIG_DRM_AMD_DC_DCN) - flush_workqueue(dm->vblank_control_workqueue); + if (dm->vblank_control_workqueue) + flush_workqueue(dm->vblank_control_workqueue); #endif amdgpu_dm_psr_disable_all(dm); } -- 2.25.1
[PATCH] drm/amd/display: Extend DMUB diagnostic logging to DCN3.1
[Why & How] Extend existing support for DCN2.1 DMUB diagnostic logging to DCN3.1 so we can collect useful information if the DMUB hangs. Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 60 +++ .../gpu/drm/amd/display/dmub/src/dmub_dcn31.h | 16 - .../gpu/drm/amd/display/dmub/src/dmub_srv.c | 5 +- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c index 8c886ece71..973de34641 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c @@ -352,3 +352,63 @@ uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub) { return REG_READ(DMCUB_TIMER_CURRENT); } + +void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data) +{ + uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset; + uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; + + if (!dmub || !diag_data) + return; + + memset(diag_data, 0, sizeof(*diag_data)); + + diag_data->dmcub_version = dmub->fw_version; + + diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + + diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + + diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + + diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + + REG_GET(DMCUB_CNTL, DMCUB_ENABLE, _dmub_enabled); + diag_data->is_dmcub_enabled = is_dmub_enabled; + + REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, _soft_reset); + diag_data->is_dmcub_soft_reset = is_soft_reset; + + REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, _sec_reset); + diag_data->is_dmcub_secure_reset = is_sec_reset; + + REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, _traceport_enabled); + diag_data->is_traceport_en = is_traceport_enabled; + + REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, _cw0_enabled); + diag_data->is_cw0_enabled = is_cw0_enabled; + + REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, _cw6_enabled); + diag_data->is_cw6_enabled = is_cw6_enabled; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h index 2829c3e9a3..9456a6a2d5 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h @@ -36,6 +36,9 @@ struct dmub_srv; DMUB_SR(DMCUB_CNTL) \ DMUB_SR(DMCUB_CNTL2) \ DMUB_SR(DMCUB_SEC_CNTL) \ + DMUB_SR(DMCUB_INBOX0_SIZE) \ + DMUB_SR(DMCUB_INBOX0_RPTR) \ + DMUB_SR(DMCUB_INBOX0_WPTR) \ DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \ DMUB_SR(DMCUB_INBOX1_SIZE) \ DMUB_SR(DMCUB_INBOX1_RPTR) \ @@ -103,11 +106,15 @@ struct dmub_srv; DMUB_SR(DMCUB_SCRATCH14) \ DMUB_SR(DMCUB_SCRATCH15) \ DMUB_SR(DMCUB_GPINT_DATAIN1) \ + DMUB_SR(DMCUB_GPINT_DATAOUT) \ DMUB_SR(CC_DC_PIPE_DIS) \ DMUB_SR(MMHUBBUB_SOFT_RESET) \ DMUB_SR(DCN_VM_FB_LOCATION_BASE) \ DMUB_SR(DCN_VM_FB_OFFSET) \ - DMUB_SR(DMCUB_TIMER_CURRENT) + DMUB_SR(DMCUB_TIMER_CURRENT) \ + DMUB_SR(DMCUB_INST_FETCH_FAULT_ADDR) \ + DMUB_SR(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR) \ + DMUB_SR(DMCUB_DATA_WRITE_FAULT_ADDR) #define DMUB_DCN31_FIELDS() \ DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \ @@ -115,6 +122,7 @@ struct dmub_srv; DMUB
[PATCH] drm/amd/display: Fix GPU scaling regression by FS video support
[Why] FS video support regressed GPU scaling and the scaled buffer ends up stuck in the top left of the screen at native size - full, aspect, center scaling modes do not function. This is because decide_crtc_timing_for_drm_display_mode() does not get called when scaling is enabled. [How] Split recalculate timing and scaling into two different flags. We don't want to call drm_mode_set_crtcinfo() for scaling, but we do want to call it for FS video. Optimize and move preferred_refresh calculation next to decide_crtc_timing_for_drm_display_mode() like it used to be since that's not used for FS video. We don't need to copy over the VIC or polarity in the case of FS video modes because those don't change. Fixes: a372f4abec ("drm/amd/display: Skip modeset for front porch change") Cc: Aurabindo Pillai Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 8cd270f129..759621b0e8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5672,7 +5672,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, struct drm_display_mode saved_mode; struct drm_display_mode *freesync_mode = NULL; bool native_mode_found = false; - bool recalculate_timing = dm_state ? (dm_state->scaling != RMX_OFF) : false; + bool recalculate_timing = false; + bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false; int mode_refresh; int preferred_refresh = 0; #if defined(CONFIG_DRM_AMD_DC_DCN) @@ -5735,7 +5736,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ DRM_DEBUG_DRIVER("No preferred mode found\n"); } else { - recalculate_timing |= amdgpu_freesync_vid_mode && + recalculate_timing = amdgpu_freesync_vid_mode && is_freesync_video_mode(, aconnector); if (recalculate_timing) { freesync_mode = get_highest_refresh_rate_mode(aconnector, false); @@ -5743,11 +5744,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, mode = *freesync_mode; } else { decide_crtc_timing_for_drm_display_mode( - , preferred_mode, - dm_state ? (dm_state->scaling != RMX_OFF) : false); - } + , preferred_mode, scale); - preferred_refresh = drm_mode_vrefresh(preferred_mode); + preferred_refresh = drm_mode_vrefresh(preferred_mode); + } } if (recalculate_timing) @@ -5759,7 +5759,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, * If scaling is enabled and refresh rate didn't change * we copy the vic and polarities of the old timings */ - if (!recalculate_timing || mode_refresh != preferred_refresh) + if (!scale || mode_refresh != preferred_refresh) fill_stream_properties_from_drm_display_mode( stream, , >base, con_state, NULL, requested_bpc); -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/powerplay: Fix hardmins not being sent to SMU for RV
[Why] DC uses these to raise the voltage as needed for higher dispclk/dppclk and to ensure that we have enough bandwidth to drive the displays. There's a bug preventing these from actuially sending messages since it's checking the actual clock (which is 0) instead of the incoming clock (which shouldn't be 0) when deciding to send the hardmin. [How] Check the clocks != 0 instead of the actual clocks. Fixes: 9ed9203c3ee7 ("drm/amd/powerplay: rv dal-pplib interface refactor powerplay part") Cc: Hersen Wu Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c index c9cfe90a2947..9ee8cf8267c8 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c @@ -204,8 +204,7 @@ static int smu10_set_min_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clo { struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - if (smu10_data->need_min_deep_sleep_dcefclk && - smu10_data->deep_sleep_dcefclk != clock) { + if (clock && smu10_data->deep_sleep_dcefclk != clock) { smu10_data->deep_sleep_dcefclk = clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk, @@ -219,8 +218,7 @@ static int smu10_set_hard_min_dcefclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t c { struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - if (smu10_data->dcf_actual_hard_min_freq && - smu10_data->dcf_actual_hard_min_freq != clock) { + if (clock && smu10_data->dcf_actual_hard_min_freq != clock) { smu10_data->dcf_actual_hard_min_freq = clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinDcefclkByFreq, @@ -234,8 +232,7 @@ static int smu10_set_hard_min_fclk_by_freq(struct pp_hwmgr *hwmgr, uint32_t cloc { struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); - if (smu10_data->f_actual_hard_min_freq && - smu10_data->f_actual_hard_min_freq != clock) { + if (clock && smu10_data->f_actual_hard_min_freq != clock) { smu10_data->f_actual_hard_min_freq = clock; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinFclkByFreq, -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Reject overlay plane configurations in multi-display scenarios
[Why] These aren't stable on some platform configurations when driving multiple displays, especially on higher resolution. In particular the delay in asserting p-state and validating from x86 outweights any power or performance benefit from the hardware composition. Under some configurations this will manifest itself as extreme stutter or unresponsiveness especially when combined with cursor movement. [How] Disable these for now. Exposing overlays to userspace doesn't guarantee that they'll be able to use them in any and all configurations and it's part of the DRM contract to have userspace gracefully handle validation failures when they occur. Valdiation occurs as part of DC and this in particular affects RV, so disable this in dcn10_global_validation. Cc: Hersen Wu Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 8 1 file changed, 8 insertions(+) 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 07571f84e0f8..1abd81e17f09 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1213,6 +1213,7 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont bool video_large = false; bool desktop_large = false; bool dcc_disabled = false; + bool mpo_enabled = false; for (i = 0; i < context->stream_count; i++) { if (context->stream_status[i].plane_count == 0) @@ -1221,6 +1222,9 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont if (context->stream_status[i].plane_count > 2) return DC_FAIL_UNSUPPORTED_1; + if (context->stream_status[i].plane_count > 1) + mpo_enabled = true; + for (j = 0; j < context->stream_status[i].plane_count; j++) { struct dc_plane_state *plane = context->stream_status[i].plane_states[j]; @@ -1244,6 +1248,10 @@ static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *cont } } + /* Disable MPO in multi-display configurations. */ + if (context->stream_count > 1 && mpo_enabled) + return DC_FAIL_UNSUPPORTED_1; + /* * Workaround: On DCN10 there is UMC issue that causes underflow when * playing 4k video on 4k desktop with video downscaled and single channel -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH v2] drm/amd/display: Replace DRM private objects with subclassed DRM atomic state
[Why] DM atomic check was structured in a way that we required old DC state in order to dynamically add and remove planes and streams from the context to build the DC state context for validation. DRM private objects were used to carry over the last DC state and were added to the context on nearly every commit - regardless of fast or full so we could check whether or not the new state could affect bandwidth. The problem with this model is that DRM private objects do not implicitly stall out other commits. So if you have two commits touching separate DRM objects they could run concurrently and potentially execute out of order - leading to a use-after-free. If we want this to be safe we have two options: 1. Stall out concurrent commits since they touch the same private object 2. Refactor DM to not require old DC state and drop private object usage [How] This implements approach #2 since it still allows for judder free updates in multi-display scenarios. I'll list the big changes in order at a high level: 1. Subclass DRM atomic state instead of using DRM private objects. DC relied on the old state to determine which changes cause bandwidth updates but now we have DM perform similar checks based on DRM state instead - dropping the requirement for old state to exist at all. This means that we can now build a new DC context from scratch whenever we have something that DM thinks could affect bandwidth. Whenever we need to rebuild bandwidth we now add all CRTCs and planes to the DRM state in order to get the absolute set of DC streams and DC planes. This introduces a stall on other commits, but this stall already exists because of the lock_and_validation logic and it's necessary since updates may move around pipes and require full reprogramming. 2. Drop workarounds to add planes to maintain z-order early in atomic check. This is no longer needed because of the changes for (1). This also involves fixing up should_plane_reset checks since we can just avoid resetting streams and planes when they haven't actually changed. 3. Rework dm_update_crtc_state and dm_update_plane_state to be single pass instead of two pass. This is necessary since we no longer have the dc_state to add and remove planes to the context in and we want to defer creation to the end of commit_check. It also makes the logic a lot simpler to follow since as an added bonus. v2: rebase, naming, comments and spelling fixes Cc: Rodrigo Siqueira Cc: Bhawanpreet Lakha Cc: Harry Wentland Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 700 +++--- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +- 2 files changed, 279 insertions(+), 432 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ff5f7f7ceec6..d76927bac737 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1839,7 +1839,6 @@ static int dm_resume(void *handle) struct drm_plane *plane; struct drm_plane_state *new_plane_state; struct dm_plane_state *dm_new_plane_state; - struct dm_atomic_state *dm_state = to_dm_atomic_state(dm->atomic_obj.state); enum dc_connection_type new_connection_type = dc_connection_none; struct dc_state *dc_state; int i, r, j; @@ -1879,11 +1878,6 @@ static int dm_resume(void *handle) return 0; } - /* Recreate dc_state - DC invalidates it when setting power state to S3. */ - dc_release_state(dm_state->context); - dm_state->context = dc_create_state(dm->dc); - /* TODO: Remove dc_state->dccg, use dc->dccg directly. */ - dc_resource_state_construct(dm->dc, dm_state->context); /* Before powering on DC we need to re-initialize DMUB. */ r = dm_dmub_hw_init(adev); @@ -2019,11 +2013,52 @@ const struct amdgpu_ip_block_version dm_ip_block = * *WIP* */ +static struct drm_atomic_state * +amdgpu_dm_atomic_state_alloc(struct drm_device *dev) +{ + struct dm_atomic_state *dm_state; + + dm_state = kzalloc(sizeof(*dm_state), GFP_KERNEL); + + if (!dm_state) + return NULL; + + if (drm_atomic_state_init(dev, _state->base) < 0) { + kfree(dm_state); + return NULL; + } + + return _state->base; +} + +static void amdgpu_dm_atomic_state_free(struct drm_atomic_state *state) +{ + struct dm_atomic_state *dm_state = to_dm_atomic_state(state); + + if (dm_state->context) { + dc_release_state(dm_state->context); + dm_state->context = NULL; + } + + drm_atomic_state_default_release(state); + kfree(state); +} + +static void amdgpu_dm_atomic_state_clear(struct drm_atomic_state *state) +{ + struct dm_atomic_state *dm_state = to_dm_atomic_state(state); + + d
[PATCH 4/7] drm/amd/display: Use validated tiling_flags and tmz_surface in commit_tail
[Why] So we're not racing with userspace or deadlocking DM. [How] These flags are now stored on dm_plane_state itself and acquried and validated during commit_check, so just use those instead. Cc: Daniel Vetter Cc: Bhawanpreet Lakha Cc: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 18 -- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f78c09c9585e..0d5f45742bb5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7094,8 +7094,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, long r; unsigned long flags; struct amdgpu_bo *abo; - uint64_t tiling_flags; - bool tmz_surface = false; uint32_t target_vblank, last_flip_vblank; bool vrr_active = amdgpu_dm_vrr_active(acrtc_state); bool pflip_present = false; @@ -7179,20 +7177,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, if (unlikely(r <= 0)) DRM_ERROR("Waiting for fences timed out!"); - /* -* We cannot reserve buffers here, which means the normal flag -* access functions don't work. Paper over this with READ_ONCE, -* but maybe the flags are invariant enough that not even that -* would be needed. -*/ - tiling_flags = READ_ONCE(abo->tiling_flags); - tmz_surface = READ_ONCE(abo->flags) & AMDGPU_GEM_CREATE_ENCRYPTED; - fill_dc_plane_info_and_addr( - dm->adev, new_plane_state, tiling_flags, + dm->adev, new_plane_state, + dm_new_plane_state->tiling_flags, >plane_infos[planes_count], - >flip_addrs[planes_count].address, tmz_surface, - false); + >flip_addrs[planes_count].address, + dm_new_plane_state->tmz_surface, false); DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n", new_plane_state->plane->index, -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/7] drm/amd/display: Reset plane when tiling flags change
[Why] Enabling or disable DCC or switching between tiled and linear formats can require bandwidth updates. They're currently skipping all DC validation by being treated as purely surface updates. [How] Treat tiling_flag changes (which encode DCC state) as a condition for resetting the plane. Cc: Bhawanpreet Lakha Cc: Rodrigo Siqueira Cc: Hersen Wu Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 --- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7cc5ab90ce13..bf1881bd492c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8332,6 +8332,8 @@ static bool should_reset_plane(struct drm_atomic_state *state, * TODO: Come up with a more elegant solution for this. */ for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) { + struct dm_plane_state *old_dm_plane_state, *new_dm_plane_state; + if (other->type == DRM_PLANE_TYPE_CURSOR) continue; @@ -8342,9 +8344,20 @@ static bool should_reset_plane(struct drm_atomic_state *state, if (old_other_state->crtc != new_other_state->crtc) return true; - /* TODO: Remove this once we can handle fast format changes. */ - if (old_other_state->fb && new_other_state->fb && - old_other_state->fb->format != new_other_state->fb->format) + /* Framebuffer checks fall at the end. */ + if (!old_other_state->fb || !new_other_state->fb) + continue; + + /* Pixel format changes can require bandwidth updates. */ + if (old_other_state->fb->format != new_other_state->fb->format) + return true; + + old_dm_plane_state = to_dm_plane_state(old_other_state); + new_dm_plane_state = to_dm_plane_state(new_other_state); + + /* Tiling and DCC changes also require bandwidth updates. */ + if (old_dm_plane_state->tiling_flags != + new_dm_plane_state->tiling_flags) return true; } -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 3/7] drm/amd/display: Avoid using unvalidated tiling_flags and tmz_surface in prepare_planes
[Why] We're racing with userspace as the flags could potentially change from when we acquired and validated them in commit_check. [How] We unfortunately can't drop this function in its entirety from prepare_planes since we don't know the afb->address at commit_check time yet. So instead of querying new tiling_flags and tmz_surface use the ones from the plane_state directly. While we're at it, also update the force_disable_dcc option based on the state from atomic check. Cc: Bhawanpreet Lakha Cc: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 36 ++- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index bf1881bd492c..f78c09c9585e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5794,14 +5794,8 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, struct list_head list; struct ttm_validate_buffer tv; struct ww_acquire_ctx ticket; - uint64_t tiling_flags; uint32_t domain; int r; - bool tmz_surface = false; - bool force_disable_dcc = false; - - dm_plane_state_old = to_dm_plane_state(plane->state); - dm_plane_state_new = to_dm_plane_state(new_state); if (!new_state->fb) { DRM_DEBUG_DRIVER("No FB bound\n"); @@ -5845,27 +5839,35 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, return r; } - amdgpu_bo_get_tiling_flags(rbo, _flags); - - tmz_surface = amdgpu_bo_encrypted(rbo); - ttm_eu_backoff_reservation(, ); afb->address = amdgpu_bo_gpu_offset(rbo); amdgpu_bo_ref(rbo); + /** +* We don't do surface updates on planes that have been newly created, +* but we also don't have the afb->address during atomic check. +* +* Fill in buffer attributes depending on the address here, but only on +* newly created planes since they're not being used by DC yet and this +* won't modify global state. +*/ + dm_plane_state_old = to_dm_plane_state(plane->state); + dm_plane_state_new = to_dm_plane_state(new_state); + if (dm_plane_state_new->dc_state && - dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) { - struct dc_plane_state *plane_state = dm_plane_state_new->dc_state; + dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) { + struct dc_plane_state *plane_state = + dm_plane_state_new->dc_state; + bool force_disable_dcc = !plane_state->dcc.enable; - force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend; fill_plane_buffer_attributes( adev, afb, plane_state->format, plane_state->rotation, - tiling_flags, _state->tiling_info, - _state->plane_size, _state->dcc, - _state->address, tmz_surface, - force_disable_dcc); + dm_plane_state_new->tiling_flags, + _state->tiling_info, _state->plane_size, + _state->dcc, _state->address, + dm_plane_state_new->tmz_surface, force_disable_dcc); } return 0; -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 5/7] drm/amd/display: Reset plane for anything that's not a FAST update
[Why] MEDIUM or FULL updates can require global validation or affect bandwidth. By treating these all simply as surface updates we aren't actually passing this through DC global validation. [How] There's currently no way to pass surface updates through DC global validation, nor do I think it's a good idea to change the interface to accept these. DC global validation itself is currently stateless, and we can move our update type checking to be stateless as well by duplicating DC surface checks in DM based on DRM properties. We wanted to rely on DC automatically determining this since DC knows best, but DM is ultimately what fills in everything into DC plane state so it does need to know as well. There are basically only three paths that we exercise in DM today: 1) Cursor (async update) 2) Pageflip (fast update) 3) Full pipe programming (medium/full updates) Which means that anything that's more than a pageflip really needs to go down path #3. So this change duplicates all the surface update checks based on DRM state instead inside of should_reset_plane(). Next step is dropping dm_determine_update_type_for_commit and we no longer require the old DC state at all for global validation. Optimization can come later so we don't reset DC planes at all for MEDIUM udpates and avoid validation, but we might require some extra checks in DM to achieve this. Cc: Bhawanpreet Lakha Cc: Hersen Wu Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 25 +++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 0d5f45742bb5..2cbb29199e61 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8336,6 +8336,31 @@ static bool should_reset_plane(struct drm_atomic_state *state, if (old_other_state->crtc != new_other_state->crtc) return true; + /* Src/dst size and scaling updates. */ + if (old_other_state->src_w != new_other_state->src_w || + old_other_state->src_h != new_other_state->src_h || + old_other_state->crtc_w != new_other_state->crtc_w || + old_other_state->crtc_h != new_other_state->crtc_h) + return true; + + /* Rotation / mirroring updates. */ + if (old_other_state->rotation != new_other_state->rotation) + return true; + + /* Blending updates. */ + if (old_other_state->pixel_blend_mode != + new_other_state->pixel_blend_mode) + return true; + + /* Alpha updates. */ + if (old_other_state->alpha != new_other_state->alpha) + return true; + + /* Colorspace changes. */ + if (old_other_state->color_range != new_other_state->color_range || + old_other_state->color_encoding != new_other_state->color_encoding) + return true; + /* Framebuffer checks fall at the end. */ if (!old_other_state->fb || !new_other_state->fb) continue; -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/7] drm/amd/display: Store tiling_flags and tmz_surface on dm_plane_state
[Why] Store these in advance so we can reuse them later in commit_tail without having to reserve the fbo again. These will also be used for checking for tiling changes when deciding to reset the plane or not. [How] This change should mostly be a refactor. Only commit check is affected for now and I'll drop the get_fb_info calls in prepare_planes and commit_tail after. This runs a prepass loop once we think that all planes have been added to the context and replaces the get_fb_info calls with accessing the dm_plane_state instead. Cc: Bhawanpreet Lakha Cc: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 60 +++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 2 + 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 8d64f5fde7e2..7cc5ab90ce13 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3700,8 +3700,17 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state, static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb, uint64_t *tiling_flags, bool *tmz_surface) { - struct amdgpu_bo *rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]); - int r = amdgpu_bo_reserve(rbo, false); + struct amdgpu_bo *rbo; + int r; + + if (!amdgpu_fb) { + *tiling_flags = 0; + *tmz_surface = false; + return 0; + } + + rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]); + r = amdgpu_bo_reserve(rbo, false); if (unlikely(r)) { /* Don't show error message when returning -ERESTARTSYS */ @@ -4124,13 +4133,10 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, struct drm_crtc_state *crtc_state) { struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); - const struct amdgpu_framebuffer *amdgpu_fb = - to_amdgpu_framebuffer(plane_state->fb); + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); struct dc_scaling_info scaling_info; struct dc_plane_info plane_info; - uint64_t tiling_flags; int ret; - bool tmz_surface = false; bool force_disable_dcc = false; ret = fill_dc_scaling_info(plane_state, _info); @@ -4142,15 +4148,12 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, dc_plane_state->clip_rect = scaling_info.clip_rect; dc_plane_state->scaling_quality = scaling_info.scaling_quality; - ret = get_fb_info(amdgpu_fb, _flags, _surface); - if (ret) - return ret; - force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend; - ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags, + ret = fill_dc_plane_info_and_addr(adev, plane_state, + dm_plane_state->tiling_flags, _info, _plane_state->address, - tmz_surface, + dm_plane_state->tmz_surface, force_disable_dcc); if (ret) return ret; @@ -5753,6 +5756,10 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) dc_plane_state_retain(dm_plane_state->dc_state); } + /* Framebuffer hasn't been updated yet, so retain old flags. */ + dm_plane_state->tiling_flags = old_dm_plane_state->tiling_flags; + dm_plane_state->tmz_surface = old_dm_plane_state->tmz_surface; + return _plane_state->base; } @@ -8557,13 +8564,9 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, continue; for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { - const struct amdgpu_framebuffer *amdgpu_fb = - to_amdgpu_framebuffer(new_plane_state->fb); struct dc_plane_info *plane_info = >plane_infos[num_plane]; struct dc_flip_addrs *flip_addr = >flip_addrs[num_plane]; struct dc_scaling_info *scaling_info = >scaling_infos[num_plane]; - uint64_t tiling_flags; - bool tmz_surface = false; new_plane_crtc = new_plane_state->crtc; new_dm_plane_state = to_dm_plane_state(new_plane_state); @@ -8610,16 +8613,12 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, bundle->surface_updates[num_pl
[PATCH 7/7] drm/amd/display: Replace DRM private objects with subclassed DRM atomic state
[Why] DM atomic check was structured in a way that we required old DC state in order to dynamically add and remove planes and streams from the context to build the DC state context for validation. DRM private objects were used to carry over the last DC state and were added to the context on nearly every commit - regardless of fast or full so we could check whether or not the new state could affect bandwidth. The problem with this model is that DRM private objects do not implicitly stall out other commits. So if you have two commits touching separate DRM objects they could run concurrently and potentially execute out of order - leading to a use-after-free. If we want this to be safe we have two options: 1. Stall out concurrent commits since they touch the same private object 2. Refactor DM to not require old DC state and drop private object usage [How] This implements approach #2 since it still allows for judder free updates in multi-display scenarios. I'll list the big changes in order at a high level: 1. Subclass DRM atomic state instead of using DRM private objects. DC relied on the old state to determine which changes cause bandwidth updates but now we have DM perform similar checks based on DRM state instead - dropping the requirement for old state to exist at all. This means that we can now build a new DC context from scratch whenever we have something that DM thinks could affect bandwidth. Whenever we need to rebuild bandwidth we now add all CRTCs and planes to the DRM state in order to get the absolute set of DC streams and DC planes. This introduces a stall on other commits, but this stall already exists because of the lock_and_validation logic and it's necessary since updates may move around pipes and require full reprogramming. 2. Drop workarounds to add planes to maintain z-order early in atomic check. This is no longer needed because of the changes for (1). This also involves fixing up should_plane_reset checks since we can just avoid resetting streams and planes when they haven't actually changed. 3. Rework dm_update_crtc_state and dm_update_plane_state to be single pass instead of two pass. This is necessary since we no longer have the dc_state to add and remove planes to the context in and we want to defer creation to the end of commit_check. It also makes the logic a lot simpler to follow since as an added bonus. Cc: Bhawanpreet Lakha Cc: Harry Wentland Cc: Leo Li Cc: Daniel Vetter Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 720 +++--- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 11 +- 2 files changed, 280 insertions(+), 451 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 59829ec81694..97a7dfc620e8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1839,7 +1839,6 @@ static int dm_resume(void *handle) struct drm_plane *plane; struct drm_plane_state *new_plane_state; struct dm_plane_state *dm_new_plane_state; - struct dm_atomic_state *dm_state = to_dm_atomic_state(dm->atomic_obj.state); enum dc_connection_type new_connection_type = dc_connection_none; struct dc_state *dc_state; int i, r, j; @@ -1879,11 +1878,6 @@ static int dm_resume(void *handle) return 0; } - /* Recreate dc_state - DC invalidates it when setting power state to S3. */ - dc_release_state(dm_state->context); - dm_state->context = dc_create_state(dm->dc); - /* TODO: Remove dc_state->dccg, use dc->dccg directly. */ - dc_resource_state_construct(dm->dc, dm_state->context); /* Before powering on DC we need to re-initialize DMUB. */ r = dm_dmub_hw_init(adev); @@ -2019,11 +2013,51 @@ const struct amdgpu_ip_block_version dm_ip_block = * *WIP* */ +struct drm_atomic_state *dm_atomic_state_alloc(struct drm_device *dev) +{ + struct dm_atomic_state *dm_state; + + dm_state = kzalloc(sizeof(*dm_state), GFP_KERNEL); + + if (!dm_state) + return NULL; + + if (drm_atomic_state_init(dev, _state->base) < 0) { + kfree(dm_state); + return NULL; + } + + return _state->base; +} + +void dm_atomic_state_free(struct drm_atomic_state *state) +{ + struct dm_atomic_state *dm_state = to_dm_atomic_state(state); + + if (dm_state->context) { + dc_release_state(dm_state->context); + dm_state->context = NULL; + } + + drm_atomic_state_default_release(state); + kfree(state); +} + +void dm_atomic_state_clear(struct drm_atomic_state *state) +{ + struct dm_atomic_state *dm_state = to_dm_atomic_state(state); + + drm_atomic_state_default_clear(_state->base); +} + static const struct drm_mode_config_func
[PATCH 0/7] drm/amd/display: Drop DRM private objects from amdgpu_dm
Based on the analysis of the bug from [1] the best course of action seems to be swapping off of DRM private objects back to subclassing DRM atomic state instead. This patch series implements this change, but not yet the other changes suggested in the threads from that bug - these will come later. CCing dri-devel per Daniel's suggestion since this issue brought some interesting misuse of private objects. [1] https://bugzilla.kernel.org/show_bug.cgi?id=207383 Nicholas Kazlauskas (7): drm/amd/display: Store tiling_flags and tmz_surface on dm_plane_state drm/amd/display: Reset plane when tiling flags change drm/amd/display: Avoid using unvalidated tiling_flags and tmz_surface in prepare_planes drm/amd/display: Use validated tiling_flags and tmz_surface in commit_tail drm/amd/display: Reset plane for anything that's not a FAST update drm/amd/display: Drop dm_determine_update_type_for_commit drm/amd/display: Replace DRM private objects with subclassed DRM atomic state .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 967 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 13 +- 2 files changed, 343 insertions(+), 637 deletions(-) -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 6/7] drm/amd/display: Drop dm_determine_update_type_for_commit
[Why] This was added in the past to solve the issue of not knowing when to stall for medium and full updates in DM. Since DC is ultimately decides what requires bandwidth changes we wanted to make use of it directly to determine this. The problem is that we can't actually pass any of the stream or surface updates into DC global validation, so we don't actually check if the new configuration is valid - we just validate the old existing config instead and stall for outstanding commits to finish. There's also the problem of grabbing the DRM private object for pageflips which can lead to page faults in the case where commits execute out of order and free a DRM private object state that was still required for commit tail. [How] Now that we reset the plane in DM with the same conditions DC checks we can have planes go through DC validation and we know when we need to check and stall based on whether the stream or planes changed. We mark lock_and_validation_needed whenever we've done this, so just go back to using that instead of dm_determine_update_type_for_commit. Since we'll skip resetting the plane for a pageflip we will no longer grab the DRM private object for pageflips as well, avoiding the page fault issued caused by pageflipping under load with commits executing out of order. Cc: Harry Wentland Cc: Bhawanpreet Lakha Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 199 ++ 1 file changed, 17 insertions(+), 182 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 2cbb29199e61..59829ec81694 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8542,161 +8542,6 @@ static int dm_update_plane_state(struct dc *dc, return ret; } -static int -dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, - struct drm_atomic_state *state, - enum surface_update_type *out_type) -{ - struct dc *dc = dm->dc; - struct dm_atomic_state *dm_state = NULL, *old_dm_state = NULL; - int i, j, num_plane, ret = 0; - struct drm_plane_state *old_plane_state, *new_plane_state; - struct dm_plane_state *new_dm_plane_state, *old_dm_plane_state; - struct drm_crtc *new_plane_crtc; - struct drm_plane *plane; - - struct drm_crtc *crtc; - struct drm_crtc_state *new_crtc_state, *old_crtc_state; - struct dm_crtc_state *new_dm_crtc_state, *old_dm_crtc_state; - struct dc_stream_status *status = NULL; - enum surface_update_type update_type = UPDATE_TYPE_FAST; - struct surface_info_bundle { - struct dc_surface_update surface_updates[MAX_SURFACES]; - struct dc_plane_info plane_infos[MAX_SURFACES]; - struct dc_scaling_info scaling_infos[MAX_SURFACES]; - struct dc_flip_addrs flip_addrs[MAX_SURFACES]; - struct dc_stream_update stream_update; - } *bundle; - - bundle = kzalloc(sizeof(*bundle), GFP_KERNEL); - - if (!bundle) { - DRM_ERROR("Failed to allocate update bundle\n"); - /* Set type to FULL to avoid crashing in DC*/ - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } - - for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - - memset(bundle, 0, sizeof(struct surface_info_bundle)); - - new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); - old_dm_crtc_state = to_dm_crtc_state(old_crtc_state); - num_plane = 0; - - if (new_dm_crtc_state->stream != old_dm_crtc_state->stream) { - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } - - if (!new_dm_crtc_state->stream) - continue; - - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { - struct dc_plane_info *plane_info = >plane_infos[num_plane]; - struct dc_flip_addrs *flip_addr = >flip_addrs[num_plane]; - struct dc_scaling_info *scaling_info = >scaling_infos[num_plane]; - - new_plane_crtc = new_plane_state->crtc; - new_dm_plane_state = to_dm_plane_state(new_plane_state); - old_dm_plane_state = to_dm_plane_state(old_plane_state); - - if (plane->type == DRM_PLANE_TYPE_CURSOR) - continue; - - if (new_dm_plane_state->dc_state != old_dm_plane_state->dc_state) { - update_type = UPDATE_TYPE_FULL; - goto cleanup; -
[PATCH 1/2] drm/amd/display: Add missing DCN30 registers and fields for OTG_CRC_CNTL2
[Why] When enabling the debugfs for CRC capture we hit assertions caused by register address and field masks and shifts missing. [How] We want these registers programmed, so add in the SRI/SF entries for this register. Cc: Bhawanpreet Lakha Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h index d4106dd5a9b0..33f13c1e7520 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h @@ -98,6 +98,7 @@ SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OTG_CRC_CNTL2, OTG, inst),\ SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ @@ -248,6 +249,10 @@ SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ @@ -280,6 +285,10 @@ SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/2] drm/amd/display: Allow for vblank enabled with no active planes
[Why] CRC capture doesn't work when the active plane count is 0 since we currently tie both vblank and pageflip interrupts to active_plane_count greater than 0. [How] The frontend is what generates the vblank interrupts while the backend is what generates pageflip interrupts. Both have a requirement for the CRTC to be active, so control the overall interrupt state based on that instead. Pageflip interrupts need to be enabled based on active plane count, but we actually rely on power gating to take care of disabling the interrupt for us on pipes that can be power gated. For pipes that can't be power gated it's still fine to leave it enabled since the interrupt only triggers after the address has been written to that particular pipe - which we won't be doing without an active plane. The issue we had before with this setup was that we couldn't force the state back on. We were essentially manipulating the refcount to enable or disable as needed in a two pass approach. However, there is a function that solves this problem more elegantly: amdgpu_irq_update() will unconditionally call the set based on what it thinks the current enablement state is. This leaves two future TODO items for our IRQ handling: - Disabling IRQs in commit tail instead of atomic commit - Mapping the pageflip interrupt to VUPDATE or something that's tied to the frontend instead of the backend since the mapping to CRTC is not correct Cc: Bhawanpreet Lakha Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 168 -- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 - 2 files changed, 78 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index d9f8e9c26390..05160c6bbc03 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4719,7 +4719,6 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) } state->active_planes = cur->active_planes; - state->interrupts_enabled = cur->interrupts_enabled; state->vrr_params = cur->vrr_params; state->vrr_infopacket = cur->vrr_infopacket; state->abm_level = cur->abm_level; @@ -5393,29 +5392,19 @@ static int count_crtc_active_planes(struct drm_crtc_state *new_crtc_state) return num_active; } -/* - * Sets whether interrupts should be enabled on a specific CRTC. - * We require that the stream be enabled and that there exist active - * DC planes on the stream. - */ -static void -dm_update_crtc_interrupt_state(struct drm_crtc *crtc, - struct drm_crtc_state *new_crtc_state) +static void dm_update_crtc_active_planes(struct drm_crtc *crtc, +struct drm_crtc_state *new_crtc_state) { struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); dm_new_crtc_state->active_planes = 0; - dm_new_crtc_state->interrupts_enabled = false; if (!dm_new_crtc_state->stream) return; dm_new_crtc_state->active_planes = count_crtc_active_planes(new_crtc_state); - - dm_new_crtc_state->interrupts_enabled = - dm_new_crtc_state->active_planes > 0; } static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, @@ -5426,13 +5415,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state); int ret = -EINVAL; - /* -* Update interrupt state for the CRTC. This needs to happen whenever -* the CRTC has changed or whenever any of its planes have changed. -* Atomic check satisfies both of these requirements since the CRTC -* is added to the state by DRM during drm_atomic_helper_check_planes. -*/ - dm_update_crtc_interrupt_state(crtc, state); + dm_update_crtc_active_planes(crtc, state); if (unlikely(!dm_crtc_state->stream && modeset_required(state, NULL, dm_crtc_state->stream))) { @@ -6547,8 +6530,10 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, bool enable) { /* -* this is not correct translation but will work as soon as VBLANK -* constant is the same as PFLIP +* We have no guarantee that the frontend index maps to the same +* backend index - some even map to more than one. +* +* TODO: Use a different interrupt or check DC itself for the mapping. */ int irq_type = amdgpu_display_crtc_idx_to_irq_type( @@ -6571,6 +6556,19 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, } } +static void dm_update_pflip_irq_state(struct amdgpu_device *adev, +
[PATCH] drm/amd/display: Fix CSC remap matrix not being applied on dcn30
[Why] DCN3 has two gamut remap matrices. When using CSC adjustment the CM remap is set to bypass and MPCC remap is used. However to bypass CM some state in the context is modified and not restored correctly resulting in subsequent calls to disable MPCC remap as well. [How] Fix logic for save/restore of remap enable flag when programming MPCC remap matrix. Cc: Bhawanpreet Lakha Signed-off-by: Aric Cyr Signed-off-by: Nicholas Kazlauskas --- .../drm/amd/display/dc/dcn20/dcn20_hwseq.c| 27 ++- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 5621c95177d2..7725a406c16e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1482,22 +1482,23 @@ static void dcn20_update_dchubp_dpp( memset(, 0, sizeof(adjust)); adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; - /* save the enablement of gamut remap for dpp*/ + + /* save the enablement of gamut remap for dpp */ enable_remap_dpp = pipe_ctx->stream->gamut_remap_matrix.enable_remap; - /*force bypass gamut remap for dpp/cm*/ + + /* force bypass gamut remap for dpp/cm */ pipe_ctx->stream->gamut_remap_matrix.enable_remap = false; dc->hwss.program_gamut_remap(pipe_ctx); - /*restore gamut remap flag for the top plane and use this remap into mpc*/ - if (pipe_ctx->top_pipe == NULL) - pipe_ctx->stream->gamut_remap_matrix.enable_remap = enable_remap_dpp; - else - pipe_ctx->stream->gamut_remap_matrix.enable_remap = false; - - 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]; + + /* restore gamut remap flag and use this remap into mpc */ + pipe_ctx->stream->gamut_remap_matrix.enable_remap = enable_remap_dpp; + + /* build remap matrix for top plane if enabled */ + if (enable_remap_dpp && pipe_ctx->top_pipe == NULL) { + 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]; } mpc->funcs->set_gamut_remap(mpc, mpcc_id, ); } else -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Use VUPDATE_NO_LOCK instead of VUPDATE for dcn30
[Why] Soft hangs occur when FreeSync is engaged since we utilize VUPDATE (which doesn't fire when holding the pipe lock) to send back vblank events when FreeSync is active. [How] The alternative (working) interrupt source for this mechanism is VUPDATE_NO_LOCK. We already use this all other DCN revisions so align dcn30 with those as well. Cc: Bhawanpreet Lakha Signed-off-by: Nicholas Kazlauskas --- .../display/dc/irq/dcn30/irq_service_dcn30.c | 28 --- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c index dd4d7a1dc3b6..49689f71f4f1 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c @@ -169,6 +169,11 @@ static const struct irq_source_info_funcs pflip_irq_info_funcs = { .ack = NULL }; +static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + static const struct irq_source_info_funcs vblank_irq_info_funcs = { .set = NULL, .ack = NULL @@ -228,12 +233,15 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { .funcs = _irq_info_funcs\ } -#define vupdate_int_entry(reg_num)\ +/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic + * of DCE's DC_IRQ_SOURCE_VUPDATEx. + */ +#define vupdate_no_lock_int_entry(reg_num)\ [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ IRQ_REG_ENTRY(OTG, reg_num,\ - OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\ - OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\ - .funcs = _irq_info_funcs\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\ + .funcs = _no_lock_irq_info_funcs\ } #define vblank_int_entry(reg_num)\ @@ -340,12 +348,12 @@ irq_source_info_dcn30[DAL_IRQ_SOURCES_NUMBER] = { dc_underflow_int_entry(6), [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), - vupdate_int_entry(0), - vupdate_int_entry(1), - vupdate_int_entry(2), - vupdate_int_entry(3), - vupdate_int_entry(4), - vupdate_int_entry(5), + vupdate_no_lock_int_entry(0), + vupdate_no_lock_int_entry(1), + vupdate_no_lock_int_entry(2), + vupdate_no_lock_int_entry(3), + vupdate_no_lock_int_entry(4), + vupdate_no_lock_int_entry(5), vblank_int_entry(0), vblank_int_entry(1), vblank_int_entry(2), -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Add missing CW4 programming for DCN30
[Why] To support inbox1 in CW4 we need to actually program CW4 instead of region 4 for newer firmware. This is done correctly on DCN20/DCN21 but this code wasn't added to DCN30. [How] Copy over the missing code. It doesn't need address translation since DCN30 uses virtual addressing. Cc: Bhawanpreet Lakha Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/dmub/src/dmub_dcn30.c | 21 ++- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c index ba8d0bfb5522..215178b8d415 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn30.c @@ -153,11 +153,22 @@ void dmub_dcn30_setup_windows(struct dmub_srv *dmub, offset = cw4->offset; - REG_WRITE(DMCUB_REGION4_OFFSET, offset.u.low_part); - REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, offset.u.high_part); - REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, DMCUB_REGION4_TOP_ADDRESS, - cw4->region.top - cw4->region.base - 1, DMCUB_REGION4_ENABLE, - 1); + /* New firmware can support CW4. */ + if (dmub->fw_version > DMUB_FW_VERSION(1, 0, 10)) { + REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base); + REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0, + DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top, + DMCUB_REGION3_CW4_ENABLE, 1); + } else { + REG_WRITE(DMCUB_REGION4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, offset.u.high_part); + REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, + DMCUB_REGION4_TOP_ADDRESS, + cw4->region.top - cw4->region.base - 1, + DMCUB_REGION4_ENABLE, 1); + } offset = cw5->offset; -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Only revalidate bandwidth on medium and fast updates
[Why] Changes that are fast don't require updating DLG parameters making this call unnecessary. Considering this is an expensive call it should not be done on every flip. DML touches clocks, p-state support, DLG params and a few other DC internal flags and these aren't expected during fast. A hang has been reported with this change when called on every flip which suggests that modifying these fields is not recommended behavior on fast updates. [How] Guard the validation to only happen if update type isn't FAST. Bug: https://gitlab.freedesktop.org/drm/amd/-/issues/1191 Fixes: e1995f0909e3 ("drm/amd/display: Revalidate bandwidth before commiting DC updates") Cc: Hersen Wu Cc: Bhawanpreet Lakha Cc: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/core/dc.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 67402d75e67e..942ceb0f6383 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2607,10 +2607,12 @@ void dc_commit_updates_for_stream(struct dc *dc, copy_stream_update_to_stream(dc, context, stream, stream_update); - if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { - DC_ERROR("Mode validation failed for stream update!\n"); - dc_release_state(context); - return; + if (update_type > UPDATE_TYPE_FAST) { + if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { + DC_ERROR("Mode validation failed for stream update!\n"); + dc_release_state(context); + return; + } } commit_planes_for_stream( -- 2.25.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Only actually breakpoint if DEBUG_KERNEL_DC is enabled
To match previous behavior and to not hang the kernel if someone accidentally builds with KGDB enabled. Fixes: 4324a1752045 ("drm/amd/display: Make BREAK_TO_DEBUGGER() a debug print") Cc: Harry Wentland Cc: Alex Deucher Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/os_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index 604ceb6c0375..c3bbfe397e8d 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -111,7 +111,7 @@ #define ASSERT(expr) WARN_ON_ONCE(!(expr)) #endif -#if defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB) +#if defined(CONFIG_DEBUG_KERNEL_DC) && (defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB)) #define BREAK_TO_DEBUGGER() \ do { \ DRM_DEBUG_DRIVER("%s():%d\n", __func__, __LINE__); \ -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Revalidate bandwidth before commiting DC updates
[Why] Whenever we switch between tiled formats without also switching pixel formats or doing anything else that recreates the DC plane state we can run into underflow or hangs since we're not updating the DML parameters before committing to the hardware. [How] If the update type is FULL then call validate_bandwidth again to update the DML parmeters before committing the state. This is basically just a workaround and protective measure against update types being added DC where we could run into this issue in the future. We can only fully validate the state in advance before applying it to the hardware if we recreate all the plane and stream states since we can't modify what's currently in use. The next step is to update DM to ensure that we're creating the plane and stream states for whatever could potentially be a full update in DC to pre-emptively recreate the state for DC global validation. The workaround can stay until this has been fixed in DM. Cc: Hersen Wu Cc: Harry Wentland Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 04c3d9f7e323..00a4f679759f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2523,6 +2523,12 @@ void dc_commit_updates_for_stream(struct dc *dc, copy_stream_update_to_stream(dc, context, stream, stream_update); + if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { + DC_ERROR("Mode validation failed for stream update!\n"); + dc_release_state(context); + return; + } + commit_planes_for_stream( dc, srf_updates, -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Make BREAK_TO_DEBUGGER() a debug print
[Why] Warnings in the kernel are generally treated as errors. The BREAK_TO_DEBUGGER macro is not a critical error or warning, but rather intended for developer use to help investigate behavior and sequences for other issues. We do still make use of DC_ERROR/ASSERT(0) in various places in the code for things that are genuine issues. Since most developers don't actually KGDB while debugging the kernel these essentially would have no value on their own since the KGDB breakpoint wouldn't trigger - ASSERT(0) was used as a shortcut to get a stacktrace. [How] Turn it into a DRM_DEBUG_DRIVER print instead. We unfortunately lose the stacktrace, but we still do retain some of the useful debug information this offers by having at least the function and line number loggable. If KGDB is supported in the kernel this will still trigger a real breakpoint as well. Cc: Harry Wentland Cc: Leo Li Cc: Bhawanpreet Lakha Cc: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/os_types.h | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index 6d7bca562eec..604ceb6c0375 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -111,7 +111,15 @@ #define ASSERT(expr) WARN_ON_ONCE(!(expr)) #endif -#define BREAK_TO_DEBUGGER() ASSERT(0) +#if defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB) +#define BREAK_TO_DEBUGGER() \ + do { \ + DRM_DEBUG_DRIVER("%s():%d\n", __func__, __LINE__); \ + kgdb_breakpoint(); \ + } while (0) +#else +#define BREAK_TO_DEBUGGER() DRM_DEBUG_DRIVER("%s():%d\n", __func__, __LINE__) +#endif #define DC_ERR(...) do { \ dm_error(__VA_ARGS__); \ -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Fix vblank and pageflip event handling for FreeSync
[Why] We're the drm vblank event a frame too early in the case where the pageflip happens close to VUPDATE and ends up blocking the signal. The implementation in DM was previously correct *before* we started sending vblank events from VSTARTUP unconditionally to handle cases where HUBP was off, OTG was ON and userspace was still requesting some DRM planes enabled. As part of that patch series we dropped VUPDATE since it was deemed close enough to VSTARTUP, but there's a key difference betweeen VSTARTUP and VUPDATE - the VUPDATE signal can be blocked if we're holding the pipe lock. There was a fix recently to revert the unconditional behavior for the DCN VSTARTUP vblank event since it was sending the pageflip event on the wrong frame - once again, due to blocking VUPDATE and having the address start scanning out two frames later. The problem with this fix is it didn't update the logic that calls drm_crtc_handle_vblank(), so the timestamps are totally bogus now. [How] Essentially reverts most of the original VSTARTUP series but retains the behavior to send back events when active planes == 0. Some refactoring/cleanup was done to not have duplicated code in both the handlers. Fixes: 16f17eda8bad ("drm/amd/display: Send vblank and user events at vsartup for DCN") Fixes: 3a2ce8d66a4b ("drm/amd/display: Disable VUpdate interrupt for DCN hardware") Fixes: 2b5aed9ac3f7 ("drm/amd/display: Fix pageflip event race condition for DCN.") Cc: Leo Li Cc: Mario Kleiner Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 137 +++--- 1 file changed, 55 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 59f1d4a94f12..30ce28f7c444 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -441,7 +441,7 @@ static void dm_vupdate_high_irq(void *interrupt_params) /** * dm_crtc_high_irq() - Handles CRTC interrupt - * @interrupt_params: ignored + * @interrupt_params: used for determining the CRTC instance * * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK * event handler. @@ -455,70 +455,6 @@ static void dm_crtc_high_irq(void *interrupt_params) unsigned long flags; acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); - - if (acrtc) { - acrtc_state = to_dm_crtc_state(acrtc->base.state); - - DRM_DEBUG_VBL("crtc:%d, vupdate-vrr:%d\n", - acrtc->crtc_id, - amdgpu_dm_vrr_active(acrtc_state)); - - /* Core vblank handling at start of front-porch is only possible -* in non-vrr mode, as only there vblank timestamping will give -* valid results while done in front-porch. Otherwise defer it -* to dm_vupdate_high_irq after end of front-porch. -*/ - if (!amdgpu_dm_vrr_active(acrtc_state)) - drm_crtc_handle_vblank(>base); - - /* Following stuff must happen at start of vblank, for crc -* computation and below-the-range btr support in vrr mode. -*/ - amdgpu_dm_crtc_handle_crc_irq(>base); - - if (acrtc_state->stream && adev->family >= AMDGPU_FAMILY_AI && - acrtc_state->vrr_params.supported && - acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) { - spin_lock_irqsave(>ddev->event_lock, flags); - mod_freesync_handle_v_update( - adev->dm.freesync_module, - acrtc_state->stream, - _state->vrr_params); - - dc_stream_adjust_vmin_vmax( - adev->dm.dc, - acrtc_state->stream, - _state->vrr_params.adjust); - spin_unlock_irqrestore(>ddev->event_lock, flags); - } - } -} - -#if defined(CONFIG_DRM_AMD_DC_DCN) -/** - * dm_dcn_crtc_high_irq() - Handles VStartup interrupt for DCN generation ASICs - * @interrupt params - interrupt parameters - * - * Notify DRM's vblank event handler at VSTARTUP - * - * Unlike DCE hardware, we trigger the handler at VSTARTUP. at which: - * * We are close enough to VUPDATE - the point of no return for hw - * * We are in the fixed portion of variable front porch when vrr is enabled - * * We are before VUPDATE, where double-buffered vrr registers are swapped - * - * It is therefore the correct place to signal vblank, send user flip events, - * and update VRR. - */ -static void dm_dcn_crtc_high_irq(void *interrupt_param
[PATCH] drm/amd/display: Only enable cursor on pipes that need it
[Why] In current code we're essentially drawing the cursor on every pipe that contains it. This only works when the planes have the same scaling for src to dest rect, otherwise we'll get "double cursor" where one cursor is incorrectly filtered and offset from the real position. [How] Without dedicated cursor planes on DCN we require at least one pipe that matches the scaling of the current timing. This is an optimization and workaround for the most common case where the top-most plane is not scaled but the bottom-most plane is scaled. Whenever a pipe has a parent pipe in the blending tree whose recout fully contains the current pipe we can disable the pipe. This only applies when the pipe is actually visible of course. Signed-off-by: Nicholas Kazlauskas --- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 30 +++ 1 file changed, 30 insertions(+) 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 index f2127afb37b2..1008ac8a0f2a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2911,6 +2911,33 @@ void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) hubbub->funcs->update_dchub(hubbub, dh_data); } +static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *test_pipe; + const struct rect *r1 = _ctx->plane_res.scl_data.recout, *r2; + int r1_r = r1->x + r1->width, r1_b = r1->y + r1->height, r2_r, r2_b; + + /** +* 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) { + if (!test_pipe->plane_state->visible) + continue; + + r2 = _pipe->plane_res.scl_data.recout; + r2_r = r2->x + r2->width; + r2_b = r2->y + r2->height; + + 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; @@ -2956,6 +2983,9 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) pos_cpy.enable = false; + if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx)) + pos_cpy.enable = false; + // Swap axis and mirror horizontally if (param.rotation == ROTATION_ANGLE_90) { uint32_t temp_x = pos_cpy.x; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 01/11] drm/amdgpu: Add ucode support for DMCUB
The DMCUB is a secondary DMCU (Display MicroController Unit) that has its own separate firmware. It's required for DMCU support on Renoir. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c | 11 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h | 9 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index 833fc4b68940..9ef312428231 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -447,6 +447,7 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, const struct common_firmware_header *header = NULL; const struct gfx_firmware_header_v1_0 *cp_hdr = NULL; const struct dmcu_firmware_header_v1_0 *dmcu_hdr = NULL; + const struct dmcub_firmware_header_v1_0 *dmcub_hdr = NULL; if (NULL == ucode->fw) return 0; @@ -460,6 +461,7 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, header = (const struct common_firmware_header *)ucode->fw->data; cp_hdr = (const struct gfx_firmware_header_v1_0 *)ucode->fw->data; dmcu_hdr = (const struct dmcu_firmware_header_v1_0 *)ucode->fw->data; + dmcub_hdr = (const struct dmcub_firmware_header_v1_0 *)ucode->fw->data; if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP || (ucode->ucode_id != AMDGPU_UCODE_ID_CP_MEC1 && @@ -470,7 +472,8 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM && ucode->ucode_id != AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM && ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_ERAM && -ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_INTV)) { +ucode->ucode_id != AMDGPU_UCODE_ID_DMCU_INTV && +ucode->ucode_id != AMDGPU_UCODE_ID_DMCUB)) { ucode->ucode_size = le32_to_cpu(header->ucode_size_bytes); memcpy(ucode->kaddr, (void *)((uint8_t *)ucode->fw->data + @@ -506,6 +509,12 @@ static int amdgpu_ucode_init_single_fw(struct amdgpu_device *adev, le32_to_cpu(header->ucode_array_offset_bytes) + le32_to_cpu(dmcu_hdr->intv_offset_bytes)), ucode->ucode_size); + } else if (ucode->ucode_id == AMDGPU_UCODE_ID_DMCUB) { + ucode->ucode_size = le32_to_cpu(dmcub_hdr->inst_const_bytes); + memcpy(ucode->kaddr, + (void *)((uint8_t *)ucode->fw->data + + le32_to_cpu(header->ucode_array_offset_bytes)), + ucode->ucode_size); } else if (ucode->ucode_id == AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL) { ucode->ucode_size = adev->gfx.rlc.save_restore_list_cntl_size_bytes; memcpy(ucode->kaddr, adev->gfx.rlc.save_restore_list_cntl, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 410587b950f3..eaf2d5b9c92f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -251,6 +251,13 @@ struct dmcu_firmware_header_v1_0 { uint32_t intv_size_bytes; /* size of interrupt vectors, in bytes */ }; +/* version_major=1, version_minor=0 */ +struct dmcub_firmware_header_v1_0 { + struct common_firmware_header header; + uint32_t inst_const_bytes; /* size of instruction region, in bytes */ + uint32_t bss_data_bytes; /* size of bss/data region, in bytes */ +}; + /* header is fixed size */ union amdgpu_firmware_header { struct common_firmware_header common; @@ -268,6 +275,7 @@ union amdgpu_firmware_header { struct sdma_firmware_header_v1_1 sdma_v1_1; struct gpu_info_firmware_header_v1_0 gpu_info; struct dmcu_firmware_header_v1_0 dmcu; + struct dmcub_firmware_header_v1_0 dmcub; uint8_t raw[0x100]; }; @@ -307,6 +315,7 @@ enum AMDGPU_UCODE_ID { AMDGPU_UCODE_ID_DMCU_INTV, AMDGPU_UCODE_ID_VCN0_RAM, AMDGPU_UCODE_ID_VCN1_RAM, + AMDGPU_UCODE_ID_DMCUB, AMDGPU_UCODE_ID_MAXIMUM, }; -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 05/11] drm/amd/display: Change dmcu init sequence for dmcub loading dmcu FW.
From: Yongqiang Sun [Why] DMCU isn't intiliazed properly by dmcub loading due to dmcub initialize sequence. [How] Change dmcu init sequece to meet dmcub initilize. Signed-off-by: Yongqiang Sun Reviewed-by: Tony Cheng --- drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 79 +++ drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h | 13 +++ .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 +- .../drm/amd/display/dc/dcn21/dcn21_resource.c | 4 +- drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h | 2 + 5 files changed, 97 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index ba995d3f2318..3417100d51e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -59,6 +59,12 @@ #define MCP_BL_SET_PWM_FRAC 0x6A /* Enable or disable Fractional PWM */ #define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x0001L +// PSP FW version +#define mmMP0_SMN_C2PMSG_580x1607A + +//Register access policy version +#define mmMP0_SMN_C2PMSG_910x1609B + static bool dce_dmcu_init(struct dmcu *dmcu) { // Do nothing @@ -373,6 +379,7 @@ static bool dcn10_dmcu_init(struct dmcu *dmcu) const struct dc_config *config = >ctx->dc->config; bool status = false; + PERF_TRACE(); /* Definition of DC_DMCU_SCRATCH * 0 : firmare not loaded * 1 : PSP load DMCU FW but not initialized @@ -429,9 +436,23 @@ static bool dcn10_dmcu_init(struct dmcu *dmcu) break; } + PERF_TRACE(); return status; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +static bool dcn21_dmcu_init(struct dmcu *dmcu) +{ + struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); + uint32_t dmcub_psp_version = REG_READ(DMCUB_SCRATCH15); + + if (dmcu->auto_load_dmcu && dmcub_psp_version == 0) { + return false; + } + + return dcn10_dmcu_init(dmcu); +} +#endif static bool dcn10_dmcu_load_iram(struct dmcu *dmcu, unsigned int start_offset, @@ -818,6 +839,21 @@ static const struct dmcu_funcs dcn20_funcs = { }; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +static const struct dmcu_funcs dcn21_funcs = { + .dmcu_init = dcn21_dmcu_init, + .load_iram = dcn10_dmcu_load_iram, + .set_psr_enable = dcn10_dmcu_set_psr_enable, + .setup_psr = dcn10_dmcu_setup_psr, + .get_psr_state = dcn10_get_dmcu_psr_state, + .set_psr_wait_loop = dcn10_psr_wait_loop, + .get_psr_wait_loop = dcn10_get_psr_wait_loop, + .is_dmcu_initialized = dcn10_is_dmcu_initialized, + .lock_phy = dcn20_lock_phy, + .unlock_phy = dcn20_unlock_phy +}; +#endif + static void dce_dmcu_construct( struct dce_dmcu *dmcu_dce, struct dc_context *ctx, @@ -836,6 +872,26 @@ static void dce_dmcu_construct( dmcu_dce->dmcu_mask = dmcu_mask; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +static void dcn21_dmcu_construct( + struct dce_dmcu *dmcu_dce, + struct dc_context *ctx, + const struct dce_dmcu_registers *regs, + const struct dce_dmcu_shift *dmcu_shift, + const struct dce_dmcu_mask *dmcu_mask) +{ + uint32_t psp_version = 0; + + dce_dmcu_construct(dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); + + if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { + psp_version = dm_read_reg(ctx, mmMP0_SMN_C2PMSG_58); + dmcu_dce->base.auto_load_dmcu = (psp_version > 0x00110029); + dmcu_dce->base.psp_version = psp_version; + } +} +#endif + struct dmcu *dce_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, @@ -903,6 +959,29 @@ struct dmcu *dcn20_dmcu_create( } #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +struct dmcu *dcn21_dmcu_create( + struct dc_context *ctx, + const struct dce_dmcu_registers *regs, + const struct dce_dmcu_shift *dmcu_shift, + const struct dce_dmcu_mask *dmcu_mask) +{ + struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_KERNEL); + + if (dmcu_dce == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn21_dmcu_construct( + dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); + + dmcu_dce->base.funcs = _funcs; + + return _dce->base; +} +#endif + void dce_dmcu_destroy(struct dmcu **dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(*dmcu); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h index cc8587683b4b..1a42b2cbb21b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h @@ -71,6 +71,10 @@ DMCU_COMMON_REG_LIST_DCE_BASE(), \ SR(DMU_MEM_PWR_CNTL) +#define
[PATCH 08/11] drm/amdgpu: Add DMCUB to firmware query interface
The DMCUB firmware version can be read using the AMDGPU_INFO ioctl or the amdgpu_firmware_info debugfs entry. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 12 include/uapi/drm/amdgpu_drm.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index e3632825bbc2..1ff0202a900d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -294,6 +294,10 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info, fw_info->ver = adev->dm.dmcu_fw_version; fw_info->feature = 0; break; + case AMDGPU_INFO_FW_DMCUB: + fw_info->ver = adev->dm.dmcub_fw_version; + fw_info->feature = 0; + break; default: return -EINVAL; } @@ -1392,6 +1396,14 @@ static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data) seq_printf(m, "DMCU feature version: %u, firmware version: 0x%08x\n", fw_info.feature, fw_info.ver); + /* DMCUB */ + query_fw.fw_type = AMDGPU_INFO_FW_DMCUB; + ret = amdgpu_firmware_info(_info, _fw, adev); + if (ret) + return ret; + seq_printf(m, "DMCUB feature version: %u, firmware version: 0x%08x\n", + fw_info.feature, fw_info.ver); + seq_printf(m, "VBIOS version: %s\n", ctx->vbios_version); diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 391c9c1bdba4..f75c6957064d 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -714,6 +714,9 @@ struct drm_amdgpu_cs_chunk_data { /* Subquery id: Query DMCU firmware version */ #define AMDGPU_INFO_FW_DMCU 0x12 #define AMDGPU_INFO_FW_TA 0x13 + /* Subquery id: Query DMCUB firmware version */ + #define AMDGPU_INFO_FW_DMCUB0x14 + /* number of bytes moved for TTM migration */ #define AMDGPU_INFO_NUM_BYTES_MOVED0x0f /* the used VRAM size */ -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 10/11] drm/amd/display: Register DMUB service with DC
[Why] DC can utilize the DMUB server to send commands to the DMUB but it's the DM responsibility to pass it the service to use. [How] Create the dc_dmub_srv after we finish initializing the dmub_srv. Cleanup the dc_dmub_srv before destroying the dmub_srv or dc. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 230fd0155463..920e84e40bbb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -34,6 +34,7 @@ #include "dmub/inc/dmub_srv.h" #include "dc/inc/hw/dmcu.h" #include "dc/inc/hw/abm.h" +#include "dc/dc_dmub_srv.h" #endif #include "vid.h" @@ -803,6 +804,12 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); } + adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv); + if (!adev->dm.dc->ctx->dmub_srv) { + DRM_ERROR("Couldn't allocate DC DMUB server!\n"); + return -ENOMEM; + } + DRM_INFO("DMUB hardware initialized: version=0x%08X\n", adev->dm.dmcub_fw_version); @@ -976,6 +983,11 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) dc_deinit_callbacks(adev->dm.dc); #endif #ifdef CONFIG_DRM_AMD_DC_DMUB + if (adev->dm.dc->ctx->dmub_srv) { + dc_dmub_srv_destroy(>dm.dc->ctx->dmub_srv); + adev->dm.dc->ctx->dmub_srv = NULL; + } + if (adev->dm.dmub_bo) amdgpu_bo_free_kernel(>dm.dmub_bo, >dm.dmub_bo_gpu_addr, -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 09/11] drm/amd/display: Add DMUB support to DC
DC will use DMUB for command submission and flow control during initialization. Register offloading as well as submitting some BIOS commands are part of the DC internal interface but are guarded behind debug options. It won't be functional in amdgpu_dm yet since we don't pass the DMUB service to DC for use. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/Makefile | 6 +- .../drm/amd/display/dc/bios/command_table2.c | 91 ++ drivers/gpu/drm/amd/display/dc/core/dc.c | 8 + drivers/gpu/drm/amd/display/dc/dc.h | 12 + drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 119 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 60 drivers/gpu/drm/amd/display/dc/dc_helper.c| 273 ++ drivers/gpu/drm/amd/display/dc/dc_types.h | 6 + .../drm/amd/display/dc/dcn10/dcn10_dpp_cm.c | 7 + .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 8 + .../gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c | 11 + .../drm/amd/display/dc/dcn21/dcn21_resource.c | 3 + drivers/gpu/drm/amd/display/dc/dm_services.h | 14 + .../gpu/drm/amd/display/dc/inc/reg_helper.h | 22 ++ drivers/gpu/drm/amd/display/dc/os_types.h | 1 + 15 files changed, 640 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c create mode 100644 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index a160512a2f04..6fe39f6392c7 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -70,5 +70,9 @@ AMD_DM_REG_UPDATE = $(addprefix $(AMDDALPATH)/dc/,dc_helper.o) AMD_DISPLAY_FILES += $(AMD_DISPLAY_CORE) AMD_DISPLAY_FILES += $(AMD_DM_REG_UPDATE) - +ifdef CONFIG_DRM_AMD_DC_DMUB +DC_DMUB += dc_dmub_srv.o +AMD_DISPLAY_DMUB = $(addprefix $(AMDDALPATH)/dc/,$(DC_DMUB)) +AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB) +endif diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index bb2e8105e6ab..a3d890050e39 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -37,6 +37,10 @@ #include "bios_parser_types_internal2.h" #include "amdgpu.h" +#ifdef CONFIG_DRM_AMD_DC_DMUB +#include "dc_dmub_srv.h" +#include "dc.h" +#endif #define DC_LOGGER \ bp->base.ctx->logger @@ -103,6 +107,21 @@ static void init_dig_encoder_control(struct bios_parser *bp) } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static void encoder_control_dmcub( + struct dc_dmub_srv *dmcub, + struct dig_encoder_stream_setup_parameters_v1_5 *dig) +{ + struct dmub_rb_cmd_digx_encoder_control encoder_control = { 0 }; + + encoder_control.header.type = DMUB_CMD__DIGX_ENCODER_CONTROL; + encoder_control.encoder_control.dig.stream_param = *dig; + + dc_dmub_srv_cmd_queue(dmcub, _control.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} +#endif static enum bp_result encoder_control_digx_v1_5( struct bios_parser *bp, struct bp_encoder_control *cntl) @@ -154,6 +173,13 @@ static enum bp_result encoder_control_digx_v1_5( default: break; } +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + encoder_control_dmcub(bp->base.ctx->dmub_srv, ); + return BP_RESULT_OK; + } +#endif if (EXEC_BIOS_CMD_TABLE(digxencodercontrol, params)) result = BP_RESULT_OK; @@ -190,7 +216,21 @@ static void init_transmitter_control(struct bios_parser *bp) break; } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static void transmitter_control_dmcub( + struct dc_dmub_srv *dmcub, + struct dig_transmitter_control_parameters_v1_6 *dig) +{ + struct dmub_rb_cmd_dig1_transmitter_control transmitter_control; + + transmitter_control.header.type = DMUB_CMD__DIG1_TRANSMITTER_CONTROL; + transmitter_control.transmitter_control.dig = *dig; + dc_dmub_srv_cmd_queue(dmcub, _control.header); + dc_dmub_srv_cmd_execute(dmcub); + dc_dmub_srv_wait_idle(dmcub); +} +#endif static enum bp_result transmitter_control_v1_6( struct bios_parser *bp, struct bp_transmitter_control *cntl) @@ -223,6 +263,14 @@ static enum bp_result transmitter_control_v1_6( } +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (bp->base.ctx->dc->ctx->dmub_srv && + bp->base.ctx->dc->debug.dmub_command_table) { + transmitter_control_dmcub(bp->base.ctx->dmub_srv, ); + return BP_RESULT_OK; + } +#endif + /*color_depth not us
[PATCH 06/11] drm/amd/display: Add PSP FW version mask.
From: Yongqiang Sun [Why] PSP version format is AB.CD.EF.GH, where CD and GH is the main version. current psp version check for dmcub loading dmcu check 0x00110029, in case of some psp version eg: 0x00110227 which main version should be 0x00110027, will result in unexpeceted dmcub loading dmcu FW. [How] Add psp version mask 0x00FF00FF for checking version. Signed-off-by: Yongqiang Sun Reviewed-by: Tony Cheng --- drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index 3417100d51e4..3276944e6997 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -886,7 +886,7 @@ static void dcn21_dmcu_construct( if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { psp_version = dm_read_reg(ctx, mmMP0_SMN_C2PMSG_58); - dmcu_dce->base.auto_load_dmcu = (psp_version > 0x00110029); + dmcu_dce->base.auto_load_dmcu = ((psp_version & 0x00FF00FF) > 0x00110029); dmcu_dce->base.psp_version = psp_version; } } -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 11/11] drm/amd/display: Drop CONFIG_DRM_AMD_DC_DMUB guards
[Why] Support for DMUB only depends on support for DC. It doesn't use floating point so we don't need to guard it by any specific DCN revision. [How] Drop the guards and cleanup the newlines around each one. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/Kconfig | 6 - drivers/gpu/drm/amd/display/Makefile | 12 +++-- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 20 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 4 --- drivers/gpu/drm/amd/display/dc/Makefile | 3 --- .../drm/amd/display/dc/bios/command_table2.c | 27 ++- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 + drivers/gpu/drm/amd/display/dc/dc.h | 7 + drivers/gpu/drm/amd/display/dc/dc_helper.c| 22 +++ drivers/gpu/drm/amd/display/dc/dc_types.h | 5 +--- .../drm/amd/display/dc/dcn10/dcn10_dpp_cm.c | 6 ++--- .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 5 +--- .../gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c | 5 +--- .../drm/amd/display/dc/dcn21/dcn21_resource.c | 2 -- drivers/gpu/drm/amd/display/dc/dm_services.h | 4 --- .../gpu/drm/amd/display/dc/inc/reg_helper.h | 3 --- drivers/gpu/drm/amd/display/dmub/src/Makefile | 2 -- 17 files changed, 22 insertions(+), 117 deletions(-) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index fced39e229d5..313183b80032 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -30,7 +30,6 @@ config DRM_AMD_DC_DCN2_1 bool "DCN 2.1 family" depends on DRM_AMD_DC && X86 depends on DRM_AMD_DC_DCN2_0 - select DRM_AMD_DC_DMUB help Choose this option if you want to have Renoir support for display engine @@ -53,11 +52,6 @@ config DRM_AMD_DC_HDCP if you want to support HDCP authentication -config DRM_AMD_DC_DMUB -def_bool n -help - DMUB support for display engine - config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 3c7332be4a89..2633de77de5e 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -34,27 +34,21 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/info_packet subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/power +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dmub/inc + ifdef CONFIG_DRM_AMD_DC_HDCP subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/hdcp endif -ifdef CONFIG_DRM_AMD_DC_DMUB -subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dmub/inc -endif - #TODO: remove when Timing Sync feature is complete subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0 -DAL_LIBS = amdgpu_dm dcmodules/freesync modules/color modules/info_packet modules/power +DAL_LIBS = amdgpu_dm dcmodules/freesync modules/color modules/info_packet modules/power dmub/src ifdef CONFIG_DRM_AMD_DC_HDCP DAL_LIBS += modules/hdcp endif -ifdef CONFIG_DRM_AMD_DC_DMUB -DAL_LIBS += dmub/src -endif - AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/,$(DAL_LIBS))) include $(AMD_DAL) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 920e84e40bbb..5fe0ed28eb01 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -30,12 +30,10 @@ #include "dc.h" #include "dc/inc/core_types.h" #include "dal_asic_id.h" -#ifdef CONFIG_DRM_AMD_DC_DMUB #include "dmub/inc/dmub_srv.h" #include "dc/inc/hw/dmcu.h" #include "dc/inc/hw/abm.h" #include "dc/dc_dmub_srv.h" -#endif #include "vid.h" #include "amdgpu.h" @@ -93,10 +91,9 @@ #include "modules/power/power_helpers.h" #include "modules/inc/mod_info_packet.h" -#ifdef CONFIG_DRM_AMD_DC_DMUB #define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); -#endif + #define FIRMWARE_RAVEN_DMCU"amdgpu/raven_dmcu.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU); @@ -677,7 +674,6 @@ void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) } } -#ifdef CONFIG_DRM_AMD_DC_DMUB static int dm_dmub_hw_init(struct amdgpu_device *adev) { const unsigned int psp_header_bytes = 0x100; @@ -816,16 +812,13 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) return 0; } -#endif static int amdgpu_dm_init(struct amdgpu_device *adev) { struct dc_init_data init_data; #ifdef CONFIG_DRM_AMD_DC_HDCP struct dc_callback_init init_params;
[PATCH 02/11] drm/amdgpu: Add PSP loading support for DMCUB ucode
DMCUB ucode requires secure loading through PSP. This is already supported in PSP as GFX_FW_TYPE_DMUB, it just needs to be mapped from AMDGPU_UCODE_ID_DMCUB to GFX_FW_TYPE_DMUB. DMUB is a shorthand name for DMCUB and can be used interchangeably. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index fd7a73f4fa70..d4cdd6fd3fbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -1276,6 +1276,9 @@ static int psp_get_fw_type(struct amdgpu_firmware_info *ucode, case AMDGPU_UCODE_ID_VCN1_RAM: *type = GFX_FW_TYPE_VCN1_RAM; break; + case AMDGPU_UCODE_ID_DMCUB: + *type = GFX_FW_TYPE_DMUB; + break; case AMDGPU_UCODE_ID_MAXIMUM: default: return -EINVAL; -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 04/11] drm/amd/display: Add the DMUB service
The DMUB service is the interface to the DMCUB. It's required to support Renoir features so it will be enabled and compiled automatically when the Renoir display engine is enabled via CONFIG_DRM_AMD_DC_DCN2_1. DMUB code will initially be guarded by CONFIG_DRM_AMD_DC_DMUB and later switched to CONFIG_DRM_AMD_DC_DCN2_1 with the config option dropped. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/Kconfig | 6 + drivers/gpu/drm/amd/display/Makefile | 8 + .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 256 + .../gpu/drm/amd/display/dmub/inc/dmub_rb.h| 129 + .../gpu/drm/amd/display/dmub/inc/dmub_srv.h | 505 ++ .../amd/display/dmub/inc/dmub_trace_buffer.h | 51 ++ .../gpu/drm/amd/display/dmub/inc/dmub_types.h | 64 +++ drivers/gpu/drm/amd/display/dmub/src/Makefile | 29 + .../gpu/drm/amd/display/dmub/src/dmub_dcn20.c | 137 + .../gpu/drm/amd/display/dmub/src/dmub_dcn20.h | 62 +++ .../gpu/drm/amd/display/dmub/src/dmub_dcn21.c | 126 + .../gpu/drm/amd/display/dmub/src/dmub_dcn21.h | 45 ++ .../gpu/drm/amd/display/dmub/src/dmub_reg.c | 109 .../gpu/drm/amd/display/dmub/src/dmub_reg.h | 120 + .../gpu/drm/amd/display/dmub/src/dmub_srv.c | 415 ++ 15 files changed, 2062 insertions(+) create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/Makefile create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 313183b80032..fced39e229d5 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -30,6 +30,7 @@ config DRM_AMD_DC_DCN2_1 bool "DCN 2.1 family" depends on DRM_AMD_DC && X86 depends on DRM_AMD_DC_DCN2_0 + select DRM_AMD_DC_DMUB help Choose this option if you want to have Renoir support for display engine @@ -52,6 +53,11 @@ config DRM_AMD_DC_HDCP if you want to support HDCP authentication +config DRM_AMD_DC_DMUB +def_bool n +help + DMUB support for display engine + config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index 36b3d6a5d04d..3c7332be4a89 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -38,6 +38,10 @@ ifdef CONFIG_DRM_AMD_DC_HDCP subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/hdcp endif +ifdef CONFIG_DRM_AMD_DC_DMUB +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dmub/inc +endif + #TODO: remove when Timing Sync feature is complete subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0 @@ -47,6 +51,10 @@ ifdef CONFIG_DRM_AMD_DC_HDCP DAL_LIBS += modules/hdcp endif +ifdef CONFIG_DRM_AMD_DC_DMUB +DAL_LIBS += dmub/src +endif + AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/,$(DAL_LIBS))) include $(AMD_DAL) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h new file mode 100644 index ..b25f92e3280d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -0,0 +1,256 @@ +/* + * Copyright 2019 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 +
[PATCH 03/11] drm/amd/display: Drop DMCUB from DCN21 resources
The interface to the DMCUB won't be through DC itself. DC will instead call into the DMUB interface introduced with a future change. The CONFIG_DRM_AMD_DC_DMUB defines will still be used for now but will be dropped at the end of the series. Since this define was never configurable in the first place this code wasn't used. Signed-off-by: Nicholas Kazlauskas --- .../drm/amd/display/dc/dcn21/dcn21_resource.c | 31 --- 1 file changed, 31 deletions(-) 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 459bd9a5caed..1042197f1859 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -373,20 +373,6 @@ static const struct dce_abm_mask abm_mask = { ABM_MASK_SH_LIST_DCN20(_MASK) }; -#ifdef CONFIG_DRM_AMD_DC_DMUB -static const struct dcn21_dmcub_registers dmcub_regs = { - DMCUB_REG_LIST_DCN() -}; - -static const struct dcn21_dmcub_shift dmcub_shift = { - DMCUB_COMMON_MASK_SH_LIST_BASE(__SHIFT) -}; - -static const struct dcn21_dmcub_mask dmcub_mask = { - DMCUB_COMMON_MASK_SH_LIST_BASE(_MASK) -}; -#endif - #define audio_regs(id)\ [id] = {\ AUD_COMMON_REG_LIST(id)\ @@ -970,11 +956,6 @@ static void destruct(struct dcn21_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(>base.dmcu); -#ifdef CONFIG_DRM_AMD_DC_DMUB - if (pool->base.dmcub != NULL) - dcn21_dmcub_destroy(>base.dmcub); -#endif - if (pool->base.dccg != NULL) dcn_dccg_destroy(>base.dccg); @@ -1766,18 +1747,6 @@ static bool construct( goto create_fail; } -#ifdef CONFIG_DRM_AMD_DC_DMUB - pool->base.dmcub = dcn21_dmcub_create(ctx, - _regs, - _shift, - _mask); - if (pool->base.dmcub == NULL) { - dm_error("DC: failed to create dmcub!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } -#endif - pool->base.pp_smu = dcn21_pp_smu_create(ctx); num_pipes = dcn2_1_ip.max_num_dpp; -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 07/11] drm/amd/display: Hook up the DMUB service in DM
[Why] We need DMCUB on Renoir to support DMCU and PHY initialization. The DMUB service provides a mechanism to load the DMCUB. [How] Include the DMUB service in amdgpu_dm. Frontdoor loading of the DMCUB firmware needs to happen via PSP. To pass the firmware to PSP we need to hand it off to the firmware list in the base driver during software initialization. Most of the DMUB service can technically be initialized at this point in time, but we don't want to be allocating framebuffer memory for hardware that doesn't support the DMCUB and in order to check that we need to be able to read registers - something DM helpers aren't setup to do in software initialization. So everything but the service creation itself will get deferred to hardware initialization. Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 267 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 50 2 files changed, 317 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 48f5b43e2698..230fd0155463 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -30,6 +30,11 @@ #include "dc.h" #include "dc/inc/core_types.h" #include "dal_asic_id.h" +#ifdef CONFIG_DRM_AMD_DC_DMUB +#include "dmub/inc/dmub_srv.h" +#include "dc/inc/hw/dmcu.h" +#include "dc/inc/hw/abm.h" +#endif #include "vid.h" #include "amdgpu.h" @@ -87,6 +92,10 @@ #include "modules/power/power_helpers.h" #include "modules/inc/mod_info_packet.h" +#ifdef CONFIG_DRM_AMD_DC_DMUB +#define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" +MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); +#endif #define FIRMWARE_RAVEN_DMCU"amdgpu/raven_dmcu.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU); @@ -667,12 +676,149 @@ void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) } } +#ifdef CONFIG_DRM_AMD_DC_DMUB +static int dm_dmub_hw_init(struct amdgpu_device *adev) +{ + const unsigned int psp_header_bytes = 0x100; + const unsigned int psp_footer_bytes = 0x100; + const struct dmcub_firmware_header_v1_0 *hdr; + struct dmub_srv *dmub_srv = adev->dm.dmub_srv; + const struct firmware *dmub_fw = adev->dm.dmub_fw; + struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu; + struct abm *abm = adev->dm.dc->res_pool->abm; + struct dmub_srv_region_params region_params; + struct dmub_srv_region_info region_info; + struct dmub_srv_fb_params fb_params; + struct dmub_srv_fb_info fb_info; + struct dmub_srv_hw_params hw_params; + enum dmub_status status; + const unsigned char *fw_inst_const, *fw_bss_data; + uint32_t i; + int r; + bool has_hw_support; + + if (!dmub_srv) + /* DMUB isn't supported on the ASIC. */ + return 0; + + if (!dmub_fw) { + /* Firmware required for DMUB support. */ + DRM_ERROR("No firmware provided for DMUB.\n"); + return -EINVAL; + } + + status = dmub_srv_has_hw_support(dmub_srv, _hw_support); + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error checking HW support for DMUB: %d\n", status); + return -EINVAL; + } + + if (!has_hw_support) { + DRM_INFO("DMUB unsupported on ASIC\n"); + return 0; + } + + hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data; + + /* Calculate the size of all the regions for the DMUB service. */ + memset(_params, 0, sizeof(region_params)); + + region_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - + psp_header_bytes - psp_footer_bytes; + region_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + region_params.vbios_size = adev->dm.dc->ctx->dc_bios->bios_size; + + status = dmub_srv_calc_region_info(dmub_srv, _params, + _info); + + if (status != DMUB_STATUS_OK) { + DRM_ERROR("Error calculating DMUB region info: %d\n", status); + return -EINVAL; + } + + /* +* Allocate a framebuffer based on the total size of all the regions. +* TODO: Move this into GART. +*/ + r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, >dm.dmub_bo, + >dm.dmub_bo_gpu_addr, + >dm.dmub_bo_cpu_addr); + if (r) + return r; + + /* Rebase the regions on the framebuffer address. */ + memset(_params,
[PATCH 00/11] Add DMCUB support for Renoir
The DMCUB is the Display MicroController Unit B, a display microcontroller that is required for Renoir to support realtime display features (ABM, PSR) and display hardware initialization. This patch series adds the required firmware loading support in amdgpu and the DMUB service support for amdgpu_dm and dc to interface with the DMCUB. The term DMCUB will generally refer to the actual microcontroller while DMUB will generally refer to the software interface. Cc: Harry Wentland Nicholas Kazlauskas (9): drm/amdgpu: Add ucode support for DMCUB drm/amdgpu: Add PSP loading support for DMCUB ucode drm/amd/display: Drop DMCUB from DCN21 resources drm/amd/display: Add the DMUB service drm/amd/display: Hook up the DMUB service in DM drm/amdgpu: Add DMCUB to firmware query interface drm/amd/display: Add DMUB support to DC drm/amd/display: Register DMUB service with DC drm/amd/display: Drop CONFIG_DRM_AMD_DC_DMUB guards Yongqiang Sun (2): drm/amd/display: Change dmcu init sequence for dmcub loading dmcu FW. drm/amd/display: Add PSP FW version mask. drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 12 + drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 3 + drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c | 11 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h | 9 + drivers/gpu/drm/amd/display/Makefile | 4 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 261 + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 46 ++ drivers/gpu/drm/amd/display/dc/Makefile | 5 +- .../drm/amd/display/dc/bios/command_table2.c | 80 +++ drivers/gpu/drm/amd/display/dc/core/dc.c | 4 + drivers/gpu/drm/amd/display/dc/dc.h | 7 + drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 119 + drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 60 +++ drivers/gpu/drm/amd/display/dc/dc_helper.c| 257 + drivers/gpu/drm/amd/display/dc/dc_types.h | 3 + drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 79 +++ drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h | 13 + .../drm/amd/display/dc/dcn10/dcn10_dpp_cm.c | 5 + .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 +- .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 5 + .../gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c | 8 + .../drm/amd/display/dc/dcn21/dcn21_resource.c | 36 +- drivers/gpu/drm/amd/display/dc/dm_services.h | 10 + drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h | 2 + .../gpu/drm/amd/display/dc/inc/reg_helper.h | 19 + drivers/gpu/drm/amd/display/dc/os_types.h | 1 + .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 256 + .../gpu/drm/amd/display/dmub/inc/dmub_rb.h| 129 + .../gpu/drm/amd/display/dmub/inc/dmub_srv.h | 505 ++ .../amd/display/dmub/inc/dmub_trace_buffer.h | 51 ++ .../gpu/drm/amd/display/dmub/inc/dmub_types.h | 64 +++ drivers/gpu/drm/amd/display/dmub/src/Makefile | 27 + .../gpu/drm/amd/display/dmub/src/dmub_dcn20.c | 137 + .../gpu/drm/amd/display/dmub/src/dmub_dcn20.h | 62 +++ .../gpu/drm/amd/display/dmub/src/dmub_dcn21.c | 126 + .../gpu/drm/amd/display/dmub/src/dmub_dcn21.h | 45 ++ .../gpu/drm/amd/display/dmub/src/dmub_reg.c | 109 .../gpu/drm/amd/display/dmub/src/dmub_reg.h | 120 + .../gpu/drm/amd/display/dmub/src/dmub_srv.c | 415 ++ include/uapi/drm/amdgpu_drm.h | 3 + 40 files changed, 3072 insertions(+), 38 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c create mode 100644 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h create mode 100644 drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/Makefile create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h create mode 100644 drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Free gamma after calculating legacy transfer function
[Why] We're leaking memory by not freeing the gamma used to calculate the transfer function for legacy gamma. [How] Release the gamma after we're done with it. Cc: Philip Yang Cc: Harry Wentland Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index b43bb7f90e4e..2233d293a707 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -210,6 +210,8 @@ static int __set_legacy_tf(struct dc_transfer_func *func, res = mod_color_calculate_regamma_params(func, gamma, true, has_rom, NULL); + dc_gamma_release(); + return res ? 0 : -ENOMEM; } -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Make plane z-pos explicit to userspace
[Why] Many userspace assumes that the DRM plane index indicates the plane z-order, with a lower index being lower depth and a higher index being higher depth. This is currently what we assume in DM. DRM has a zpos plane property to make this explicit to userspace and there are clients that make use of this information. [How] Attach the immutable zpos property to the plane. While we can technically order the planes in any manner since we virtualize them in DC we don't currently have the software support. The z-pos could potentially become immutable later but for now just let userspace do the ordering. Cc: Leo Li Cc: Harry Wentland Cc: Rodrigo Siqueira Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 239b1ae86007..e58b0b7e3c52 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4897,6 +4897,9 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, if (res) return res; + /* Make z-pos of each plane explicit - lower ID is lower depth */ + drm_plane_create_zpos_immutable_property(plane, plane->index); + if (plane->type == DRM_PLANE_TYPE_OVERLAY && plane_cap && plane_cap->per_pixel_alpha) { unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | -- 2.20.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Calculate bpc based on max_requested_bpc
[Why] The only place where state->max_bpc is updated on the connector is at the start of atomic check during drm_atomic_connector_check. It isn't updated when adding the connectors to the atomic state after the fact. It also doesn't necessarily reflect the right value when called in amdgpu during mode validation outside of atomic check. This can cause the wrong bpc to be used even if the max_requested_bpc is the correct value. [How] Don't rely on state->max_bpc reflecting the real bpc value and just do the min(...) based on display info bpc and max_requested_bpc. Cc: David Francis Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c| 16 ++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7cf8dbccce95..73ed7b6bd8d3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3216,13 +3216,25 @@ static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector, const struct drm_connector_state *state) { - uint32_t bpc = connector->display_info.bpc; + uint8_t bpc = (uint8_t)connector->display_info.bpc; + + /* Assume 8 bpc by default if no bpc is specified. */ + bpc = bpc ? bpc : 8; if (!state) state = connector->state; if (state) { - bpc = state->max_bpc; + /* +* Cap display bpc based on the user requested value. +* +* The value for state->max_bpc may not correctly updated +* depending on when the connector gets added to the state +* or if this was called outside of atomic check, so it +* can't be used directly. +*/ + bpc = min(bpc, state->max_requested_bpc); + /* Round down to the nearest even number. */ bpc = bpc - (bpc & 1); } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 4/4] drm/amd/display: Lock the CRTC when setting CRC source
[Why] We need to ensure that we're holding the lock on the CRTC when setting the CRC source since we're modifying the CRTC state directly. We also need to wait for any outstanding non-blocking commits to finish so they aren't reading state that's potentially being modified - non-blocking commits don't hold the CRTC lock while doing commit tail work. [How] Lock the CRTC using its mutex. While holding the lock check if there's any commit active on the CRTC - if there is, it's non-blocking and we should wait until it's finished by waiting for hw_done to be signaled since that's the last point where we touch CRTC state. Cc: David Francis Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 63 +++ 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index e9d5b1fad625..fa86b9e706af 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -135,13 +135,13 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { - struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); + enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); + struct drm_crtc_commit *commit; + struct dm_crtc_state *crtc_state; struct drm_dp_aux *aux = NULL; bool enable = false; bool enabled = false; - int ret; - - enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); + int ret = 0; if (source < 0) { DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n", @@ -149,7 +149,33 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) return -EINVAL; } + ret = drm_modeset_lock(>mutex, NULL); + if (ret) + return ret; + + spin_lock(>commit_lock); + commit = list_first_entry_or_null(>commit_list, + struct drm_crtc_commit, commit_entry); + if (commit) + drm_crtc_commit_get(commit); + spin_unlock(>commit_lock); + + if (commit) { + /* +* Need to wait for all outstanding programming to complete +* in commit tail since it can modify CRC related fields and +* hardware state. Since we're holding the CRTC lock we're +* guaranteed that no other commit work can be queued off +* before we modify the state below. +*/ + ret = wait_for_completion_interruptible_timeout( + >hw_done, 10 * HZ); + if (ret) + goto cleanup; + } + enable = amdgpu_dm_is_valid_crc_source(source); + crtc_state = to_dm_crtc_state(crtc->state); /* * USER REQ SRC | CURRENT SRC | BEHAVIOR @@ -183,19 +209,23 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) if (!aconn) { DRM_DEBUG_DRIVER("No amd connector matching CRTC-%d\n", crtc->index); - return -EINVAL; + ret = -EINVAL; + goto cleanup; } aux = >dm_dp_aux.aux; if (!aux) { DRM_DEBUG_DRIVER("No dp aux for amd connector\n"); - return -EINVAL; + ret = -EINVAL; + goto cleanup; } } - if (amdgpu_dm_crtc_configure_crc_source(crtc, crtc_state, source)) - return -EINVAL; + if (amdgpu_dm_crtc_configure_crc_source(crtc, crtc_state, source)) { + ret = -EINVAL; + goto cleanup; + } /* * Reading the CRC requires the vblank interrupt handler to be @@ -205,12 +235,13 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) if (!enabled && enable) { ret = drm_crtc_vblank_get(crtc); if (ret) - return ret; + goto cleanup; if (dm_is_crc_source_dprx(source)) { if (drm_dp_start_crc(aux, crtc)) { DRM_DEBUG_DRIVER("dp start crc failed\n"); - return -EINVAL; + ret = -EINVAL; + goto cleanup; } } } else if (enabled && !enable) { @@ -218,7 +249,8 @@ int amdgpu_dm_crtc_set_crc_source(struct d
[PATCH 1/4] drm/amd/display: Check return code for CRC drm_crtc_vblank_get
[Why] The call to drm_crtc_vblank_get can fail if vblank is disabled and we try to increment the reference. Since drm_crtc_vblank_get internally drops the reference when it fails it means the subsequent drm_crtc_vblank_put(...) when closing the file drops a zero reference. This was found via igt@kms_plane@pixel-format-pipe-A-planes. [How] Check the return code and return it on failure. We wouldn't have been able to enable CRC reading anyway since vblank wasn't enabled. Cc: David Francis Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index b01256a4692e..f675626ef56b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -105,6 +105,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) struct drm_dp_aux *aux = NULL; bool enable = false; bool enabled = false; + int ret; enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); @@ -175,7 +176,10 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) */ enabled = amdgpu_dm_is_valid_crc_source(crtc_state->crc_src); if (!enabled && enable) { - drm_crtc_vblank_get(crtc); + ret = drm_crtc_vblank_get(crtc); + if (ret) + return ret; + if (dm_is_crc_source_dprx(source)) { if (drm_dp_start_crc(aux, crtc)) { DRM_DEBUG_DRIVER("dp start crc failed\n"); -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/4] drm/amd/display: Use connector list for finding DPRX CRC aux
[Why] This change is a refactor in preparation for adding locking and removing the requirement for a stream state on the CRTC for enabling CRC capture to fix igt@kms_plane_multiple@* warnings. [How] We can get the aux by finding the matching connector for the CRTC with the assumption that we're not doing cloning. Cc: David Francis Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 19 +++ 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index f675626ef56b..c57ff8821fe2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -101,7 +101,6 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) struct amdgpu_device *adev = crtc->dev->dev_private; struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); struct dc_stream_state *stream_state = crtc_state->stream; - struct amdgpu_dm_connector *aconn; struct drm_dp_aux *aux = NULL; bool enable = false; bool enabled = false; @@ -137,9 +136,21 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) * DPRX DITHER | | Enable DPRX CRC, need 'aux', set dither */ if (dm_is_crc_source_dprx(source) || - (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE && -dm_is_crc_source_dprx(crtc_state->crc_src))) { - aconn = stream_state->link->priv; + (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE && +dm_is_crc_source_dprx(crtc_state->crc_src))) { + struct amdgpu_dm_connector *aconn = NULL; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + + drm_connector_list_iter_begin(crtc->dev, _iter); + drm_for_each_connector_iter (connector, _iter) { + if (!connector->state || connector->state->crtc != crtc) + continue; + + aconn = to_amdgpu_dm_connector(connector); + break; + } + drm_connector_list_iter_end(_iter); if (!aconn) { DRM_DEBUG_DRIVER("No amd connector matching CRTC-%d\n", crtc->index); -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 3/4] drm/amd/display: Split out DC programming for CRC capture
[Why] Calling amdgpu_dm_crtc_set_crc_source in amdgpu_dm directly has the consequence of adding additional vblank references or starting DPRX CRC capture more than once without calling stop first. Vblank references for CRC capture should be managed entirely by opening and closing the CRC file from userspace. Stream state also shouldn't be required on the CRC so we can close the file after the CRTC has been disabled. [How] Do DC programming required for configuring CRC capture separately from setting the source. Whenever we re-enable or reset a CRC this programming should be reapplied. CRC vblank reference handling in amdgpu_dm can be entirely dropped after this. Stream state also no longer needs to be required since we can just defer the programming to when the stream is actually enabled. Cc: David Francis Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 25 ++-- .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 62 --- .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h | 6 ++ 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 911fe78b47c1..7cf8dbccce95 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5967,11 +5967,9 @@ static void amdgpu_dm_enable_crtc_interrupts(struct drm_device *dev, /* The stream has changed so CRC capture needs to re-enabled. */ source = dm_new_crtc_state->crc_src; if (amdgpu_dm_is_valid_crc_source(source)) { - dm_new_crtc_state->crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE; - if (source == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) - amdgpu_dm_crtc_set_crc_source(crtc, "crtc"); - else if (source == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) - amdgpu_dm_crtc_set_crc_source(crtc, "dprx"); + amdgpu_dm_crtc_configure_crc_source( + crtc, dm_new_crtc_state, + dm_new_crtc_state->crc_src); } #endif } @@ -6022,23 +6020,8 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev, if (dm_old_crtc_state->interrupts_enabled && (!dm_new_crtc_state->interrupts_enabled || -drm_atomic_crtc_needs_modeset(new_crtc_state))) { - /* -* Drop the extra vblank reference added by CRC -* capture if applicable. -*/ - if (amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) - drm_crtc_vblank_put(crtc); - - /* -* Only keep CRC capture enabled if there's -* still a stream for the CRTC. -*/ - if (!dm_new_crtc_state->stream) - dm_new_crtc_state->crc_src = AMDGPU_DM_PIPE_CRC_SOURCE_NONE; - +drm_atomic_crtc_needs_modeset(new_crtc_state))) manage_dm_interrupts(adev, acrtc, false); - } } /* * Add check here for SoC's that support hardware cursor plane, to diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index c57ff8821fe2..e9d5b1fad625 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -96,11 +96,46 @@ amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name, return 0; } -int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) +int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, + struct dm_crtc_state *dm_crtc_state, + enum amdgpu_dm_pipe_crc_source source) { struct amdgpu_device *adev = crtc->dev->dev_private; + struct dc_stream_state *stream_state = dm_crtc_state->stream; + bool enable = amdgpu_dm_is_valid_crc_source(source); + int ret = 0; + + /* Configuration will be deferred to stream enable. */ + if (!stream_state) + return 0; + + mutex_lock(>dm.dc_lock); + + /* Enable CRTC CRC generation if necessary. */ + if (dm_is_crc_source_crtc(source)) { + if (!dc_stream_configure_crc(stream_state->ctx->dc, +stream_state, enable, enable)) { + ret = -EINVAL; + goto unlock; + } + } + +
[PATCH 2/2] drm/amd/display: Block immediate flips for non-fast updates
[Why] Underflow can occur in the case where we change buffer pitch, DCC state, rotation or mirroring for a plane while also performing an immediate flip. It can also generate a p-state warning stack trace on DCN1 which is typically observed during the cursor handler pipe locking because of how frequent cursor updates can occur. [How] Store the update type on each CRTC - every plane will have access to the CRTC state if it's flipping. If the update type is not UPDATE_TYPE_FAST then the immediate flip should be disallowed. No changes to the target vblank sequencing need to be done, we just need to ensure that the surface registers do a double buffered update. Cc: David Francis Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c| 16 +++- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h| 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ffb3c7247ac6..e941d0d3794b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5690,8 +5690,14 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].plane_info = >plane_infos[planes_count]; + /* +* Only allow immediate flips for fast updates that don't +* change FB pitch, DCC state, rotation or mirroing. +*/ bundle->flip_addrs[planes_count].flip_immediate = - (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0; + (crtc->state->pageflip_flags & +DRM_MODE_PAGE_FLIP_ASYNC) != 0 && + acrtc_state->update_type == UPDATE_TYPE_FAST; timestamp_ns = ktime_get_ns(); bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); @@ -7311,6 +7317,14 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, state->async_update = !drm_atomic_helper_async_check(dev, state); } + /* Store the overall update type for use later in atomic check. */ + for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) { + struct dm_crtc_state *dm_new_crtc_state = + to_dm_crtc_state(new_crtc_state); + + dm_new_crtc_state->update_type = (int)overall_update_type; + } + /* Must be success */ WARN_ON(ret); return ret; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index da48a857949f..cbd6608f58e6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -307,6 +307,7 @@ struct dm_crtc_state { bool cm_has_degamma; bool cm_is_degamma_srgb; + int update_type; int active_planes; bool interrupts_enabled; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/2] drm/amd/display: Validate dc_plane_info and dc_plane_size in atomic check
[Why] Pitch, DCC, rotation and mirroring can result in updates that are not UPDATE_TYPE_FAST but UPDATE_TYPE_MED instead. DC needs dc_plane_info and dc_plane_size to make this determination and we aren't currently passing this into DC during atomic check. Underflow (visible or non-visible) can occur if we don't validate this correctly. This also will generally trigger p-state warnings, typically via the cursor handler when locking. [How] Get the framebuffer tiling flags and generate the required structures for DC in dm_determine_update_type_for_commit. Cc: David Francis Cc: Bhawanpreet Lakha Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 +++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 040169180a63..ffb3c7247ac6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6987,6 +6987,12 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, continue; for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { + const struct amdgpu_framebuffer *amdgpu_fb = + to_amdgpu_framebuffer(new_plane_state->fb); + struct dc_plane_info plane_info; + struct dc_flip_addrs flip_addr; + uint64_t tiling_flags; + new_plane_crtc = new_plane_state->crtc; old_plane_crtc = old_plane_state->crtc; new_dm_plane_state = to_dm_plane_state(new_plane_state); @@ -7030,6 +7036,24 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, updates[num_plane].scaling_info = _info; + if (amdgpu_fb) { + ret = get_fb_info(amdgpu_fb, _flags); + if (ret) + goto cleanup; + + memset(_addr, 0, sizeof(flip_addr)); + + ret = fill_dc_plane_info_and_addr( + dm->adev, new_plane_state, tiling_flags, + _info, + _addr.address); + if (ret) + goto cleanup; + + updates[num_plane].plane_info = _info; + updates[num_plane].flip_addr = _addr; + } + num_plane++; } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/3] drm/amd/display: Skip determining update type for async updates
[Why] By passing through the dm_determine_update_type_for_commit for atomic commits that can be done asynchronously we are incurring a performance penalty by locking access to the global private object and holding that access until the end of the programming sequence. This is also allocating a new large dc_state on every access in addition to retaining all the references on each stream and plane until the end of the programming sequence. [How] Shift the determination for async update before validation. Return early if it's going to be an async update. Cc: Leo Li Cc: David Francis Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 27 ++- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 2efb0eadf602..4c90662e9fa2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7216,6 +7216,26 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (ret) goto fail; + if (state->legacy_cursor_update) { + /* +* This is a fast cursor update coming from the plane update +* helper, check if it can be done asynchronously for better +* performance. +*/ + state->async_update = + !drm_atomic_helper_async_check(dev, state); + + /* +* Skip the remaining global validation if this is an async +* update. Cursor updates can be done without affecting +* state or bandwidth calcs and this avoids the performance +* penalty of locking the private state object and +* allocating a new dc_state. +*/ + if (state->async_update) + return 0; + } + /* Check scaling and underscan changes*/ /* TODO Removed scaling changes validation due to inability to commit * new stream into context w\o causing full reset. Need to @@ -7268,13 +7288,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = -EINVAL; goto fail; } - } else if (state->legacy_cursor_update) { - /* -* This is a fast cursor update coming from the plane update -* helper, check if it can be done asynchronously for better -* performance. -*/ - state->async_update = !drm_atomic_helper_async_check(dev, state); } /* Must be success */ -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 3/3] drm/amd/display: Don't replace the dc_state for fast updates
[Why] DRM private objects have no hw_done/flip_done fencing mechanism on their own and cannot be used to sequence commits accordingly. When issuing commits that don't touch the same set of hardware resources like page-flips on different CRTCs we can run into the issue below because of this: 1. Client requests non-blocking Commit #1, has a new dc_state #1, state is swapped, commit tail is deferred to work queue 2. Client requests non-blocking Commit #2, has a new dc_state #2, state is swapped, commit tail is deferred to work queue 3. Commit #2 work starts, commit tail finishes, atomic state is cleared, dc_state #1 is freed 4. Commit #1 work starts, commit tail encounters null pointer deref on dc_state #1 In order to change the DC state as in the private object we need to ensure that we wait for all outstanding commits to finish and that any other pending commits must wait for the current one to finish as well. We do this for MEDIUM and FULL updates. But not for FAST updates, nor would we want to since it would cause stuttering from the delays. FAST updates that go through dm_determine_update_type_for_commit always create a new dc_state and lock the DRM private object if there are any changed planes. We need the old state to validate, but we don't actually need the new state here. [How] If the commit isn't a full update then the use after free can be resolved by simply discarding the new state entirely and retaining the existing one instead. With this change the sequence above can be reexamined. Commit #2 will still free Commit #1's reference, but before this happens we actually added an additional reference as part of Commit #2. If an update comes in during this that needs to change the dc_state it will need to wait on Commit #1 and Commit #2 to finish. Then it'll swap the state, finish the work in commit tail and drop the last reference on Commit #2's dc_state. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=204181 Cc: Leo Li Cc: David Francis Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 4c90662e9fa2..fe5291b16193 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -7288,6 +7288,29 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = -EINVAL; goto fail; } + } else { + /* +* The commit is a fast update. Fast updates shouldn't change +* the DC context, affect global validation, and can have their +* commit work done in parallel with other commits not touching +* the same resource. If we have a new DC context as part of +* the DM atomic state from validation we need to free it and +* retain the existing one instead. +*/ + struct dm_atomic_state *new_dm_state, *old_dm_state; + + new_dm_state = dm_atomic_get_new_state(state); + old_dm_state = dm_atomic_get_old_state(state); + + if (new_dm_state && old_dm_state) { + if (new_dm_state->context) + dc_release_state(new_dm_state->context); + + new_dm_state->context = old_dm_state->context; + + if (old_dm_state->context) + dc_retain_state(old_dm_state->context); + } } /* Must be success */ -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/3] drm/amd/display: Allow cursor async updates for framebuffer swaps
[Why] We previously allowed framebuffer swaps as async updates for cursor planes but had to disable them due to a bug in DRM with async update handling and incorrect ref counting. The check to block framebuffer swaps has been added to DRM for a while now, so this check is redundant. The real fix that allows this to properly in DRM has also finally been merged and is getting backported into stable branches, so dropping this now seems to be the right time to do so. [How] Drop the redundant check for old_fb != new_fb. With the proper fix in DRM, this should also fix some cursor stuttering issues with xf86-video-amdgpu since it double buffers the cursor. IGT tests that swap framebuffers (-varying-size for example) should also pass again. Cc: Leo Li Cc: David Francis Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 -- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 040169180a63..2efb0eadf602 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4504,20 +4504,10 @@ static int dm_plane_atomic_check(struct drm_plane *plane, static int dm_plane_atomic_async_check(struct drm_plane *plane, struct drm_plane_state *new_plane_state) { - struct drm_plane_state *old_plane_state = - drm_atomic_get_old_plane_state(new_plane_state->state, plane); - /* Only support async updates on cursor planes. */ if (plane->type != DRM_PLANE_TYPE_CURSOR) return -EINVAL; - /* -* DRM calls prepare_fb and cleanup_fb on new_plane_state for -* async commits so don't allow fb changes. -*/ - if (old_plane_state->fb != new_plane_state->fb) - return -EINVAL; - return 0; } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/2] drm/amd/display: Embed DCN2 SOC bounding box
[Why] In order to support uclk switching on NV10 the SOC bounding box needs to be updated. [How] We currently read the constants from the gpu info FW, but supporting workarounds in DC for different versions of the FW adds additional complexity to the codebase. NV10 has been released so it's cleanest to keep the bounding box and source code in sync by embedding the bounding box like we do for other ASICs. Fixes: 02316e963a5a ("drm/amd/display: Force uclk to max for every state") Cc: Alex Deucher Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../drm/amd/display/dc/dcn20/dcn20_resource.c | 114 +- 1 file changed, 112 insertions(+), 2 deletions(-) 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 44537651f0a1..ff30f5cc4981 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -80,7 +80,7 @@ #include "amdgpu_socbb.h" -#define SOC_BOUNDING_BOX_VALID false +#define SOC_BOUNDING_BOX_VALID true #define DC_LOGGER_INIT(logger) struct _vcs_dpi_ip_params_st dcn2_0_ip = { @@ -154,7 +154,117 @@ struct _vcs_dpi_ip_params_st dcn2_0_ip = { .xfc_fill_constant_bytes = 0, }; -struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = { 0 }; +struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = { + /* Defaults that get patched on driver load from firmware. */ + .clock_limits = { + { + .state = 0, + .dcfclk_mhz = 560.0, + .fabricclk_mhz = 560.0, + .dispclk_mhz = 513.0, + .dppclk_mhz = 513.0, + .phyclk_mhz = 540.0, + .socclk_mhz = 560.0, + .dscclk_mhz = 171.0, + .dram_speed_mts = 8960.0, + }, + { + .state = 1, + .dcfclk_mhz = 694.0, + .fabricclk_mhz = 694.0, + .dispclk_mhz = 642.0, + .dppclk_mhz = 642.0, + .phyclk_mhz = 600.0, + .socclk_mhz = 694.0, + .dscclk_mhz = 214.0, + .dram_speed_mts = 11104.0, + }, + { + .state = 2, + .dcfclk_mhz = 875.0, + .fabricclk_mhz = 875.0, + .dispclk_mhz = 734.0, + .dppclk_mhz = 734.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 875.0, + .dscclk_mhz = 245.0, + .dram_speed_mts = 14000.0, + }, + { + .state = 3, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 1000.0, + .dispclk_mhz = 1100.0, + .dppclk_mhz = 1100.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1000.0, + .dscclk_mhz = 367.0, + .dram_speed_mts = 16000.0, + }, + { + .state = 4, + .dcfclk_mhz = 1200.0, + .fabricclk_mhz = 1200.0, + .dispclk_mhz = 1284.0, + .dppclk_mhz = 1284.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1200.0, + .dscclk_mhz = 428.0, + .dram_speed_mts = 16000.0, + }, + /*Extra state, no dispclk ramping*/ + { + .state = 5, + .dcfclk_mhz = 1200.0, + .fabricclk_mhz = 1200.0, + .dispclk_mhz = 1284.0, + .dppclk_mhz = 1284.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1200.0, + .dscclk_mhz = 428.0, + .dram_speed_mts = 16000.0, + }, + }, + .num_states = 5, + .sr_exit_time_us = 8.6, + .sr_enter_plus_exit_time_us = 10.9, + .urgent_latency_us = 4.0, + .urgent_latency_pixe
[PATCH 1/2] drm/amd/display: Expose audio inst from DC to DM
[Why] In order to give pin notifications to the sound driver from DM we need to know whether audio is enabled on a stream and what pin it's using from DC. [How] Expose the instance via stream status if it's a mapped resource for the stream. It will be -1 if there's no audio mapped. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 3 +++ drivers/gpu/drm/amd/display/dc/dc_stream.h| 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index d10ebfd33a60..5b85139fb3ce 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2008,6 +2008,9 @@ enum dc_status resource_map_pool_resources( if (context->streams[i] == stream) { context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->id; + context->stream_status[i].audio_inst = + pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1; + return DC_OK; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index e253a5c591f6..0fa1c26bc20d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -42,6 +42,7 @@ struct dc_stream_status { int primary_otg_inst; int stream_enc_inst; int plane_count; + int audio_inst; struct timing_sync_info timing_sync_info; struct dc_plane_state *plane_states[MAX_SURFACE_NUM]; }; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/2] drm/amd/display: Add drm_audio_component support to amdgpu_dm
[Why] The drm_audio_component can be used to give pin ELD notifications directly to the sound driver. This fixes audio endpoints disappearing due to missing unsolicited notifications. [How] Send the notification via the audio component whenever we enable or disable audio state on a stream. This matches what i915 does with their drm_audio_component and what Takashi Iwai's proposed hack for radeon/amdpgu did. This is a bit delayed in when the notification actually occurs, however. We wait until after all the programming is complete rather than sending the notification mid sequence. Particular care is needed for the get ELD callback since it can happen outside the locking and fencing DRM does for atomic commits. Cc: Takashi Iwai Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 222 ++ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 25 ++ 2 files changed, 247 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f26c7b348aa9..9ef785497eb5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,7 @@ #include #include #include +#include #if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" @@ -506,6 +508,139 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector) } +static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, + int pipe, bool *enabled, + unsigned char *buf, int max_bytes) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = dev->dev_private; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct amdgpu_dm_connector *aconnector; + int ret = 0; + + *enabled = false; + + mutex_lock(>dm.audio_lock); + + drm_connector_list_iter_begin(dev, _iter); + drm_for_each_connector_iter(connector, _iter) { + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->audio_inst != port) + continue; + + *enabled = true; + ret = drm_eld_size(connector->eld); + memcpy(buf, connector->eld, min(max_bytes, ret)); + + break; + } + drm_connector_list_iter_end(_iter); + + mutex_unlock(>dm.audio_lock); + + DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); + + return ret; +} + +static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = { + .get_eld = amdgpu_dm_audio_component_get_eld, +}; + +static int amdgpu_dm_audio_component_bind(struct device *kdev, + struct device *hda_kdev, void *data) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = dev->dev_private; + struct drm_audio_component *acomp = data; + + acomp->ops = _dm_audio_component_ops; + acomp->dev = kdev; + adev->dm.audio_component = acomp; + + return 0; +} + +static void amdgpu_dm_audio_component_unbind(struct device *kdev, + struct device *hda_kdev, void *data) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = dev->dev_private; + struct drm_audio_component *acomp = data; + + acomp->ops = NULL; + acomp->dev = NULL; + adev->dm.audio_component = NULL; +} + +static const struct component_ops amdgpu_dm_audio_component_bind_ops = { + .bind = amdgpu_dm_audio_component_bind, + .unbind = amdgpu_dm_audio_component_unbind, +}; + +static int amdgpu_dm_audio_init(struct amdgpu_device *adev) +{ + int i, ret; + + if (!amdgpu_audio) + return 0; + + adev->mode_info.audio.enabled = true; + + adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count; + + for (i = 0; i < adev->mode_info.audio.num_pins; i++) { + adev->mode_info.audio.pin[i].channels = -1; + adev->mode_info.audio.pin[i].rate = -1; + adev->mode_info.audio.pin[i].bits_per_sample = -1; + adev->mode_info.audio.pin[i].status_bits = 0; + adev->mode_info.audio.pin[i].category_code = 0; + adev->mode_info.audio.pin[i].connected = false; + adev->mode_info.audio.pin[i].id = + adev->dm.dc->res_pool->audios[i]->inst; + adev->mode_info.audio.pin[i].offset = 0; + } + + ret = component_add(adev->dev,
[PATCH v2] drm/amd/display: update infoframe after dig fe is turned on (v2)
[Why] The AVI infoframe is incorrectly programmed on DCN1/2 when enabling a stream - causing the wrong pixel encoding to be used for display. This is because the AVI infoframe is programmed before the DIG BE is connected to the FE and turned on, so enabling the AFMT block doesn't actually work and the registers subsequently can't be written to. [How] Program the infoframe *after* turning on the DIG FE. This was the behavior previously used but it was incorrectly reverted when adding the DCN2 HW sequencer code. v2: Don't call update_info_frame twice Fixes: 54ff35915948 ("drm/amd/display: Add DCN2 HW Sequencer and Resource") Cc: Harry Wentland Cc: Roman Li Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 1 + 1 file changed, 1 insertion(+) 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 index 940e74b7d2c6..84d90b475e2a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -686,6 +686,7 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) dmdata_dp : dmdata_hdmi); } #endif + dce110_update_info_frame(pipe_ctx); /* enable early control to avoid corruption on DP monitor*/ active_total_with_borders = -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: update infoframe after dig fe is turned on (v2)
[Why] The AVI infoframe is incorrectly programmed on DCN1/2 when enabling a stream - causing the wrong pixel encoding to be used for display. This is because the AVI infoframe is programmed before the DIG BE is connected to the FE and turned on, so enabling the AFMT block doesn't actually work and the registers subsequently can't be written to. [How] Program the infoframe *after* turning on the DIG FE. This was the behavior previously used but it was incorrectly reverted when adding the DCN2 HW sequencer code. Fixes: 54ff35915948 ("drm/amd/display: Add DCN2 HW Sequencer and Resource") Cc: Harry Wentland Cc: Roman Li Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 2 ++ 1 file changed, 2 insertions(+) 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 index 940e74b7d2c6..b4b8ded16e22 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -666,6 +666,7 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) /* update AVI info frame (HDMI, DP)*/ /* TODO: FPGA may change to hwss.update_info_frame */ + dce110_update_info_frame(pipe_ctx); #if defined(CONFIG_DRM_AMD_DC_DCN2_0) if (pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata != NULL && @@ -686,6 +687,7 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) dmdata_dp : dmdata_hdmi); } #endif + dce110_update_info_frame(pipe_ctx); /* enable early control to avoid corruption on DP monitor*/ active_total_with_borders = -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] Revert "drm/amd/display: Enable fast plane updates when state->allow_modeset = true"
This reverts commit ebc8c6f18322ad54275997a888ca1731d74b711f. There are still missing corner cases with cursor interaction and these fast plane updates on Picasso and Raven2 leading to endless PSTATE warnings for typical desktop usage depending on the userspace. This change should be reverted until these issues have been resolved. Cc: David Francis Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 33dcd4187157..d6acbcfa570c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6471,6 +6471,14 @@ static bool should_reset_plane(struct drm_atomic_state *state, struct drm_crtc_state *new_crtc_state; int i; + /* +* TODO: Remove this hack once the checks below are sufficient +* enough to determine when we need to reset all the planes on +* the stream. +*/ + if (state->allow_modeset) + return true; + /* Exit early if we know that we're adding or removing the plane. */ if (old_plane_state->crtc != new_plane_state->crtc) return true; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Allow cursor async updates for framebuffer swaps
[Why] We previously allowed framebuffer swaps as async updates for cursor planes but had to disable them due to a bug in DRM with async update handling and incorrect ref counting. The check to block framebuffer swaps has been added to DRM for a while now, so this check is redundant. The real fix that allows this to properly in DRM has also finally been merged and is getting backported into stable branches, so dropping this now seems to be the right time to do so. [How] Drop the redundant check for old_fb != new_fb. With the proper fix in DRM, this should also fix some cursor stuttering issues with xf86-video-amdgpu since it double buffers the cursor. IGT tests that swap framebuffers (-varying-size for example) should also pass again. Cc: David Francis Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 -- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 45f0d5b6c468..100b2c60ff1c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4315,20 +4315,10 @@ static int dm_plane_atomic_check(struct drm_plane *plane, static int dm_plane_atomic_async_check(struct drm_plane *plane, struct drm_plane_state *new_plane_state) { - struct drm_plane_state *old_plane_state = - drm_atomic_get_old_plane_state(new_plane_state->state, plane); - /* Only support async updates on cursor planes. */ if (plane->type != DRM_PLANE_TYPE_CURSOR) return -EINVAL; - /* -* DRM calls prepare_fb and cleanup_fb on new_plane_state for -* async commits so don't allow fb changes. -*/ - if (old_plane_state->fb != new_plane_state->fb) - return -EINVAL; - return 0; } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Enable fast plane updates when state->allow_modeset = true
[Why] Whenever the a modeset is allowed (but not neccessarily required) we currently recreate all the planes in the state. Most IGT tests and legacy IOCTLs create atomic commits with this flag set, so the pipes are often unnecessarily reprogrammed. Poor performance and stuttering can occur when many of these commits are frequently issued. This flag was needed when the appropriate conditions for checking whether the planes needed a reset were not in place, but should_reset_plane should cover everything needed now. [How] Drop the check for state->allow_modeset in should_reset_plane. All planes on a CRTC should reset in the following conditions: - The CRTC needs a modeset - The CRTC degamma changes - Planes are added or removed to the CRTC These conditions are all covered in should_reset_plane. We still can't drop the format change check in should_reset_plane since fill_dc_plane_info_and_addr isn't called when validating the state, so we can't tell if a FULL update is needed or not. Cc: David Francis Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a698c8f272ed..45f0d5b6c468 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6446,14 +6446,6 @@ static bool should_reset_plane(struct drm_atomic_state *state, struct drm_crtc_state *new_crtc_state; int i; - /* -* TODO: Remove this hack once the checks below are sufficient -* enough to determine when we need to reset all the planes on -* the stream. -*/ - if (state->allow_modeset) - return true; - /* Exit early if we know that we're adding or removing the plane. */ if (old_plane_state->crtc != new_plane_state->crtc) return true; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/2] drm/amd/display: Set default ABM level to module parameter
[Why] The module parameter to specify the default ABM level is now defined, so hook it up in DM. [How] On connector reset specify the default level. DC will program this as part of the modeset since it gets passed onto the stream in dm_update_crtc_state. It's only set for eDP connectors, but it doesn't matter if this is specified for connectors or hardware that doesn't support ABM. It's DC's responsibility to check that ABM can be set or adjusted, and DC does check that the DMCU firmware is running and if there's backlight control available. Cc: Harry Wentland Cc: David Francis Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a698c8f272ed..f0c216d78a07 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3821,6 +3821,9 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->underscan_hborder = 0; state->underscan_vborder = 0; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + state->abm_level = amdgpu_dm_abm_level; + __drm_atomic_helper_connector_reset(connector, >base); } } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/2] drm/amd/amdgpu: Add module parameter for specifying default ABM level
[Why] It's non trivial to configure or specify an ABM reduction level for userspace outside of X. There is also no method to specify the default ABM value at boot time. A parameter should be added to configure this. [How] Expose a module parameter that can specify the default ABM level to use for eDP connectors on DC enabled hardware that loads the DMCU firmware. The default is still disabled (0), but levels can range from 1-4. Levels control how much the backlight can be reduced, with being the least amount of reduction and four being the most reduction. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 16 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 19a00282e34c..4beb26738e1e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -155,6 +155,7 @@ extern int amdgpu_gpu_recovery; extern int amdgpu_emu_mode; extern uint amdgpu_smu_memory_pool_size; extern uint amdgpu_dc_feature_mask; +extern uint amdgpu_dm_abm_level; extern struct amdgpu_mgpu_info mgpu_info; extern int amdgpu_ras_enable; extern uint amdgpu_ras_mask; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 1f38d6fc1fe3..dde53f8e230b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -686,6 +686,22 @@ MODULE_PARM_DESC(hws_gws_support, "MEC FW support gws barriers (false = not supp MODULE_PARM_DESC(dcfeaturemask, "all stable DC features enabled (default))"); module_param_named(dcfeaturemask, amdgpu_dc_feature_mask, uint, 0444); +/** + * DOC: abmlevel (uint) + * Override the default ABM (Adaptive Backlight Management) level used for DC + * enabled hardware. Requires DMCU to be supported and loaded. + * Valid levels are 0-4. A value of 0 indicates that ABM should be disabled by + * default. Values 1-4 control the maximum allowable brightness reduction via + * the ABM algorithm, with 1 being the least reduction and 4 being the most + * reduction. + * + * Defaults to 0, or disabled. Userspace can still override this level later + * after boot. + */ +uint amdgpu_dm_abm_level = 0; +MODULE_PARM_DESC(abmlevel, "ABM level (0 = off (default), 1-4 = backlight reduction level) "); +module_param_named(abmlevel, amdgpu_dm_abm_level, uint, 0444); + static const struct pci_device_id pciidlist[] = { #ifdef CONFIG_DRM_AMDGPU_SI {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI}, -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Use current connector state if NULL when checking bpc
[Why] The old logic for checking which output depth to use relied on using the current connector state rather than the new proposed state. This was a problem when performing atomic commits since we weren't verifying it against the incoming max_requested_bpc. But switching this to only use the new state and not the current state breaks filtering modes - it'll always assume that the maximum bpc supported by the display is in use, which will cause certain modes like 1440p@144Hz to be filtered even when using 8bpc. [How] Still use the connector->state if we aren't passed an explicit state. This will respect the max_bpc the user currently has when filtering modes. Also remember to reset the default max_requested_bpc to 8 whenever connector reset is called to retain old behavior when using the new property. Cc: Harry Wentland Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a698c8f272ed..f627c17a1039 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3046,6 +3046,9 @@ convert_color_depth_from_display_info(const struct drm_connector *connector, { uint32_t bpc = connector->display_info.bpc; + if (!state) + state = connector->state; + if (state) { bpc = state->max_bpc; /* Round down to the nearest even number. */ @@ -3820,6 +3823,7 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->underscan_enable = false; state->underscan_hborder = 0; state->underscan_vborder = 0; + state->base.max_requested_bpc = 8; __drm_atomic_helper_connector_reset(connector, >base); } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Always allocate initial connector state state
[Why] Unlike our regular connectors, MST connectors don't start off with an initial connector state. This causes a NULL pointer dereference to occur when attaching the bpc property since it tries to modify the connector state. We need an initial connector state on the connector to avoid the crash. [How] Use our reset helper to allocate an initial state and reset the values to their defaults. We were already doing this before, just not for MST connectors. Cc: Leo Li Cc: Roman Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a698c8f272ed..4523ab100bc3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4743,6 +4743,13 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, { struct amdgpu_device *adev = dm->ddev->dev_private; + /* +* Some of the properties below require access to state, like bpc. +* Allocate some default initial connector state with our reset helper. +*/ + if (aconnector->base.funcs->reset) + aconnector->base.funcs->reset(>base); + aconnector->connector_id = link_index; aconnector->dc_link = link; aconnector->base.interlace_allowed = false; @@ -4932,9 +4939,6 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, >base, _dm_connector_helper_funcs); - if (aconnector->base.funcs->reset) - aconnector->base.funcs->reset(>base); - amdgpu_dm_connector_init_helper( dm, aconnector, -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH v2] drm/amd/display: Add connector debugfs for "output_bpc"
[Why] This will be useful for verifying whether we enter the correct output color depth from IGT. [How] Locks the connector and associated CRTC if available and outputs the current and maximum output bpc values. Example: cat /sys/kernel/debug/dri/0/DP-1/output_bpc Current: 8 Maximum: 10 v2: Drop unneeded connector status check Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 71 ++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 1d5fc5ad3bee..a3e362fa6747 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -672,6 +672,71 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us return bytes_from_user; } +/* + * Returns the current and maximum output bpc for the connector. + * Example usage: cat /sys/kernel/debug/dri/0/DP-1/output_bpc + */ +static int output_bpc_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = NULL; + struct dm_crtc_state *dm_crtc_state = NULL; + int res = -ENODEV; + unsigned int bpc; + + mutex_lock(>mode_config.mutex); + drm_modeset_lock(>mode_config.connection_mutex, NULL); + + if (connector->state == NULL) + goto unlock; + + crtc = connector->state->crtc; + if (crtc == NULL) + goto unlock; + + drm_modeset_lock(>mutex, NULL); + if (crtc->state == NULL) + goto unlock; + + dm_crtc_state = to_dm_crtc_state(crtc->state); + if (dm_crtc_state->stream == NULL) + goto unlock; + + switch (dm_crtc_state->stream->timing.display_color_depth) { + case COLOR_DEPTH_666: + bpc = 6; + break; + case COLOR_DEPTH_888: + bpc = 8; + break; + case COLOR_DEPTH_101010: + bpc = 10; + break; + case COLOR_DEPTH_121212: + bpc = 12; + break; + case COLOR_DEPTH_161616: + bpc = 16; + break; + default: + goto unlock; + } + + seq_printf(m, "Current: %u\n", bpc); + seq_printf(m, "Maximum: %u\n", connector->display_info.bpc); + res = 0; + +unlock: + if (crtc) + drm_modeset_unlock(>mutex); + + drm_modeset_unlock(>mode_config.connection_mutex); + mutex_unlock(>mode_config.mutex); + + return res; +} + /* * Returns the min and max vrr vfreq through the connector's debugfs file. * Example usage: cat /sys/kernel/debug/dri/0/DP-1/vrr_range @@ -730,8 +795,6 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b return write_size; } -DEFINE_SHOW_ATTRIBUTE(vrr_range); - static ssize_t dp_dpcd_address_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { @@ -814,6 +877,9 @@ static ssize_t dp_dpcd_data_read(struct file *f, char __user *buf, return read_size - r; } +DEFINE_SHOW_ATTRIBUTE(output_bpc); +DEFINE_SHOW_ATTRIBUTE(vrr_range); + static const struct file_operations dp_link_settings_debugfs_fops = { .owner = THIS_MODULE, .read = dp_link_settings_read, @@ -866,6 +932,7 @@ static const struct { {"link_settings", _link_settings_debugfs_fops}, {"phy_settings", _phy_settings_debugfs_fop}, {"test_pattern", _phy_test_pattern_fops}, + {"output_bpc", _bpc_fops}, {"vrr_range", _range_fops}, {"sdp_message", _message_fops}, {"aux_dpcd_address", _dpcd_address_debugfs_fops}, -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Add connector debugfs for "output_bpc"
[Why] This will be useful for verifying whether we enter the correct output color depth from IGT. [How] Locks the connector and associated CRTC if available and outputs the current and maximum output bpc values. Example: cat /sys/kernel/debug/dri/0/DP-1/output_bpc Current: 8 Maximum: 10 Change-Id: Ic881c0c729c5444b80256ccfe55ac52cec345388 Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 74 ++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 1d5fc5ad3bee..0de86a7e31b5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -672,6 +672,74 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us return bytes_from_user; } +/* + * Returns the current and maximum output bpc for the connector. + * Example usage: cat /sys/kernel/debug/dri/0/DP-1/output_bpc + */ +static int output_bpc_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = NULL; + struct dm_crtc_state *dm_crtc_state = NULL; + int res = -ENODEV; + unsigned int bpc; + + mutex_lock(>mode_config.mutex); + drm_modeset_lock(>mode_config.connection_mutex, NULL); + + if (connector->state == NULL) + goto unlock; + + crtc = connector->state->crtc; + if (crtc == NULL) + goto unlock; + + drm_modeset_lock(>mutex, NULL); + if (crtc->state == NULL) + goto unlock; + + dm_crtc_state = to_dm_crtc_state(crtc->state); + if (dm_crtc_state->stream == NULL) + goto unlock; + + if (connector->status != connector_status_connected) + return -ENODEV; + + switch (dm_crtc_state->stream->timing.display_color_depth) { + case COLOR_DEPTH_666: + bpc = 6; + break; + case COLOR_DEPTH_888: + bpc = 8; + break; + case COLOR_DEPTH_101010: + bpc = 10; + break; + case COLOR_DEPTH_121212: + bpc = 12; + break; + case COLOR_DEPTH_161616: + bpc = 16; + break; + default: + goto unlock; + } + + seq_printf(m, "Current: %u\n", bpc); + seq_printf(m, "Maximum: %u\n", connector->display_info.bpc); + res = 0; + +unlock: + if (crtc) + drm_modeset_unlock(>mutex); + + drm_modeset_unlock(>mode_config.connection_mutex); + mutex_unlock(>mode_config.mutex); + + return res; +} + /* * Returns the min and max vrr vfreq through the connector's debugfs file. * Example usage: cat /sys/kernel/debug/dri/0/DP-1/vrr_range @@ -730,8 +798,6 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b return write_size; } -DEFINE_SHOW_ATTRIBUTE(vrr_range); - static ssize_t dp_dpcd_address_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { @@ -814,6 +880,9 @@ static ssize_t dp_dpcd_data_read(struct file *f, char __user *buf, return read_size - r; } +DEFINE_SHOW_ATTRIBUTE(output_bpc); +DEFINE_SHOW_ATTRIBUTE(vrr_range); + static const struct file_operations dp_link_settings_debugfs_fops = { .owner = THIS_MODULE, .read = dp_link_settings_read, @@ -866,6 +935,7 @@ static const struct { {"link_settings", _link_settings_debugfs_fops}, {"phy_settings", _phy_settings_debugfs_fop}, {"test_pattern", _phy_test_pattern_fops}, + {"output_bpc", _bpc_fops}, {"vrr_range", _range_fops}, {"sdp_message", _message_fops}, {"aux_dpcd_address", _dpcd_address_debugfs_fops}, -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Add back missing hw translate init for DCN1_01
[Why] DCN_VERSION_1_01 is no longer handled in the dal_hw_translate_init switch since it was inadvertently dropped in the patch that removed the unnecessary DCN1_01 guards. This caused numerous regressions on DCN1_01 when loading the driver. [How] Add it back. Cc: Harry Wentland Fixes: 97df424fe7a7 ("drm/amd/display: Drop DCN1_01 guards") Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index 77615146b96e..1f9833dc8cfe 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -81,6 +81,7 @@ bool dal_hw_translate_init( return true; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: + case DCN_VERSION_1_01: dal_hw_translate_dcn10_init(translate); return true; #endif -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Don't set mode_changed=false if the stream was removed
[Why] When switching from vt to desktop with EDID emulation we can receive an atomic commit such that we have a crtc where mode_changed = true. During the dm_update_crtc_state disable pass we remove the stream from the context and free it on the dm_new_crtc_state. During the enable pass we compare the new provisional stream to the dm_old_crtc_state->stream and determine that the stream is unchanged and no scaling has been changed. Following this, new_crtc_state->mode_changed is then set to false. The connectors haven't changed and the CRTC active state hasn't changed so drm_atomic_crtc_needs_modeset returns false, so we jump to skip_modeset and we hit: BUG_ON(dm_new_crtc_state->stream == NULL); ...since the old stream is gone from the context and the new stream is also still NULL. [How] Ensure that we still a stream to reuse before checking if we can reuse the old stream without a full modeset. Cc: Roman Li Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 57359037ed7c..796f83ca7a4c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6248,7 +6248,17 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level; - if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && + /* +* If we already removed the old stream from the context +* (and set the new stream to NULL) then we can't reuse +* the old stream even if the stream and scaling are unchanged. +* We'll hit the BUG_ON and black screen. +* +* TODO: Refactor this function to allow this check to work +* in all conditions. +*/ + if (dm_new_crtc_state->stream && + dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) { new_crtc_state->mode_changed = false; DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d", -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 0/2] drm/amd/display: Add HDR output metadata support for amdgpu
This patch series enables HDR output metadata support in amdgpu using the DRM HDR interface merged in drm-misc-next. Enabled for DCE and DCN ASICs over DP and HDMI. It's limited to static HDR metadata support for now since that's all the DRM interface supports. It requires a modeset for entering and exiting HDR but the metadata can be changed without one. Cc: Harry Wentland Nicholas Kazlauskas (2): drm/amd/display: Expose HDR output metadata for supported connectors drm/amd/display: Only force modesets when toggling HDR .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 155 +- 1 file changed, 151 insertions(+), 4 deletions(-) -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/2] drm/amd/display: Expose HDR output metadata for supported connectors
[Why] For userspace to send static HDR metadata to the display we need to attach the property on the connector and send it to DC. [How] The property is attached to HDMI and DP connectors. Since the metadata isn't actually available when creating the connector this isn't a property we can dynamically support based on the extension block being available or not. When the HDR metadata is changed a modeset will be forced for now. We need to switch from 8bpc to 10bpc in most cases anyway, and we want to fully exit HDR mode when userspace gives us a NULL metadata, so this isn't completely unnecessary. The requirement can later be reduced to just entering and exiting HDR or switching max bpc. Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 125 ++ 1 file changed, 125 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 995f9df66142..eb31acca7ed6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3871,6 +3871,121 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec return result; } +static int fill_hdr_info_packet(const struct drm_connector_state *state, + struct dc_info_packet *out) +{ + struct hdmi_drm_infoframe frame; + unsigned char buf[30]; /* 26 + 4 */ + ssize_t len; + int ret, i; + + memset(out, 0, sizeof(*out)); + + if (!state->hdr_output_metadata) + return 0; + + ret = drm_hdmi_infoframe_set_hdr_metadata(, state); + if (ret) + return ret; + + len = hdmi_drm_infoframe_pack_only(, buf, sizeof(buf)); + if (len < 0) + return (int)len; + + /* Static metadata is a fixed 26 bytes + 4 byte header. */ + if (len != 30) + return -EINVAL; + + /* Prepare the infopacket for DC. */ + switch (state->connector->connector_type) { + case DRM_MODE_CONNECTOR_HDMIA: + out->hb0 = 0x87; /* type */ + out->hb1 = 0x01; /* version */ + out->hb2 = 0x1A; /* length */ + out->sb[0] = buf[3]; /* checksum */ + i = 1; + break; + + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_eDP: + out->hb0 = 0x00; /* sdp id, zero */ + out->hb1 = 0x87; /* type */ + out->hb2 = 0x1D; /* payload len - 1 */ + out->hb3 = (0x13 << 2); /* sdp version */ + out->sb[0] = 0x01; /* version */ + out->sb[1] = 0x1A; /* length */ + i = 2; + break; + + default: + return -EINVAL; + } + + memcpy(>sb[i], [4], 26); + out->valid = true; + + print_hex_dump(KERN_DEBUG, "HDR SB:", DUMP_PREFIX_NONE, 16, 1, out->sb, + sizeof(out->sb), false); + + return 0; +} + +static bool +is_hdr_metadata_different(const struct drm_connector_state *old_state, + const struct drm_connector_state *new_state) +{ + struct drm_property_blob *old_blob = old_state->hdr_output_metadata; + struct drm_property_blob *new_blob = new_state->hdr_output_metadata; + + if (old_blob != new_blob) { + if (old_blob && new_blob && + old_blob->length == new_blob->length) + return memcmp(old_blob->data, new_blob->data, + old_blob->length); + + return true; + } + + return false; +} + +static int +amdgpu_dm_connector_atomic_check(struct drm_connector *conn, +struct drm_connector_state *new_con_state) +{ + struct drm_atomic_state *state = new_con_state->state; + struct drm_connector_state *old_con_state = + drm_atomic_get_old_connector_state(state, conn); + struct drm_crtc *crtc = new_con_state->crtc; + struct drm_crtc_state *new_crtc_state; + int ret; + + if (!crtc) + return 0; + + if (is_hdr_metadata_different(old_con_state, new_con_state)) { + struct dc_info_packet hdr_infopacket; + + ret = fill_hdr_info_packet(new_con_state, _infopacket); + if (ret) + return ret; + + new_crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(new_crtc_state)) + return PTR_ERR(new_crtc_state); + + /* +* DC considers the stream backends changed if the +* static metadata changes. Forcing the modeset also +* gives a simple way for userspace to switch fr
[PATCH 2/2] drm/amd/display: Only force modesets when toggling HDR
[Why] We can issue HDR static metadata as part of stream updates for non-modesets as long as we force a modeset when entering or exiting HDR. This avoids unnecessary blanking for simple metadata updates. [How] When changing scaling and abm for the stream also check if HDR has changed and send the stream update. This will only happen in non-modeset cases. Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 34 +++ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index eb31acca7ed6..443b13ec268d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3978,9 +3978,16 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn, * DC considers the stream backends changed if the * static metadata changes. Forcing the modeset also * gives a simple way for userspace to switch from -* 8bpc to 10bpc when setting the metadata. +* 8bpc to 10bpc when setting the metadata to enter +* or exit HDR. +* +* Changing the static metadata after it's been +* set is permissible, however. So only force a +* modeset if we're entering or exiting HDR. */ - new_crtc_state->mode_changed = true; + new_crtc_state->mode_changed = + !old_con_state->hdr_output_metadata || + !new_con_state->hdr_output_metadata; } return 0; @@ -5881,7 +5888,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); struct dc_surface_update dummy_updates[MAX_SURFACES]; struct dc_stream_update stream_update; + struct dc_info_packet hdr_packet; struct dc_stream_status *status = NULL; + bool abm_changed, hdr_changed, scaling_changed; memset(_updates, 0, sizeof(dummy_updates)); memset(_update, 0, sizeof(stream_update)); @@ -5898,11 +5907,19 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); - if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state) && - (dm_new_crtc_state->abm_level == dm_old_crtc_state->abm_level)) + scaling_changed = is_scaling_state_different(dm_new_con_state, +dm_old_con_state); + + abm_changed = dm_new_crtc_state->abm_level != + dm_old_crtc_state->abm_level; + + hdr_changed = + is_hdr_metadata_different(old_con_state, new_con_state); + + if (!scaling_changed && !abm_changed && !hdr_changed) continue; - if (is_scaling_state_different(dm_new_con_state, dm_old_con_state)) { + if (scaling_changed) { update_stream_scaling_settings(_new_con_state->base.crtc->mode, dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream); @@ -5910,12 +5927,17 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) stream_update.dst = dm_new_crtc_state->stream->dst; } - if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) { + if (abm_changed) { dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level; stream_update.abm_level = _new_crtc_state->abm_level; } + if (hdr_changed) { + fill_hdr_info_packet(new_con_state, _packet); + stream_update.hdr_static_metadata = _packet; + } + status = dc_stream_get_status(dm_new_crtc_state->stream); WARN_ON(!status); WARN_ON(!status->plane_count); -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH v2 1/2] drm/amd/display: Switch the custom "max bpc" property to the DRM prop
[Why] The custom "max bpc" property was added to limit color depth while the DRM one was still being merged. It's been a few kernel versions since then and this TODO was still sticking around. [How] Attach the DRM max bpc property to the connector and drop all of our custom property management. Set the max bpc to 8 by default since DRM defaults to the max in the range which would be 16 in this case. No behavioral changes are intended with this patch, it should just be a refactor. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas Acked-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 4 --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 2 -- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 29 --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 - 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 4e944737b708..767ee6991ef4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -631,10 +631,6 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) amdgpu_dither_enum_list, sz); if (amdgpu_device_has_dc_support(adev)) { - adev->mode_info.max_bpc_property = - drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16); - if (!adev->mode_info.max_bpc_property) - return -ENOMEM; adev->mode_info.abm_level_property = drm_property_create_range(adev->ddev, 0, "abm level", 0, 4); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index c7940af42f76..8bda00ce8816 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -332,8 +332,6 @@ struct amdgpu_mode_info { struct drm_property *audio_property; /* FMT dithering */ struct drm_property *dither_property; - /* maximum number of bits per channel for monitor color */ - struct drm_property *max_bpc_property; /* Adaptive Backlight Modulation (power feature) */ struct drm_property *abm_level_property; /* it is used to allow enablement of freesync mode */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 4a1755bce96c..b8e88209ef5d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3040,14 +3040,14 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector) { - struct dm_connector_state *dm_conn_state = - to_dm_connector_state(connector->state); uint32_t bpc = connector->display_info.bpc; - /* TODO: Remove this when there's support for max_bpc in drm */ - if (dm_conn_state && bpc > dm_conn_state->max_bpc) - /* Round down to nearest even number. */ - bpc = dm_conn_state->max_bpc - (dm_conn_state->max_bpc & 1); + /* TODO: Use passed in state instead of the current state. */ + if (connector->state) { + bpc = connector->state->max_bpc; + /* Round down to the nearest even number. */ + bpc = bpc - (bpc & 1); + } switch (bpc) { case 0: @@ -3689,9 +3689,6 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { dm_new_state->underscan_enable = val; ret = 0; - } else if (property == adev->mode_info.max_bpc_property) { - dm_new_state->max_bpc = val; - ret = 0; } else if (property == adev->mode_info.abm_level_property) { dm_new_state->abm_level = val; ret = 0; @@ -3743,9 +3740,6 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { *val = dm_state->underscan_enable; ret = 0; - } else if (property == adev->mode_info.max_bpc_property) { - *val = dm_state->max_bpc; - ret = 0; } else if (property == adev->mode_info.abm_level_property) { *val = dm_state->abm_level; ret = 0; @@ -3808,7 +3802,6 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->underscan_enable = false;
[PATCH v2 2/2] drm/amd/display: Use new connector state when getting color depth
[Why] The current state on the connector is queried when getting the max bpc rather than the new state. This means that a new max bpc value can only currently take effect on the commit *after* it changes. The new state should be passed in instead. [How] Pass down the dm_state as drm state to where we do color depth lookup. The passed in state can still be NULL when called from amdgpu_dm_connector_mode_valid, so make sure that we have reasonable defaults in place. That should probably be addressed at some point. This change now (correctly) causes a modeset to occur when changing the max bpc for a connector. v2: Drop extra TODO. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas Acked-by: Alex Deucher --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 27 ++- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index b8e88209ef5d..fd0421794e0f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3038,13 +3038,13 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, } static enum dc_color_depth -convert_color_depth_from_display_info(const struct drm_connector *connector) +convert_color_depth_from_display_info(const struct drm_connector *connector, + const struct drm_connector_state *state) { uint32_t bpc = connector->display_info.bpc; - /* TODO: Use passed in state instead of the current state. */ - if (connector->state) { - bpc = connector->state->max_bpc; + if (state) { + bpc = state->max_bpc; /* Round down to the nearest even number. */ bpc = bpc - (bpc & 1); } @@ -3165,11 +3165,12 @@ static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_ } -static void -fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, -const struct drm_display_mode *mode_in, -const struct drm_connector *connector, -const struct dc_stream_state *old_stream) +static void fill_stream_properties_from_drm_display_mode( + struct dc_stream_state *stream, + const struct drm_display_mode *mode_in, + const struct drm_connector *connector, + const struct drm_connector_state *connector_state, + const struct dc_stream_state *old_stream) { struct dc_crtc_timing *timing_out = >timing; const struct drm_display_info *info = >display_info; @@ -3192,7 +3193,7 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE; timing_out->display_color_depth = convert_color_depth_from_display_info( - connector); + connector, connector_state); timing_out->scan_type = SCANNING_TYPE_NODATA; timing_out->hdmi_vic = 0; @@ -3389,6 +3390,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, { struct drm_display_mode *preferred_mode = NULL; struct drm_connector *drm_connector; + const struct drm_connector_state *con_state = + dm_state ? _state->base : NULL; struct dc_stream_state *stream = NULL; struct drm_display_mode mode = *drm_mode; bool native_mode_found = false; @@ -3461,10 +3464,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ if (!scale || mode_refresh != preferred_refresh) fill_stream_properties_from_drm_display_mode(stream, - , >base, NULL); + , >base, con_state, NULL); else fill_stream_properties_from_drm_display_mode(stream, - , >base, old_stream); + , >base, con_state, old_stream); update_stream_scaling_settings(, dm_state, stream); -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 2/2] drm/amd/display: Use new connector state when getting color depth
[Why] The current state on the connector is queried when getting the max bpc rather than the new state. This means that a new max bpc value can only currently take effect on the commit *after* it changes. The new state should be passed in instead. [How] Pass down the dm_state as drm state to where we do color depth lookup. The passed in state can still be NULL when called from amdgpu_dm_connector_mode_valid, so make sure that we have reasonable defaults in place. That should probably be addressed at some point. This change now (correctly) causes a modeset to occur when changing the max bpc for a connector. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 26 +++ 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a7a9e4d81a17..580c324891fd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3038,13 +3038,14 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, } static enum dc_color_depth -convert_color_depth_from_display_info(const struct drm_connector *connector) +convert_color_depth_from_display_info(const struct drm_connector *connector, + const struct drm_connector_state *state) { uint32_t bpc = 8; /* TODO: Use passed in state instead of the current state. */ - if (connector->state) { - bpc = connector->state->max_bpc; + if (state) { + bpc = state->max_bpc; /* Round down to the nearest even number. */ bpc = bpc - (bpc & 1); } @@ -3165,11 +3166,12 @@ static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_ } -static void -fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, -const struct drm_display_mode *mode_in, -const struct drm_connector *connector, -const struct dc_stream_state *old_stream) +static void fill_stream_properties_from_drm_display_mode( + struct dc_stream_state *stream, + const struct drm_display_mode *mode_in, + const struct drm_connector *connector, + const struct drm_connector_state *connector_state, + const struct dc_stream_state *old_stream) { struct dc_crtc_timing *timing_out = >timing; const struct drm_display_info *info = >display_info; @@ -3192,7 +3194,7 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE; timing_out->display_color_depth = convert_color_depth_from_display_info( - connector); + connector, connector_state); timing_out->scan_type = SCANNING_TYPE_NODATA; timing_out->hdmi_vic = 0; @@ -3389,6 +3391,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, { struct drm_display_mode *preferred_mode = NULL; struct drm_connector *drm_connector; + const struct drm_connector_state *con_state = + dm_state ? _state->base : NULL; struct dc_stream_state *stream = NULL; struct drm_display_mode mode = *drm_mode; bool native_mode_found = false; @@ -3461,10 +3465,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ if (!scale || mode_refresh != preferred_refresh) fill_stream_properties_from_drm_display_mode(stream, - , >base, NULL); + , >base, con_state, NULL); else fill_stream_properties_from_drm_display_mode(stream, - , >base, old_stream); + , >base, con_state, old_stream); update_stream_scaling_settings(, dm_state, stream); -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH 1/2] drm/amd/display: Switch the custom "max bpc" property to the DRM prop
[Why] The custom "max bpc" property was added to limit color depth while the DRM one was still being merged. It's been a few kernel versions since then and this TODO was still sticking around. [How] Attach the DRM max bpc property to the connector and drop all of our custom property management. Set the max bpc to 8 by default since DRM defaults to the max in the range which would be 16 in this case. No behavioral changes are intended with this patch, it should just be a refactor. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 4 --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 2 -- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 31 --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 - 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 4e944737b708..767ee6991ef4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -631,10 +631,6 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) amdgpu_dither_enum_list, sz); if (amdgpu_device_has_dc_support(adev)) { - adev->mode_info.max_bpc_property = - drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16); - if (!adev->mode_info.max_bpc_property) - return -ENOMEM; adev->mode_info.abm_level_property = drm_property_create_range(adev->ddev, 0, "abm level", 0, 4); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index c7940af42f76..8bda00ce8816 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -332,8 +332,6 @@ struct amdgpu_mode_info { struct drm_property *audio_property; /* FMT dithering */ struct drm_property *dither_property; - /* maximum number of bits per channel for monitor color */ - struct drm_property *max_bpc_property; /* Adaptive Backlight Modulation (power feature) */ struct drm_property *abm_level_property; /* it is used to allow enablement of freesync mode */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 4a1755bce96c..a7a9e4d81a17 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3040,14 +3040,14 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector) { - struct dm_connector_state *dm_conn_state = - to_dm_connector_state(connector->state); - uint32_t bpc = connector->display_info.bpc; + uint32_t bpc = 8; - /* TODO: Remove this when there's support for max_bpc in drm */ - if (dm_conn_state && bpc > dm_conn_state->max_bpc) - /* Round down to nearest even number. */ - bpc = dm_conn_state->max_bpc - (dm_conn_state->max_bpc & 1); + /* TODO: Use passed in state instead of the current state. */ + if (connector->state) { + bpc = connector->state->max_bpc; + /* Round down to the nearest even number. */ + bpc = bpc - (bpc & 1); + } switch (bpc) { case 0: @@ -3689,9 +3689,6 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { dm_new_state->underscan_enable = val; ret = 0; - } else if (property == adev->mode_info.max_bpc_property) { - dm_new_state->max_bpc = val; - ret = 0; } else if (property == adev->mode_info.abm_level_property) { dm_new_state->abm_level = val; ret = 0; @@ -3743,9 +3740,6 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { *val = dm_state->underscan_enable; ret = 0; - } else if (property == adev->mode_info.max_bpc_property) { - *val = dm_state->max_bpc; - ret = 0; } else if (property == adev->mode_info.abm_level_property) { *val = dm_state->abm_level; ret = 0; @@ -3808,7 +3802,6 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->underscan_enable = false;
[PATCH v2] drm/amd/display: Use long for signed error code checks in commit planes
[Why] The type of 'r' is uint32_t and the return codes for both: - reservation_object_wait_timeout_rcu - amdgpu_bo_reserve ...are signed. While it works for the latter since the check is done on != 0 it doesn't work for the former since we check <= 0. [How] Make 'r' a long in commit planes so we're not doing any unsigned/signed conversion here in the first place. v2: use long instead of int (Christian) Cc: Christian König Reported-by: Dan Carpenter Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index becd8cb3aab6..ac22f7351a42 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5332,7 +5332,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct drm_crtc *pcrtc, bool wait_for_vblank) { - uint32_t i, r; + uint32_t i; uint64_t timestamp_ns; struct drm_plane *plane; struct drm_plane_state *old_plane_state, *new_plane_state; @@ -5343,6 +5343,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc)); int planes_count = 0, vpos, hpos; + long r; unsigned long flags; struct amdgpu_bo *abo; uint64_t tiling_flags; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Use int for signed error code checks in commit planes
[Why] The type of 'r' is uint32_t and the return codes for both: - reservation_object_wait_timeout_rcu - amdgpu_bo_reserve ...are signed. While it works for the latter since the check is done on != 0 it doesn't work for the former since we check <= 0. [How] Make 'r' an int in commit planes so we're not doing any unsigned/signed conversion here in the first place. Reported-by: Dan Carpenter Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index becd8cb3aab6..722f863ce4a4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5332,7 +5332,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct drm_crtc *pcrtc, bool wait_for_vblank) { - uint32_t i, r; + uint32_t i; uint64_t timestamp_ns; struct drm_plane *plane; struct drm_plane_state *old_plane_state, *new_plane_state; @@ -5342,7 +5342,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state); struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc)); - int planes_count = 0, vpos, hpos; + int r, planes_count = 0, vpos, hpos; unsigned long flags; struct amdgpu_bo *abo; uint64_t tiling_flags; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Expose DRM_FORMAT_RGB565 on overlay planes
RGB565 support isn't restricted to just the primary plane in DC, so also expose support for it on overlays. Cc: Harry Wentland Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a5cacf846e1b..0d07226ca8b7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -4283,6 +4283,7 @@ static const uint32_t overlay_formats[] = { DRM_FORMAT_RGBA, DRM_FORMAT_XBGR, DRM_FORMAT_ABGR, + DRM_FORMAT_RGB565 }; static const u32 cursor_formats[] = { -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Remove semicolon from to_dm_plane_state definition
The extra ; in the macro definition creates an empty statement preventing any variable declarations from occuring after any use of to_dm_plane_state(...). Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 87ca5746f861..94b77488a0e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -57,7 +57,7 @@ struct amdgpu_hpd; #define to_amdgpu_encoder(x) container_of(x, struct amdgpu_encoder, base) #define to_amdgpu_framebuffer(x) container_of(x, struct amdgpu_framebuffer, base) -#define to_dm_plane_state(x) container_of(x, struct dm_plane_state, base); +#define to_dm_plane_state(x) container_of(x, struct dm_plane_state, base) #define AMDGPU_MAX_HPD_PINS 6 #define AMDGPU_MAX_CRTCS 6 -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH v2] drm/amd/display: Add debugfs entry for amdgpu_dm_visual_confirm
[Why] DC provides a few visual confirmation debug options that can be dynamically changed at runtime to help debug surface programming issues but we don't have any way to access it from userspace. [How] Add the amdgpu_dm_visual_confirm debugfs entry. It accepts a string containing the DC visual confirm enum value using the debugfs attribute helpers. The debugfs_create_file_unsafe can be used instead of debugfs_create_file as per the documentation. v2: Use debugfs helpers for getting and setting the value (Christian) Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 39 ++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 1a9e3d3dfa38..1d5fc5ad3bee 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -995,6 +995,35 @@ static const struct drm_info_list amdgpu_dm_debugfs_list[] = { {"amdgpu_target_backlight_pwm", _backlight_read}, }; +/* + * Sets the DC visual confirm debug option from the given string. + * Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_visual_confirm + */ +static int visual_confirm_set(void *data, u64 val) +{ + struct amdgpu_device *adev = data; + + adev->dm.dc->debug.visual_confirm = (enum visual_confirm)val; + + return 0; +} + +/* + * Reads the DC visual confirm debug option value into the given buffer. + * Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_visual_confirm + */ +static int visual_confirm_get(void *data, u64 *val) +{ + struct amdgpu_device *adev = data; + + *val = adev->dm.dc->debug.visual_confirm; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(visual_confirm_fops, visual_confirm_get, +visual_confirm_set, "%llu\n"); + int dtn_debugfs_init(struct amdgpu_device *adev) { static const struct file_operations dtn_log_fops = { @@ -1020,5 +1049,13 @@ int dtn_debugfs_init(struct amdgpu_device *adev) adev, _log_fops); - return PTR_ERR_OR_ZERO(ent); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + ent = debugfs_create_file_unsafe("amdgpu_dm_visual_confirm", 0644, root, +adev, _confirm_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return 0; } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH v2] drm/amd/display: Initialize stream_update with memset
The brace initialization used here generates warnings on some compilers. For example, on GCC 4.9: [...] In function ‘dm_determine_update_type_for_commit’: [...] error: missing braces around initializer [-Werror=missing-braces] struct dc_stream_update stream_update = { 0 }; ^ Use memset to make this more portable. v2: Specify the compiler / diagnostic in the commit message (Paul) Cc: Sun peng Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5b7a85e28fab..9cdd52edfc3d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5982,7 +5982,9 @@ dm_determine_update_type_for_commit(struct dc *dc, } for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - struct dc_stream_update stream_update = { 0 }; + struct dc_stream_update stream_update; + + memset(_update, 0, sizeof(stream_update)); new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); old_dm_crtc_state = to_dm_crtc_state(old_crtc_state); -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Initialize stream_update with memset
The brace initialization used here generates errors on some compilers. Use memset to make this more portable. Cc: Sun peng Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5b7a85e28fab..9cdd52edfc3d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5982,7 +5982,9 @@ dm_determine_update_type_for_commit(struct dc *dc, } for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - struct dc_stream_update stream_update = { 0 }; + struct dc_stream_update stream_update; + + memset(_update, 0, sizeof(stream_update)); new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); old_dm_crtc_state = to_dm_crtc_state(old_crtc_state); -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Only allow VRR when vrefresh is within supported range
[Why] Black screens or artifacting can occur when enabling FreeSync outside of the supported range of the monitor. This can happen since the supported range isn't always the min/max vrefresh range available for the monitor. [How] There was previously a fix that prevented this from happening in the low range but it didn't cover the upper range. Expand the condition to include both. Cc: Sun peng Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 01a46119512b..5b7a85e28fab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5551,9 +5551,11 @@ static void get_freesync_config_for_crtc( struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(new_con_state->base.connector); struct drm_display_mode *mode = _crtc_state->base.mode; + int vrefresh = drm_mode_vrefresh(mode); new_crtc_state->vrr_supported = new_con_state->freesync_capable && - aconnector->min_vfreq <= drm_mode_vrefresh(mode); + vrefresh >= aconnector->min_vfreq && + vrefresh <= aconnector->max_vfreq; if (new_crtc_state->vrr_supported) { new_crtc_state->stream->ignore_msa_timing_param = true; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Add debugfs entry for amdgpu_dm_visual_confirm
[Why] DC provides a few visual confirmation debug options that can be dynamically changed at runtime to help debug surface programming issues but we don't have any way to access it from userspace. [How] Add the amdgpu_dm_visual_confirm debugfs entry. It accepts a string containing the DC visual confirm enum value. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 77 ++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 4a55cde027cf..1d6bfb84d7cf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -803,6 +803,65 @@ static ssize_t dtn_log_write( return size; } +/* + * Reads the DC visual confirm debug option value into the given buffer. + * Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_visual_confirm + */ +static ssize_t visual_confirm_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = file_inode(f)->i_private; + struct dc *dc = adev->dm.dc; + size_t to_copy = 0; + int len; + char tmp[16]; + + if (!buf || !size) + return -EINVAL; + + len = snprintf(tmp, sizeof(tmp), "%d\n", dc->debug.visual_confirm); + if (len < 0 || len >= sizeof(tmp)) + return -EINVAL; + + if (*pos >= len) + return 0; + + to_copy = len - *pos; + if (to_copy > size) + return 0; + + if (copy_to_user(buf, tmp + *pos, to_copy)) + return -EFAULT; + + *pos += to_copy; + + return to_copy; +} + +/* + * Sets the DC visual confirm debug option from the given string. + * Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_visual_confirm + */ +static ssize_t visual_confirm_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_device *adev = file_inode(f)->i_private; + struct dc *dc = adev->dm.dc; + int ret; + u16 val; + + if (size == 0) + return 0; + + ret = kstrtou16_from_user(buf, size, 0, ); + if (ret) + return ret; + + dc->debug.visual_confirm = val; + + return size; +} + /* * Backlight at this moment. Read only. * As written to display, taking ABM and backlight lut into account. @@ -850,7 +909,12 @@ int dtn_debugfs_init(struct amdgpu_device *adev) .write = dtn_log_write, .llseek = default_llseek }; - + static const struct file_operations visual_confirm_fops = { + .owner = THIS_MODULE, + .read = visual_confirm_read, + .write = visual_confirm_write, + .llseek = default_llseek + }; struct drm_minor *minor = adev->ddev->primary; struct dentry *ent, *root = minor->debugfs_root; int ret; @@ -867,5 +931,14 @@ int dtn_debugfs_init(struct amdgpu_device *adev) adev, _log_fops); - return PTR_ERR_OR_ZERO(ent); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + ent = debugfs_create_file("amdgpu_dm_visual_confirm", 0644, root, adev, + _confirm_fops); + + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return 0; } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Only put primary planes into the mode_info->planes list
We want DRM planes to be initialized in the following order: - primary planes - overlay planes - cursor planes to support existing userspace expectations for plane z-ordering. This means that we also need to register CRTCs after all planes have been initialized since overlay planes can be placed on any CRTC. So the only reason why we have the mode_info->planes list is to remember the primary planes for use later when we need to register the CRTC. Overlay planes have no purpose being in this list. DRM will cleanup any planes that we've registered for us, so the only planes that need to be explicitly cleaned up are the ones that have failed to register. By dropping the explicit free on every plane in the mode_info->planes list this patch also fixes a double-free in the case where we fail to initialize only some of the planes. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 19 +-- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index cde0da3ae964..f770de36121f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1818,8 +1818,6 @@ static int initialize_plane(struct amdgpu_display_manager *dm, int ret = 0; plane = kzalloc(sizeof(struct drm_plane), GFP_KERNEL); - mode_info->planes[plane_id] = plane; - if (!plane) { DRM_ERROR("KMS: Failed to allocate plane\n"); return -ENOMEM; @@ -1836,13 +1834,17 @@ static int initialize_plane(struct amdgpu_display_manager *dm, if (plane_id >= dm->dc->caps.max_streams) possible_crtcs = 0xff; - ret = amdgpu_dm_plane_init(dm, mode_info->planes[plane_id], possible_crtcs); + ret = amdgpu_dm_plane_init(dm, plane, possible_crtcs); if (ret) { DRM_ERROR("KMS: Failed to initialize plane\n"); + kfree(plane); return ret; } + if (mode_info) + mode_info->planes[plane_id] = plane; + return ret; } @@ -1885,7 +1887,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) struct amdgpu_encoder *aencoder = NULL; struct amdgpu_mode_info *mode_info = >mode_info; uint32_t link_cnt; - int32_t overlay_planes, primary_planes, total_planes; + int32_t overlay_planes, primary_planes; enum dc_connection_type new_connection_type = dc_connection_none; link_cnt = dm->dc->caps.max_links; @@ -1914,9 +1916,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) /* There is one primary plane per CRTC */ primary_planes = dm->dc->caps.max_streams; - - total_planes = primary_planes + overlay_planes; - ASSERT(total_planes <= AMDGPU_MAX_PLANES); + ASSERT(primary_planes <= AMDGPU_MAX_PLANES); /* * Initialize primary planes, implicit planes for legacy IOCTLS. @@ -1937,7 +1937,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) * Order is reversed to match iteration order in atomic check. */ for (i = (overlay_planes - 1); i >= 0; i--) { - if (initialize_plane(dm, mode_info, primary_planes + i, + if (initialize_plane(dm, NULL, primary_planes + i, DRM_PLANE_TYPE_OVERLAY)) { DRM_ERROR("KMS: Failed to initialize overlay plane\n"); goto fail; @@ -2041,8 +2041,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) fail: kfree(aencoder); kfree(aconnector); - for (i = 0; i < primary_planes; i++) - kfree(mode_info->planes[i]); + return -EINVAL; } -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Respect DRM framebuffer info for video surfaces
[Why] Incorrect hardcoded assumptions are made regarding luma and chroma alignment. The actual values set for the DRM framebuffer should be used when programming the address. [How] Respect the given pitch for both luma and chroma planes - it's not like we can force the alignment to anything else at this point anyway. Use the FB offset for the chroma planes directly. DRM already provides this to us so there's no need to calculate it manually. While we don't actually use the chroma surface size parameters on Raven, these should have technically been fb->width / 2 and fb->height / 2 since the chroma plane is half size of the luma plane for NV12. Leave a TODO indicating that those should be set based on the actual surface format instead since this is only correct for YUV420 formats. Cc: Leo Li Cc: Harry Wentland Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 21 +-- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index cde0da3ae964..5f1e23ba75e1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2465,8 +2465,7 @@ fill_plane_tiling_attributes(struct amdgpu_device *adev, address->grph.addr.high_part = upper_32_bits(afb->address); } else { const struct drm_framebuffer *fb = >base; - uint64_t awidth = ALIGN(fb->width, 64); - uint64_t chroma_addr = afb->address + awidth * fb->height; + uint64_t chroma_addr = afb->address + fb->offsets[1]; address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE; address->video_progressive.luma_addr.low_part = @@ -2542,7 +2541,6 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, const struct amdgpu_framebuffer *amdgpu_fb) { uint64_t tiling_flags; - unsigned int awidth; const struct drm_framebuffer *fb = _fb->base; int ret = 0; struct drm_format_name_buf format_name; @@ -2602,20 +2600,21 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, plane_state->color_space = COLOR_SPACE_SRGB; } else { - awidth = ALIGN(fb->width, 64); - plane_state->plane_size.video.luma_size.x = 0; plane_state->plane_size.video.luma_size.y = 0; - plane_state->plane_size.video.luma_size.width = awidth; + plane_state->plane_size.video.luma_size.width = fb->width; plane_state->plane_size.video.luma_size.height = fb->height; - /* TODO: unhardcode */ - plane_state->plane_size.video.luma_pitch = awidth; + plane_state->plane_size.video.luma_pitch = + fb->pitches[0] / fb->format->cpp[0]; plane_state->plane_size.video.chroma_size.x = 0; plane_state->plane_size.video.chroma_size.y = 0; - plane_state->plane_size.video.chroma_size.width = awidth; - plane_state->plane_size.video.chroma_size.height = fb->height; - plane_state->plane_size.video.chroma_pitch = awidth / 2; + /* TODO: set these based on surface format */ + plane_state->plane_size.video.chroma_size.width = fb->width / 2; + plane_state->plane_size.video.chroma_size.height = fb->height / 2; + + plane_state->plane_size.video.chroma_pitch = + fb->pitches[1] / fb->format->cpp[1]; /* TODO: unhardcode */ plane_state->color_space = COLOR_SPACE_YCBCR709; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amdgpu: Only clear dumb buffers if ring is enabled
The buffers should be cleared when possible but we also don't want buffer creation to fail in the rare case where the ring isn't ready during the call. This could happen during some suspend/resume sequences. Cc: Christian König Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index a58072bbc9b8..9ee8d7a3c6d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -733,18 +733,25 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, struct amdgpu_device *adev = dev->dev_private; struct drm_gem_object *gobj; uint32_t handle; + u64 flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; u32 domain; int r; + /* +* The buffer returned from this function should be cleared, but +* it can only be done if the ring is enabled or we'll fail to +* create the buffer. +*/ + if (adev->mman.buffer_funcs_enabled) + flags |= AMDGPU_GEM_CREATE_VRAM_CLEARED; + args->pitch = amdgpu_align_pitch(adev, args->width, DIV_ROUND_UP(args->bpp, 8), 0); args->size = (u64)args->pitch * args->height; args->size = ALIGN(args->size, PAGE_SIZE); domain = amdgpu_bo_get_preferred_pin_domain(adev, amdgpu_display_supported_domains(adev)); - r = amdgpu_gem_object_create(adev, args->size, 0, domain, -AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | -AMDGPU_GEM_CREATE_VRAM_CLEARED, + r = amdgpu_gem_object_create(adev, args->size, 0, domain, flags, ttm_bo_type_device, NULL, ); if (r) return -ENOMEM; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx
[PATCH] drm/amd/display: Fix plane address updates for video surface formats
[Why] For new DC planes the correct plane address fields are filled based on whether the plane had a graphics or video format. However, when we perform stream and plane updates using DC we only ever fill in the graphics format fields. This causing corruption and hangs when using video surface formats like NV12 for planes. [How] Use the same logic everywhere we update dc_plane_address - always fill in the correct fields based on the surface format type. There are 3 places this is done: - Atomic check, during DC plane creation - Atomic commit, during plane prepare_fb - Atomic commit tail, during amdgpu_dm_commit_planes We use the fill_plane_tiling_attributes in all 3 locations and it already needs the address to update DCC attributes, so the surface address update logic can be moved into this helper. Cc: Leo Li Signed-off-by: Nicholas Kazlauskas --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 57 +-- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 59a8045c9e2a..e0c0621f40d4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2457,6 +2457,27 @@ fill_plane_tiling_attributes(struct amdgpu_device *adev, memset(tiling_info, 0, sizeof(*tiling_info)); memset(dcc, 0, sizeof(*dcc)); + memset(address, 0, sizeof(*address)); + + if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + address->type = PLN_ADDR_TYPE_GRAPHICS; + address->grph.addr.low_part = lower_32_bits(afb->address); + address->grph.addr.high_part = upper_32_bits(afb->address); + } else { + const struct drm_framebuffer *fb = >base; + uint64_t awidth = ALIGN(fb->width, 64); + uint64_t chroma_addr = afb->address + awidth * fb->height; + + address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE; + address->video_progressive.luma_addr.low_part = + lower_32_bits(afb->address); + address->video_progressive.luma_addr.high_part = + upper_32_bits(afb->address); + address->video_progressive.chroma_addr.low_part = + lower_32_bits(chroma_addr); + address->video_progressive.chroma_addr.high_part = + upper_32_bits(chroma_addr); + } /* Fill GFX8 params */ if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) { @@ -2571,7 +2592,6 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, memset(_state->address, 0, sizeof(plane_state->address)); if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { - plane_state->address.type = PLN_ADDR_TYPE_GRAPHICS; plane_state->plane_size.grph.surface_size.x = 0; plane_state->plane_size.grph.surface_size.y = 0; plane_state->plane_size.grph.surface_size.width = fb->width; @@ -2583,7 +2603,7 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, } else { awidth = ALIGN(fb->width, 64); - plane_state->address.type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE; + plane_state->plane_size.video.luma_size.x = 0; plane_state->plane_size.video.luma_size.y = 0; plane_state->plane_size.video.luma_size.width = awidth; @@ -3738,10 +3758,8 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_gem_object *obj; struct amdgpu_device *adev; struct amdgpu_bo *rbo; - uint64_t chroma_addr = 0; struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old; - uint64_t tiling_flags, dcc_address; - unsigned int awidth; + uint64_t tiling_flags; uint32_t domain; int r; @@ -3794,29 +3812,9 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) { struct dc_plane_state *plane_state = dm_plane_state_new->dc_state; - if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { - plane_state->address.grph.addr.low_part = lower_32_bits(afb->address); - plane_state->address.grph.addr.high_part = upper_32_bits(afb->address); - - dcc_address = - get_dcc_address(afb->address, tiling_flags); - plane_state->address.grph.meta_addr.low_part = - lower_32_bits(dcc_address); - plane_state->address.grph.meta_addr.hig
[PATCH] drm/amdgpu: Clear VRAM for DRM dumb_create buffers
The dumb_create API isn't intended for high performance rendering and it's more useful for userspace (ie. IGT) to have them precleared. The bonus here is that we also won't needlessly leak whatever was previously in VRAM, but it also probably wasn't sensitive if it was going through this API. Signed-off-by: Nicholas Kazlauskas --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index fcaaac30e84b..a58072bbc9b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -743,7 +743,8 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, domain = amdgpu_bo_get_preferred_pin_domain(adev, amdgpu_display_supported_domains(adev)); r = amdgpu_gem_object_create(adev, args->size, 0, domain, -AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | +AMDGPU_GEM_CREATE_VRAM_CLEARED, ttm_bo_type_device, NULL, ); if (r) return -ENOMEM; -- 2.17.1 ___ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx