static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) { struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); int dprefclk_wdivider; int dprefclk_src_sel; int dp_ref_clk_khz = 600000; int target_div = INVALID_DIVIDER; /* ASSERT DP Reference Clock source is from DFS*/ REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel); ASSERT(dprefclk_src_sel == 0); /* Read the mmDENTIST_DISPCLK_CNTL to get the currently * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider); /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ target_div = dce_divider_range_get_divider( clk_dce->divider_ranges, DIVIDER_RANGE_MAX, dprefclk_wdivider); if (target_div != INVALID_DIVIDER) { /* Calculate the current DFS clock, in kHz.*/ dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR * clk_dce->dentist_vco_freq_khz) / target_div; } /* SW will adjust DP REF Clock average value for all purposes * (DP DTO / DP Audio DTO and DP GTC) if clock is spread for all cases: -if SS enabled on DP Ref clock and HW de-spreading enabled with SW calculations for DS_INCR/DS_MODULO (this is planned to be default case) -if SS enabled on DP Ref clock and HW de-spreading enabled with HW calculations (not planned to be used, but average clock should still be valid) -if SS enabled on DP Ref clock and HW de-spreading disabled (should not be case with CIK) then SW should program all rates generated according to average value (case as with previous ASICs) */ if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( dal_fixed32_32_from_fraction( clk_dce->dprefclk_ss_percentage, clk_dce->dprefclk_ss_divider), 200); struct fixed32_32 adj_dp_ref_clk_khz; ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, ss_percentage); adj_dp_ref_clk_khz = dal_fixed32_32_mul_int( ss_percentage, dp_ref_clk_khz); dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); } return dp_ref_clk_khz; }
/* TODO: This is DCN DPREFCLK: it could be program by DENTIST by VBIOS * or CLK0_CLK11 by SMU. For DCE120, it is wlays 600Mhz. Will re-visit * clock implementation */ static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk) { struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); int dp_ref_clk_khz = 600000; if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( dal_fixed32_32_from_fraction( clk_dce->dprefclk_ss_percentage, clk_dce->dprefclk_ss_divider), 200); struct fixed32_32 adj_dp_ref_clk_khz; ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, ss_percentage); adj_dp_ref_clk_khz = dal_fixed32_32_mul_int( ss_percentage, dp_ref_clk_khz); dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); } return dp_ref_clk_khz; }
static uint32_t calc_single_display_min_clks( struct display_clock *base, struct min_clock_params *params, bool set_clk) { struct fixed32_32 h_scale_ratio = dal_fixed32_32_one; struct fixed32_32 v_scale_ratio = dal_fixed32_32_one; uint32_t pix_clk_khz = 0; uint32_t lb_source_width = 0; struct fixed32_32 deep_color_factor; struct fixed32_32 scaler_efficiency; struct fixed32_32 v_filter_init; uint32_t v_filter_init_trunc; uint32_t num_lines_at_frame_start = 3; struct fixed32_32 v_filter_init_ceil; struct fixed32_32 lines_per_lines_out_at_frame_start; struct fixed32_32 lb_lines_in_per_line_out; /* in middle of the frame*/ uint32_t src_wdth_rnd_to_chunks; struct fixed32_32 scaling_coeff; struct fixed32_32 h_blank_granularity_factor = dal_fixed32_32_one; struct fixed32_32 fx_disp_clk_mhz; struct fixed32_32 line_time; struct fixed32_32 disp_pipe_pix_throughput; struct fixed32_32 fx_alt_disp_clk_mhz; uint32_t disp_clk_khz; uint32_t alt_disp_clk_khz; struct display_clock_dce110 *disp_clk_110 = DCLCK110_FROM_BASE(base); uint32_t max_clk_khz = get_validation_clock(base); bool panning_allowed = false; /* TODO: receive this value from AS */ if (params == NULL) { dal_logger_write(base->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "Invalid input parameter in %s", __func__); return 0; } deep_color_factor = get_deep_color_factor(params); scaler_efficiency = get_scaler_efficiency(base->ctx, params); pix_clk_khz = params->requested_pixel_clock; lb_source_width = params->source_view.width; if (0 != params->dest_view.height && 0 != params->dest_view.width) { h_scale_ratio = dal_fixed32_32_from_fraction( params->source_view.width, params->dest_view.width); v_scale_ratio = dal_fixed32_32_from_fraction( params->source_view.height, params->dest_view.height); } else { dal_logger_write(base->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "Destination height or width is 0!\n"); } v_filter_init = dal_fixed32_32_add( v_scale_ratio, dal_fixed32_32_add_int( dal_fixed32_32_div_int( dal_fixed32_32_mul_int( v_scale_ratio, params->timing_info.INTERLACED), 2), params->scaling_info.v_taps + 1)); v_filter_init = dal_fixed32_32_div_int(v_filter_init, 2); v_filter_init_trunc = dal_fixed32_32_floor(v_filter_init); v_filter_init_ceil = dal_fixed32_32_from_fraction( v_filter_init_trunc, 2); v_filter_init_ceil = dal_fixed32_32_from_int( dal_fixed32_32_ceil(v_filter_init_ceil)); v_filter_init_ceil = dal_fixed32_32_mul_int(v_filter_init_ceil, 2); lines_per_lines_out_at_frame_start = dal_fixed32_32_div_int(v_filter_init_ceil, num_lines_at_frame_start); lb_lines_in_per_line_out = get_lb_lines_in_per_line_out(params, v_scale_ratio); if (panning_allowed) src_wdth_rnd_to_chunks = ((lb_source_width - 1) / 128) * 128 + 256; else src_wdth_rnd_to_chunks = ((lb_source_width + 127) / 128) * 128; scaling_coeff = dal_fixed32_32_div( dal_fixed32_32_from_int(params->scaling_info.v_taps), scaler_efficiency); if (dal_fixed32_32_le(h_scale_ratio, dal_fixed32_32_one)) scaling_coeff = dal_fixed32_32_max( dal_fixed32_32_from_int( dal_fixed32_32_ceil( dal_fixed32_32_from_fraction( params->scaling_info.h_taps, 4))), dal_fixed32_32_max( dal_fixed32_32_mul( scaling_coeff, h_scale_ratio), dal_fixed32_32_one)); if (!params->line_buffer_prefetch_enabled && dal_fixed32_32_floor(lb_lines_in_per_line_out) != 2 && dal_fixed32_32_floor(lb_lines_in_per_line_out) != 4) { uint32_t line_total_pixel = params->timing_info.h_total + lb_source_width - 256; h_blank_granularity_factor = dal_fixed32_32_div( dal_fixed32_32_from_int(params->timing_info.h_total), dal_fixed32_32_div( dal_fixed32_32_from_fraction( line_total_pixel, 2), h_scale_ratio)); } /* Calculate display clock with ramping. Ramping factor is 1.1*/ fx_disp_clk_mhz = dal_fixed32_32_div_int( dal_fixed32_32_mul_int(scaling_coeff, 11), 10); line_time = dal_fixed32_32_from_fraction( params->timing_info.h_total * 1000, pix_clk_khz); disp_pipe_pix_throughput = dal_fixed32_32_mul( lb_lines_in_per_line_out, h_blank_granularity_factor); disp_pipe_pix_throughput = dal_fixed32_32_max( disp_pipe_pix_throughput, lines_per_lines_out_at_frame_start); disp_pipe_pix_throughput = dal_fixed32_32_div(dal_fixed32_32_mul_int( disp_pipe_pix_throughput, src_wdth_rnd_to_chunks), line_time); if (0 != params->timing_info.h_total) { fx_disp_clk_mhz = dal_fixed32_32_max( dal_fixed32_32_div_int( dal_fixed32_32_mul_int( scaling_coeff, pix_clk_khz), 1000), disp_pipe_pix_throughput); fx_disp_clk_mhz = dal_fixed32_32_mul( fx_disp_clk_mhz, dal_fixed32_32_from_fraction(11, 10)); } fx_disp_clk_mhz = dal_fixed32_32_max(fx_disp_clk_mhz, dal_fixed32_32_mul(deep_color_factor, dal_fixed32_32_from_fraction(11, 10))); /* Calculate display clock without ramping */ fx_alt_disp_clk_mhz = scaling_coeff; if (0 != params->timing_info.h_total) { fx_alt_disp_clk_mhz = dal_fixed32_32_max( dal_fixed32_32_div_int(dal_fixed32_32_mul_int( scaling_coeff, pix_clk_khz), 1000), dal_fixed32_32_div_int(dal_fixed32_32_mul_int( disp_pipe_pix_throughput, 105), 100)); } if (set_clk && disp_clk_110->ss_on_gpu_pll && disp_clk_110->gpu_pll_ss_divider) fx_alt_disp_clk_mhz = dal_fixed32_32_mul(fx_alt_disp_clk_mhz, dal_fixed32_32_add_int( dal_fixed32_32_div_int( dal_fixed32_32_div_int( dal_fixed32_32_from_fraction( disp_clk_110->gpu_pll_ss_percentage, disp_clk_110->gpu_pll_ss_divider), 100), 2), 1)); /* convert to integer */ disp_clk_khz = dal_fixed32_32_round( dal_fixed32_32_mul_int(fx_disp_clk_mhz, 1000)); alt_disp_clk_khz = dal_fixed32_32_round( dal_fixed32_32_mul_int(fx_alt_disp_clk_mhz, 1000)); if ((disp_clk_khz > max_clk_khz) && (alt_disp_clk_khz <= max_clk_khz)) disp_clk_khz = alt_disp_clk_khz; if (set_clk) { /* only compensate clock if we are going to set it.*/ disp_clk_khz = get_actual_required_display_clk( disp_clk_110, disp_clk_khz); } disp_clk_khz = disp_clk_khz > max_clk_khz ? max_clk_khz : disp_clk_khz; return disp_clk_khz; }
static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc) { uint32_t dispclk_cntl_value; uint32_t dp_ref_clk_cntl_value; uint32_t dp_ref_clk_cntl_src_sel_value; uint32_t dp_ref_clk_khz = 600000; uint32_t target_div = INVALID_DIVIDER; struct display_clock_dce110 *disp_clk = FROM_DISPLAY_CLOCK(dc); /* ASSERT DP Reference Clock source is from DFS*/ dp_ref_clk_cntl_value = dm_read_reg(dc->ctx, mmDPREFCLK_CNTL); dp_ref_clk_cntl_src_sel_value = get_reg_field_value( dp_ref_clk_cntl_value, DPREFCLK_CNTL, DPREFCLK_SRC_SEL); ASSERT(dp_ref_clk_cntl_src_sel_value == 0); /* Read the mmDENTIST_DISPCLK_CNTL to get the currently * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ dispclk_cntl_value = dm_read_reg(dc->ctx, mmDENTIST_DISPCLK_CNTL); /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ target_div = dal_divider_range_get_divider( divider_ranges, DIVIDER_RANGE_MAX, get_reg_field_value(dispclk_cntl_value, DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER)); if (target_div != INVALID_DIVIDER) { /* Calculate the current DFS clock, in kHz.*/ dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR * disp_clk->dentist_vco_freq_khz) / target_div; } /* SW will adjust DP REF Clock average value for all purposes * (DP DTO / DP Audio DTO and DP GTC) if clock is spread for all cases: -if SS enabled on DP Ref clock and HW de-spreading enabled with SW calculations for DS_INCR/DS_MODULO (this is planned to be default case) -if SS enabled on DP Ref clock and HW de-spreading enabled with HW calculations (not planned to be used, but average clock should still be valid) -if SS enabled on DP Ref clock and HW de-spreading disabled (should not be case with CIK) then SW should program all rates generated according to average value (case as with previous ASICs) */ if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) { struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( dal_fixed32_32_from_fraction( disp_clk->gpu_pll_ss_percentage, disp_clk->gpu_pll_ss_divider), 200); struct fixed32_32 adj_dp_ref_clk_khz; ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, ss_percentage); adj_dp_ref_clk_khz = dal_fixed32_32_mul_int( ss_percentage, dp_ref_clk_khz); dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); } return dp_ref_clk_khz; }