Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2020-2021 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 #include "resource.h"
0026 #include "clk_mgr.h"
0027 #include "reg_helper.h"
0028 #include "dcn_calc_math.h"
0029 #include "dcn20/dcn20_resource.h"
0030 #include "dcn30/dcn30_resource.h"
0031 
0032 #include "clk_mgr/dcn30/dcn30_smu11_driver_if.h"
0033 #include "display_mode_vba_30.h"
0034 #include "dcn30_fpu.h"
0035 
0036 #define REG(reg)\
0037     optc1->tg_regs->reg
0038 
0039 #define CTX \
0040     optc1->base.ctx
0041 
0042 #undef FN
0043 #define FN(reg_name, field_name) \
0044     optc1->tg_shift->field_name, optc1->tg_mask->field_name
0045 
0046 
0047 struct _vcs_dpi_ip_params_st dcn3_0_ip = {
0048     .use_min_dcfclk = 0,
0049     .clamp_min_dcfclk = 0,
0050     .odm_capable = 1,
0051     .gpuvm_enable = 0,
0052     .hostvm_enable = 0,
0053     .gpuvm_max_page_table_levels = 4,
0054     .hostvm_max_page_table_levels = 4,
0055     .hostvm_cached_page_table_levels = 0,
0056     .pte_group_size_bytes = 2048,
0057     .num_dsc = 6,
0058     .rob_buffer_size_kbytes = 184,
0059     .det_buffer_size_kbytes = 184,
0060     .dpte_buffer_size_in_pte_reqs_luma = 84,
0061     .pde_proc_buffer_size_64k_reqs = 48,
0062     .dpp_output_buffer_pixels = 2560,
0063     .opp_output_buffer_lines = 1,
0064     .pixel_chunk_size_kbytes = 8,
0065     .pte_enable = 1,
0066     .max_page_table_levels = 2,
0067     .pte_chunk_size_kbytes = 2,  // ?
0068     .meta_chunk_size_kbytes = 2,
0069     .writeback_chunk_size_kbytes = 8,
0070     .line_buffer_size_bits = 789504,
0071     .is_line_buffer_bpp_fixed = 0,  // ?
0072     .line_buffer_fixed_bpp = 0,     // ?
0073     .dcc_supported = true,
0074     .writeback_interface_buffer_size_kbytes = 90,
0075     .writeback_line_buffer_buffer_size = 0,
0076     .max_line_buffer_lines = 12,
0077     .writeback_luma_buffer_size_kbytes = 12,  // writeback_line_buffer_buffer_size = 656640
0078     .writeback_chroma_buffer_size_kbytes = 8,
0079     .writeback_chroma_line_buffer_width_pixels = 4,
0080     .writeback_max_hscl_ratio = 1,
0081     .writeback_max_vscl_ratio = 1,
0082     .writeback_min_hscl_ratio = 1,
0083     .writeback_min_vscl_ratio = 1,
0084     .writeback_max_hscl_taps = 1,
0085     .writeback_max_vscl_taps = 1,
0086     .writeback_line_buffer_luma_buffer_size = 0,
0087     .writeback_line_buffer_chroma_buffer_size = 14643,
0088     .cursor_buffer_size = 8,
0089     .cursor_chunk_size = 2,
0090     .max_num_otg = 6,
0091     .max_num_dpp = 6,
0092     .max_num_wb = 1,
0093     .max_dchub_pscl_bw_pix_per_clk = 4,
0094     .max_pscl_lb_bw_pix_per_clk = 2,
0095     .max_lb_vscl_bw_pix_per_clk = 4,
0096     .max_vscl_hscl_bw_pix_per_clk = 4,
0097     .max_hscl_ratio = 6,
0098     .max_vscl_ratio = 6,
0099     .hscl_mults = 4,
0100     .vscl_mults = 4,
0101     .max_hscl_taps = 8,
0102     .max_vscl_taps = 8,
0103     .dispclk_ramp_margin_percent = 1,
0104     .underscan_factor = 1.11,
0105     .min_vblank_lines = 32,
0106     .dppclk_delay_subtotal = 46,
0107     .dynamic_metadata_vm_enabled = true,
0108     .dppclk_delay_scl_lb_only = 16,
0109     .dppclk_delay_scl = 50,
0110     .dppclk_delay_cnvc_formatter = 27,
0111     .dppclk_delay_cnvc_cursor = 6,
0112     .dispclk_delay_subtotal = 119,
0113     .dcfclk_cstate_latency = 5.2, // SRExitTime
0114     .max_inter_dcn_tile_repeaters = 8,
0115     .max_num_hdmi_frl_outputs = 1,
0116     .odm_combine_4to1_supported = true,
0117 
0118     .xfc_supported = false,
0119     .xfc_fill_bw_overhead_percent = 10.0,
0120     .xfc_fill_constant_bytes = 0,
0121     .gfx7_compat_tiling_supported = 0,
0122     .number_of_cursors = 1,
0123 };
0124 
0125 struct _vcs_dpi_soc_bounding_box_st dcn3_0_soc = {
0126     .clock_limits = {
0127             {
0128                 .state = 0,
0129                 .dispclk_mhz = 562.0,
0130                 .dppclk_mhz = 300.0,
0131                 .phyclk_mhz = 300.0,
0132                 .phyclk_d18_mhz = 667.0,
0133                 .dscclk_mhz = 405.6,
0134             },
0135         },
0136 
0137     .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */
0138     .num_states = 1,
0139     .sr_exit_time_us = 15.5,
0140     .sr_enter_plus_exit_time_us = 20,
0141     .urgent_latency_us = 4.0,
0142     .urgent_latency_pixel_data_only_us = 4.0,
0143     .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
0144     .urgent_latency_vm_data_only_us = 4.0,
0145     .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
0146     .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
0147     .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
0148     .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
0149     .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
0150     .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
0151     .max_avg_sdp_bw_use_normal_percent = 60.0,
0152     .max_avg_dram_bw_use_normal_percent = 40.0,
0153     .writeback_latency_us = 12.0,
0154     .max_request_size_bytes = 256,
0155     .fabric_datapath_to_dcn_data_return_bytes = 64,
0156     .dcn_downspread_percent = 0.5,
0157     .downspread_percent = 0.38,
0158     .dram_page_open_time_ns = 50.0,
0159     .dram_rw_turnaround_time_ns = 17.5,
0160     .dram_return_buffer_per_channel_bytes = 8192,
0161     .round_trip_ping_latency_dcfclk_cycles = 191,
0162     .urgent_out_of_order_return_per_channel_bytes = 4096,
0163     .channel_interleave_bytes = 256,
0164     .num_banks = 8,
0165     .gpuvm_min_page_size_bytes = 4096,
0166     .hostvm_min_page_size_bytes = 4096,
0167     .dram_clock_change_latency_us = 404,
0168     .dummy_pstate_latency_us = 5,
0169     .writeback_dram_clock_change_latency_us = 23.0,
0170     .return_bus_width_bytes = 64,
0171     .dispclk_dppclk_vco_speed_mhz = 3650,
0172     .xfc_bus_transport_time_us = 20,      // ?
0173     .xfc_xbuf_latency_tolerance_us = 4,  // ?
0174     .use_urgent_burst_bw = 1,            // ?
0175     .do_urgent_latency_adjustment = true,
0176     .urgent_latency_adjustment_fabric_clock_component_us = 1.0,
0177     .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
0178 };
0179 
0180 
0181 void optc3_fpu_set_vrr_m_const(struct timing_generator *optc,
0182         double vtotal_avg)
0183 {
0184     struct optc *optc1 = DCN10TG_FROM_TG(optc);
0185     double vtotal_min, vtotal_max;
0186     double ratio, modulo, phase;
0187     uint32_t vblank_start;
0188     uint32_t v_total_mask_value = 0;
0189 
0190     dc_assert_fp_enabled();
0191 
0192     /* Compute VTOTAL_MIN and VTOTAL_MAX, so that
0193      * VOTAL_MAX - VTOTAL_MIN = 1
0194      */
0195     v_total_mask_value = 16;
0196     vtotal_min = dcn_bw_floor(vtotal_avg);
0197     vtotal_max = dcn_bw_ceil(vtotal_avg);
0198 
0199     /* Check that bottom VBLANK is at least 2 lines tall when running with
0200      * VTOTAL_MIN. Note that VTOTAL registers are defined as 'total number
0201      * of lines in a frame - 1'.
0202      */
0203     REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START,
0204         &vblank_start);
0205     ASSERT(vtotal_min >= vblank_start + 1);
0206 
0207     /* Special case where the average frame rate can be achieved
0208      * without using the DTO
0209      */
0210     if (vtotal_min == vtotal_max) {
0211         REG_SET(OTG_V_TOTAL, 0, OTG_V_TOTAL, (uint32_t)vtotal_min);
0212 
0213         optc->funcs->set_vtotal_min_max(optc, 0, 0);
0214         REG_SET(OTG_M_CONST_DTO0, 0, OTG_M_CONST_DTO_PHASE, 0);
0215         REG_SET(OTG_M_CONST_DTO1, 0, OTG_M_CONST_DTO_MODULO, 0);
0216         REG_UPDATE_3(OTG_V_TOTAL_CONTROL,
0217             OTG_V_TOTAL_MIN_SEL, 0,
0218             OTG_V_TOTAL_MAX_SEL, 0,
0219             OTG_SET_V_TOTAL_MIN_MASK_EN, 0);
0220         return;
0221     }
0222 
0223     ratio = vtotal_max - vtotal_avg;
0224     modulo = 65536.0 * 65536.0 - 1.0; /* 2^32 - 1 */
0225     phase = ratio * modulo;
0226 
0227     /* Special cases where the DTO phase gets rounded to 0 or
0228      * to DTO modulo
0229      */
0230     if (phase <= 0 || phase >= modulo) {
0231         REG_SET(OTG_V_TOTAL, 0, OTG_V_TOTAL,
0232             phase <= 0 ?
0233                 (uint32_t)vtotal_max : (uint32_t)vtotal_min);
0234         REG_SET(OTG_V_TOTAL_MIN, 0, OTG_V_TOTAL_MIN, 0);
0235         REG_SET(OTG_V_TOTAL_MAX, 0, OTG_V_TOTAL_MAX, 0);
0236         REG_SET(OTG_M_CONST_DTO0, 0, OTG_M_CONST_DTO_PHASE, 0);
0237         REG_SET(OTG_M_CONST_DTO1, 0, OTG_M_CONST_DTO_MODULO, 0);
0238         REG_UPDATE_3(OTG_V_TOTAL_CONTROL,
0239             OTG_V_TOTAL_MIN_SEL, 0,
0240             OTG_V_TOTAL_MAX_SEL, 0,
0241             OTG_SET_V_TOTAL_MIN_MASK_EN, 0);
0242         return;
0243     }
0244     REG_UPDATE_6(OTG_V_TOTAL_CONTROL,
0245         OTG_V_TOTAL_MIN_SEL, 1,
0246         OTG_V_TOTAL_MAX_SEL, 1,
0247         OTG_SET_V_TOTAL_MIN_MASK_EN, 1,
0248         OTG_SET_V_TOTAL_MIN_MASK, v_total_mask_value,
0249         OTG_VTOTAL_MID_REPLACING_MIN_EN, 0,
0250         OTG_VTOTAL_MID_REPLACING_MAX_EN, 0);
0251     REG_SET(OTG_V_TOTAL, 0, OTG_V_TOTAL, (uint32_t)vtotal_min);
0252     optc->funcs->set_vtotal_min_max(optc, vtotal_min, vtotal_max);
0253     REG_SET(OTG_M_CONST_DTO0, 0, OTG_M_CONST_DTO_PHASE, (uint32_t)phase);
0254     REG_SET(OTG_M_CONST_DTO1, 0, OTG_M_CONST_DTO_MODULO, (uint32_t)modulo);
0255 }
0256 
0257 void dcn30_fpu_populate_dml_writeback_from_context(
0258         struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes)
0259 {
0260     int pipe_cnt, i, j;
0261     double max_calc_writeback_dispclk;
0262     double writeback_dispclk;
0263     struct writeback_st dout_wb;
0264 
0265     dc_assert_fp_enabled();
0266 
0267     for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
0268         struct dc_stream_state *stream = res_ctx->pipe_ctx[i].stream;
0269 
0270         if (!stream)
0271             continue;
0272         max_calc_writeback_dispclk = 0;
0273 
0274         /* Set writeback information */
0275         pipes[pipe_cnt].dout.wb_enable = 0;
0276         pipes[pipe_cnt].dout.num_active_wb = 0;
0277         for (j = 0; j < stream->num_wb_info; j++) {
0278             struct dc_writeback_info *wb_info = &stream->writeback_info[j];
0279 
0280             if (wb_info->wb_enabled && wb_info->writeback_source_plane &&
0281                     (wb_info->writeback_source_plane == res_ctx->pipe_ctx[i].plane_state)) {
0282                 pipes[pipe_cnt].dout.wb_enable = 1;
0283                 pipes[pipe_cnt].dout.num_active_wb++;
0284                 dout_wb.wb_src_height = wb_info->dwb_params.cnv_params.crop_en ?
0285                     wb_info->dwb_params.cnv_params.crop_height :
0286                     wb_info->dwb_params.cnv_params.src_height;
0287                 dout_wb.wb_src_width = wb_info->dwb_params.cnv_params.crop_en ?
0288                     wb_info->dwb_params.cnv_params.crop_width :
0289                     wb_info->dwb_params.cnv_params.src_width;
0290                 dout_wb.wb_dst_width = wb_info->dwb_params.dest_width;
0291                 dout_wb.wb_dst_height = wb_info->dwb_params.dest_height;
0292 
0293                 /* For IP that doesn't support WB scaling, set h/v taps to 1 to avoid DML validation failure */
0294                 if (dc->dml.ip.writeback_max_hscl_taps > 1) {
0295                     dout_wb.wb_htaps_luma = wb_info->dwb_params.scaler_taps.h_taps;
0296                     dout_wb.wb_vtaps_luma = wb_info->dwb_params.scaler_taps.v_taps;
0297                 } else {
0298                     dout_wb.wb_htaps_luma = 1;
0299                     dout_wb.wb_vtaps_luma = 1;
0300                 }
0301                 dout_wb.wb_htaps_chroma = 0;
0302                 dout_wb.wb_vtaps_chroma = 0;
0303                 dout_wb.wb_hratio = wb_info->dwb_params.cnv_params.crop_en ?
0304                     (double)wb_info->dwb_params.cnv_params.crop_width /
0305                         (double)wb_info->dwb_params.dest_width :
0306                     (double)wb_info->dwb_params.cnv_params.src_width /
0307                         (double)wb_info->dwb_params.dest_width;
0308                 dout_wb.wb_vratio = wb_info->dwb_params.cnv_params.crop_en ?
0309                     (double)wb_info->dwb_params.cnv_params.crop_height /
0310                         (double)wb_info->dwb_params.dest_height :
0311                     (double)wb_info->dwb_params.cnv_params.src_height /
0312                         (double)wb_info->dwb_params.dest_height;
0313                 if (wb_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_ARGB ||
0314                     wb_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_RGBA)
0315                     dout_wb.wb_pixel_format = dm_444_64;
0316                 else
0317                     dout_wb.wb_pixel_format = dm_444_32;
0318 
0319                 /* Workaround for cases where multiple writebacks are connected to same plane
0320                  * In which case, need to compute worst case and set the associated writeback parameters
0321                  * This workaround is necessary due to DML computation assuming only 1 set of writeback
0322                  * parameters per pipe
0323                  */
0324                 writeback_dispclk = dml30_CalculateWriteBackDISPCLK(
0325                         dout_wb.wb_pixel_format,
0326                         pipes[pipe_cnt].pipe.dest.pixel_rate_mhz,
0327                         dout_wb.wb_hratio,
0328                         dout_wb.wb_vratio,
0329                         dout_wb.wb_htaps_luma,
0330                         dout_wb.wb_vtaps_luma,
0331                         dout_wb.wb_src_width,
0332                         dout_wb.wb_dst_width,
0333                         pipes[pipe_cnt].pipe.dest.htotal,
0334                         dc->current_state->bw_ctx.dml.ip.writeback_line_buffer_buffer_size);
0335 
0336                 if (writeback_dispclk > max_calc_writeback_dispclk) {
0337                     max_calc_writeback_dispclk = writeback_dispclk;
0338                     pipes[pipe_cnt].dout.wb = dout_wb;
0339                 }
0340             }
0341         }
0342 
0343         pipe_cnt++;
0344     }
0345 }
0346 
0347 void dcn30_fpu_set_mcif_arb_params(struct mcif_arb_params *wb_arb_params,
0348     struct display_mode_lib *dml,
0349     display_e2e_pipe_params_st *pipes,
0350     int pipe_cnt,
0351     int cur_pipe)
0352 {
0353     int i;
0354 
0355     dc_assert_fp_enabled();
0356 
0357     for (i = 0; i < ARRAY_SIZE(wb_arb_params->cli_watermark); i++) {
0358         wb_arb_params->cli_watermark[i] = get_wm_writeback_urgent(dml, pipes, pipe_cnt) * 1000;
0359         wb_arb_params->pstate_watermark[i] = get_wm_writeback_dram_clock_change(dml, pipes, pipe_cnt) * 1000;
0360     }
0361 
0362     wb_arb_params->dram_speed_change_duration = dml->vba.WritebackAllowDRAMClockChangeEndPosition[cur_pipe] * pipes[0].clks_cfg.refclk_mhz; /* num_clock_cycles = us * MHz */
0363 }
0364 
0365 void dcn30_fpu_update_soc_for_wm_a(struct dc *dc, struct dc_state *context)
0366 {
0367 
0368     dc_assert_fp_enabled();
0369 
0370     if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].valid) {
0371         context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
0372         context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us;
0373         context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us;
0374     }
0375 }
0376 
0377 void dcn30_fpu_calculate_wm_and_dlg(
0378         struct dc *dc, struct dc_state *context,
0379         display_e2e_pipe_params_st *pipes,
0380         int pipe_cnt,
0381         int vlevel)
0382 {
0383     int maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb;
0384     int i, pipe_idx;
0385     double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][maxMpcComb];
0386     bool pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] != dm_dram_clock_change_unsupported;
0387 
0388     dc_assert_fp_enabled();
0389 
0390     if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk)
0391         dcfclk = context->bw_ctx.dml.soc.min_dcfclk;
0392 
0393     pipes[0].clks_cfg.voltage = vlevel;
0394     pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
0395     pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
0396 
0397     /* Set B:
0398      * DCFCLK: 1GHz or min required above 1GHz
0399      * FCLK/UCLK: Max
0400      */
0401     if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) {
0402         if (vlevel == 0) {
0403             pipes[0].clks_cfg.voltage = 1;
0404             pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dcfclk_mhz;
0405         }
0406         context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us;
0407         context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us;
0408         context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us;
0409     }
0410     context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0411     context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0412     context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0413     context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0414     context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0415     context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0416     context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0417     context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0418 
0419     pipes[0].clks_cfg.voltage = vlevel;
0420     pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
0421 
0422     /* Set D:
0423      * DCFCLK: Min Required
0424      * FCLK(proportional to UCLK): 1GHz or Max
0425      * MALL stutter, sr_enter_exit = 4, sr_exit = 2us
0426      */
0427     /*
0428     if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) {
0429         context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us;
0430         context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us;
0431         context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us;
0432     }
0433     context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0434     context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0435     context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0436     context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0437     context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0438     context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0439     context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0440     context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0441     */
0442 
0443     /* Set C:
0444      * DCFCLK: Min Required
0445      * FCLK(proportional to UCLK): 1GHz or Max
0446      * pstate latency overridden to 5us
0447      */
0448     if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) {
0449         unsigned int min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed;
0450         unsigned int min_dram_speed_mts_margin = 160;
0451 
0452         if (context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_dram_clock_change_unsupported)
0453             min_dram_speed_mts = dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz * 16;
0454 
0455         /* find largest table entry that is lower than dram speed, but lower than DPM0 still uses DPM0 */
0456         for (i = 3; i > 0; i--)
0457             if (min_dram_speed_mts + min_dram_speed_mts_margin > dc->clk_mgr->bw_params->dummy_pstate_table[i].dram_speed_mts)
0458                 break;
0459 
0460         context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->dummy_pstate_table[i].dummy_pstate_latency_us;
0461 
0462         context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us;
0463         context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us;
0464     }
0465 
0466     context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0467     context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0468     context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0469     context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0470     context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0471     context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0472     context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0473     context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0474 
0475     if (!pstate_en) {
0476         /* The only difference between A and C is p-state latency, if p-state is not supported we want to
0477          * calculate DLG based on dummy p-state latency, and max out the set A p-state watermark
0478          */
0479         context->bw_ctx.bw.dcn.watermarks.a = context->bw_ctx.bw.dcn.watermarks.c;
0480         context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 0;
0481     } else {
0482         /* Set A:
0483          * DCFCLK: Min Required
0484          * FCLK(proportional to UCLK): 1GHz or Max
0485          *
0486          * Set A calculated last so that following calculations are based on Set A
0487          */
0488         dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
0489         context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0490         context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0491         context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0492         context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0493         context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0494         context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0495         context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0496         context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
0497     }
0498 
0499     context->perf_params.stutter_period_us = context->bw_ctx.dml.vba.StutterPeriod;
0500 
0501     /* Make set D = set A until set D is enabled */
0502     context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a;
0503 
0504     for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
0505         if (!context->res_ctx.pipe_ctx[i].stream)
0506             continue;
0507 
0508         pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
0509         pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
0510 
0511         if (dc->config.forced_clocks) {
0512             pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
0513             pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
0514         }
0515         if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
0516             pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
0517         if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
0518             pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
0519 
0520         pipe_idx++;
0521     }
0522 
0523     DC_FP_START();
0524     dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
0525     DC_FP_END();
0526 
0527     if (!pstate_en)
0528         /* Restore full p-state latency */
0529         context->bw_ctx.dml.soc.dram_clock_change_latency_us =
0530                 dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
0531 
0532     if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching)
0533         dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(dc, context);
0534 }
0535 
0536 void dcn30_fpu_update_dram_channel_width_bytes(struct dc *dc)
0537 {
0538     dc_assert_fp_enabled();
0539 
0540     if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
0541         dcn3_0_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
0542 }
0543 
0544 void dcn30_fpu_update_max_clk(struct dc_bounding_box_max_clk *dcn30_bb_max_clk)
0545 {
0546         dc_assert_fp_enabled();
0547 
0548         if (!dcn30_bb_max_clk->max_dcfclk_mhz)
0549             dcn30_bb_max_clk->max_dcfclk_mhz = dcn3_0_soc.clock_limits[0].dcfclk_mhz;
0550         if (!dcn30_bb_max_clk->max_dispclk_mhz)
0551             dcn30_bb_max_clk->max_dispclk_mhz = dcn3_0_soc.clock_limits[0].dispclk_mhz;
0552         if (!dcn30_bb_max_clk->max_dppclk_mhz)
0553             dcn30_bb_max_clk->max_dppclk_mhz = dcn3_0_soc.clock_limits[0].dppclk_mhz;
0554         if (!dcn30_bb_max_clk->max_phyclk_mhz)
0555             dcn30_bb_max_clk->max_phyclk_mhz = dcn3_0_soc.clock_limits[0].phyclk_mhz;
0556 }
0557 
0558 void dcn30_fpu_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
0559         unsigned int *optimal_dcfclk,
0560         unsigned int *optimal_fclk)
0561 {
0562     double bw_from_dram, bw_from_dram1, bw_from_dram2;
0563 
0564     dc_assert_fp_enabled();
0565 
0566     bw_from_dram1 = uclk_mts * dcn3_0_soc.num_chans *
0567         dcn3_0_soc.dram_channel_width_bytes * (dcn3_0_soc.max_avg_dram_bw_use_normal_percent / 100);
0568     bw_from_dram2 = uclk_mts * dcn3_0_soc.num_chans *
0569         dcn3_0_soc.dram_channel_width_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100);
0570 
0571     bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
0572 
0573     if (optimal_fclk)
0574         *optimal_fclk = bw_from_dram /
0575         (dcn3_0_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100));
0576 
0577     if (optimal_dcfclk)
0578         *optimal_dcfclk =  bw_from_dram /
0579         (dcn3_0_soc.return_bus_width_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100));
0580 }
0581 
0582 void dcn30_fpu_update_bw_bounding_box(struct dc *dc,
0583     struct clk_bw_params *bw_params,
0584     struct dc_bounding_box_max_clk *dcn30_bb_max_clk,
0585     unsigned int *dcfclk_mhz,
0586     unsigned int *dram_speed_mts)
0587 {
0588     unsigned int i;
0589 
0590     dc_assert_fp_enabled();
0591 
0592     dcn3_0_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
0593     dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
0594 
0595     for (i = 0; i < dcn3_0_soc.num_states; i++) {
0596         dcn3_0_soc.clock_limits[i].state = i;
0597         dcn3_0_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
0598         dcn3_0_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
0599         dcn3_0_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
0600 
0601         /* Fill all states with max values of all other clocks */
0602         dcn3_0_soc.clock_limits[i].dispclk_mhz = dcn30_bb_max_clk->max_dispclk_mhz;
0603         dcn3_0_soc.clock_limits[i].dppclk_mhz  = dcn30_bb_max_clk->max_dppclk_mhz;
0604         dcn3_0_soc.clock_limits[i].phyclk_mhz  = dcn30_bb_max_clk->max_phyclk_mhz;
0605         dcn3_0_soc.clock_limits[i].dtbclk_mhz = dcn3_0_soc.clock_limits[0].dtbclk_mhz;
0606         /* These clocks cannot come from bw_params, always fill from dcn3_0_soc[1] */
0607         /* FCLK, PHYCLK_D18, SOCCLK, DSCCLK */
0608         dcn3_0_soc.clock_limits[i].phyclk_d18_mhz = dcn3_0_soc.clock_limits[0].phyclk_d18_mhz;
0609         dcn3_0_soc.clock_limits[i].socclk_mhz = dcn3_0_soc.clock_limits[0].socclk_mhz;
0610         dcn3_0_soc.clock_limits[i].dscclk_mhz = dcn3_0_soc.clock_limits[0].dscclk_mhz;
0611     }
0612     /* re-init DML with updated bb */
0613     dml_init_instance(&dc->dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30);
0614     if (dc->current_state)
0615         dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30);
0616 
0617 }
0618 
0619 /**
0620  * Finds dummy_latency_index when MCLK switching using firmware based
0621  * vblank stretch is enabled. This function will iterate through the
0622  * table of dummy pstate latencies until the lowest value that allows
0623  * dm_allow_self_refresh_and_mclk_switch to happen is found
0624  */
0625 int dcn30_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc,
0626                                 struct dc_state *context,
0627                                 display_e2e_pipe_params_st *pipes,
0628                                 int pipe_cnt,
0629                                 int vlevel)
0630 {
0631     const int max_latency_table_entries = 4;
0632     int dummy_latency_index = 0;
0633 
0634     dc_assert_fp_enabled();
0635 
0636     while (dummy_latency_index < max_latency_table_entries) {
0637         context->bw_ctx.dml.soc.dram_clock_change_latency_us =
0638                 dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us;
0639         dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false);
0640 
0641         if (context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank ==
0642             dm_allow_self_refresh_and_mclk_switch)
0643             break;
0644 
0645         dummy_latency_index++;
0646     }
0647 
0648     if (dummy_latency_index == max_latency_table_entries) {
0649         ASSERT(dummy_latency_index != max_latency_table_entries);
0650         /* If the execution gets here, it means dummy p_states are
0651          * not possible. This should never happen and would mean
0652          * something is severely wrong.
0653          * Here we reset dummy_latency_index to 3, because it is
0654          * better to have underflows than system crashes.
0655          */
0656         dummy_latency_index = 3;
0657     }
0658 
0659     return dummy_latency_index;
0660 }
0661 
0662 void dcn3_fpu_build_wm_range_table(struct clk_mgr *base)
0663 {
0664     /* defaults */
0665     double pstate_latency_us = base->ctx->dc->dml.soc.dram_clock_change_latency_us;
0666     double sr_exit_time_us = base->ctx->dc->dml.soc.sr_exit_time_us;
0667     double sr_enter_plus_exit_time_us = base->ctx->dc->dml.soc.sr_enter_plus_exit_time_us;
0668     uint16_t min_uclk_mhz = base->bw_params->clk_table.entries[0].memclk_mhz;
0669 
0670     dc_assert_fp_enabled();
0671 
0672     /* Set A - Normal - default values*/
0673     base->bw_params->wm_table.nv_entries[WM_A].valid = true;
0674     base->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us = pstate_latency_us;
0675     base->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us = sr_exit_time_us;
0676     base->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
0677     base->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.wm_type = WATERMARKS_CLOCK_RANGE;
0678     base->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_dcfclk = 0;
0679     base->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_dcfclk = 0xFFFF;
0680     base->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_uclk = min_uclk_mhz;
0681     base->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_uclk = 0xFFFF;
0682 
0683     /* Set B - Performance - higher minimum clocks */
0684 //  base->bw_params->wm_table.nv_entries[WM_B].valid = true;
0685 //  base->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us = pstate_latency_us;
0686 //  base->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us = sr_exit_time_us;
0687 //  base->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
0688 //  base->bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.wm_type = WATERMARKS_CLOCK_RANGE;
0689 //  base->bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_dcfclk = TUNED VALUE;
0690 //  base->bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.max_dcfclk = 0xFFFF;
0691 //  base->bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_uclk = TUNED VALUE;
0692 //  base->bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.max_uclk = 0xFFFF;
0693 
0694     /* Set C - Dummy P-State - P-State latency set to "dummy p-state" value */
0695     base->bw_params->wm_table.nv_entries[WM_C].valid = true;
0696     base->bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us = 0;
0697     base->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us = sr_exit_time_us;
0698     base->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
0699     base->bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.wm_type = WATERMARKS_DUMMY_PSTATE;
0700     base->bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.min_dcfclk = 0;
0701     base->bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.max_dcfclk = 0xFFFF;
0702     base->bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.min_uclk = min_uclk_mhz;
0703     base->bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.max_uclk = 0xFFFF;
0704     base->bw_params->dummy_pstate_table[0].dram_speed_mts = 1600;
0705     base->bw_params->dummy_pstate_table[0].dummy_pstate_latency_us = 38;
0706     base->bw_params->dummy_pstate_table[1].dram_speed_mts = 8000;
0707     base->bw_params->dummy_pstate_table[1].dummy_pstate_latency_us = 9;
0708     base->bw_params->dummy_pstate_table[2].dram_speed_mts = 10000;
0709     base->bw_params->dummy_pstate_table[2].dummy_pstate_latency_us = 8;
0710     base->bw_params->dummy_pstate_table[3].dram_speed_mts = 16000;
0711     base->bw_params->dummy_pstate_table[3].dummy_pstate_latency_us = 5;
0712 
0713     /* Set D - MALL - SR enter and exit times adjusted for MALL */
0714     base->bw_params->wm_table.nv_entries[WM_D].valid = true;
0715     base->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us = pstate_latency_us;
0716     base->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us = 2;
0717     base->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us = 4;
0718     base->bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.wm_type = WATERMARKS_MALL;
0719     base->bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.min_dcfclk = 0;
0720     base->bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.max_dcfclk = 0xFFFF;
0721     base->bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.min_uclk = min_uclk_mhz;
0722     base->bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.max_uclk = 0xFFFF;
0723 }
0724 
0725 void patch_dcn30_soc_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *dcn3_0_ip)
0726 {
0727     dc_assert_fp_enabled();
0728 
0729     if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
0730         struct bp_soc_bb_info bb_info = {0};
0731 
0732         if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) {
0733             if (bb_info.dram_clock_change_latency_100ns > 0)
0734                 dcn3_0_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10;
0735 
0736             if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
0737                 dcn3_0_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10;
0738 
0739             if (bb_info.dram_sr_exit_latency_100ns > 0)
0740                 dcn3_0_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10;
0741         }
0742     }
0743 }