Example #1
0
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;
}
Example #2
0
/* 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;
}