diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn10')
18 files changed, 689 insertions, 706 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 55f293c8a3c0..032f872be89c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -24,7 +24,7 @@ DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o dcn10_hw_sequencer_debug.o \ dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ - dcn10_hubp.o dcn10_mpc.o dcn10_clk_mgr.o \ + dcn10_hubp.o dcn10_mpc.o \ dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o \ dcn10_hubbub.o dcn10_stream_encoder.o dcn10_link_encoder.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c deleted file mode 100644 index 2b2de1d913c9..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 2018 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dcn10_clk_mgr.h" - -#include "reg_helper.h" -#include "core_types.h" - -#define TO_DCE_CLK_MGR(clocks)\ - container_of(clocks, struct dce_clk_mgr, base) - -#define REG(reg) \ - (clk_mgr_dce->regs->reg) - -#undef FN -#define FN(reg_name, field_name) \ - clk_mgr_dce->clk_mgr_shift->field_name, clk_mgr_dce->clk_mgr_mask->field_name - -#define CTX \ - clk_mgr_dce->base.ctx -#define DC_LOGGER \ - clk_mgr->ctx->logger - -static int dcn1_determine_dppclk_threshold(struct clk_mgr *clk_mgr, struct dc_clocks *new_clocks) -{ - bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; - bool dispclk_increase = new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz; - int disp_clk_threshold = new_clocks->max_supported_dppclk_khz; - bool cur_dpp_div = clk_mgr->clks.dispclk_khz > clk_mgr->clks.dppclk_khz; - - /* increase clock, looking for div is 0 for current, request div is 1*/ - if (dispclk_increase) { - /* already divided by 2, no need to reach target clk with 2 steps*/ - if (cur_dpp_div) - return new_clocks->dispclk_khz; - - /* request disp clk is lower than maximum supported dpp clk, - * no need to reach target clk with two steps. - */ - if (new_clocks->dispclk_khz <= disp_clk_threshold) - return new_clocks->dispclk_khz; - - /* target dpp clk not request divided by 2, still within threshold */ - if (!request_dpp_div) - return new_clocks->dispclk_khz; - - } else { - /* decrease clock, looking for current dppclk divided by 2, - * request dppclk not divided by 2. - */ - - /* current dpp clk not divided by 2, no need to ramp*/ - if (!cur_dpp_div) - return new_clocks->dispclk_khz; - - /* current disp clk is lower than current maximum dpp clk, - * no need to ramp - */ - if (clk_mgr->clks.dispclk_khz <= disp_clk_threshold) - return new_clocks->dispclk_khz; - - /* request dpp clk need to be divided by 2 */ - if (request_dpp_div) - return new_clocks->dispclk_khz; - } - - return disp_clk_threshold; -} - -static void dcn1_ramp_up_dispclk_with_dpp(struct clk_mgr *clk_mgr, struct dc_clocks *new_clocks) -{ - struct dc *dc = clk_mgr->ctx->dc; - int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(clk_mgr, new_clocks); - bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; - int i; - - /* set disp clk to dpp clk threshold */ - dce112_set_clock(clk_mgr, dispclk_to_dpp_threshold); - - /* update request dpp clk division option */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->plane_state) - continue; - - pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( - pipe_ctx->plane_res.dpp, - request_dpp_div, - true); - } - - /* If target clk not same as dppclk threshold, set to target clock */ - if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz) - dce112_set_clock(clk_mgr, new_clocks->dispclk_khz); - - clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz; - clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz; - clk_mgr->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz; -} - -static int get_active_display_cnt( - struct dc *dc, - struct dc_state *context) -{ - int i, display_count; - - display_count = 0; - for (i = 0; i < context->stream_count; i++) { - const struct dc_stream_state *stream = context->streams[i]; - - /* - * Only notify active stream or virtual stream. - * Need to notify virtual stream to work around - * headless case. HPD does not fire when system is in - * S0i2. - */ - if (!stream->dpms_off || stream->signal == SIGNAL_TYPE_VIRTUAL) - display_count++; - } - - return display_count; -} - -static void dcn1_update_clocks(struct clk_mgr *clk_mgr, - struct dc_state *context, - bool safe_to_lower) -{ - struct dc *dc = clk_mgr->ctx->dc; - struct dc_debug_options *debug = &dc->debug; - struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; - struct pp_smu_funcs_rv *pp_smu = NULL; - bool send_request_to_increase = false; - bool send_request_to_lower = false; - int display_count; - - bool enter_display_off = false; - - display_count = get_active_display_cnt(dc, context); - if (dc->res_pool->pp_smu) - pp_smu = &dc->res_pool->pp_smu->rv_funcs; - if (display_count == 0) - enter_display_off = true; - - if (enter_display_off == safe_to_lower) { - /* - * Notify SMU active displays - * if function pointer not set up, this message is - * sent as part of pplib_apply_display_requirements. - */ - if (pp_smu && pp_smu->set_display_count) - pp_smu->set_display_count(&pp_smu->pp_smu, display_count); - } - - if (new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz - || new_clocks->phyclk_khz > clk_mgr->clks.phyclk_khz - || new_clocks->fclk_khz > clk_mgr->clks.fclk_khz - || new_clocks->dcfclk_khz > clk_mgr->clks.dcfclk_khz) - send_request_to_increase = true; - - if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) { - clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz; - send_request_to_lower = true; - } - - // F Clock - if (debug->force_fclk_khz != 0) - new_clocks->fclk_khz = debug->force_fclk_khz; - - if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr->clks.fclk_khz)) { - clk_mgr->clks.fclk_khz = new_clocks->fclk_khz; - send_request_to_lower = true; - } - - //DCF Clock - if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) { - clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz; - send_request_to_lower = true; - } - - if (should_set_clock(safe_to_lower, - new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) { - clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; - send_request_to_lower = true; - } - - /* make sure dcf clk is before dpp clk to - * make sure we have enough voltage to run dpp clk - */ - if (send_request_to_increase) { - /*use dcfclk to request voltage*/ - if (pp_smu && pp_smu->set_hard_min_fclk_by_freq && - pp_smu->set_hard_min_dcfclk_by_freq && - pp_smu->set_min_deep_sleep_dcfclk) { - - pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, new_clocks->fclk_khz / 1000); - pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, new_clocks->dcfclk_khz / 1000); - pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, (new_clocks->dcfclk_deep_sleep_khz + 999) / 1000); - } - } - - /* dcn1 dppclk is tied to dispclk */ - /* program dispclk on = as a w/a for sleep resume clock ramping issues */ - if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz) - || new_clocks->dispclk_khz == clk_mgr->clks.dispclk_khz) { - dcn1_ramp_up_dispclk_with_dpp(clk_mgr, new_clocks); - clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz; - send_request_to_lower = true; - } - - if (!send_request_to_increase && send_request_to_lower) { - /*use dcfclk to request voltage*/ - if (pp_smu && pp_smu->set_hard_min_fclk_by_freq && - pp_smu->set_hard_min_dcfclk_by_freq && - pp_smu->set_min_deep_sleep_dcfclk) { - - pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, new_clocks->fclk_khz / 1000); - pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, new_clocks->dcfclk_khz / 1000); - pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, (new_clocks->dcfclk_deep_sleep_khz + 999) / 1000); - } - } -} -static const struct clk_mgr_funcs dcn1_funcs = { - .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, - .update_clocks = dcn1_update_clocks -}; -struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx) -{ - struct dc_debug_options *debug = &ctx->dc->debug; - struct dc_bios *bp = ctx->dc_bios; - struct dc_firmware_info fw_info = { { 0 } }; - struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), GFP_KERNEL); - - if (clk_mgr_dce == NULL) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - clk_mgr_dce->base.ctx = ctx; - clk_mgr_dce->base.funcs = &dcn1_funcs; - - clk_mgr_dce->dfs_bypass_disp_clk = 0; - - clk_mgr_dce->dprefclk_ss_percentage = 0; - clk_mgr_dce->dprefclk_ss_divider = 1000; - clk_mgr_dce->ss_on_dprefclk = false; - - clk_mgr_dce->dprefclk_khz = 600000; - if (bp->integrated_info) - clk_mgr_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; - if (clk_mgr_dce->dentist_vco_freq_khz == 0) { - bp->funcs->get_firmware_info(bp, &fw_info); - clk_mgr_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq; - if (clk_mgr_dce->dentist_vco_freq_khz == 0) - clk_mgr_dce->dentist_vco_freq_khz = 3600000; - } - - if (!debug->disable_dfs_bypass && bp->integrated_info) - if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) - clk_mgr_dce->dfs_bypass_enabled = true; - - dce_clock_read_ss_info(clk_mgr_dce); - - return &clk_mgr_dce->base; -} - - diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h deleted file mode 100644 index 97007cf33665..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DCN10_CLK_MGR_H__ -#define __DCN10_CLK_MGR_H__ - -#include "../dce/dce_clk_mgr.h" - -struct clk_bypass { - uint32_t dcfclk_bypass; - uint32_t dispclk_pypass; - uint32_t dprefclk_bypass; -}; - -struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx); - -#endif //__DCN10_CLK_MGR_H__ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h index 5ae4d69391a5..3b8cd7410498 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h @@ -38,6 +38,22 @@ type exp_resion_start_segment;\ type field_region_linear_slope +#define TF_HELPER_REG_LIST \ + uint32_t start_cntl_b; \ + uint32_t start_cntl_g; \ + uint32_t start_cntl_r; \ + uint32_t start_slope_cntl_b; \ + uint32_t start_slope_cntl_g; \ + uint32_t start_slope_cntl_r; \ + uint32_t start_end_cntl1_b; \ + uint32_t start_end_cntl2_b; \ + uint32_t start_end_cntl1_g; \ + uint32_t start_end_cntl2_g; \ + uint32_t start_end_cntl1_r; \ + uint32_t start_end_cntl2_r; \ + uint32_t region_start; \ + uint32_t region_end + #define TF_CM_REG_FIELD_LIST(type) \ type csc_c11; \ type csc_c12 @@ -54,20 +70,7 @@ struct xfer_func_reg { struct xfer_func_shift shifts; struct xfer_func_mask masks; - uint32_t start_cntl_b; - uint32_t start_cntl_g; - uint32_t start_cntl_r; - uint32_t start_slope_cntl_b; - uint32_t start_slope_cntl_g; - uint32_t start_slope_cntl_r; - uint32_t start_end_cntl1_b; - uint32_t start_end_cntl2_b; - uint32_t start_end_cntl1_g; - uint32_t start_end_cntl2_g; - uint32_t start_end_cntl1_r; - uint32_t start_end_cntl2_r; - uint32_t region_start; - uint32_t region_end; + TF_HELPER_REG_LIST; }; struct cm_color_matrix_shift { 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 0db2a6e96fc0..a1c824efa686 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -23,6 +23,8 @@ * */ +#include <linux/delay.h> + #include "dm_services.h" #include "dcn10_hubp.h" #include "dcn10_hubbub.h" @@ -263,20 +265,15 @@ void hubbub1_wm_change_req_wa(struct hubbub *hubbub) DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); } -void hubbub1_program_watermarks( +void hubbub1_program_urgent_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, unsigned int refclk_mhz, bool safe_to_lower) { struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); - /* - * Need to clamp to max of the register values (i.e. no wrap) - * for dcn1, all wm registers are 21-bit wide - */ uint32_t prog_wm_value; - /* Repeat for water mark set A, B, C and D. */ /* clock state A */ if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) { @@ -291,60 +288,14 @@ void hubbub1_program_watermarks( watermarks->a.urgent_ns, prog_wm_value); } - if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A)) { - if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub1->watermarks.a.pte_meta_urgent_ns) { - hubbub1->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.pte_meta_urgent_ns, prog_wm_value); - } - } - - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { - if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, - DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); - } - - if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns - > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) { - hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns = - watermarks->a.cstate_pstate.cstate_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, - DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); - } - } - - if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns - > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) { - hubbub1->watermarks.a.cstate_pstate.pstate_change_ns = - watermarks->a.cstate_pstate.pstate_change_ns; - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.pstate_change_ns, + if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub1->watermarks.a.pte_meta_urgent_ns) { + hubbub1->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0, - DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.pte_meta_urgent_ns, prog_wm_value); } /* clock state B */ @@ -360,60 +311,14 @@ void hubbub1_program_watermarks( watermarks->b.urgent_ns, prog_wm_value); } - if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B)) { - if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub1->watermarks.b.pte_meta_urgent_ns) { - hubbub1->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.pte_meta_urgent_ns, prog_wm_value); - } - } - - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { - if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, - DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); - } - - if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns - > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) { - hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns = - watermarks->b.cstate_pstate.cstate_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, - DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); - } - } - - if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns - > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) { - hubbub1->watermarks.b.cstate_pstate.pstate_change_ns = - watermarks->b.cstate_pstate.pstate_change_ns; - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.pstate_change_ns, + if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub1->watermarks.b.pte_meta_urgent_ns) { + hubbub1->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0, - DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.pte_meta_urgent_ns, prog_wm_value); } /* clock state C */ @@ -429,60 +334,14 @@ void hubbub1_program_watermarks( watermarks->c.urgent_ns, prog_wm_value); } - if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C)) { - if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub1->watermarks.c.pte_meta_urgent_ns) { - hubbub1->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.pte_meta_urgent_ns, prog_wm_value); - } - } - - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { - if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, - DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); - } - - if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns - > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) { - hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns = - watermarks->c.cstate_pstate.cstate_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, - DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); - } - } - - if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns - > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) { - hubbub1->watermarks.c.cstate_pstate.pstate_change_ns = - watermarks->c.cstate_pstate.pstate_change_ns; - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.pstate_change_ns, + if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub1->watermarks.c.pte_meta_urgent_ns) { + hubbub1->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0, - DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.pte_meta_urgent_ns, prog_wm_value); } /* clock state D */ @@ -498,48 +357,199 @@ void hubbub1_program_watermarks( watermarks->d.urgent_ns, prog_wm_value); } - if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D)) { - if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub1->watermarks.d.pte_meta_urgent_ns) { - hubbub1->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.pte_meta_urgent_ns, prog_wm_value); - } + if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub1->watermarks.d.pte_meta_urgent_ns) { + hubbub1->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.pte_meta_urgent_ns, prog_wm_value); } +} - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { - if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, - DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); - } +void hubbub1_program_stutter_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + uint32_t prog_wm_value; - if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns - > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) { - hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns = - watermarks->d.cstate_pstate.cstate_exit_ns; - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_exit_ns, - refclk_mhz, 0x1fffff); - REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, - DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); - } + /* clock state A */ + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns = + watermarks->a.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + /* clock state B */ + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns = + watermarks->b.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + /* clock state C */ + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns = + watermarks->c.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + /* clock state D */ + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns = + watermarks->d.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + +} + +void hubbub1_program_pstate_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + uint32_t prog_wm_value; + + /* clock state A */ + if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns + > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.a.cstate_pstate.pstate_change_ns = + watermarks->a.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); } + /* clock state B */ + if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns + > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.b.cstate_pstate.pstate_change_ns = + watermarks->b.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); + } + + /* clock state C */ + if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns + > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.c.cstate_pstate.pstate_change_ns = + watermarks->c.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); + } + + /* clock state D */ if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) { hubbub1->watermarks.d.cstate_pstate.pstate_change_ns = @@ -553,6 +563,22 @@ void hubbub1_program_watermarks( "HW register value = 0x%x\n\n", watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); } +} + +void hubbub1_program_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + /* + * Need to clamp to max of the register values (i.e. no wrap) + * for dcn1, all wm registers are 21-bit wide + */ + hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); @@ -903,9 +929,7 @@ void hubbub1_construct(struct hubbub *hubbub, hubbub1->masks = hubbub_mask; hubbub1->debug_test_index_pstate = 0x7; -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) if (ctx->dce_version == DCN_VERSION_1_01) hubbub1->debug_test_index_pstate = 0xB; -#endif } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 85811b24a497..7c2559c9ae23 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -262,4 +262,20 @@ void hubbub1_construct(struct hubbub *hubbub, const struct dcn_hubbub_shift *hubbub_shift, const struct dcn_hubbub_mask *hubbub_mask); +void hubbub1_program_urgent_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); +void hubbub1_program_stutter_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); +void hubbub1_program_pstate_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); + #endif 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 33d311cea28c..821a280eb481 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 @@ -45,6 +45,8 @@ #include "dcn10_cm_common.h" #include "dc_link_dp.h" #include "dccg.h" +#include "clk_mgr.h" + #define DC_LOGGER_INIT(logger) @@ -658,16 +660,15 @@ static enum dc_status dcn10_enable_stream_timing( BREAK_TO_DEBUGGER(); return DC_ERROR_UNEXPECTED; } - pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; - pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; - - pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; pipe_ctx->stream_res.tg->funcs->program_timing( pipe_ctx->stream_res.tg, &stream->timing, + pipe_ctx->pipe_dlg_param.vready_offset, + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width, + pipe_ctx->stream->signal, true); #if 0 /* move to after enable_crtc */ @@ -1101,9 +1102,6 @@ static void dcn10_init_hw(struct dc *dc) */ struct dc_link *link = dc->links[i]; - if (link->link_enc->connector.id == CONNECTOR_ID_EDP) - dc->hwss.edp_power_control(link, true); - link->link_enc->funcs->hw_init(link->link_enc); /* Check for enabled DIG to identify enabled display */ @@ -1145,6 +1143,9 @@ static void dcn10_init_hw(struct dc *dc) if (dmcu != NULL) dmcu->funcs->dmcu_init(dmcu); + if (abm != NULL && dmcu != NULL) + abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ REG_WRITE(DIO_MEM_PWR_CTRL, 0); @@ -1159,7 +1160,7 @@ static void dcn10_init_hw(struct dc *dc) enable_power_gating_plane(dc->hwseq, true); - memset(&dc->res_pool->clk_mgr->clks, 0, sizeof(dc->res_pool->clk_mgr->clks)); + memset(&dc->clk_mgr->clks, 0, sizeof(dc->clk_mgr->clks)); } static void dcn10_reset_hw_ctx_wrap( @@ -1756,7 +1757,7 @@ static void dcn10_program_output_csc(struct dc *dc, bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) { - if (pipe_ctx->plane_state->visible) + if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) return true; if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) return true; @@ -1765,7 +1766,7 @@ bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) { - if (pipe_ctx->plane_state->visible) + if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) return true; if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) return true; @@ -1774,7 +1775,7 @@ bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) { - if (pipe_ctx->plane_state->visible) + if (pipe_ctx->plane_state && pipe_ctx->plane_state->visible) return true; if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) return true; @@ -1920,7 +1921,7 @@ static uint16_t fixed_point_to_int_frac( return result; } -void build_prescale_params(struct dc_bias_and_scale *bias_and_scale, +void dcn10_build_prescale_params(struct dc_bias_and_scale *bias_and_scale, const struct dc_plane_state *plane_state) { if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN @@ -1953,7 +1954,7 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) plane_state->color_space); //set scale and bias registers - build_prescale_params(&bns_params, plane_state); + dcn10_build_prescale_params(&bns_params, plane_state); if (dpp->funcs->dpp_program_bias_and_scale) dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); } @@ -2071,7 +2072,7 @@ void update_dchubp_dpp( */ if (plane_state->update_flags.bits.full_update) { bool should_divided_by_2 = context->bw_ctx.bw.dcn.clk.dppclk_khz <= - dc->res_pool->clk_mgr->clks.dispclk_khz / 2; + dc->clk_mgr->clks.dispclk_khz / 2; dpp->funcs->dpp_dppclk_control( dpp, @@ -2084,9 +2085,9 @@ void update_dchubp_dpp( dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz); else - dc->res_pool->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? - dc->res_pool->clk_mgr->clks.dispclk_khz / 2 : - dc->res_pool->clk_mgr->clks.dispclk_khz; + dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? + dc->clk_mgr->clks.dispclk_khz / 2 : + dc->clk_mgr->clks.dispclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG @@ -2279,14 +2280,15 @@ static void program_all_pipe_in_tree( if (pipe_ctx->top_pipe == NULL) { bool blank = !is_pipe_tree_visible(pipe_ctx); - pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; - pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; - pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; - pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; - pipe_ctx->stream_res.tg->funcs->program_global_sync( - pipe_ctx->stream_res.tg); + pipe_ctx->stream_res.tg, + pipe_ctx->pipe_dlg_param.vready_offset, + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width); + + pipe_ctx->stream_res.tg->funcs->set_vtg_params( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); @@ -2448,8 +2450,8 @@ static void dcn10_prepare_bandwidth( if (context->stream_count == 0) context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; - dc->res_pool->clk_mgr->funcs->update_clocks( - dc->res_pool->clk_mgr, + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, context, false); } @@ -2480,8 +2482,8 @@ static void dcn10_optimize_bandwidth( if (context->stream_count == 0) context->bw_ctx.bw.dcn.clk.phyclk_khz = 0; - dc->res_pool->clk_mgr->funcs->update_clocks( - dc->res_pool->clk_mgr, + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, context, true); } @@ -2504,8 +2506,8 @@ static void set_drr(struct pipe_ctx **pipe_ctx, { int i = 0; struct drr_params params = {0}; - // DRR should set trigger event to monitor surface update event - unsigned int event_triggers = 0x80; + // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow + unsigned int event_triggers = 0x800; params.vertical_total_max = vmax; params.vertical_total_min = vmin; @@ -2644,9 +2646,6 @@ static void dcn10_wait_for_mpcc_disconnect( res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst); pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false; hubp->funcs->set_blank(hubp, true); - /*DC_LOG_ERROR(dc->ctx->logger, - "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n", - i);*/ } } @@ -2790,7 +2789,6 @@ static void apply_front_porch_workaround( int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) { - struct timing_generator *optc = pipe_ctx->stream_res.tg; const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing; struct dc_crtc_timing patched_crtc_timing; int vesa_sync_start; @@ -2813,7 +2811,7 @@ int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx) * interlace_factor; vertical_line_start = asic_blank_end - - optc->dlg_otg_param.vstartup_start + 1; + pipe_ctx->pipe_dlg_param.vstartup_start + 1; return vertical_line_start; } @@ -2961,6 +2959,18 @@ static void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx, } } +static void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size) +{ + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message( + pipe_ctx->stream_res.stream_enc, + custom_sdp_message, + sdp_message_size); + } +} + static const struct hw_sequencer_funcs dcn10_funcs = { .program_gamut_remap = program_gamut_remap, .init_hw = dcn10_init_hw, @@ -2980,6 +2990,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .enable_timing_synchronization = dcn10_enable_timing_synchronization, .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, .enable_stream = dce110_enable_stream, .disable_stream = dce110_disable_stream, .unblank_stream = dcn10_unblank_stream, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 4b3b27a5d23b..ef94d6b15843 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -83,6 +83,8 @@ struct pipe_ctx *find_top_pipe_for_stream( int get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx); +void dcn10_build_prescale_params(struct dc_bias_and_scale *bias_and_scale, + const struct dc_plane_state *plane_state); void lock_all_pipes(struct dc *dc, struct dc_state *context, bool lock); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 991622da9ed5..6e47444109d7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -43,7 +43,7 @@ #include "dcn10_hubp.h" #include "dcn10_hubbub.h" #include "dcn10_cm_common.h" -#include "dcn10_clk_mgr.h" +#include "clk_mgr.h" static unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, ...) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c index 08db1e6b5166..0e0c6850247d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c @@ -23,6 +23,8 @@ * */ +#include <linux/slab.h> + #include "dm_services.h" #include "dcn10_ipp.h" #include "reg_helper.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 0126a44ba012..0a520591fd3a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -23,6 +23,9 @@ * */ +#include <linux/delay.h> +#include <linux/slab.h> + #include "reg_helper.h" #include "core_types.h" @@ -726,6 +729,8 @@ void dcn10_link_encoder_construct( enc10->base.features.flags.bits.IS_HBR3_CAPABLE = bp_cap_info.DP_HBR3_EN; enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; + enc10->base.features.flags.bits.DP_IS_USB_C = + bp_cap_info.DP_IS_USB_C; } else { DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", __func__, @@ -1357,5 +1362,5 @@ void dcn10_aux_initialize(struct dcn10_link_encoder *enc10) /* 1/4 window (the maximum allowed) */ AUX_REG_UPDATE(AUX_DPHY_RX_CONTROL0, - AUX_RX_RECEIVE_WINDOW, 1); + AUX_RX_RECEIVE_WINDOW, 0); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c index ab958cff3b76..cec69cecf521 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c @@ -23,6 +23,8 @@ * */ +#include <linux/slab.h> + #include "dm_services.h" #include "dcn10_opp.h" #include "reg_helper.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 0345d51e9d6f..e4b850a2d31f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -46,9 +46,7 @@ * This is a workaround for a bug that has existed since R5xx and has not been * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. */ -static void optc1_apply_front_porch_workaround( - struct timing_generator *optc, - struct dc_crtc_timing *timing) +static void apply_front_porch_workaround(struct dc_crtc_timing *timing) { if (timing->flags.INTERLACE == 1) { if (timing->v_front_porch < 2) @@ -60,24 +58,33 @@ static void optc1_apply_front_porch_workaround( } void optc1_program_global_sync( - struct timing_generator *optc) + struct timing_generator *optc, + int vready_offset, + int vstartup_start, + int vupdate_offset, + int vupdate_width) { struct optc *optc1 = DCN10TG_FROM_TG(optc); - if (optc->dlg_otg_param.vstartup_start == 0) { + optc1->vready_offset = vready_offset; + optc1->vstartup_start = vstartup_start; + optc1->vupdate_offset = vupdate_offset; + optc1->vupdate_width = vupdate_width; + + if (optc1->vstartup_start == 0) { BREAK_TO_DEBUGGER(); return; } REG_SET(OTG_VSTARTUP_PARAM, 0, - VSTARTUP_START, optc->dlg_otg_param.vstartup_start); + VSTARTUP_START, optc1->vstartup_start); REG_SET_2(OTG_VUPDATE_PARAM, 0, - VUPDATE_OFFSET, optc->dlg_otg_param.vupdate_offset, - VUPDATE_WIDTH, optc->dlg_otg_param.vupdate_width); + VUPDATE_OFFSET, optc1->vupdate_offset, + VUPDATE_WIDTH, optc1->vupdate_width); REG_SET(OTG_VREADY_PARAM, 0, - VREADY_OFFSET, optc->dlg_otg_param.vready_offset); + VREADY_OFFSET, optc1->vready_offset); } static void optc1_disable_stereo(struct timing_generator *optc) @@ -132,25 +139,32 @@ void optc1_setup_vertical_interrupt2( void optc1_program_timing( struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing, + int vready_offset, + int vstartup_start, + int vupdate_offset, + int vupdate_width, + const enum signal_type signal, bool use_vbios) { struct dc_crtc_timing patched_crtc_timing; - uint32_t vesa_sync_start; uint32_t asic_blank_end; uint32_t asic_blank_start; uint32_t v_total; uint32_t v_sync_end; - uint32_t v_init, v_fp2; uint32_t h_sync_polarity, v_sync_polarity; uint32_t start_point = 0; uint32_t field_num = 0; uint32_t h_div_2; - int32_t vertical_line_start; struct optc *optc1 = DCN10TG_FROM_TG(optc); + optc1->signal = signal; + optc1->vready_offset = vready_offset; + optc1->vstartup_start = vstartup_start; + optc1->vupdate_offset = vupdate_offset; + optc1->vupdate_width = vupdate_width; patched_crtc_timing = *dc_crtc_timing; - optc1_apply_front_porch_workaround(optc, &patched_crtc_timing); + apply_front_porch_workaround(&patched_crtc_timing); /* Load horizontal timing */ @@ -163,24 +177,16 @@ void optc1_program_timing( OTG_H_SYNC_A_START, 0, OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width); - /* asic_h_blank_end = HsyncWidth + HbackPorch = - * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart - - * vesa.h_left_border - */ - vesa_sync_start = patched_crtc_timing.h_addressable + - patched_crtc_timing.h_border_right + + /* blank_start = line end - front porch */ + asic_blank_start = patched_crtc_timing.h_total - patched_crtc_timing.h_front_porch; - asic_blank_end = patched_crtc_timing.h_total - - vesa_sync_start - + /* blank_end = blank_start - active */ + asic_blank_end = asic_blank_start - + patched_crtc_timing.h_border_right - + patched_crtc_timing.h_addressable - patched_crtc_timing.h_border_left; - /* h_blank_start = v_blank_end + v_active */ - asic_blank_start = asic_blank_end + - patched_crtc_timing.h_border_left + - patched_crtc_timing.h_addressable + - patched_crtc_timing.h_border_right; - REG_UPDATE_2(OTG_H_BLANK_START_END, OTG_H_BLANK_START, asic_blank_start, OTG_H_BLANK_END, asic_blank_end); @@ -212,24 +218,15 @@ void optc1_program_timing( OTG_V_SYNC_A_START, 0, OTG_V_SYNC_A_END, v_sync_end); - vesa_sync_start = patched_crtc_timing.v_addressable + - patched_crtc_timing.v_border_bottom + + /* blank_start = frame end - front porch */ + asic_blank_start = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch; - asic_blank_end = (patched_crtc_timing.v_total - - vesa_sync_start - - patched_crtc_timing.v_border_top); - - /* v_blank_start = v_blank_end + v_active */ - asic_blank_start = asic_blank_end + - (patched_crtc_timing.v_border_top + - patched_crtc_timing.v_addressable + - patched_crtc_timing.v_border_bottom); - - vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; - v_fp2 = 0; - if (vertical_line_start < 0) - v_fp2 = -vertical_line_start; + /* blank_end = blank_start - active */ + asic_blank_end = asic_blank_start - + patched_crtc_timing.v_border_bottom - + patched_crtc_timing.v_addressable - + patched_crtc_timing.v_border_top; REG_UPDATE_2(OTG_V_BLANK_START_END, OTG_V_BLANK_START, asic_blank_start, @@ -242,10 +239,9 @@ void optc1_program_timing( REG_UPDATE(OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, v_sync_polarity); - v_init = asic_blank_start; - if (optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT || - optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT_MST || - optc->dlg_otg_param.signal == SIGNAL_TYPE_EDP) { + if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT || + optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + optc1->signal == SIGNAL_TYPE_EDP) { start_point = 1; if (patched_crtc_timing.flags.INTERLACE == 1) field_num = 1; @@ -253,13 +249,10 @@ void optc1_program_timing( /* Interlace */ if (REG(OTG_INTERLACE_CONTROL)) { - if (patched_crtc_timing.flags.INTERLACE == 1) { + if (patched_crtc_timing.flags.INTERLACE == 1) REG_UPDATE(OTG_INTERLACE_CONTROL, OTG_INTERLACE_ENABLE, 1); - v_init = v_init / 2; - if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end) - v_fp2 = v_fp2 / 2; - } else + else REG_UPDATE(OTG_INTERLACE_CONTROL, OTG_INTERLACE_ENABLE, 0); } @@ -268,16 +261,18 @@ void optc1_program_timing( REG_UPDATE(CONTROL, VTG0_ENABLE, 0); - REG_UPDATE_2(CONTROL, - VTG0_FP2, v_fp2, - VTG0_VCOUNT_INIT, v_init); - /* original code is using VTG offset to address OTG reg, seems wrong */ REG_UPDATE_2(OTG_CONTROL, OTG_START_POINT_CNTL, start_point, OTG_FIELD_NUMBER_CNTL, field_num); - optc1_program_global_sync(optc); + optc->funcs->program_global_sync(optc, + vready_offset, + vstartup_start, + vupdate_offset, + vupdate_width); + + optc->funcs->set_vtg_params(optc, dc_crtc_timing); /* TODO * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1 @@ -296,6 +291,48 @@ void optc1_program_timing( } +void optc1_set_vtg_params(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct dc_crtc_timing patched_crtc_timing; + uint32_t asic_blank_end; + uint32_t v_init; + uint32_t v_fp2 = 0; + int32_t vertical_line_start; + + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + patched_crtc_timing = *dc_crtc_timing; + apply_front_porch_workaround(&patched_crtc_timing); + + /* VCOUNT_INIT is the start of blank */ + v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch; + + /* end of blank = v_init - active */ + asic_blank_end = v_init - + patched_crtc_timing.v_border_bottom - + patched_crtc_timing.v_addressable - + patched_crtc_timing.v_border_top; + + /* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */ + vertical_line_start = asic_blank_end - optc1->vstartup_start + 1; + if (vertical_line_start < 0) + v_fp2 = -vertical_line_start; + + /* Interlace */ + if (REG(OTG_INTERLACE_CONTROL)) { + if (patched_crtc_timing.flags.INTERLACE == 1) { + v_init = v_init / 2; + if ((optc1->vstartup_start/2)*2 > asic_blank_end) + v_fp2 = v_fp2 / 2; + } + } + + REG_UPDATE_2(CONTROL, + VTG0_FP2, v_fp2, + VTG0_VCOUNT_INIT, v_init); +} + void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable) { struct optc *optc1 = DCN10TG_FROM_TG(optc); @@ -754,6 +791,32 @@ void optc1_set_static_screen_control( OTG_STATIC_SCREEN_FRAME_COUNT, 2); } +void optc1_setup_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL2, 0, + MANUAL_FLOW_CONTROL_SEL, optc->inst); + + REG_SET_8(OTG_TRIGA_CNTL, 0, + OTG_TRIGA_SOURCE_SELECT, 22, + OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, + OTG_TRIGA_POLARITY_SELECT, 0, + OTG_TRIGA_FREQUENCY_SELECT, 0, + OTG_TRIGA_DELAY, 0, + OTG_TRIGA_CLEAR, 1); +} + +void optc1_program_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, + MANUAL_FLOW_CONTROL, 1); +} + /** ***************************************************************************** @@ -786,6 +849,10 @@ void optc1_set_drr( OTG_FORCE_LOCK_ON_EVENT, 0, OTG_SET_V_TOTAL_MIN_MASK_EN, 0, OTG_SET_V_TOTAL_MIN_MASK, 0); + + // Setup manual flow control for EOF via TRIG_A + optc->funcs->setup_manual_trigger(optc); + } else { REG_UPDATE_4(OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, 0, @@ -1420,6 +1487,9 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .clear_optc_underflow = optc1_clear_optc_underflow, .get_crc = optc1_get_crc, .configure_crc = optc1_configure_crc, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc1_program_manual_trigger, + .setup_manual_trigger = optc1_setup_manual_trigger }; void dcn10_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 4eb9a898c237..444c56c8104f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -84,13 +84,18 @@ SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst) + SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ + SR(GSL_SOURCE_SELECT),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst) + #define TG_COMMON_REG_LIST_DCN1_0(inst) \ TG_COMMON_REG_LIST_DCN(inst),\ SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\ SRI(OTG_TEST_PATTERN_CONTROL, OTG, inst),\ - SRI(OTG_TEST_PATTERN_COLOR, OTG, inst) + SRI(OTG_TEST_PATTERN_COLOR, OTG, inst),\ + SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst) struct dcn_optc_registers { @@ -124,6 +129,8 @@ struct dcn_optc_registers { uint32_t OTG_V_TOTAL_MIN; uint32_t OTG_V_TOTAL_CONTROL; uint32_t OTG_TRIGA_CNTL; + uint32_t OTG_TRIGA_MANUAL_TRIG; + uint32_t OTG_MANUAL_FLOW_CONTROL; uint32_t OTG_FORCE_COUNT_NOW_CNTL; uint32_t OTG_STATIC_SCREEN_CONTROL; uint32_t OTG_STATUS_FRAME_COUNT; @@ -156,6 +163,7 @@ struct dcn_optc_registers { uint32_t OTG_CRC0_WINDOWA_Y_CONTROL; uint32_t OTG_CRC0_WINDOWB_X_CONTROL; uint32_t OTG_CRC0_WINDOWB_Y_CONTROL; + uint32_t GSL_SOURCE_SELECT; }; #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ @@ -213,6 +221,11 @@ struct dcn_optc_registers { SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ @@ -266,8 +279,11 @@ struct dcn_optc_registers { SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh) - + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh) #define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\ TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ @@ -282,7 +298,8 @@ struct dcn_optc_registers { SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_COLOR_FORMAT, mask_sh),\ SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_MASK, mask_sh),\ SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_DATA, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh) + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh),\ + SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh),\ #define TG_REG_FIELD_LIST_DCN1_0(type) \ type VSTARTUP_START;\ @@ -338,6 +355,11 @@ struct dcn_optc_registers { type OTG_TRIGA_SOURCE_PIPE_SELECT;\ type OTG_TRIGA_RISING_EDGE_DETECT_CNTL;\ type OTG_TRIGA_FALLING_EDGE_DETECT_CNTL;\ + type OTG_TRIGA_POLARITY_SELECT;\ + type OTG_TRIGA_FREQUENCY_SELECT;\ + type OTG_TRIGA_DELAY;\ + type OTG_TRIGA_CLEAR;\ + type OTG_TRIGA_MANUAL_TRIG;\ type OTG_STATIC_SCREEN_EVENT_MASK;\ type OTG_STATIC_SCREEN_FRAME_COUNT;\ type OTG_FRAME_COUNT;\ @@ -413,7 +435,12 @@ struct dcn_optc_registers { type OTG_CRC0_WINDOWB_X_START;\ type OTG_CRC0_WINDOWB_X_END;\ type OTG_CRC0_WINDOWB_Y_START;\ - type OTG_CRC0_WINDOWB_Y_END; + type OTG_CRC0_WINDOWB_Y_END;\ + type GSL0_READY_SOURCE_SEL;\ + type GSL1_READY_SOURCE_SEL;\ + type GSL2_READY_SOURCE_SEL;\ + type MANUAL_FLOW_CONTROL;\ + type MANUAL_FLOW_CONTROL_SEL; #define TG_REG_FIELD_LIST(type) \ @@ -446,6 +473,12 @@ struct optc { uint32_t min_v_sync_width; uint32_t min_v_blank; uint32_t min_v_blank_interlace; + + int vstartup_start; + int vupdate_offset; + int vupdate_width; + int vready_offset; + enum signal_type signal; }; void dcn10_timing_generator_init(struct optc *optc); @@ -481,6 +514,11 @@ bool optc1_validate_timing( void optc1_program_timing( struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing, + int vready_offset, + int vstartup_start, + int vupdate_offset, + int vupdate_width, + const enum signal_type signal, bool use_vbios); void optc1_setup_vertical_interrupt0( @@ -495,7 +533,11 @@ void optc1_setup_vertical_interrupt2( uint32_t start_line); void optc1_program_global_sync( - struct timing_generator *optc); + struct timing_generator *optc, + int vready_offset, + int vstartup_start, + int vupdate_offset, + int vupdate_width); bool optc1_disable_crtc(struct timing_generator *optc); @@ -582,4 +624,7 @@ bool optc1_get_crc(struct timing_generator *optc, bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); +void optc1_set_vtg_params(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing); + #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ 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 7eccb54c421d..3272030c82c5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -23,13 +23,14 @@ * */ +#include <linux/slab.h> + #include "dm_services.h" #include "dc.h" #include "resource.h" #include "include/irq_service_interface.h" #include "dcn10_resource.h" - #include "dcn10_ipp.h" #include "dcn10_mpc.h" #include "irq/dcn10/irq_service_dcn10.h" @@ -40,7 +41,6 @@ #include "dcn10_opp.h" #include "dcn10_link_encoder.h" #include "dcn10_stream_encoder.h" -#include "dcn10_clk_mgr.h" #include "dce/dce_clock_source.h" #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" @@ -153,9 +153,7 @@ enum dcn10_clk_src_array_id { DCN10_CLK_SRC_PLL2, DCN10_CLK_SRC_PLL3, DCN10_CLK_SRC_TOTAL, -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) DCN101_CLK_SRC_TOTAL = DCN10_CLK_SRC_PLL3 -#endif }; /* begin ********************* @@ -202,6 +200,7 @@ enum dcn10_clk_src_array_id { #define MMHUB_SR(reg_name)\ .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ mm ## reg_name + /* macros to expend register list macro defined in HW object header file * end *********************/ @@ -445,7 +444,6 @@ static const struct bios_registers bios_regs = { HUBP_REG_LIST_DCN10(id)\ } - static const struct dcn_mi_registers hubp_regs[] = { hubp_regs(0), hubp_regs(1), @@ -461,7 +459,6 @@ static const struct dcn_mi_mask hubp_mask = { HUBP_MASK_SH_LIST_DCN10(_MASK) }; - static const struct dcn_hubbub_registers hubbub_reg = { HUBBUB_REG_LIST_DCN10(0) }; @@ -504,7 +501,6 @@ static const struct resource_caps res_cap = { .num_ddc = 4, }; -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) static const struct resource_caps rv2_res_cap = { .num_timing_generator = 3, .num_opp = 3, @@ -514,7 +510,6 @@ static const struct resource_caps rv2_res_cap = { .num_pll = 3, .num_ddc = 3, }; -#endif static const struct dc_plane_cap plane_cap = { .type = DC_PLANE_TYPE_DCN_UNIVERSAL, @@ -966,9 +961,6 @@ static void destruct(struct dcn10_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.clk_mgr != NULL) - dce_clk_mgr_destroy(&pool->base.clk_mgr); - kfree(pool->base.pp_smu); } @@ -1217,6 +1209,38 @@ static enum dc_status dcn10_get_default_swizzle_mode(struct dc_plane_state *plan return result; } +struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + int i; + int j = -1; + struct dc_link *link = stream->link; + + for (i = 0; i < pool->stream_enc_count; i++) { + if (!res_ctx->is_stream_enc_acquired[i] && + pool->stream_enc[i]) { + /* Store first available for MST second display + * in daisy chain use case + */ + j = i; + if (pool->stream_enc[i]->id == + link->link_enc->preferred_engine) + return pool->stream_enc[i]; + } + } + + /* + * For CZ and later, we can allow DIG FE and BE to differ for all display types + */ + + if (j >= 0) + return pool->stream_enc[j]; + + return NULL; +} + static const struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn10_get_dcc_compression_cap }; @@ -1229,7 +1253,8 @@ static const struct resource_funcs dcn10_res_pool_funcs = { .validate_plane = dcn10_validate_plane, .validate_global = dcn10_validate_global, .add_stream_to_ctx = dcn10_add_stream_to_ctx, - .get_default_swizzle_mode = dcn10_get_default_swizzle_mode + .get_default_swizzle_mode = dcn10_get_default_swizzle_mode, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link }; static uint32_t read_pipe_fuses(struct dc_context *ctx) @@ -1252,11 +1277,9 @@ static bool construct( ctx->dc_bios->regs = &bios_regs; -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) if (ctx->dce_version == DCN_VERSION_1_01) pool->base.res_cap = &rv2_res_cap; else -#endif pool->base.res_cap = &res_cap; pool->base.funcs = &dcn10_res_pool_funcs; @@ -1273,10 +1296,8 @@ static bool construct( /* max pipe num for ASIC before check pipe fuses */ pool->base.pipe_count = pool->base.res_cap->num_timing_generator; -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) if (dc->ctx->dce_version == DCN_VERSION_1_01) pool->base.pipe_count = 3; -#endif dc->caps.max_video_width = 3840; dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 100; @@ -1309,26 +1330,17 @@ static bool construct( CLOCK_SOURCE_COMBO_PHY_PLL2, &clk_src_regs[2], false); -#ifdef CONFIG_DRM_AMD_DC_DCN1_01 if (dc->ctx->dce_version == DCN_VERSION_1_0) { pool->base.clock_sources[DCN10_CLK_SRC_PLL3] = dcn10_clock_source_create(ctx, ctx->dc_bios, CLOCK_SOURCE_COMBO_PHY_PLL3, &clk_src_regs[3], false); } -#else - pool->base.clock_sources[DCN10_CLK_SRC_PLL3] = - dcn10_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); -#endif pool->base.clk_src_count = DCN10_CLK_SRC_TOTAL; -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) if (dc->ctx->dce_version == DCN_VERSION_1_01) pool->base.clk_src_count = DCN101_CLK_SRC_TOTAL; -#endif pool->base.dp_clock_source = dcn10_clock_source_create(ctx, ctx->dc_bios, @@ -1343,12 +1355,6 @@ static bool construct( goto fail; } } - pool->base.clk_mgr = dcn1_clk_mgr_create(ctx); - if (pool->base.clk_mgr == NULL) { - dm_error("DC: failed to create display clock!\n"); - BREAK_TO_DEBUGGER(); - goto fail; - } pool->base.dmcu = dcn10_dmcu_create(ctx, &dmcu_regs, @@ -1374,7 +1380,6 @@ static bool construct( memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults)); memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults)); -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) if (dc->ctx->dce_version == DCN_VERSION_1_01) { struct dcn_soc_bounding_box *dcn_soc = dc->dcn_soc; struct dcn_ip_params *dcn_ip = dc->dcn_ip; @@ -1385,7 +1390,6 @@ static bool construct( dcn_soc->dram_clock_change_latency = 23; dcn_ip->max_num_dpp = 3; } -#endif if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { dc->dcn_soc->urgent_latency = 3; dc->debug.disable_dmcu = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h index 999c684a0b36..633025ccb870 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h @@ -42,6 +42,11 @@ struct resource_pool *dcn10_create_resource_pool( const struct dc_init_data *init_data, struct dc *dc); +struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream); + #endif /* __DC_RESOURCE_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index 8ee9f6dc1d62..b9ffbf6b58ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -23,6 +23,7 @@ * */ +#include <linux/delay.h> #include "dc_bios_types.h" #include "dcn10_stream_encoder.h" @@ -415,6 +416,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( case COLOR_SPACE_APPCTRL: case COLOR_SPACE_CUSTOMPOINTS: case COLOR_SPACE_UNKNOWN: + case COLOR_SPACE_YCBCR709_BLACK: /* do nothing */ break; } @@ -471,7 +473,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom); } -static void enc1_stream_encoder_set_stream_attribute_helper( +void enc1_stream_encoder_set_stream_attribute_helper( struct dcn10_stream_encoder *enc1, struct dc_crtc_timing *crtc_timing) { @@ -726,11 +728,9 @@ void enc1_stream_encoder_update_dp_info_packets( 3, /* packetIndex */ &info_frame->hdrsmd); - if (info_frame->dpsdp.valid) - enc1_update_generic_info_packet( - enc1, - 4,/* packetIndex */ - &info_frame->dpsdp); + /* packetIndex 4 is used for send immediate sdp message, and please + * use other packetIndex (such as 5,6) for other info packet + */ /* enable/disable transmission of packet(s). * If enabled, packet transmission begins on the next frame @@ -738,7 +738,101 @@ void enc1_stream_encoder_update_dp_info_packets( REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, info_frame->vsc.valid); REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, info_frame->spd.valid); REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, info_frame->hdrsmd.valid); - REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP4_ENABLE, info_frame->dpsdp.valid); + + + /* This bit is the master enable bit. + * When enabling secondary stream engine, + * this master bit must also be set. + * This register shared with audio info frame. + * Therefore we need to enable master bit + * if at least on of the fields is not 0 + */ + value = REG_READ(DP_SEC_CNTL); + if (value) + REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1); +} + +void enc1_stream_encoder_send_immediate_sdp_message( + struct stream_encoder *enc, + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + uint32_t value = 0; + + /* TODOFPGA Figure out a proper number for max_retries polling for lock + * use 50 for now. + */ + uint32_t max_retries = 50; + + /* check if GSP4 is transmitted */ + REG_WAIT(DP_SEC_CNTL2, DP_SEC_GSP4_SEND_PENDING, + 0, 10, max_retries); + + /* disable GSP4 transmitting */ + REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP4_SEND, 0); + + /* transmit GSP4 at the earliest time in a frame */ + REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP4_SEND_ANY_LINE, 1); + + /*we need turn on clock before programming AFMT block*/ + REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1); + + /* check if HW reading GSP memory */ + REG_WAIT(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT, + 0, 10, max_retries); + + /* HW does is not reading GSP memory not reading too long -> + * something wrong. clear GPS memory access and notify? + * hw SW is writing to GSP memory + */ + REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT_CLR, 1); + + /* use generic packet 4 for immediate sdp message */ + REG_UPDATE(AFMT_VBI_PACKET_CONTROL, + AFMT_GENERIC_INDEX, 4); + + /* write generic packet header + * (4th byte is for GENERIC0 only) + */ + REG_SET_4(AFMT_GENERIC_HDR, 0, + AFMT_GENERIC_HB0, custom_sdp_message[0], + AFMT_GENERIC_HB1, custom_sdp_message[1], + AFMT_GENERIC_HB2, custom_sdp_message[2], + AFMT_GENERIC_HB3, custom_sdp_message[3]); + + /* write generic packet contents + * (we never use last 4 bytes) + * there are 8 (0-7) mmDIG0_AFMT_GENERIC0_x registers + */ + { + const uint32_t *content = + (const uint32_t *) &custom_sdp_message[4]; + + REG_WRITE(AFMT_GENERIC_0, *content++); + REG_WRITE(AFMT_GENERIC_1, *content++); + REG_WRITE(AFMT_GENERIC_2, *content++); + REG_WRITE(AFMT_GENERIC_3, *content++); + REG_WRITE(AFMT_GENERIC_4, *content++); + REG_WRITE(AFMT_GENERIC_5, *content++); + REG_WRITE(AFMT_GENERIC_6, *content++); + REG_WRITE(AFMT_GENERIC_7, *content); + } + + /* check whether GENERIC4 registers double buffer update in immediate mode + * is pending + */ + REG_WAIT(AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_IMMEDIATE_UPDATE_PENDING, + 0, 10, max_retries); + + /* atomically update double-buffered GENERIC4 registers in immediate mode + * (update immediately) + */ + REG_UPDATE(AFMT_VBI_PACKET_CONTROL1, + AFMT_GENERIC4_IMMEDIATE_UPDATE, 1); + + /* enable GSP4 transmitting */ + REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP4_SEND, 1); /* This bit is the master enable bit. * When enabling secondary stream engine, @@ -998,19 +1092,6 @@ union audio_cea_channels { } channels; }; -struct audio_clock_info { - /* pixel clock frequency*/ - uint32_t pixel_clock_in_10khz; - /* N - 32KHz audio */ - uint32_t n_32khz; - /* CTS - 32KHz audio*/ - uint32_t cts_32khz; - uint32_t n_44khz; - uint32_t cts_44khz; - uint32_t n_48khz; - uint32_t cts_48khz; -}; - /* 25.2MHz/1.001*/ /* 25.2MHz/1.001*/ /* 25.2MHz*/ @@ -1113,7 +1194,7 @@ static union audio_cea_channels speakers_to_channels( return cea_channels; } -static void get_audio_clock_info( +void get_audio_clock_info( enum dc_color_depth color_depth, uint32_t crtc_pixel_clock_in_khz, uint32_t actual_pixel_clock_in_khz, @@ -1317,7 +1398,7 @@ static void enc1_se_setup_dp_audio( REG_UPDATE(AFMT_60958_0, AFMT_60958_CS_CLOCK_ACCURACY, 0); } -static void enc1_se_enable_audio_clock( +void enc1_se_enable_audio_clock( struct stream_encoder *enc, bool enable) { @@ -1339,7 +1420,7 @@ static void enc1_se_enable_audio_clock( */ } -static void enc1_se_enable_dp_audio( +void enc1_se_enable_dp_audio( struct stream_encoder *enc) { struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); @@ -1462,6 +1543,8 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = { enc1_stream_encoder_stop_hdmi_info_packets, .update_dp_info_packets = enc1_stream_encoder_update_dp_info_packets, + .send_immediate_sdp_message = + enc1_stream_encoder_send_immediate_sdp_message, .stop_dp_info_packets = enc1_stream_encoder_stop_dp_info_packets, .dp_blank = diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h index e654c2f55971..46c93ffc28d2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h @@ -81,6 +81,7 @@ SRI(DP_MSE_RATE_UPDATE, DP, id), \ SRI(DP_PIXEL_FORMAT, DP, id), \ SRI(DP_SEC_CNTL, DP, id), \ + SRI(DP_SEC_CNTL2, DP, id), \ SRI(DP_STEER_FIFO, DP, id), \ SRI(DP_VID_M, DP, id), \ SRI(DP_VID_N, DP, id), \ @@ -118,10 +119,12 @@ struct dcn10_stream_enc_registers { uint32_t AFMT_60958_1; uint32_t AFMT_60958_2; uint32_t DIG_FE_CNTL; + uint32_t DIG_FE_CNTL2; uint32_t DP_MSE_RATE_CNTL; uint32_t DP_MSE_RATE_UPDATE; uint32_t DP_PIXEL_FORMAT; uint32_t DP_SEC_CNTL; + uint32_t DP_SEC_CNTL2; uint32_t DP_STEER_FIFO; uint32_t DP_VID_M; uint32_t DP_VID_N; @@ -191,6 +194,10 @@ struct dcn10_stream_enc_registers { SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL, DP_SEC_MPG_ENABLE, mask_sh),\ + SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND, mask_sh),\ + SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND_PENDING, mask_sh),\ + SE_SF(DP0_DP_SEC_CNTL4, DP_SEC_GSP4_LINE_NUM, mask_sh),\ + SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND_ANY_LINE, mask_sh),\ SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, mask_sh),\ SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, mask_sh),\ SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, mask_sh),\ @@ -245,6 +252,7 @@ struct dcn10_stream_enc_registers { SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC2_FRAME_UPDATE_PENDING, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC3_FRAME_UPDATE_PENDING, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_FRAME_UPDATE_PENDING, mask_sh),\ + SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_IMMEDIATE_UPDATE_PENDING, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC5_FRAME_UPDATE_PENDING, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC6_FRAME_UPDATE_PENDING, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_FRAME_UPDATE_PENDING, mask_sh),\ @@ -253,6 +261,7 @@ struct dcn10_stream_enc_registers { SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC2_FRAME_UPDATE, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC3_FRAME_UPDATE, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_FRAME_UPDATE, mask_sh),\ + SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC4_IMMEDIATE_UPDATE, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC5_FRAME_UPDATE, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC6_FRAME_UPDATE, mask_sh),\ SE_SF(DIG0_AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_FRAME_UPDATE, mask_sh),\ @@ -260,6 +269,7 @@ struct dcn10_stream_enc_registers { SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP6_ENABLE, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, mask_sh),\ + SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP7_PPS, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP7_SEND, mask_sh),\ SE_SF(DP0_DP_DB_CNTL, DP_DB_DISABLE, mask_sh),\ SE_SF(DP0_DP_MSA_COLORIMETRY, DP_MSA_MISC0, mask_sh),\ @@ -304,6 +314,7 @@ struct dcn10_stream_enc_registers { type AFMT_GENERIC2_FRAME_UPDATE_PENDING;\ type AFMT_GENERIC3_FRAME_UPDATE_PENDING;\ type AFMT_GENERIC4_FRAME_UPDATE_PENDING;\ + type AFMT_GENERIC4_IMMEDIATE_UPDATE_PENDING;\ type AFMT_GENERIC5_FRAME_UPDATE_PENDING;\ type AFMT_GENERIC6_FRAME_UPDATE_PENDING;\ type AFMT_GENERIC7_FRAME_UPDATE_PENDING;\ @@ -312,6 +323,7 @@ struct dcn10_stream_enc_registers { type AFMT_GENERIC2_FRAME_UPDATE;\ type AFMT_GENERIC3_FRAME_UPDATE;\ type AFMT_GENERIC4_FRAME_UPDATE;\ + type AFMT_GENERIC4_IMMEDIATE_UPDATE;\ type AFMT_GENERIC5_FRAME_UPDATE;\ type AFMT_GENERIC6_FRAME_UPDATE;\ type AFMT_GENERIC7_FRAME_UPDATE;\ @@ -366,7 +378,12 @@ struct dcn10_stream_enc_registers { type DP_SEC_GSP5_ENABLE;\ type DP_SEC_GSP6_ENABLE;\ type DP_SEC_GSP7_ENABLE;\ + type DP_SEC_GSP7_PPS;\ type DP_SEC_GSP7_SEND;\ + type DP_SEC_GSP4_SEND;\ + type DP_SEC_GSP4_SEND_PENDING;\ + type DP_SEC_GSP4_LINE_NUM;\ + type DP_SEC_GSP4_SEND_ANY_LINE;\ type DP_SEC_MPG_ENABLE;\ type DP_VID_STREAM_DIS_DEFER;\ type DP_VID_STREAM_ENABLE;\ @@ -484,6 +501,11 @@ void enc1_stream_encoder_update_dp_info_packets( struct stream_encoder *enc, const struct encoder_info_frame *info_frame); +void enc1_stream_encoder_send_immediate_sdp_message( + struct stream_encoder *enc, + const uint8_t *custom_sdp_message, + unsigned int sdp_message_size); + void enc1_stream_encoder_stop_dp_info_packets( struct stream_encoder *enc); @@ -530,4 +552,21 @@ void enc1_dig_connect_to_otg( struct stream_encoder *enc, int tg_inst); +void enc1_stream_encoder_set_stream_attribute_helper( + struct dcn10_stream_encoder *enc1, + struct dc_crtc_timing *crtc_timing); + +void enc1_se_enable_audio_clock( + struct stream_encoder *enc, + bool enable); + +void enc1_se_enable_dp_audio( + struct stream_encoder *enc); + +void get_audio_clock_info( + enum dc_color_depth color_depth, + uint32_t crtc_pixel_clock_in_khz, + uint32_t actual_pixel_clock_in_khz, + struct audio_clock_info *audio_clock_info); + #endif /* __DC_STREAM_ENCODER_DCN10_H__ */ |