drm/i915/bw: Fix DCLK rounding mess

Fix up the total mess when calculating the DCLK
frequency. Some codepaths are trying to do both DIV_ROUND_UP()
and an open coded "round to nearest" at the same time. The
MTL+ codepath was the only one that was correct (using
DIV_ROUND_CLOSEST()).

Let's unify all of them, and borrow the actual '100/6'
approach from adl_calc_psf_bw() so that we get even less
rounding errors.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patch.msgid.link/20260522200346.17377-3-ville.syrjala@linux.intel.com
Reviewed-by: Vinod Govindapillai <vinod.govindapillai@intel.com>
This commit is contained in:
Ville Syrjälä 2026-05-22 23:03:38 +03:00
parent 85bfe1cec2
commit 1f0d572b27

View File

@ -67,25 +67,31 @@ struct intel_qgv_info {
u8 deinterleave;
};
static int dclk_freq_mhz(int ratio)
{
/* multiple of 16.666 MHz (100/6) */
return DIV_ROUND_CLOSEST(ratio * 100, 6);
}
static int dg1_mchbar_read_qgv_point_info(struct intel_display *display,
struct intel_qgv_point *sp,
int point)
{
u32 dclk_ratio, dclk_reference;
u32 dclk_ratio;
u32 val;
val = intel_mchbar_read(display, SA_PERF_STATUS_0_0_0_MCHBAR_PC);
dclk_ratio = REG_FIELD_GET(DG1_QCLK_RATIO_MASK, val);
if (val & DG1_QCLK_REFERENCE)
dclk_reference = 6; /* 6 * 16.666 MHz = 100 MHz */
dclk_ratio *= 6; /* 6 * 16.666 MHz = 100 MHz */
else
dclk_reference = 8; /* 8 * 16.666 MHz = 133 MHz */
sp->dclk = DIV_ROUND_UP((16667 * dclk_ratio * dclk_reference) + 500, 1000);
dclk_ratio *= 8; /* 8 * 16.666 MHz = 133 MHz */
val = intel_mchbar_read(display, SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU);
if (val & DG1_GEAR_TYPE)
sp->dclk *= 2;
dclk_ratio *= 2;
sp->dclk = dclk_freq_mhz(dclk_ratio);
if (sp->dclk == 0)
return -EINVAL;
@ -107,7 +113,6 @@ static int icl_pcode_read_qgv_point_info(struct intel_display *display,
int point)
{
u32 val = 0, val2 = 0;
u16 dclk;
int ret;
ret = intel_parent_pcode_read(display, ICL_PCODE_MEM_SUBSYSYSTEM_INFO |
@ -116,9 +121,7 @@ static int icl_pcode_read_qgv_point_info(struct intel_display *display,
if (ret)
return ret;
dclk = val & 0xffff;
sp->dclk = DIV_ROUND_UP((16667 * dclk) + (DISPLAY_VER(display) >= 12 ? 500 : 0),
1000);
sp->dclk = dclk_freq_mhz(val & 0xffff);
sp->t_rp = (val & 0xff0000) >> 16;
sp->t_rcd = (val & 0xff000000) >> 24;
@ -208,12 +211,11 @@ static int mtl_read_qgv_point_info(struct intel_display *display,
struct intel_qgv_point *sp, int point)
{
u32 val, val2;
u16 dclk;
val = intel_de_read(display, MTL_MEM_SS_INFO_QGV_POINT_LOW(point));
val2 = intel_de_read(display, MTL_MEM_SS_INFO_QGV_POINT_HIGH(point));
dclk = REG_FIELD_GET(MTL_DCLK_MASK, val);
sp->dclk = DIV_ROUND_CLOSEST(16667 * dclk, 1000);
sp->dclk = dclk_freq_mhz(REG_FIELD_GET(MTL_DCLK_MASK, val));
sp->t_rp = REG_FIELD_GET(MTL_TRP_MASK, val);
sp->t_rcd = REG_FIELD_GET(MTL_TRCD_MASK, val);