xref: /openbmc/linux/drivers/gpu/drm/i915/display/intel_bw.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1df0566a6SJani Nikula // SPDX-License-Identifier: MIT
2df0566a6SJani Nikula /*
3df0566a6SJani Nikula  * Copyright © 2019 Intel Corporation
4df0566a6SJani Nikula  */
5df0566a6SJani Nikula 
6df0566a6SJani Nikula #include <drm/drm_atomic_state_helper.h>
7df0566a6SJani Nikula 
842a0d256SVille Syrjälä #include "i915_drv.h"
9ce2fce25SMatt Roper #include "i915_reg.h"
10a7f46d5bSTvrtko Ursulin #include "i915_utils.h"
1120f505f2SStanislav Lisovskiy #include "intel_atomic.h"
12cac91e67SStanislav Lisovskiy #include "intel_bw.h"
13cd191546SStanislav Lisovskiy #include "intel_cdclk.h"
1442a0d256SVille Syrjälä #include "intel_display_core.h"
15cac91e67SStanislav Lisovskiy #include "intel_display_types.h"
1642a0d256SVille Syrjälä #include "skl_watermark.h"
17e30e6c7bSMatt Roper #include "intel_mchbar_regs.h"
184dd4375bSJani Nikula #include "intel_pcode.h"
19df0566a6SJani Nikula 
20df0566a6SJani Nikula /* Parameters for Qclk Geyserville (QGV) */
21df0566a6SJani Nikula struct intel_qgv_point {
22df0566a6SJani Nikula 	u16 dclk, t_rp, t_rdpre, t_rc, t_ras, t_rcd;
23df0566a6SJani Nikula };
24df0566a6SJani Nikula 
25192fbfb7SStanislav Lisovskiy struct intel_psf_gv_point {
26192fbfb7SStanislav Lisovskiy 	u8 clk; /* clock in multiples of 16.6666 MHz */
27192fbfb7SStanislav Lisovskiy };
28192fbfb7SStanislav Lisovskiy 
29df0566a6SJani Nikula struct intel_qgv_info {
309b93daa9SStanislav Lisovskiy 	struct intel_qgv_point points[I915_NUM_QGV_POINTS];
31192fbfb7SStanislav Lisovskiy 	struct intel_psf_gv_point psf_points[I915_NUM_PSF_GV_POINTS];
32df0566a6SJani Nikula 	u8 num_points;
33192fbfb7SStanislav Lisovskiy 	u8 num_psf_points;
34df0566a6SJani Nikula 	u8 t_bl;
35c64a9a7cSRadhakrishna Sripada 	u8 max_numchannels;
36c64a9a7cSRadhakrishna Sripada 	u8 channel_width;
37c64a9a7cSRadhakrishna Sripada 	u8 deinterleave;
38df0566a6SJani Nikula };
39df0566a6SJani Nikula 
dg1_mchbar_read_qgv_point_info(struct drm_i915_private * dev_priv,struct intel_qgv_point * sp,int point)404de06246SClint Taylor static int dg1_mchbar_read_qgv_point_info(struct drm_i915_private *dev_priv,
414de06246SClint Taylor 					  struct intel_qgv_point *sp,
424de06246SClint Taylor 					  int point)
434de06246SClint Taylor {
444de06246SClint Taylor 	u32 dclk_ratio, dclk_reference;
454de06246SClint Taylor 	u32 val;
464de06246SClint Taylor 
474de06246SClint Taylor 	val = intel_uncore_read(&dev_priv->uncore, SA_PERF_STATUS_0_0_0_MCHBAR_PC);
484de06246SClint Taylor 	dclk_ratio = REG_FIELD_GET(DG1_QCLK_RATIO_MASK, val);
494de06246SClint Taylor 	if (val & DG1_QCLK_REFERENCE)
504de06246SClint Taylor 		dclk_reference = 6; /* 6 * 16.666 MHz = 100 MHz */
514de06246SClint Taylor 	else
524de06246SClint Taylor 		dclk_reference = 8; /* 8 * 16.666 MHz = 133 MHz */
53c64a9a7cSRadhakrishna Sripada 	sp->dclk = DIV_ROUND_UP((16667 * dclk_ratio * dclk_reference) + 500, 1000);
544de06246SClint Taylor 
554de06246SClint Taylor 	val = intel_uncore_read(&dev_priv->uncore, SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU);
564de06246SClint Taylor 	if (val & DG1_GEAR_TYPE)
574de06246SClint Taylor 		sp->dclk *= 2;
584de06246SClint Taylor 
594de06246SClint Taylor 	if (sp->dclk == 0)
604de06246SClint Taylor 		return -EINVAL;
614de06246SClint Taylor 
624de06246SClint Taylor 	val = intel_uncore_read(&dev_priv->uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR);
634de06246SClint Taylor 	sp->t_rp = REG_FIELD_GET(DG1_DRAM_T_RP_MASK, val);
644de06246SClint Taylor 	sp->t_rdpre = REG_FIELD_GET(DG1_DRAM_T_RDPRE_MASK, val);
654de06246SClint Taylor 
664de06246SClint Taylor 	val = intel_uncore_read(&dev_priv->uncore, MCHBAR_CH0_CR_TC_PRE_0_0_0_MCHBAR_HIGH);
674de06246SClint Taylor 	sp->t_rcd = REG_FIELD_GET(DG1_DRAM_T_RCD_MASK, val);
684de06246SClint Taylor 	sp->t_ras = REG_FIELD_GET(DG1_DRAM_T_RAS_MASK, val);
694de06246SClint Taylor 
704de06246SClint Taylor 	sp->t_rc = sp->t_rp + sp->t_ras;
714de06246SClint Taylor 
724de06246SClint Taylor 	return 0;
734de06246SClint Taylor }
744de06246SClint Taylor 
icl_pcode_read_qgv_point_info(struct drm_i915_private * dev_priv,struct intel_qgv_point * sp,int point)75df0566a6SJani Nikula static int icl_pcode_read_qgv_point_info(struct drm_i915_private *dev_priv,
76df0566a6SJani Nikula 					 struct intel_qgv_point *sp,
77df0566a6SJani Nikula 					 int point)
78df0566a6SJani Nikula {
79b12d5944SVille Syrjälä 	u32 val = 0, val2 = 0;
80c64a9a7cSRadhakrishna Sripada 	u16 dclk;
81df0566a6SJani Nikula 	int ret;
82df0566a6SJani Nikula 
83ee421bb4SAshutosh Dixit 	ret = snb_pcode_read(&dev_priv->uncore, ICL_PCODE_MEM_SUBSYSYSTEM_INFO |
84df0566a6SJani Nikula 			     ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point),
85df0566a6SJani Nikula 			     &val, &val2);
86df0566a6SJani Nikula 	if (ret)
87df0566a6SJani Nikula 		return ret;
88df0566a6SJani Nikula 
89c64a9a7cSRadhakrishna Sripada 	dclk = val & 0xffff;
90c64a9a7cSRadhakrishna Sripada 	sp->dclk = DIV_ROUND_UP((16667 * dclk) + (DISPLAY_VER(dev_priv) > 11 ? 500 : 0), 1000);
91df0566a6SJani Nikula 	sp->t_rp = (val & 0xff0000) >> 16;
92df0566a6SJani Nikula 	sp->t_rcd = (val & 0xff000000) >> 24;
93df0566a6SJani Nikula 
94df0566a6SJani Nikula 	sp->t_rdpre = val2 & 0xff;
95df0566a6SJani Nikula 	sp->t_ras = (val2 & 0xff00) >> 8;
96df0566a6SJani Nikula 
97df0566a6SJani Nikula 	sp->t_rc = sp->t_rp + sp->t_ras;
98df0566a6SJani Nikula 
99df0566a6SJani Nikula 	return 0;
100df0566a6SJani Nikula }
101df0566a6SJani Nikula 
adls_pcode_read_psf_gv_point_info(struct drm_i915_private * dev_priv,struct intel_psf_gv_point * points)102192fbfb7SStanislav Lisovskiy static int adls_pcode_read_psf_gv_point_info(struct drm_i915_private *dev_priv,
103192fbfb7SStanislav Lisovskiy 					    struct intel_psf_gv_point *points)
104192fbfb7SStanislav Lisovskiy {
105192fbfb7SStanislav Lisovskiy 	u32 val = 0;
106192fbfb7SStanislav Lisovskiy 	int ret;
107192fbfb7SStanislav Lisovskiy 	int i;
108192fbfb7SStanislav Lisovskiy 
109ee421bb4SAshutosh Dixit 	ret = snb_pcode_read(&dev_priv->uncore, ICL_PCODE_MEM_SUBSYSYSTEM_INFO |
1106650ebcbSJani Nikula 			     ADL_PCODE_MEM_SS_READ_PSF_GV_INFO, &val, NULL);
111192fbfb7SStanislav Lisovskiy 	if (ret)
112192fbfb7SStanislav Lisovskiy 		return ret;
113192fbfb7SStanislav Lisovskiy 
114192fbfb7SStanislav Lisovskiy 	for (i = 0; i < I915_NUM_PSF_GV_POINTS; i++) {
115192fbfb7SStanislav Lisovskiy 		points[i].clk = val & 0xff;
116192fbfb7SStanislav Lisovskiy 		val >>= 8;
117192fbfb7SStanislav Lisovskiy 	}
118192fbfb7SStanislav Lisovskiy 
119192fbfb7SStanislav Lisovskiy 	return 0;
120192fbfb7SStanislav Lisovskiy }
121192fbfb7SStanislav Lisovskiy 
icl_qgv_points_mask(struct drm_i915_private * i915)122*9541fd16SVille Syrjälä static u16 icl_qgv_points_mask(struct drm_i915_private *i915)
123*9541fd16SVille Syrjälä {
124*9541fd16SVille Syrjälä 	unsigned int num_psf_gv_points = i915->display.bw.max[0].num_psf_gv_points;
125*9541fd16SVille Syrjälä 	unsigned int num_qgv_points = i915->display.bw.max[0].num_qgv_points;
126*9541fd16SVille Syrjälä 	u16 qgv_points = 0, psf_points = 0;
127*9541fd16SVille Syrjälä 
128*9541fd16SVille Syrjälä 	/*
129*9541fd16SVille Syrjälä 	 * We can _not_ use the whole ADLS_QGV_PT_MASK here, as PCode rejects
130*9541fd16SVille Syrjälä 	 * it with failure if we try masking any unadvertised points.
131*9541fd16SVille Syrjälä 	 * So need to operate only with those returned from PCode.
132*9541fd16SVille Syrjälä 	 */
133*9541fd16SVille Syrjälä 	if (num_qgv_points > 0)
134*9541fd16SVille Syrjälä 		qgv_points = GENMASK(num_qgv_points - 1, 0);
135*9541fd16SVille Syrjälä 
136*9541fd16SVille Syrjälä 	if (num_psf_gv_points > 0)
137*9541fd16SVille Syrjälä 		psf_points = GENMASK(num_psf_gv_points - 1, 0);
138*9541fd16SVille Syrjälä 
139*9541fd16SVille Syrjälä 	return ICL_PCODE_REQ_QGV_PT(qgv_points) | ADLS_PCODE_REQ_PSF_PT(psf_points);
140*9541fd16SVille Syrjälä }
141*9541fd16SVille Syrjälä 
is_sagv_enabled(struct drm_i915_private * i915,u16 points_mask)142*9541fd16SVille Syrjälä static bool is_sagv_enabled(struct drm_i915_private *i915, u16 points_mask)
143*9541fd16SVille Syrjälä {
144*9541fd16SVille Syrjälä 	return !is_power_of_2(~points_mask & icl_qgv_points_mask(i915) &
145*9541fd16SVille Syrjälä 			      ICL_PCODE_REQ_QGV_PT_MASK);
146*9541fd16SVille Syrjälä }
147*9541fd16SVille Syrjälä 
icl_pcode_restrict_qgv_points(struct drm_i915_private * dev_priv,u32 points_mask)14820f505f2SStanislav Lisovskiy int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
14920f505f2SStanislav Lisovskiy 				  u32 points_mask)
15020f505f2SStanislav Lisovskiy {
15120f505f2SStanislav Lisovskiy 	int ret;
15220f505f2SStanislav Lisovskiy 
15320f505f2SStanislav Lisovskiy 	if (DISPLAY_VER(dev_priv) >= 14)
154ee421bb4SAshutosh Dixit 		return 0;
15520f505f2SStanislav Lisovskiy 
1564bdba4f4SVille Syrjälä 	/* bspec says to keep retrying for at least 1 ms */
1574bdba4f4SVille Syrjälä 	ret = skl_pcode_request(&dev_priv->uncore, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG,
15820f505f2SStanislav Lisovskiy 				points_mask,
15920f505f2SStanislav Lisovskiy 				ICL_PCODE_REP_QGV_MASK | ADLS_PCODE_REP_PSF_MASK,
16020f505f2SStanislav Lisovskiy 				ICL_PCODE_REP_QGV_SAFE | ADLS_PCODE_REP_PSF_SAFE,
161192fbfb7SStanislav Lisovskiy 				1);
16220f505f2SStanislav Lisovskiy 
16320f505f2SStanislav Lisovskiy 	if (ret < 0) {
16420f505f2SStanislav Lisovskiy 		drm_err(&dev_priv->drm, "Failed to disable qgv points (%d) points: 0x%x\n", ret, points_mask);
165*9541fd16SVille Syrjälä 		return ret;
166*9541fd16SVille Syrjälä 	}
167*9541fd16SVille Syrjälä 
16820f505f2SStanislav Lisovskiy 	dev_priv->display.sagv.status = is_sagv_enabled(dev_priv, points_mask) ?
16920f505f2SStanislav Lisovskiy 		I915_SAGV_ENABLED : I915_SAGV_DISABLED;
17020f505f2SStanislav Lisovskiy 
171825477e7SRadhakrishna Sripada 	return 0;
172825477e7SRadhakrishna Sripada }
173825477e7SRadhakrishna Sripada 
mtl_read_qgv_point_info(struct drm_i915_private * dev_priv,struct intel_qgv_point * sp,int point)174825477e7SRadhakrishna Sripada static int mtl_read_qgv_point_info(struct drm_i915_private *dev_priv,
175825477e7SRadhakrishna Sripada 				   struct intel_qgv_point *sp, int point)
176825477e7SRadhakrishna Sripada {
177825477e7SRadhakrishna Sripada 	u32 val, val2;
178825477e7SRadhakrishna Sripada 	u16 dclk;
179825477e7SRadhakrishna Sripada 
180825477e7SRadhakrishna Sripada 	val = intel_uncore_read(&dev_priv->uncore,
181825477e7SRadhakrishna Sripada 				MTL_MEM_SS_INFO_QGV_POINT_LOW(point));
182825477e7SRadhakrishna Sripada 	val2 = intel_uncore_read(&dev_priv->uncore,
183825477e7SRadhakrishna Sripada 				 MTL_MEM_SS_INFO_QGV_POINT_HIGH(point));
184825477e7SRadhakrishna Sripada 	dclk = REG_FIELD_GET(MTL_DCLK_MASK, val);
185825477e7SRadhakrishna Sripada 	sp->dclk = DIV_ROUND_CLOSEST(16667 * dclk, 1000);
186825477e7SRadhakrishna Sripada 	sp->t_rp = REG_FIELD_GET(MTL_TRP_MASK, val);
187825477e7SRadhakrishna Sripada 	sp->t_rcd = REG_FIELD_GET(MTL_TRCD_MASK, val);
188825477e7SRadhakrishna Sripada 
189825477e7SRadhakrishna Sripada 	sp->t_rdpre = REG_FIELD_GET(MTL_TRDPRE_MASK, val2);
190825477e7SRadhakrishna Sripada 	sp->t_ras = REG_FIELD_GET(MTL_TRAS_MASK, val2);
191825477e7SRadhakrishna Sripada 
192825477e7SRadhakrishna Sripada 	sp->t_rc = sp->t_rp + sp->t_ras;
193825477e7SRadhakrishna Sripada 
194825477e7SRadhakrishna Sripada 	return 0;
195825477e7SRadhakrishna Sripada }
196825477e7SRadhakrishna Sripada 
197825477e7SRadhakrishna Sripada static int
intel_read_qgv_point_info(struct drm_i915_private * dev_priv,struct intel_qgv_point * sp,int point)198825477e7SRadhakrishna Sripada intel_read_qgv_point_info(struct drm_i915_private *dev_priv,
199825477e7SRadhakrishna Sripada 			  struct intel_qgv_point *sp,
200825477e7SRadhakrishna Sripada 			  int point)
201825477e7SRadhakrishna Sripada {
202825477e7SRadhakrishna Sripada 	if (DISPLAY_VER(dev_priv) >= 14)
203825477e7SRadhakrishna Sripada 		return mtl_read_qgv_point_info(dev_priv, sp, point);
204825477e7SRadhakrishna Sripada 	else if (IS_DG1(dev_priv))
205825477e7SRadhakrishna Sripada 		return dg1_mchbar_read_qgv_point_info(dev_priv, sp, point);
206825477e7SRadhakrishna Sripada 	else
207df0566a6SJani Nikula 		return icl_pcode_read_qgv_point_info(dev_priv, sp, point);
208c64a9a7cSRadhakrishna Sripada }
209c64a9a7cSRadhakrishna Sripada 
icl_get_qgv_points(struct drm_i915_private * dev_priv,struct intel_qgv_info * qi,bool is_y_tile)210df0566a6SJani Nikula static int icl_get_qgv_points(struct drm_i915_private *dev_priv,
2115d0c938eSJosé Roberto de Souza 			      struct intel_qgv_info *qi,
212df0566a6SJani Nikula 			      bool is_y_tile)
213df0566a6SJani Nikula {
2145d0c938eSJosé Roberto de Souza 	const struct dram_info *dram_info = &dev_priv->dram_info;
215192fbfb7SStanislav Lisovskiy 	int i, ret;
2165d0c938eSJosé Roberto de Souza 
2173eb4ad93SRadhakrishna Sripada 	qi->num_points = dram_info->num_qgv_points;
2183eb4ad93SRadhakrishna Sripada 	qi->num_psf_points = dram_info->num_psf_gv_points;
2193eb4ad93SRadhakrishna Sripada 
2203eb4ad93SRadhakrishna Sripada 	if (DISPLAY_VER(dev_priv) >= 14) {
2213eb4ad93SRadhakrishna Sripada 		switch (dram_info->type) {
2223eb4ad93SRadhakrishna Sripada 		case INTEL_DRAM_DDR4:
2233eb4ad93SRadhakrishna Sripada 			qi->t_bl = 4;
2243eb4ad93SRadhakrishna Sripada 			qi->max_numchannels = 2;
2253eb4ad93SRadhakrishna Sripada 			qi->channel_width = 64;
2263eb4ad93SRadhakrishna Sripada 			qi->deinterleave = 2;
2273eb4ad93SRadhakrishna Sripada 			break;
2283eb4ad93SRadhakrishna Sripada 		case INTEL_DRAM_DDR5:
2293eb4ad93SRadhakrishna Sripada 			qi->t_bl = 8;
2303eb4ad93SRadhakrishna Sripada 			qi->max_numchannels = 4;
2313eb4ad93SRadhakrishna Sripada 			qi->channel_width = 32;
2323eb4ad93SRadhakrishna Sripada 			qi->deinterleave = 2;
2333eb4ad93SRadhakrishna Sripada 			break;
2343eb4ad93SRadhakrishna Sripada 		case INTEL_DRAM_LPDDR4:
2353eb4ad93SRadhakrishna Sripada 		case INTEL_DRAM_LPDDR5:
2363eb4ad93SRadhakrishna Sripada 			qi->t_bl = 16;
2373eb4ad93SRadhakrishna Sripada 			qi->max_numchannels = 8;
2383eb4ad93SRadhakrishna Sripada 			qi->channel_width = 16;
2393eb4ad93SRadhakrishna Sripada 			qi->deinterleave = 4;
2403eb4ad93SRadhakrishna Sripada 			break;
2413eb4ad93SRadhakrishna Sripada 		default:
2423eb4ad93SRadhakrishna Sripada 			MISSING_CASE(dram_info->type);
2431f1257a6SClint Taylor 			return -EINVAL;
2441f1257a6SClint Taylor 		}
245c64a9a7cSRadhakrishna Sripada 	} else if (DISPLAY_VER(dev_priv) >= 12) {
246c64a9a7cSRadhakrishna Sripada 		switch (dram_info->type) {
247c64a9a7cSRadhakrishna Sripada 		case INTEL_DRAM_DDR4:
248c64a9a7cSRadhakrishna Sripada 			qi->t_bl = is_y_tile ? 8 : 4;
2491f1257a6SClint Taylor 			qi->max_numchannels = 2;
2501f1257a6SClint Taylor 			qi->channel_width = 64;
251c64a9a7cSRadhakrishna Sripada 			qi->deinterleave = is_y_tile ? 1 : 2;
252c64a9a7cSRadhakrishna Sripada 			break;
253c64a9a7cSRadhakrishna Sripada 		case INTEL_DRAM_DDR5:
254c64a9a7cSRadhakrishna Sripada 			qi->t_bl = is_y_tile ? 16 : 8;
255c64a9a7cSRadhakrishna Sripada 			qi->max_numchannels = 4;
256c64a9a7cSRadhakrishna Sripada 			qi->channel_width = 32;
257c64a9a7cSRadhakrishna Sripada 			qi->deinterleave = is_y_tile ? 1 : 2;
2581f1257a6SClint Taylor 			break;
259c64a9a7cSRadhakrishna Sripada 		case INTEL_DRAM_LPDDR4:
260c64a9a7cSRadhakrishna Sripada 			if (IS_ROCKETLAKE(dev_priv)) {
261c64a9a7cSRadhakrishna Sripada 				qi->t_bl = 8;
262c64a9a7cSRadhakrishna Sripada 				qi->max_numchannels = 4;
263c64a9a7cSRadhakrishna Sripada 				qi->channel_width = 32;
264c64a9a7cSRadhakrishna Sripada 				qi->deinterleave = 2;
265c64a9a7cSRadhakrishna Sripada 				break;
266c64a9a7cSRadhakrishna Sripada 			}
267c64a9a7cSRadhakrishna Sripada 			fallthrough;
268c64a9a7cSRadhakrishna Sripada 		case INTEL_DRAM_LPDDR5:
269c64a9a7cSRadhakrishna Sripada 			qi->t_bl = 16;
2701f1257a6SClint Taylor 			qi->max_numchannels = 8;
2711f1257a6SClint Taylor 			qi->channel_width = 16;
2721f1257a6SClint Taylor 			qi->deinterleave = is_y_tile ? 2 : 4;
273c64a9a7cSRadhakrishna Sripada 			break;
2741f1257a6SClint Taylor 		default:
2751f1257a6SClint Taylor 			qi->t_bl = 16;
2763eb4ad93SRadhakrishna Sripada 			qi->max_numchannels = 1;
2775d0c938eSJosé Roberto de Souza 			break;
278c64a9a7cSRadhakrishna Sripada 		}
279c64a9a7cSRadhakrishna Sripada 	} else if (DISPLAY_VER(dev_priv) == 11) {
280df0566a6SJani Nikula 		qi->t_bl = dev_priv->dram_info.type == INTEL_DRAM_DDR4 ? 4 : 8;
281f4224a4cSPankaj Bharadiya 		qi->max_numchannels = 1;
282f4224a4cSPankaj Bharadiya 	}
283df0566a6SJani Nikula 
284df0566a6SJani Nikula 	if (drm_WARN_ON(&dev_priv->drm,
285df0566a6SJani Nikula 			qi->num_points > ARRAY_SIZE(qi->points)))
286df0566a6SJani Nikula 		qi->num_points = ARRAY_SIZE(qi->points);
287df0566a6SJani Nikula 
288825477e7SRadhakrishna Sripada 	for (i = 0; i < qi->num_points; i++) {
289df0566a6SJani Nikula 		struct intel_qgv_point *sp = &qi->points[i];
290df0566a6SJani Nikula 
291df0566a6SJani Nikula 		ret = intel_read_qgv_point_info(dev_priv, sp, i);
2922e3586ceSWambui Karuga 		if (ret)
2932e3586ceSWambui Karuga 			return ret;
294df0566a6SJani Nikula 
295df0566a6SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
296df0566a6SJani Nikula 			    "QGV %d: DCLK=%d tRP=%d tRDPRE=%d tRAS=%d tRCD=%d tRC=%d\n",
297df0566a6SJani Nikula 			    i, sp->dclk, sp->t_rp, sp->t_rdpre, sp->t_ras,
298192fbfb7SStanislav Lisovskiy 			    sp->t_rcd, sp->t_rc);
299192fbfb7SStanislav Lisovskiy 	}
300192fbfb7SStanislav Lisovskiy 
301192fbfb7SStanislav Lisovskiy 	if (qi->num_psf_points > 0) {
302192fbfb7SStanislav Lisovskiy 		ret = adls_pcode_read_psf_gv_point_info(dev_priv, qi->psf_points);
303192fbfb7SStanislav Lisovskiy 		if (ret) {
304192fbfb7SStanislav Lisovskiy 			drm_err(&dev_priv->drm, "Failed to read PSF point data; PSF points will not be considered in bandwidth calculations.\n");
305192fbfb7SStanislav Lisovskiy 			qi->num_psf_points = 0;
306192fbfb7SStanislav Lisovskiy 		}
307192fbfb7SStanislav Lisovskiy 
308192fbfb7SStanislav Lisovskiy 		for (i = 0; i < qi->num_psf_points; i++)
309192fbfb7SStanislav Lisovskiy 			drm_dbg_kms(&dev_priv->drm,
310192fbfb7SStanislav Lisovskiy 				    "PSF GV %d: CLK=%d \n",
311df0566a6SJani Nikula 				    i, qi->psf_points[i].clk);
312df0566a6SJani Nikula 	}
313df0566a6SJani Nikula 
314192fbfb7SStanislav Lisovskiy 	return 0;
315192fbfb7SStanislav Lisovskiy }
316192fbfb7SStanislav Lisovskiy 
adl_calc_psf_bw(int clk)317192fbfb7SStanislav Lisovskiy static int adl_calc_psf_bw(int clk)
318192fbfb7SStanislav Lisovskiy {
319192fbfb7SStanislav Lisovskiy 	/*
320192fbfb7SStanislav Lisovskiy 	 * clk is multiples of 16.666MHz (100/6)
321192fbfb7SStanislav Lisovskiy 	 * According to BSpec PSF GV bandwidth is
322192fbfb7SStanislav Lisovskiy 	 * calculated as BW = 64 * clk * 16.666Mhz
323192fbfb7SStanislav Lisovskiy 	 */
324df0566a6SJani Nikula 	return DIV_ROUND_CLOSEST(64 * clk * 100, 6);
325df0566a6SJani Nikula }
326df0566a6SJani Nikula 
icl_sagv_max_dclk(const struct intel_qgv_info * qi)327df0566a6SJani Nikula static int icl_sagv_max_dclk(const struct intel_qgv_info *qi)
328df0566a6SJani Nikula {
329df0566a6SJani Nikula 	u16 dclk = 0;
330df0566a6SJani Nikula 	int i;
331df0566a6SJani Nikula 
332df0566a6SJani Nikula 	for (i = 0; i < qi->num_points; i++)
333df0566a6SJani Nikula 		dclk = max(dclk, qi->points[i].dclk);
334df0566a6SJani Nikula 
335df0566a6SJani Nikula 	return dclk;
3361b74d467SStanislav Lisovskiy }
337f6d66fc8SRadhakrishna Sripada 
338df0566a6SJani Nikula struct intel_sa_info {
339df0566a6SJani Nikula 	u16 displayrtids;
340df0566a6SJani Nikula 	u8 deburst, deprogbwlimit, derating;
341df0566a6SJani Nikula };
342df0566a6SJani Nikula 
343df0566a6SJani Nikula static const struct intel_sa_info icl_sa_info = {
344f6d66fc8SRadhakrishna Sripada 	.deburst = 8,
345df0566a6SJani Nikula 	.deprogbwlimit = 25, /* GB/s */
346df0566a6SJani Nikula 	.displayrtids = 128,
3471b74d467SStanislav Lisovskiy 	.derating = 10,
3481b74d467SStanislav Lisovskiy };
3491b74d467SStanislav Lisovskiy 
3501b74d467SStanislav Lisovskiy static const struct intel_sa_info tgl_sa_info = {
351f6d66fc8SRadhakrishna Sripada 	.deburst = 16,
3521b74d467SStanislav Lisovskiy 	.deprogbwlimit = 34, /* GB/s */
3531b74d467SStanislav Lisovskiy 	.displayrtids = 256,
354affd7bb6SMatt Roper 	.derating = 10,
355c64a9a7cSRadhakrishna Sripada };
356affd7bb6SMatt Roper 
357affd7bb6SMatt Roper static const struct intel_sa_info rkl_sa_info = {
358f6d66fc8SRadhakrishna Sripada 	.deburst = 8,
359affd7bb6SMatt Roper 	.deprogbwlimit = 20, /* GB/s */
360affd7bb6SMatt Roper 	.displayrtids = 128,
361918cc934STejas Upadhyay 	.derating = 10,
362918cc934STejas Upadhyay };
363918cc934STejas Upadhyay 
364918cc934STejas Upadhyay static const struct intel_sa_info adls_sa_info = {
365f6d66fc8SRadhakrishna Sripada 	.deburst = 16,
366f6d66fc8SRadhakrishna Sripada 	.deprogbwlimit = 38, /* GB/s */
367f6d66fc8SRadhakrishna Sripada 	.displayrtids = 256,
368f6d66fc8SRadhakrishna Sripada 	.derating = 10,
369f6d66fc8SRadhakrishna Sripada };
370f6d66fc8SRadhakrishna Sripada 
371f6d66fc8SRadhakrishna Sripada static const struct intel_sa_info adlp_sa_info = {
372f6d66fc8SRadhakrishna Sripada 	.deburst = 16,
373918cc934STejas Upadhyay 	.deprogbwlimit = 38, /* GB/s */
374918cc934STejas Upadhyay 	.displayrtids = 256,
3753eb4ad93SRadhakrishna Sripada 	.derating = 20,
3763eb4ad93SRadhakrishna Sripada };
3773eb4ad93SRadhakrishna Sripada 
3783eb4ad93SRadhakrishna Sripada static const struct intel_sa_info mtl_sa_info = {
3793eb4ad93SRadhakrishna Sripada 	.deburst = 32,
3803eb4ad93SRadhakrishna Sripada 	.deprogbwlimit = 38, /* GB/s */
3813eb4ad93SRadhakrishna Sripada 	.displayrtids = 256,
3821b74d467SStanislav Lisovskiy 	.derating = 10,
383df0566a6SJani Nikula };
384df0566a6SJani Nikula 
icl_get_bw_info(struct drm_i915_private * dev_priv,const struct intel_sa_info * sa)385df0566a6SJani Nikula static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel_sa_info *sa)
386b554065cSJosé Roberto de Souza {
387c64a9a7cSRadhakrishna Sripada 	struct intel_qgv_info qi = {};
388df0566a6SJani Nikula 	bool is_y_tile = true; /* assume y tile may be used */
389df0566a6SJani Nikula 	int num_channels = max_t(u8, 1, dev_priv->dram_info.num_channels);
390f0acaf9dSJani Nikula 	int ipqdepth, ipqdepthpch = 16;
391df0566a6SJani Nikula 	int dclk_max;
392df0566a6SJani Nikula 	int maxdebw;
393c64a9a7cSRadhakrishna Sripada 	int num_groups = ARRAY_SIZE(dev_priv->display.bw.max);
394df0566a6SJani Nikula 	int i, ret;
3952e3586ceSWambui Karuga 
3962e3586ceSWambui Karuga 	ret = icl_get_qgv_points(dev_priv, &qi, is_y_tile);
397df0566a6SJani Nikula 	if (ret) {
398df0566a6SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
399df0566a6SJani Nikula 			    "Failed to get memory subsystem information, ignoring bandwidth limits");
400df0566a6SJani Nikula 		return ret;
401c64a9a7cSRadhakrishna Sripada 	}
402df0566a6SJani Nikula 
403c64a9a7cSRadhakrishna Sripada 	dclk_max = icl_sagv_max_dclk(&qi);
404df0566a6SJani Nikula 	maxdebw = min(sa->deprogbwlimit * 1000, dclk_max * 16 * 6 / 10);
405c64a9a7cSRadhakrishna Sripada 	ipqdepth = min(ipqdepthpch, sa->displayrtids / num_channels);
406f0acaf9dSJani Nikula 	qi.deinterleave = DIV_ROUND_UP(num_channels, is_y_tile ? 4 : 2);
407df0566a6SJani Nikula 
408df0566a6SJani Nikula 	for (i = 0; i < num_groups; i++) {
409df0566a6SJani Nikula 		struct intel_bw_info *bi = &dev_priv->display.bw.max[i];
410c64a9a7cSRadhakrishna Sripada 		int clpchgroup;
411df0566a6SJani Nikula 		int j;
412df0566a6SJani Nikula 
41356e9371bSVille Syrjälä 		clpchgroup = (sa->deburst * qi.deinterleave / num_channels) << i;
414192fbfb7SStanislav Lisovskiy 		bi->num_planes = (ipqdepth - clpchgroup) / clpchgroup + 1;
41556e9371bSVille Syrjälä 
416df0566a6SJani Nikula 		bi->num_qgv_points = qi.num_points;
417df0566a6SJani Nikula 		bi->num_psf_gv_points = qi.num_psf_points;
418df0566a6SJani Nikula 
419df0566a6SJani Nikula 		for (j = 0; j < qi.num_points; j++) {
420df0566a6SJani Nikula 			const struct intel_qgv_point *sp = &qi.points[j];
421df0566a6SJani Nikula 			int ct, bw;
422df0566a6SJani Nikula 
423df0566a6SJani Nikula 			/*
424df0566a6SJani Nikula 			 * Max row cycle time
425df0566a6SJani Nikula 			 *
426df0566a6SJani Nikula 			 * FIXME what is the logic behind the
427df0566a6SJani Nikula 			 * assumed burst length?
428c64a9a7cSRadhakrishna Sripada 			 */
429c64a9a7cSRadhakrishna Sripada 			ct = max_t(int, sp->t_rc, sp->t_rp + sp->t_rcd +
430c64a9a7cSRadhakrishna Sripada 				   (clpchgroup - 1) * qi.t_bl + sp->t_rdpre);
431c64a9a7cSRadhakrishna Sripada 			bw = DIV_ROUND_UP(sp->dclk * clpchgroup * 32 * num_channels, ct);
432c64a9a7cSRadhakrishna Sripada 
433c64a9a7cSRadhakrishna Sripada 			bi->deratedbw[j] = min(maxdebw,
434c64a9a7cSRadhakrishna Sripada 					       bw * (100 - sa->derating) / 100);
435c64a9a7cSRadhakrishna Sripada 
436c64a9a7cSRadhakrishna Sripada 			drm_dbg_kms(&dev_priv->drm,
437c64a9a7cSRadhakrishna Sripada 				    "BW%d / QGV %d: num_planes=%d deratedbw=%u\n",
438c64a9a7cSRadhakrishna Sripada 				    i, j, bi->num_planes, bi->deratedbw[j]);
439c64a9a7cSRadhakrishna Sripada 		}
440c64a9a7cSRadhakrishna Sripada 	}
441c64a9a7cSRadhakrishna Sripada 	/*
442c64a9a7cSRadhakrishna Sripada 	 * In case if SAGV is disabled in BIOS, we always get 1
443c64a9a7cSRadhakrishna Sripada 	 * SAGV point, but we can't send PCode commands to restrict it
444c3704f19SJani Nikula 	 * as it will fail and pointless anyway.
445c64a9a7cSRadhakrishna Sripada 	 */
446c3704f19SJani Nikula 	if (qi.num_points == 1)
447c64a9a7cSRadhakrishna Sripada 		dev_priv->display.sagv.status = I915_SAGV_NOT_CONTROLLED;
448c64a9a7cSRadhakrishna Sripada 	else
449c64a9a7cSRadhakrishna Sripada 		dev_priv->display.sagv.status = I915_SAGV_ENABLED;
450c64a9a7cSRadhakrishna Sripada 
451c64a9a7cSRadhakrishna Sripada 	return 0;
452c64a9a7cSRadhakrishna Sripada }
453c64a9a7cSRadhakrishna Sripada 
tgl_get_bw_info(struct drm_i915_private * dev_priv,const struct intel_sa_info * sa)454c64a9a7cSRadhakrishna Sripada static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel_sa_info *sa)
455c64a9a7cSRadhakrishna Sripada {
456c64a9a7cSRadhakrishna Sripada 	struct intel_qgv_info qi = {};
457c64a9a7cSRadhakrishna Sripada 	const struct dram_info *dram_info = &dev_priv->dram_info;
458c64a9a7cSRadhakrishna Sripada 	bool is_y_tile = true; /* assume y tile may be used */
459c64a9a7cSRadhakrishna Sripada 	int num_channels = max_t(u8, 1, dev_priv->dram_info.num_channels);
460c64a9a7cSRadhakrishna Sripada 	int ipqdepth, ipqdepthpch = 16;
461f0acaf9dSJani Nikula 	int dclk_max;
462c64a9a7cSRadhakrishna Sripada 	int maxdebw, peakbw;
463c64a9a7cSRadhakrishna Sripada 	int clperchgroup;
464c64a9a7cSRadhakrishna Sripada 	int num_groups = ARRAY_SIZE(dev_priv->display.bw.max);
465c64a9a7cSRadhakrishna Sripada 	int i, ret;
466c64a9a7cSRadhakrishna Sripada 
467c64a9a7cSRadhakrishna Sripada 	ret = icl_get_qgv_points(dev_priv, &qi, is_y_tile);
468c64a9a7cSRadhakrishna Sripada 	if (ret) {
469c64a9a7cSRadhakrishna Sripada 		drm_dbg_kms(&dev_priv->drm,
470c64a9a7cSRadhakrishna Sripada 			    "Failed to get memory subsystem information, ignoring bandwidth limits");
471244c679bSRadhakrishna Sripada 		return ret;
472244c679bSRadhakrishna Sripada 	}
473c64a9a7cSRadhakrishna Sripada 
474c64a9a7cSRadhakrishna Sripada 	if (DISPLAY_VER(dev_priv) < 14 &&
475c64a9a7cSRadhakrishna Sripada 	    (dram_info->type == INTEL_DRAM_LPDDR4 || dram_info->type == INTEL_DRAM_LPDDR5))
476c64a9a7cSRadhakrishna Sripada 		num_channels *= 2;
477c64a9a7cSRadhakrishna Sripada 
478c64a9a7cSRadhakrishna Sripada 	qi.deinterleave = qi.deinterleave ? : DIV_ROUND_UP(num_channels, is_y_tile ? 4 : 2);
479c64a9a7cSRadhakrishna Sripada 
480c64a9a7cSRadhakrishna Sripada 	if (num_channels < qi.max_numchannels && DISPLAY_VER(dev_priv) >= 12)
481c64a9a7cSRadhakrishna Sripada 		qi.deinterleave = max(DIV_ROUND_UP(qi.deinterleave, 2), 1);
482c64a9a7cSRadhakrishna Sripada 
483c64a9a7cSRadhakrishna Sripada 	if (DISPLAY_VER(dev_priv) > 11 && num_channels > qi.max_numchannels)
484c64a9a7cSRadhakrishna Sripada 		drm_warn(&dev_priv->drm, "Number of channels exceeds max number of channels.");
485c64a9a7cSRadhakrishna Sripada 	if (qi.max_numchannels != 0)
486c64a9a7cSRadhakrishna Sripada 		num_channels = min_t(u8, num_channels, qi.max_numchannels);
487c64a9a7cSRadhakrishna Sripada 
488c64a9a7cSRadhakrishna Sripada 	dclk_max = icl_sagv_max_dclk(&qi);
489c64a9a7cSRadhakrishna Sripada 
490c64a9a7cSRadhakrishna Sripada 	peakbw = num_channels * DIV_ROUND_UP(qi.channel_width, 8) * dclk_max;
491c64a9a7cSRadhakrishna Sripada 	maxdebw = min(sa->deprogbwlimit * 1000, peakbw * 6 / 10); /* 60% */
492c64a9a7cSRadhakrishna Sripada 
493c64a9a7cSRadhakrishna Sripada 	ipqdepth = min(ipqdepthpch, sa->displayrtids / num_channels);
494c64a9a7cSRadhakrishna Sripada 	/*
495c64a9a7cSRadhakrishna Sripada 	 * clperchgroup = 4kpagespermempage * clperchperblock,
496c64a9a7cSRadhakrishna Sripada 	 * clperchperblock = 8 / num_channels * interleave
497c64a9a7cSRadhakrishna Sripada 	 */
498f0acaf9dSJani Nikula 	clperchgroup = 4 * DIV_ROUND_UP(8, num_channels) * qi.deinterleave;
499c64a9a7cSRadhakrishna Sripada 
500c64a9a7cSRadhakrishna Sripada 	for (i = 0; i < num_groups; i++) {
501c64a9a7cSRadhakrishna Sripada 		struct intel_bw_info *bi = &dev_priv->display.bw.max[i];
502c64a9a7cSRadhakrishna Sripada 		struct intel_bw_info *bi_next;
503c64a9a7cSRadhakrishna Sripada 		int clpchgroup;
504c64a9a7cSRadhakrishna Sripada 		int j;
505c247cd03SŁukasz Bartosik 
506f0acaf9dSJani Nikula 		clpchgroup = (sa->deburst * qi.deinterleave / num_channels) << i;
507c247cd03SŁukasz Bartosik 
508c247cd03SŁukasz Bartosik 		if (i < num_groups - 1) {
509c247cd03SŁukasz Bartosik 			bi_next = &dev_priv->display.bw.max[i + 1];
510c247cd03SŁukasz Bartosik 
511c64a9a7cSRadhakrishna Sripada 			if (clpchgroup < clperchgroup)
512c64a9a7cSRadhakrishna Sripada 				bi_next->num_planes = (ipqdepth - clpchgroup) /
513c247cd03SŁukasz Bartosik 						       clpchgroup + 1;
514c64a9a7cSRadhakrishna Sripada 			else
515c64a9a7cSRadhakrishna Sripada 				bi_next->num_planes = 0;
516c64a9a7cSRadhakrishna Sripada 		}
517c64a9a7cSRadhakrishna Sripada 
518c64a9a7cSRadhakrishna Sripada 		bi->num_qgv_points = qi.num_points;
519c64a9a7cSRadhakrishna Sripada 		bi->num_psf_gv_points = qi.num_psf_points;
520c64a9a7cSRadhakrishna Sripada 
521c64a9a7cSRadhakrishna Sripada 		for (j = 0; j < qi.num_points; j++) {
522c64a9a7cSRadhakrishna Sripada 			const struct intel_qgv_point *sp = &qi.points[j];
523c64a9a7cSRadhakrishna Sripada 			int ct, bw;
524c64a9a7cSRadhakrishna Sripada 
525c64a9a7cSRadhakrishna Sripada 			/*
526c64a9a7cSRadhakrishna Sripada 			 * Max row cycle time
527c64a9a7cSRadhakrishna Sripada 			 *
528c64a9a7cSRadhakrishna Sripada 			 * FIXME what is the logic behind the
529c64a9a7cSRadhakrishna Sripada 			 * assumed burst length?
530c64a9a7cSRadhakrishna Sripada 			 */
531df0566a6SJani Nikula 			ct = max_t(int, sp->t_rc, sp->t_rp + sp->t_rcd +
532df0566a6SJani Nikula 				   (clpchgroup - 1) * qi.t_bl + sp->t_rdpre);
533f6d66fc8SRadhakrishna Sripada 			bw = DIV_ROUND_UP(sp->dclk * clpchgroup * 32 * num_channels, ct);
534df0566a6SJani Nikula 
5352e3586ceSWambui Karuga 			bi->deratedbw[j] = min(maxdebw,
5362e3586ceSWambui Karuga 					       bw * (100 - sa->derating) / 100);
537df0566a6SJani Nikula 			bi->peakbw[j] = DIV_ROUND_CLOSEST(sp->dclk *
538df0566a6SJani Nikula 							  num_channels *
539df0566a6SJani Nikula 							  qi.channel_width, 8);
540192fbfb7SStanislav Lisovskiy 
541192fbfb7SStanislav Lisovskiy 			drm_dbg_kms(&dev_priv->drm,
542192fbfb7SStanislav Lisovskiy 				    "BW%d / QGV %d: num_planes=%d deratedbw=%u peakbw: %u\n",
543192fbfb7SStanislav Lisovskiy 				    i, j, bi->num_planes, bi->deratedbw[j],
544192fbfb7SStanislav Lisovskiy 				    bi->peakbw[j]);
545192fbfb7SStanislav Lisovskiy 		}
546192fbfb7SStanislav Lisovskiy 
547192fbfb7SStanislav Lisovskiy 		for (j = 0; j < qi.num_psf_points; j++) {
548192fbfb7SStanislav Lisovskiy 			const struct intel_psf_gv_point *sp = &qi.psf_points[j];
549df0566a6SJani Nikula 
550df0566a6SJani Nikula 			bi->psf_bw[j] = adl_calc_psf_bw(sp->clk);
55120f505f2SStanislav Lisovskiy 
55220f505f2SStanislav Lisovskiy 			drm_dbg_kms(&dev_priv->drm,
55320f505f2SStanislav Lisovskiy 				    "BW%d / PSF GV %d: num_planes=%d bw=%u\n",
55420f505f2SStanislav Lisovskiy 				    i, j, bi->num_planes, bi->psf_bw[j]);
55520f505f2SStanislav Lisovskiy 		}
55620f505f2SStanislav Lisovskiy 	}
557c3704f19SJani Nikula 
55820f505f2SStanislav Lisovskiy 	/*
559c3704f19SJani Nikula 	 * In case if SAGV is disabled in BIOS, we always get 1
56020f505f2SStanislav Lisovskiy 	 * SAGV point, but we can't send PCode commands to restrict it
561df0566a6SJani Nikula 	 * as it will fail and pointless anyway.
562df0566a6SJani Nikula 	 */
563df0566a6SJani Nikula 	if (qi.num_points == 1)
56434ba3c8aSMatt Roper 		dev_priv->display.sagv.status = I915_SAGV_NOT_CONTROLLED;
56534ba3c8aSMatt Roper 	else
566bc58192aSVinod Govindapillai 		dev_priv->display.sagv.status = I915_SAGV_ENABLED;
567f0acaf9dSJani Nikula 
568bc58192aSVinod Govindapillai 	return 0;
56934ba3c8aSMatt Roper }
57034ba3c8aSMatt Roper 
dg2_get_bw_info(struct drm_i915_private * i915)57134ba3c8aSMatt Roper static void dg2_get_bw_info(struct drm_i915_private *i915)
572bc58192aSVinod Govindapillai {
573bc58192aSVinod Govindapillai 	unsigned int deratedbw = IS_DG2_G11(i915) ? 38000 : 50000;
574bc58192aSVinod Govindapillai 	int num_groups = ARRAY_SIZE(i915->display.bw.max);
575bc58192aSVinod Govindapillai 	int i;
57634ba3c8aSMatt Roper 
577bc58192aSVinod Govindapillai 	/*
578f0acaf9dSJani Nikula 	 * DG2 doesn't have SAGV or QGV points, just a constant max bandwidth
579bc58192aSVinod Govindapillai 	 * that doesn't depend on the number of planes enabled. So fill all the
58034ba3c8aSMatt Roper 	 * plane group with constant bw information for uniformity with other
581bc58192aSVinod Govindapillai 	 * platforms. DG2-G10 platforms have a constant 50 GB/s bandwidth,
58234ba3c8aSMatt Roper 	 * whereas DG2-G11 platforms have 38 GB/s.
583bc58192aSVinod Govindapillai 	 */
584bc58192aSVinod Govindapillai 	for (i = 0; i < num_groups; i++) {
58534ba3c8aSMatt Roper 		struct intel_bw_info *bi = &i915->display.bw.max[i];
586c3704f19SJani Nikula 
58734ba3c8aSMatt Roper 		bi->num_planes = 1;
58834ba3c8aSMatt Roper 		/* Need only one dummy QGV point per group */
589df0566a6SJani Nikula 		bi->num_qgv_points = 1;
590df0566a6SJani Nikula 		bi->deratedbw[0] = deratedbw;
591df0566a6SJani Nikula 	}
592df0566a6SJani Nikula 
593df0566a6SJani Nikula 	i915->display.sagv.status = I915_SAGV_NOT_CONTROLLED;
59420f505f2SStanislav Lisovskiy }
59520f505f2SStanislav Lisovskiy 
icl_max_bw_index(struct drm_i915_private * dev_priv,int num_planes,int qgv_point)59620f505f2SStanislav Lisovskiy static unsigned int icl_max_bw_index(struct drm_i915_private *dev_priv,
59720f505f2SStanislav Lisovskiy 				     int num_planes, int qgv_point)
59820f505f2SStanislav Lisovskiy {
599f0acaf9dSJani Nikula 	int i;
600df0566a6SJani Nikula 
601f0acaf9dSJani Nikula 	/*
602df0566a6SJani Nikula 	 * Let's return max bw for 0 planes
60356e9371bSVille Syrjälä 	 */
60456e9371bSVille Syrjälä 	num_planes = max(1, num_planes);
60556e9371bSVille Syrjälä 
60656e9371bSVille Syrjälä 	for (i = 0; i < ARRAY_SIZE(dev_priv->display.bw.max); i++) {
60756e9371bSVille Syrjälä 		const struct intel_bw_info *bi =
60856e9371bSVille Syrjälä 			&dev_priv->display.bw.max[i];
60956e9371bSVille Syrjälä 
610df0566a6SJani Nikula 		/*
611df0566a6SJani Nikula 		 * Pcode will not expose all QGV points when
612df0566a6SJani Nikula 		 * SAGV is forced to off/min/med/max.
613df0566a6SJani Nikula 		 */
614df0566a6SJani Nikula 		if (qgv_point >= bi->num_qgv_points)
615df0566a6SJani Nikula 			return UINT_MAX;
616df0566a6SJani Nikula 
617c64a9a7cSRadhakrishna Sripada 		if (num_planes >= bi->num_planes)
618c64a9a7cSRadhakrishna Sripada 			return i;
619c64a9a7cSRadhakrishna Sripada 	}
620c64a9a7cSRadhakrishna Sripada 
621c64a9a7cSRadhakrishna Sripada 	return UINT_MAX;
622c64a9a7cSRadhakrishna Sripada }
623c64a9a7cSRadhakrishna Sripada 
tgl_max_bw_index(struct drm_i915_private * dev_priv,int num_planes,int qgv_point)624c64a9a7cSRadhakrishna Sripada static unsigned int tgl_max_bw_index(struct drm_i915_private *dev_priv,
625c64a9a7cSRadhakrishna Sripada 				     int num_planes, int qgv_point)
626c64a9a7cSRadhakrishna Sripada {
627f0acaf9dSJani Nikula 	int i;
628c64a9a7cSRadhakrishna Sripada 
629f0acaf9dSJani Nikula 	/*
630c64a9a7cSRadhakrishna Sripada 	 * Let's return max bw for 0 planes
631c64a9a7cSRadhakrishna Sripada 	 */
632c64a9a7cSRadhakrishna Sripada 	num_planes = max(1, num_planes);
633c64a9a7cSRadhakrishna Sripada 
634c64a9a7cSRadhakrishna Sripada 	for (i = ARRAY_SIZE(dev_priv->display.bw.max) - 1; i >= 0; i--) {
635c64a9a7cSRadhakrishna Sripada 		const struct intel_bw_info *bi =
636c64a9a7cSRadhakrishna Sripada 			&dev_priv->display.bw.max[i];
637c64a9a7cSRadhakrishna Sripada 
638c64a9a7cSRadhakrishna Sripada 		/*
639c64a9a7cSRadhakrishna Sripada 		 * Pcode will not expose all QGV points when
640c64a9a7cSRadhakrishna Sripada 		 * SAGV is forced to off/min/med/max.
641c64a9a7cSRadhakrishna Sripada 		 */
642f0acaf9dSJani Nikula 		if (qgv_point >= bi->num_qgv_points)
643c64a9a7cSRadhakrishna Sripada 			return UINT_MAX;
644c64a9a7cSRadhakrishna Sripada 
645192fbfb7SStanislav Lisovskiy 		if (num_planes <= bi->num_planes)
646192fbfb7SStanislav Lisovskiy 			return i;
647192fbfb7SStanislav Lisovskiy 	}
648192fbfb7SStanislav Lisovskiy 
649f0acaf9dSJani Nikula 	return 0;
650192fbfb7SStanislav Lisovskiy }
651192fbfb7SStanislav Lisovskiy 
adl_psf_bw(struct drm_i915_private * dev_priv,int psf_gv_point)652192fbfb7SStanislav Lisovskiy static unsigned int adl_psf_bw(struct drm_i915_private *dev_priv,
653192fbfb7SStanislav Lisovskiy 			       int psf_gv_point)
654df0566a6SJani Nikula {
655df0566a6SJani Nikula 	const struct intel_bw_info *bi =
6568a126392SStuart Summers 			&dev_priv->display.bw.max[0];
6578a126392SStuart Summers 
6588a126392SStuart Summers 	return bi->psf_bw[psf_gv_point];
6593eb4ad93SRadhakrishna Sripada }
6603eb4ad93SRadhakrishna Sripada 
intel_bw_init_hw(struct drm_i915_private * dev_priv)6613eb4ad93SRadhakrishna Sripada void intel_bw_init_hw(struct drm_i915_private *dev_priv)
66234ba3c8aSMatt Roper {
663f6d66fc8SRadhakrishna Sripada 	if (!HAS_DISPLAY(dev_priv))
664c64a9a7cSRadhakrishna Sripada 		return;
665f6d66fc8SRadhakrishna Sripada 
666c64a9a7cSRadhakrishna Sripada 	if (DISPLAY_VER(dev_priv) >= 14)
667918cc934STejas Upadhyay 		tgl_get_bw_info(dev_priv, &mtl_sa_info);
668c64a9a7cSRadhakrishna Sripada 	else if (IS_DG2(dev_priv))
66993e7e61eSLucas De Marchi 		dg2_get_bw_info(dev_priv);
670c64a9a7cSRadhakrishna Sripada 	else if (IS_ALDERLAKE_P(dev_priv))
67193e7e61eSLucas De Marchi 		tgl_get_bw_info(dev_priv, &adlp_sa_info);
6721b74d467SStanislav Lisovskiy 	else if (IS_ALDERLAKE_S(dev_priv))
673df0566a6SJani Nikula 		tgl_get_bw_info(dev_priv, &adls_sa_info);
674df0566a6SJani Nikula 	else if (IS_ROCKETLAKE(dev_priv))
675df0566a6SJani Nikula 		tgl_get_bw_info(dev_priv, &rkl_sa_info);
676df0566a6SJani Nikula 	else if (DISPLAY_VER(dev_priv) == 12)
677df0566a6SJani Nikula 		tgl_get_bw_info(dev_priv, &tgl_sa_info);
678df0566a6SJani Nikula 	else if (DISPLAY_VER(dev_priv) == 11)
679df0566a6SJani Nikula 		icl_get_bw_info(dev_priv, &icl_sa_info);
680df0566a6SJani Nikula }
681df0566a6SJani Nikula 
intel_bw_crtc_num_active_planes(const struct intel_crtc_state * crtc_state)682df0566a6SJani Nikula static unsigned int intel_bw_crtc_num_active_planes(const struct intel_crtc_state *crtc_state)
683df0566a6SJani Nikula {
684df0566a6SJani Nikula 	/*
685df0566a6SJani Nikula 	 * We assume cursors are small enough
6862225f3c6SMaarten Lankhorst 	 * to not not cause bandwidth problems.
687943ed3ccSVille Syrjälä 	 */
688df0566a6SJani Nikula 	return hweight8(crtc_state->active_planes & ~BIT(PLANE_CURSOR));
689df0566a6SJani Nikula }
690df0566a6SJani Nikula 
intel_bw_crtc_data_rate(const struct intel_crtc_state * crtc_state)691df0566a6SJani Nikula static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_state)
692df0566a6SJani Nikula {
693df0566a6SJani Nikula 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
694df0566a6SJani Nikula 	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
695df0566a6SJani Nikula 	unsigned int data_rate = 0;
696df0566a6SJani Nikula 	enum plane_id plane_id;
697df0566a6SJani Nikula 
698df0566a6SJani Nikula 	for_each_plane_id_on_crtc(crtc, plane_id) {
699df0566a6SJani Nikula 		/*
700943ed3ccSVille Syrjälä 		 * We assume cursors are small enough
701943ed3ccSVille Syrjälä 		 * to not not cause bandwidth problems.
702943ed3ccSVille Syrjälä 		 */
703df0566a6SJani Nikula 		if (plane_id == PLANE_CURSOR)
704df0566a6SJani Nikula 			continue;
705df0566a6SJani Nikula 
706df0566a6SJani Nikula 		data_rate += crtc_state->data_rate[plane_id];
707cac91e67SStanislav Lisovskiy 
708ea083969SVille Syrjälä 		if (DISPLAY_VER(i915) < 11)
709ea083969SVille Syrjälä 			data_rate += crtc_state->data_rate_y[plane_id];
710ea083969SVille Syrjälä 	}
711ea083969SVille Syrjälä 
712ea083969SVille Syrjälä 	return data_rate;
713ea083969SVille Syrjälä }
714ea083969SVille Syrjälä 
715ea083969SVille Syrjälä /* "Maximum Pipe Read Bandwidth" */
intel_bw_crtc_min_cdclk(const struct intel_crtc_state * crtc_state)716ea083969SVille Syrjälä static int intel_bw_crtc_min_cdclk(const struct intel_crtc_state *crtc_state)
717ea083969SVille Syrjälä {
718ea083969SVille Syrjälä 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
719ea083969SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
720df0566a6SJani Nikula 
721df0566a6SJani Nikula 	if (DISPLAY_VER(i915) < 12)
722df0566a6SJani Nikula 		return 0;
7232225f3c6SMaarten Lankhorst 
724c3f81563SJani Nikula 	return DIV_ROUND_UP_ULL(mul_u32_u32(intel_bw_crtc_data_rate(crtc_state), 10), 512);
725df0566a6SJani Nikula }
726df0566a6SJani Nikula 
intel_bw_crtc_update(struct intel_bw_state * bw_state,const struct intel_crtc_state * crtc_state)727df0566a6SJani Nikula void intel_bw_crtc_update(struct intel_bw_state *bw_state,
728df0566a6SJani Nikula 			  const struct intel_crtc_state *crtc_state)
729df0566a6SJani Nikula {
730df0566a6SJani Nikula 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
731c3f81563SJani Nikula 	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
732df0566a6SJani Nikula 
733df0566a6SJani Nikula 	bw_state->data_rate[crtc->pipe] =
734df0566a6SJani Nikula 		intel_bw_crtc_data_rate(crtc_state);
735df0566a6SJani Nikula 	bw_state->num_active_planes[crtc->pipe] =
736df0566a6SJani Nikula 		intel_bw_crtc_num_active_planes(crtc_state);
737df0566a6SJani Nikula 
738df0566a6SJani Nikula 	drm_dbg_kms(&i915->drm, "pipe %c data rate %u num active planes %u\n",
739df0566a6SJani Nikula 		    pipe_name(crtc->pipe),
740df0566a6SJani Nikula 		    bw_state->data_rate[crtc->pipe],
741df0566a6SJani Nikula 		    bw_state->num_active_planes[crtc->pipe]);
742df0566a6SJani Nikula }
743df0566a6SJani Nikula 
intel_bw_num_active_planes(struct drm_i915_private * dev_priv,const struct intel_bw_state * bw_state)744df0566a6SJani Nikula static unsigned int intel_bw_num_active_planes(struct drm_i915_private *dev_priv,
745df0566a6SJani Nikula 					       const struct intel_bw_state *bw_state)
746df0566a6SJani Nikula {
747df0566a6SJani Nikula 	unsigned int num_active_planes = 0;
748df0566a6SJani Nikula 	enum pipe pipe;
749df0566a6SJani Nikula 
750df0566a6SJani Nikula 	for_each_pipe(dev_priv, pipe)
751df0566a6SJani Nikula 		num_active_planes += bw_state->num_active_planes[pipe];
752df0566a6SJani Nikula 
753df0566a6SJani Nikula 	return num_active_planes;
754df0566a6SJani Nikula }
755df0566a6SJani Nikula 
intel_bw_data_rate(struct drm_i915_private * dev_priv,const struct intel_bw_state * bw_state)756df0566a6SJani Nikula static unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv,
757df0566a6SJani Nikula 				       const struct intel_bw_state *bw_state)
758a7f46d5bSTvrtko Ursulin {
7596c69d0bbSVille Syrjälä 	unsigned int data_rate = 0;
7600788abdeSMatt Roper 	enum pipe pipe;
761df0566a6SJani Nikula 
762df0566a6SJani Nikula 	for_each_pipe(dev_priv, pipe)
763df0566a6SJani Nikula 		data_rate += bw_state->data_rate[pipe];
764442e7ee8SStanislav Lisovskiy 
765442e7ee8SStanislav Lisovskiy 	if (DISPLAY_VER(dev_priv) >= 13 && i915_vtd_active(dev_priv))
766442e7ee8SStanislav Lisovskiy 		data_rate = DIV_ROUND_UP(data_rate * 105, 100);
767442e7ee8SStanislav Lisovskiy 
768442e7ee8SStanislav Lisovskiy 	return data_rate;
769442e7ee8SStanislav Lisovskiy }
770f0acaf9dSJani Nikula 
771442e7ee8SStanislav Lisovskiy struct intel_bw_state *
intel_atomic_get_old_bw_state(struct intel_atomic_state * state)772442e7ee8SStanislav Lisovskiy intel_atomic_get_old_bw_state(struct intel_atomic_state *state)
773442e7ee8SStanislav Lisovskiy {
774442e7ee8SStanislav Lisovskiy 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
775442e7ee8SStanislav Lisovskiy 	struct intel_global_state *bw_state;
776442e7ee8SStanislav Lisovskiy 
777442e7ee8SStanislav Lisovskiy 	bw_state = intel_atomic_get_old_global_obj_state(state, &dev_priv->display.bw.obj);
778442e7ee8SStanislav Lisovskiy 
779442e7ee8SStanislav Lisovskiy 	return to_intel_bw_state(bw_state);
780442e7ee8SStanislav Lisovskiy }
781f0acaf9dSJani Nikula 
782442e7ee8SStanislav Lisovskiy struct intel_bw_state *
intel_atomic_get_new_bw_state(struct intel_atomic_state * state)783442e7ee8SStanislav Lisovskiy intel_atomic_get_new_bw_state(struct intel_atomic_state *state)
784442e7ee8SStanislav Lisovskiy {
785442e7ee8SStanislav Lisovskiy 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
786442e7ee8SStanislav Lisovskiy 	struct intel_global_state *bw_state;
787366b6200SJani Nikula 
788366b6200SJani Nikula 	bw_state = intel_atomic_get_new_global_obj_state(state, &dev_priv->display.bw.obj);
789366b6200SJani Nikula 
790fd1a9bbaSVille Syrjälä 	return to_intel_bw_state(bw_state);
791366b6200SJani Nikula }
792f0acaf9dSJani Nikula 
793366b6200SJani Nikula struct intel_bw_state *
intel_atomic_get_bw_state(struct intel_atomic_state * state)794366b6200SJani Nikula intel_atomic_get_bw_state(struct intel_atomic_state *state)
795366b6200SJani Nikula {
796366b6200SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
797366b6200SJani Nikula 	struct intel_global_state *bw_state;
798366b6200SJani Nikula 
7996731eb04SVille Syrjälä 	bw_state = intel_atomic_get_global_obj_state(state, &dev_priv->display.bw.obj);
8006731eb04SVille Syrjälä 	if (IS_ERR(bw_state))
8016731eb04SVille Syrjälä 		return ERR_CAST(bw_state);
8026731eb04SVille Syrjälä 
8036731eb04SVille Syrjälä 	return to_intel_bw_state(bw_state);
8046731eb04SVille Syrjälä }
8056731eb04SVille Syrjälä 
mtl_find_qgv_points(struct drm_i915_private * i915,unsigned int data_rate,unsigned int num_active_planes,struct intel_bw_state * new_bw_state)8066731eb04SVille Syrjälä static int mtl_find_qgv_points(struct drm_i915_private *i915,
8076731eb04SVille Syrjälä 			       unsigned int data_rate,
8086731eb04SVille Syrjälä 			       unsigned int num_active_planes,
8096731eb04SVille Syrjälä 			       struct intel_bw_state *new_bw_state)
8106731eb04SVille Syrjälä {
8116731eb04SVille Syrjälä 	unsigned int best_rate = UINT_MAX;
8126731eb04SVille Syrjälä 	unsigned int num_qgv_points = i915->display.bw.max[0].num_qgv_points;
8135ac860ccSVille Syrjälä 	unsigned int qgv_peak_bw  = 0;
8145ac860ccSVille Syrjälä 	int i;
8156731eb04SVille Syrjälä 	int ret;
8166731eb04SVille Syrjälä 
817ea083969SVille Syrjälä 	ret = intel_atomic_lock_global_state(&new_bw_state->base);
818ea083969SVille Syrjälä 	if (ret)
819ea083969SVille Syrjälä 		return ret;
8206731eb04SVille Syrjälä 
8216731eb04SVille Syrjälä 	/*
8225ac860ccSVille Syrjälä 	 * If SAGV cannot be enabled, disable the pcode SAGV by passing all 1's
8235ac860ccSVille Syrjälä 	 * for qgv peak bw in PM Demand request. So assign UINT_MAX if SAGV is
8245ac860ccSVille Syrjälä 	 * not enabled. PM Demand code will clamp the value for the register
8255ac860ccSVille Syrjälä 	 */
8265ac860ccSVille Syrjälä 	if (!intel_can_enable_sagv(i915, new_bw_state)) {
8275ac860ccSVille Syrjälä 		new_bw_state->qgv_point_peakbw = U16_MAX;
8285ac860ccSVille Syrjälä 		drm_dbg_kms(&i915->drm, "No SAGV, use UINT_MAX as peak bw.");
8295ac860ccSVille Syrjälä 		return 0;
8305ac860ccSVille Syrjälä 	}
8315ac860ccSVille Syrjälä 
8325ac860ccSVille Syrjälä 	/*
8335ac860ccSVille Syrjälä 	 * Find the best QGV point by comparing the data_rate with max data rate
8345ac860ccSVille Syrjälä 	 * offered per plane group
8355ac860ccSVille Syrjälä 	 */
8365ac860ccSVille Syrjälä 	for (i = 0; i < num_qgv_points; i++) {
8375ac860ccSVille Syrjälä 		unsigned int bw_index =
8385ac860ccSVille Syrjälä 			tgl_max_bw_index(i915, num_active_planes, i);
8395ac860ccSVille Syrjälä 		unsigned int max_data_rate;
8405ac860ccSVille Syrjälä 
8415ac860ccSVille Syrjälä 		if (bw_index >= ARRAY_SIZE(i915->display.bw.max))
8425ac860ccSVille Syrjälä 			continue;
8435ac860ccSVille Syrjälä 
8446731eb04SVille Syrjälä 		max_data_rate = i915->display.bw.max[bw_index].deratedbw[i];
8456731eb04SVille Syrjälä 
846cad3fab4SVille Syrjälä 		if (max_data_rate < data_rate)
847cad3fab4SVille Syrjälä 			continue;
848cad3fab4SVille Syrjälä 
849cad3fab4SVille Syrjälä 		if (max_data_rate - data_rate < best_rate) {
850cad3fab4SVille Syrjälä 			best_rate = max_data_rate - data_rate;
851cad3fab4SVille Syrjälä 			qgv_peak_bw = i915->display.bw.max[bw_index].peakbw[i];
852cad3fab4SVille Syrjälä 		}
853cad3fab4SVille Syrjälä 
8545ac860ccSVille Syrjälä 		drm_dbg_kms(&i915->drm, "QGV point %d: max bw %d required %d qgv_peak_bw: %d\n",
855cad3fab4SVille Syrjälä 			    i, max_data_rate, data_rate, qgv_peak_bw);
856cad3fab4SVille Syrjälä 	}
857cad3fab4SVille Syrjälä 
858cad3fab4SVille Syrjälä 	drm_dbg_kms(&i915->drm, "Matching peaks QGV bw: %d for required data rate: %d\n",
859cad3fab4SVille Syrjälä 		    qgv_peak_bw, data_rate);
8605ac860ccSVille Syrjälä 
8615ac860ccSVille Syrjälä 	/*
8625ac860ccSVille Syrjälä 	 * The display configuration cannot be supported if no QGV point
8635ac860ccSVille Syrjälä 	 * satisfying the required data rate is found
8645ac860ccSVille Syrjälä 	 */
8655ac860ccSVille Syrjälä 	if (qgv_peak_bw == 0) {
8665ac860ccSVille Syrjälä 		drm_dbg_kms(&i915->drm, "No QGV points for bw %d for display configuration(%d active planes).\n",
8675ac860ccSVille Syrjälä 			    data_rate, num_active_planes);
8685ac860ccSVille Syrjälä 		return -EINVAL;
8695ac860ccSVille Syrjälä 	}
8705ac860ccSVille Syrjälä 
8715ac860ccSVille Syrjälä 	/* MTL PM DEMAND expects QGV BW parameter in multiples of 100 mbps */
8725ac860ccSVille Syrjälä 	new_bw_state->qgv_point_peakbw = DIV_ROUND_CLOSEST(qgv_peak_bw, 100);
8735ac860ccSVille Syrjälä 
8745ac860ccSVille Syrjälä 	return 0;
8755ac860ccSVille Syrjälä }
8765ac860ccSVille Syrjälä 
icl_find_qgv_points(struct drm_i915_private * i915,unsigned int data_rate,unsigned int num_active_planes,const struct intel_bw_state * old_bw_state,struct intel_bw_state * new_bw_state)8775ac860ccSVille Syrjälä static int icl_find_qgv_points(struct drm_i915_private *i915,
8785ac860ccSVille Syrjälä 			       unsigned int data_rate,
8795ac860ccSVille Syrjälä 			       unsigned int num_active_planes,
8805ac860ccSVille Syrjälä 			       const struct intel_bw_state *old_bw_state,
8815ac860ccSVille Syrjälä 			       struct intel_bw_state *new_bw_state)
8825ac860ccSVille Syrjälä {
8835ac860ccSVille Syrjälä 	unsigned int max_bw_point = 0;
884cad3fab4SVille Syrjälä 	unsigned int max_bw = 0;
885cad3fab4SVille Syrjälä 	unsigned int num_psf_gv_points = i915->display.bw.max[0].num_psf_gv_points;
8865ac860ccSVille Syrjälä 	unsigned int num_qgv_points = i915->display.bw.max[0].num_qgv_points;
8875ac860ccSVille Syrjälä 	u16 psf_points = 0;
8885ac860ccSVille Syrjälä 	u16 qgv_points = 0;
8895ac860ccSVille Syrjälä 	int i;
8905ac860ccSVille Syrjälä 	int ret;
8915ac860ccSVille Syrjälä 
8925ac860ccSVille Syrjälä 	ret = intel_atomic_lock_global_state(&new_bw_state->base);
8935ac860ccSVille Syrjälä 	if (ret)
8945ac860ccSVille Syrjälä 		return ret;
8955ac860ccSVille Syrjälä 
8965ac860ccSVille Syrjälä 	for (i = 0; i < num_qgv_points; i++) {
8975ac860ccSVille Syrjälä 		unsigned int idx;
8985ac860ccSVille Syrjälä 		unsigned int max_data_rate;
8995ac860ccSVille Syrjälä 
9005ac860ccSVille Syrjälä 		if (DISPLAY_VER(i915) > 11)
9015ac860ccSVille Syrjälä 			idx = tgl_max_bw_index(i915, num_active_planes, i);
9025ac860ccSVille Syrjälä 		else
9035ac860ccSVille Syrjälä 			idx = icl_max_bw_index(i915, num_active_planes, i);
904943ed3ccSVille Syrjälä 
905cad3fab4SVille Syrjälä 		if (idx >= ARRAY_SIZE(i915->display.bw.max))
9065ac860ccSVille Syrjälä 			continue;
907cad3fab4SVille Syrjälä 
908cad3fab4SVille Syrjälä 		max_data_rate = i915->display.bw.max[idx].deratedbw[i];
9095ac860ccSVille Syrjälä 
9105ac860ccSVille Syrjälä 		/*
9115ac860ccSVille Syrjälä 		 * We need to know which qgv point gives us
912ea083969SVille Syrjälä 		 * maximum bandwidth in order to disable SAGV
913ea083969SVille Syrjälä 		 * if we find that we exceed SAGV block time
914ea083969SVille Syrjälä 		 * with watermarks. By that moment we already
915ea083969SVille Syrjälä 		 * have those, as it is calculated earlier in
916ea083969SVille Syrjälä 		 * intel_atomic_check,
917ea083969SVille Syrjälä 		 */
918ea083969SVille Syrjälä 		if (max_data_rate > max_bw) {
919ea083969SVille Syrjälä 			max_bw_point = i;
920ea083969SVille Syrjälä 			max_bw = max_data_rate;
9215ac860ccSVille Syrjälä 		}
9225ac860ccSVille Syrjälä 		if (max_data_rate >= data_rate)
9235ac860ccSVille Syrjälä 			qgv_points |= BIT(i);
9245ac860ccSVille Syrjälä 
925cd191546SStanislav Lisovskiy 		drm_dbg_kms(&i915->drm, "QGV point %d: max bw %d required %d\n",
926cd191546SStanislav Lisovskiy 			    i, max_data_rate, data_rate);
927cac91e67SStanislav Lisovskiy 	}
9285ac860ccSVille Syrjälä 
9295ac860ccSVille Syrjälä 	for (i = 0; i < num_psf_gv_points; i++) {
930cd191546SStanislav Lisovskiy 		unsigned int max_data_rate = adl_psf_bw(i915, i);
9315ac860ccSVille Syrjälä 
932cd191546SStanislav Lisovskiy 		if (max_data_rate >= data_rate)
933cac91e67SStanislav Lisovskiy 			psf_points |= BIT(i);
934cd191546SStanislav Lisovskiy 
9357243867cSVille Syrjälä 		drm_dbg_kms(&i915->drm, "PSF GV point %d: max bw %d"
9367243867cSVille Syrjälä 			    " required %d\n",
9377243867cSVille Syrjälä 			    i, max_data_rate, data_rate);
938cd191546SStanislav Lisovskiy 	}
939cd191546SStanislav Lisovskiy 
940cd191546SStanislav Lisovskiy 	/*
941cd191546SStanislav Lisovskiy 	 * BSpec states that we always should have at least one allowed point
942cd191546SStanislav Lisovskiy 	 * left, so if we couldn't - simply reject the configuration for obvious
94319aefbc7SStanislav Lisovskiy 	 * reasons.
94419aefbc7SStanislav Lisovskiy 	 */
945cad3fab4SVille Syrjälä 	if (qgv_points == 0) {
946ea083969SVille Syrjälä 		drm_dbg_kms(&i915->drm, "No QGV points provide sufficient memory"
947ea083969SVille Syrjälä 			    " bandwidth %d for display configuration(%d active planes).\n",
948ea083969SVille Syrjälä 			    data_rate, num_active_planes);
94919aefbc7SStanislav Lisovskiy 		return -EINVAL;
95019aefbc7SStanislav Lisovskiy 	}
95119aefbc7SStanislav Lisovskiy 
95219aefbc7SStanislav Lisovskiy 	if (num_psf_gv_points > 0 && psf_points == 0) {
95319aefbc7SStanislav Lisovskiy 		drm_dbg_kms(&i915->drm, "No PSF GV points provide sufficient memory"
9546731eb04SVille Syrjälä 			    " bandwidth %d for display configuration(%d active planes).\n",
955cd191546SStanislav Lisovskiy 			    data_rate, num_active_planes);
956cd191546SStanislav Lisovskiy 		return -EINVAL;
957cd191546SStanislav Lisovskiy 	}
958cd191546SStanislav Lisovskiy 
959cd191546SStanislav Lisovskiy 	/*
9605ac860ccSVille Syrjälä 	 * Leave only single point with highest bandwidth, if
9615ac860ccSVille Syrjälä 	 * we can't enable SAGV due to the increased memory latency it may
9625ac860ccSVille Syrjälä 	 * cause.
9635ac860ccSVille Syrjälä 	 */
9645ac860ccSVille Syrjälä 	if (!intel_can_enable_sagv(i915, new_bw_state)) {
965ea083969SVille Syrjälä 		qgv_points = BIT(max_bw_point);
9665ac860ccSVille Syrjälä 		drm_dbg_kms(&i915->drm, "No SAGV, using single QGV point %d\n",
967ea083969SVille Syrjälä 			    max_bw_point);
9685ac860ccSVille Syrjälä 	}
9695ac860ccSVille Syrjälä 
9705ac860ccSVille Syrjälä 	/*
9715ac860ccSVille Syrjälä 	 * We store the ones which need to be masked as that is what PCode
9725ac860ccSVille Syrjälä 	 * actually accepts as a parameter.
9735ac860ccSVille Syrjälä 	 */
9745ac860ccSVille Syrjälä 	new_bw_state->qgv_points_mask =
9755ac860ccSVille Syrjälä 		~(ICL_PCODE_REQ_QGV_PT(qgv_points) |
9765ac860ccSVille Syrjälä 		  ADLS_PCODE_REQ_PSF_PT(psf_points)) &
9775ac860ccSVille Syrjälä 		icl_qgv_points_mask(i915);
9785ac860ccSVille Syrjälä 
9795ac860ccSVille Syrjälä 	/*
980ea083969SVille Syrjälä 	 * If the actual mask had changed we need to make sure that
9815ac860ccSVille Syrjälä 	 * the commits are serialized(in case this is a nomodeset, nonblocking)
982ea083969SVille Syrjälä 	 */
9835ac860ccSVille Syrjälä 	if (new_bw_state->qgv_points_mask != old_bw_state->qgv_points_mask) {
9845ac860ccSVille Syrjälä 		ret = intel_atomic_serialize_global_state(&new_bw_state->base);
9855ac860ccSVille Syrjälä 		if (ret)
9865ac860ccSVille Syrjälä 			return ret;
9875ac860ccSVille Syrjälä 	}
9885ac860ccSVille Syrjälä 
9895ac860ccSVille Syrjälä 	return 0;
9905ac860ccSVille Syrjälä }
9915ac860ccSVille Syrjälä 
intel_bw_check_qgv_points(struct drm_i915_private * i915,const struct intel_bw_state * old_bw_state,struct intel_bw_state * new_bw_state)9925ac860ccSVille Syrjälä static int intel_bw_check_qgv_points(struct drm_i915_private *i915,
9935ac860ccSVille Syrjälä 				     const struct intel_bw_state *old_bw_state,
994cd191546SStanislav Lisovskiy 				     struct intel_bw_state *new_bw_state)
995cd191546SStanislav Lisovskiy {
996cd191546SStanislav Lisovskiy 	unsigned int data_rate = intel_bw_data_rate(i915, new_bw_state);
9976d8ebef5SVille Syrjälä 	unsigned int num_active_planes =
998df0566a6SJani Nikula 			intel_bw_num_active_planes(i915, new_bw_state);
9996d8ebef5SVille Syrjälä 
10006d8ebef5SVille Syrjälä 	data_rate = DIV_ROUND_UP(data_rate, 1000);
1001df0566a6SJani Nikula 
10026d8ebef5SVille Syrjälä 	if (DISPLAY_VER(i915) >= 14)
1003df0566a6SJani Nikula 		return mtl_find_qgv_points(i915, data_rate, num_active_planes,
1004df0566a6SJani Nikula 					   new_bw_state);
1005df0566a6SJani Nikula 	else
1006df0566a6SJani Nikula 		return icl_find_qgv_points(i915, data_rate, num_active_planes,
1007df0566a6SJani Nikula 					   old_bw_state, new_bw_state);
1008df0566a6SJani Nikula }
1009df0566a6SJani Nikula 
intel_bw_state_changed(struct drm_i915_private * i915,const struct intel_bw_state * old_bw_state,const struct intel_bw_state * new_bw_state)1010df0566a6SJani Nikula static bool intel_bw_state_changed(struct drm_i915_private *i915,
1011df0566a6SJani Nikula 				   const struct intel_bw_state *old_bw_state,
1012df0566a6SJani Nikula 				   const struct intel_bw_state *new_bw_state)
1013df0566a6SJani Nikula {
10146d8ebef5SVille Syrjälä 	enum pipe pipe;
1015df0566a6SJani Nikula 
1016df0566a6SJani Nikula 	for_each_pipe(i915, pipe) {
1017df0566a6SJani Nikula 		const struct intel_dbuf_bw *old_crtc_bw =
1018df0566a6SJani Nikula 			&old_bw_state->dbuf_bw[pipe];
1019df0566a6SJani Nikula 		const struct intel_dbuf_bw *new_crtc_bw =
1020df0566a6SJani Nikula 			&new_bw_state->dbuf_bw[pipe];
1021df0566a6SJani Nikula 		enum dbuf_slice slice;
1022df0566a6SJani Nikula 
1023df0566a6SJani Nikula 		for_each_dbuf_slice(i915, slice) {
10249ff79708SStanislav Lisovskiy 			if (old_crtc_bw->max_bw[slice] != new_crtc_bw->max_bw[slice] ||
10259ff79708SStanislav Lisovskiy 			    old_crtc_bw->active_planes[slice] != new_crtc_bw->active_planes[slice])
10269ff79708SStanislav Lisovskiy 				return true;
1027df0566a6SJani Nikula 		}
10289ff79708SStanislav Lisovskiy 
10299ff79708SStanislav Lisovskiy 		if (old_bw_state->min_cdclk[pipe] != new_bw_state->min_cdclk[pipe])
1030df0566a6SJani Nikula 			return true;
10316d8ebef5SVille Syrjälä 	}
10326b728595SVille Syrjälä 
10336d8ebef5SVille Syrjälä 	return false;
10346d8ebef5SVille Syrjälä }
10356d8ebef5SVille Syrjälä 
skl_plane_calc_dbuf_bw(struct intel_bw_state * bw_state,struct intel_crtc * crtc,enum plane_id plane_id,const struct skl_ddb_entry * ddb,unsigned int data_rate)10369ff79708SStanislav Lisovskiy static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state,
10379ff79708SStanislav Lisovskiy 				   struct intel_crtc *crtc,
1038df0566a6SJani Nikula 				   enum plane_id plane_id,
1039df0566a6SJani Nikula 				   const struct skl_ddb_entry *ddb,
10406d8ebef5SVille Syrjälä 				   unsigned int data_rate)
10416d8ebef5SVille Syrjälä {
10426d8ebef5SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
10436d8ebef5SVille Syrjälä 	struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe];
10446d8ebef5SVille Syrjälä 	unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(i915, ddb);
10456d8ebef5SVille Syrjälä 	enum dbuf_slice slice;
10466d8ebef5SVille Syrjälä 
10476d8ebef5SVille Syrjälä 	/*
10486d8ebef5SVille Syrjälä 	 * The arbiter can only really guarantee an
10496d8ebef5SVille Syrjälä 	 * equal share of the total bw to each plane.
10506d8ebef5SVille Syrjälä 	 */
1051f8a1cb3fSVille Syrjälä 	for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask) {
10526d8ebef5SVille Syrjälä 		crtc_bw->max_bw[slice] = max(crtc_bw->max_bw[slice], data_rate);
1053f0acaf9dSJani Nikula 		crtc_bw->active_planes[slice] |= BIT(plane_id);
1054f0acaf9dSJani Nikula 	}
10556d8ebef5SVille Syrjälä }
10566d8ebef5SVille Syrjälä 
skl_crtc_calc_dbuf_bw(struct intel_bw_state * bw_state,const struct intel_crtc_state * crtc_state)10576d8ebef5SVille Syrjälä static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state,
10586d8ebef5SVille Syrjälä 				  const struct intel_crtc_state *crtc_state)
10596d8ebef5SVille Syrjälä {
10606d8ebef5SVille Syrjälä 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
10616d8ebef5SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(crtc->base.dev);
10626d8ebef5SVille Syrjälä 	struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe];
10636d8ebef5SVille Syrjälä 	enum plane_id plane_id;
10646d8ebef5SVille Syrjälä 
10656b728595SVille Syrjälä 	memset(crtc_bw, 0, sizeof(*crtc_bw));
10666b728595SVille Syrjälä 
10676b728595SVille Syrjälä 	if (!crtc_state->hw.active)
10686b728595SVille Syrjälä 		return;
10696b728595SVille Syrjälä 
10706b728595SVille Syrjälä 	for_each_plane_id_on_crtc(crtc, plane_id) {
10716b728595SVille Syrjälä 		/*
10726b728595SVille Syrjälä 		 * We assume cursors are small enough
10736b728595SVille Syrjälä 		 * to not cause bandwidth problems.
10746b728595SVille Syrjälä 		 */
10756b728595SVille Syrjälä 		if (plane_id == PLANE_CURSOR)
10766b728595SVille Syrjälä 			continue;
10776b728595SVille Syrjälä 
1078df0566a6SJani Nikula 		skl_plane_calc_dbuf_bw(bw_state, crtc, plane_id,
1079df0566a6SJani Nikula 				       &crtc_state->wm.skl.plane_ddb[plane_id],
10809ff79708SStanislav Lisovskiy 				       crtc_state->data_rate[plane_id]);
1081fd1a9bbaSVille Syrjälä 
1082fd1a9bbaSVille Syrjälä 		if (DISPLAY_VER(i915) < 11)
1083fd1a9bbaSVille Syrjälä 			skl_plane_calc_dbuf_bw(bw_state, crtc, plane_id,
10849ff79708SStanislav Lisovskiy 					       &crtc_state->wm.skl.plane_ddb_y[plane_id],
1085df0566a6SJani Nikula 					       crtc_state->data_rate[plane_id]);
1086df0566a6SJani Nikula 	}
108720f505f2SStanislav Lisovskiy }
108820f505f2SStanislav Lisovskiy 
108920f505f2SStanislav Lisovskiy /* "Maximum Data Buffer Bandwidth" */
109020f505f2SStanislav Lisovskiy static int
intel_bw_dbuf_min_cdclk(struct drm_i915_private * i915,const struct intel_bw_state * bw_state)109120f505f2SStanislav Lisovskiy intel_bw_dbuf_min_cdclk(struct drm_i915_private *i915,
1092c64a9a7cSRadhakrishna Sripada 			const struct intel_bw_state *bw_state)
1093c64a9a7cSRadhakrishna Sripada {
1094c64a9a7cSRadhakrishna Sripada 	unsigned int total_max_bw = 0;
109520f505f2SStanislav Lisovskiy 	enum dbuf_slice slice;
109620f505f2SStanislav Lisovskiy 
109720f505f2SStanislav Lisovskiy 	for_each_dbuf_slice(i915, slice) {
109820f505f2SStanislav Lisovskiy 		int num_active_planes = 0;
109920f505f2SStanislav Lisovskiy 		unsigned int max_bw = 0;
110020f505f2SStanislav Lisovskiy 		enum pipe pipe;
110120f505f2SStanislav Lisovskiy 
110220f505f2SStanislav Lisovskiy 		/*
110320f505f2SStanislav Lisovskiy 		 * The arbiter can only really guarantee an
110420f505f2SStanislav Lisovskiy 		 * equal share of the total bw to each plane.
110520f505f2SStanislav Lisovskiy 		 */
110620f505f2SStanislav Lisovskiy 		for_each_pipe(i915, pipe) {
110720f505f2SStanislav Lisovskiy 			const struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[pipe];
110820f505f2SStanislav Lisovskiy 
1109f8a1cb3fSVille Syrjälä 			max_bw = max(crtc_bw->max_bw[slice], max_bw);
1110192fbfb7SStanislav Lisovskiy 			num_active_planes += hweight8(crtc_bw->active_planes[slice]);
111120f505f2SStanislav Lisovskiy 		}
111220f505f2SStanislav Lisovskiy 		max_bw *= num_active_planes;
111320f505f2SStanislav Lisovskiy 
111420f505f2SStanislav Lisovskiy 		total_max_bw = max(total_max_bw, max_bw);
1115192fbfb7SStanislav Lisovskiy 	}
1116192fbfb7SStanislav Lisovskiy 
1117192fbfb7SStanislav Lisovskiy 	return DIV_ROUND_UP(total_max_bw, 64);
1118192fbfb7SStanislav Lisovskiy }
1119f8a1cb3fSVille Syrjälä 
intel_bw_min_cdclk(struct drm_i915_private * i915,const struct intel_bw_state * bw_state)1120192fbfb7SStanislav Lisovskiy int intel_bw_min_cdclk(struct drm_i915_private *i915,
1121192fbfb7SStanislav Lisovskiy 		       const struct intel_bw_state *bw_state)
1122192fbfb7SStanislav Lisovskiy {
1123192fbfb7SStanislav Lisovskiy 	enum pipe pipe;
1124192fbfb7SStanislav Lisovskiy 	int min_cdclk;
1125192fbfb7SStanislav Lisovskiy 
112620f505f2SStanislav Lisovskiy 	min_cdclk = intel_bw_dbuf_min_cdclk(i915, bw_state);
112720f505f2SStanislav Lisovskiy 
112820f505f2SStanislav Lisovskiy 	for_each_pipe(i915, pipe)
112920f505f2SStanislav Lisovskiy 		min_cdclk = max(bw_state->min_cdclk[pipe], min_cdclk);
113020f505f2SStanislav Lisovskiy 
1131f8a1cb3fSVille Syrjälä 	return min_cdclk;
113220f505f2SStanislav Lisovskiy }
113320f505f2SStanislav Lisovskiy 
intel_bw_calc_min_cdclk(struct intel_atomic_state * state,bool * need_cdclk_calc)113420f505f2SStanislav Lisovskiy int intel_bw_calc_min_cdclk(struct intel_atomic_state *state,
1135df0566a6SJani Nikula 			    bool *need_cdclk_calc)
1136df0566a6SJani Nikula {
1137df0566a6SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
1138f8a1cb3fSVille Syrjälä 	struct intel_bw_state *new_bw_state = NULL;
1139192fbfb7SStanislav Lisovskiy 	const struct intel_bw_state *old_bw_state = NULL;
1140192fbfb7SStanislav Lisovskiy 	const struct intel_cdclk_state *cdclk_state;
1141192fbfb7SStanislav Lisovskiy 	const struct intel_crtc_state *crtc_state;
1142192fbfb7SStanislav Lisovskiy 	int old_min_cdclk, new_min_cdclk;
1143192fbfb7SStanislav Lisovskiy 	struct intel_crtc *crtc;
1144192fbfb7SStanislav Lisovskiy 	int i;
114520f505f2SStanislav Lisovskiy 
114620f505f2SStanislav Lisovskiy 	if (DISPLAY_VER(dev_priv) < 9)
114720f505f2SStanislav Lisovskiy 		return 0;
114820f505f2SStanislav Lisovskiy 
114920f505f2SStanislav Lisovskiy 	for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
115020f505f2SStanislav Lisovskiy 		new_bw_state = intel_atomic_get_bw_state(state);
1151f8a1cb3fSVille Syrjälä 		if (IS_ERR(new_bw_state))
115220f505f2SStanislav Lisovskiy 			return PTR_ERR(new_bw_state);
115320f505f2SStanislav Lisovskiy 
115420f505f2SStanislav Lisovskiy 		old_bw_state = intel_atomic_get_old_bw_state(state);
1155f8a1cb3fSVille Syrjälä 
115620f505f2SStanislav Lisovskiy 		skl_crtc_calc_dbuf_bw(new_bw_state, crtc_state);
115720f505f2SStanislav Lisovskiy 
115820f505f2SStanislav Lisovskiy 		new_bw_state->min_cdclk[crtc->pipe] =
115920f505f2SStanislav Lisovskiy 			intel_bw_crtc_min_cdclk(crtc_state);
1160f8a1cb3fSVille Syrjälä 	}
11614bdba4f4SVille Syrjälä 
11624bdba4f4SVille Syrjälä 	if (!old_bw_state)
1163d5b8da37SVille Syrjälä 		return 0;
116420f505f2SStanislav Lisovskiy 
116520f505f2SStanislav Lisovskiy 	if (intel_bw_state_changed(dev_priv, old_bw_state, new_bw_state)) {
116620f505f2SStanislav Lisovskiy 		int ret = intel_atomic_lock_global_state(&new_bw_state->base);
116720f505f2SStanislav Lisovskiy 		if (ret)
116820f505f2SStanislav Lisovskiy 			return ret;
116920f505f2SStanislav Lisovskiy 	}
117020f505f2SStanislav Lisovskiy 
117120f505f2SStanislav Lisovskiy 	old_min_cdclk = intel_bw_min_cdclk(dev_priv, old_bw_state);
117220f505f2SStanislav Lisovskiy 	new_min_cdclk = intel_bw_min_cdclk(dev_priv, new_bw_state);
117320f505f2SStanislav Lisovskiy 
117420f505f2SStanislav Lisovskiy 	/*
1175df0566a6SJani Nikula 	 * No need to check against the cdclk state if
1176df0566a6SJani Nikula 	 * the min cdclk doesn't increase.
1177df0566a6SJani Nikula 	 *
1178fd1a9bbaSVille Syrjälä 	 * Ie. we only ever increase the cdclk due to bandwidth
1179fd1a9bbaSVille Syrjälä 	 * requirements. This can reduce back and forth
1180df0566a6SJani Nikula 	 * display blinking due to constant cdclk changes.
1181df0566a6SJani Nikula 	 */
1182df0566a6SJani Nikula 	if (new_min_cdclk <= old_min_cdclk)
1183df0566a6SJani Nikula 		return 0;
1184df0566a6SJani Nikula 
1185df0566a6SJani Nikula 	cdclk_state = intel_atomic_get_cdclk_state(state);
1186df0566a6SJani Nikula 	if (IS_ERR(cdclk_state))
1187df0566a6SJani Nikula 		return PTR_ERR(cdclk_state);
1188df0566a6SJani Nikula 
1189df0566a6SJani Nikula 	/*
1190fd1a9bbaSVille Syrjälä 	 * No need to recalculate the cdclk state if
1191fd1a9bbaSVille Syrjälä 	 * the min cdclk doesn't increase.
1192df0566a6SJani Nikula 	 *
1193df0566a6SJani Nikula 	 * Ie. we only ever increase the cdclk due to bandwidth
1194df0566a6SJani Nikula 	 * requirements. This can reduce back and forth
1195df0566a6SJani Nikula 	 * display blinking due to constant cdclk changes.
1196fd1a9bbaSVille Syrjälä 	 */
1197df0566a6SJani Nikula 	if (new_min_cdclk <= cdclk_state->bw_min_cdclk)
1198df0566a6SJani Nikula 		return 0;
1199df0566a6SJani Nikula 
1200df0566a6SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
1201df0566a6SJani Nikula 		    "new bandwidth min cdclk (%d kHz) > old min cdclk (%d kHz)\n",
1202df0566a6SJani Nikula 		    new_min_cdclk, cdclk_state->bw_min_cdclk);
1203df0566a6SJani Nikula 	*need_cdclk_calc = true;
1204df0566a6SJani Nikula 
1205df0566a6SJani Nikula 	return 0;
1206df0566a6SJani Nikula }
1207df0566a6SJani Nikula 
intel_bw_check_data_rate(struct intel_atomic_state * state,bool * changed)1208df0566a6SJani Nikula static int intel_bw_check_data_rate(struct intel_atomic_state *state, bool *changed)
1209f0acaf9dSJani Nikula {
1210df0566a6SJani Nikula 	struct drm_i915_private *i915 = to_i915(state->base.dev);
1211df0566a6SJani Nikula 	const struct intel_crtc_state *new_crtc_state, *old_crtc_state;
1212df0566a6SJani Nikula 	struct intel_crtc *crtc;
1213df0566a6SJani Nikula 	int i;
1214 
1215 	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
1216 					    new_crtc_state, i) {
1217 		unsigned int old_data_rate =
1218 			intel_bw_crtc_data_rate(old_crtc_state);
1219 		unsigned int new_data_rate =
1220 			intel_bw_crtc_data_rate(new_crtc_state);
1221 		unsigned int old_active_planes =
1222 			intel_bw_crtc_num_active_planes(old_crtc_state);
1223 		unsigned int new_active_planes =
1224 			intel_bw_crtc_num_active_planes(new_crtc_state);
1225 		struct intel_bw_state *new_bw_state;
1226 
1227 		/*
1228 		 * Avoid locking the bw state when
1229 		 * nothing significant has changed.
1230 		 */
1231 		if (old_data_rate == new_data_rate &&
1232 		    old_active_planes == new_active_planes)
1233 			continue;
1234 
1235 		new_bw_state = intel_atomic_get_bw_state(state);
1236 		if (IS_ERR(new_bw_state))
1237 			return PTR_ERR(new_bw_state);
1238 
1239 		new_bw_state->data_rate[crtc->pipe] = new_data_rate;
1240 		new_bw_state->num_active_planes[crtc->pipe] = new_active_planes;
1241 
1242 		*changed = true;
1243 
1244 		drm_dbg_kms(&i915->drm,
1245 			    "[CRTC:%d:%s] data rate %u num active planes %u\n",
1246 			    crtc->base.base.id, crtc->base.name,
1247 			    new_bw_state->data_rate[crtc->pipe],
1248 			    new_bw_state->num_active_planes[crtc->pipe]);
1249 	}
1250 
1251 	return 0;
1252 }
1253 
intel_bw_atomic_check(struct intel_atomic_state * state)1254 int intel_bw_atomic_check(struct intel_atomic_state *state)
1255 {
1256 	bool changed = false;
1257 	struct drm_i915_private *i915 = to_i915(state->base.dev);
1258 	struct intel_bw_state *new_bw_state;
1259 	const struct intel_bw_state *old_bw_state;
1260 	int ret;
1261 
1262 	/* FIXME earlier gens need some checks too */
1263 	if (DISPLAY_VER(i915) < 11)
1264 		return 0;
1265 
1266 	ret = intel_bw_check_data_rate(state, &changed);
1267 	if (ret)
1268 		return ret;
1269 
1270 	old_bw_state = intel_atomic_get_old_bw_state(state);
1271 	new_bw_state = intel_atomic_get_new_bw_state(state);
1272 
1273 	if (new_bw_state &&
1274 	    intel_can_enable_sagv(i915, old_bw_state) !=
1275 	    intel_can_enable_sagv(i915, new_bw_state))
1276 		changed = true;
1277 
1278 	/*
1279 	 * If none of our inputs (data rates, number of active
1280 	 * planes, SAGV yes/no) changed then nothing to do here.
1281 	 */
1282 	if (!changed)
1283 		return 0;
1284 
1285 	ret = intel_bw_check_qgv_points(i915, old_bw_state, new_bw_state);
1286 	if (ret)
1287 		return ret;
1288 
1289 	return 0;
1290 }
1291 
1292 static struct intel_global_state *
intel_bw_duplicate_state(struct intel_global_obj * obj)1293 intel_bw_duplicate_state(struct intel_global_obj *obj)
1294 {
1295 	struct intel_bw_state *state;
1296 
1297 	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
1298 	if (!state)
1299 		return NULL;
1300 
1301 	return &state->base;
1302 }
1303 
intel_bw_destroy_state(struct intel_global_obj * obj,struct intel_global_state * state)1304 static void intel_bw_destroy_state(struct intel_global_obj *obj,
1305 				   struct intel_global_state *state)
1306 {
1307 	kfree(state);
1308 }
1309 
1310 static const struct intel_global_state_funcs intel_bw_funcs = {
1311 	.atomic_duplicate_state = intel_bw_duplicate_state,
1312 	.atomic_destroy_state = intel_bw_destroy_state,
1313 };
1314 
intel_bw_init(struct drm_i915_private * dev_priv)1315 int intel_bw_init(struct drm_i915_private *dev_priv)
1316 {
1317 	struct intel_bw_state *state;
1318 
1319 	state = kzalloc(sizeof(*state), GFP_KERNEL);
1320 	if (!state)
1321 		return -ENOMEM;
1322 
1323 	intel_atomic_global_obj_init(dev_priv, &dev_priv->display.bw.obj,
1324 				     &state->base, &intel_bw_funcs);
1325 
1326 	return 0;
1327 }
1328