Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915/fbc: handle dirty rect coords for the first frame

During enabling FBC, for the very first frame, the prepare dirty
rect routine wouldnt have executed as at that time the plane
reference in the fbc_state would be NULL. So this could make
driver program some invalid entries as the damage area. Though
fbc hw ignores the dirty rect values programmed for the first
frame after enabling FBC, driver must ensure that valid dirty
rect coords are programmed. So ensure that for the first frame
correct dirty rect coords are updated to the HW.

Signed-off-by: Vinod Govindapillai <vinod.govindapillai@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Mika Kahola <mika.kahola@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250228093802.27091-10-vinod.govindapillai@intel.com

authored by

Vinod Govindapillai and committed by
Mika Kahola
af23476a e2364a56

+99 -44
+2 -1
drivers/gpu/drm/i915/display/intel_display.c
··· 7272 7272 7273 7273 intel_atomic_prepare_plane_clear_colors(state); 7274 7274 7275 - intel_fbc_prepare_dirty_rect(state); 7275 + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) 7276 + intel_fbc_prepare_dirty_rect(state, crtc); 7276 7277 7277 7278 for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) 7278 7279 intel_atomic_dsb_finish(state, crtc);
+95 -42
drivers/gpu/drm/i915/display/intel_fbc.c
··· 1205 1205 } 1206 1206 1207 1207 static void 1208 - intel_fbc_dirty_rect_update(struct intel_dsb *dsb, struct intel_fbc *fbc) 1208 + intel_fbc_invalidate_dirty_rect(struct intel_fbc *fbc) 1209 + { 1210 + lockdep_assert_held(&fbc->lock); 1211 + 1212 + fbc->state.dirty_rect = DRM_RECT_INIT(0, 0, 0, 0); 1213 + } 1214 + 1215 + static void 1216 + intel_fbc_program_dirty_rect(struct intel_dsb *dsb, struct intel_fbc *fbc, 1217 + const struct drm_rect *fbc_dirty_rect) 1209 1218 { 1210 1219 struct intel_display *display = fbc->display; 1211 - const struct drm_rect *fbc_dirty_rect = &fbc->state.dirty_rect; 1212 1220 1213 - lockdep_assert_held(&fbc->lock); 1221 + drm_WARN_ON(display->drm, fbc_dirty_rect->y2 == 0); 1214 1222 1215 1223 intel_de_write_dsb(display, dsb, XE3_FBC_DIRTY_RECT(fbc->id), 1216 1224 FBC_DIRTY_RECT_START_LINE(fbc_dirty_rect->y1) | 1217 1225 FBC_DIRTY_RECT_END_LINE(fbc_dirty_rect->y2 - 1)); 1226 + } 1227 + 1228 + static void 1229 + intel_fbc_dirty_rect_update(struct intel_dsb *dsb, struct intel_fbc *fbc) 1230 + { 1231 + const struct drm_rect *fbc_dirty_rect = &fbc->state.dirty_rect; 1232 + 1233 + lockdep_assert_held(&fbc->lock); 1234 + 1235 + if (!drm_rect_visible(fbc_dirty_rect)) 1236 + return; 1237 + 1238 + intel_fbc_program_dirty_rect(dsb, fbc, fbc_dirty_rect); 1218 1239 } 1219 1240 1220 1241 void ··· 1257 1236 } 1258 1237 1259 1238 static void 1260 - __intel_fbc_prepare_dirty_rect(const struct intel_plane_state *plane_state) 1239 + intel_fbc_hw_intialize_dirty_rect(struct intel_fbc *fbc, 1240 + const struct intel_plane_state *plane_state) 1261 1241 { 1262 - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 1263 - struct intel_fbc *fbc = plane->fbc; 1264 - struct drm_rect *fbc_dirty_rect = &fbc->state.dirty_rect; 1265 - int width = drm_rect_width(&plane_state->uapi.src) >> 16; 1266 - const struct drm_rect *damage = &plane_state->damage; 1267 - int y_offset = plane_state->view.color_plane[0].y; 1242 + struct drm_rect src; 1268 1243 1269 - lockdep_assert_held(&fbc->lock); 1244 + /* 1245 + * Initializing the FBC HW with the whole plane area as the dirty rect. 1246 + * This is to ensure that we have valid coords be written to the 1247 + * HW as dirty rect. 1248 + */ 1249 + drm_rect_fp_to_int(&src, &plane_state->uapi.src); 1270 1250 1271 - if (drm_rect_visible(damage)) 1272 - *fbc_dirty_rect = *damage; 1273 - else 1274 - /* dirty rect must cover at least one line */ 1275 - *fbc_dirty_rect = DRM_RECT_INIT(0, y_offset, width, 1); 1276 - } 1277 - 1278 - void 1279 - intel_fbc_prepare_dirty_rect(struct intel_atomic_state *state) 1280 - { 1281 - struct intel_display *display = to_intel_display(state); 1282 - struct intel_plane_state *plane_state; 1283 - struct intel_plane *plane; 1284 - int i; 1285 - 1286 - if (!HAS_FBC_DIRTY_RECT(display)) 1287 - return; 1288 - 1289 - for_each_new_intel_plane_in_state(state, plane, plane_state, i) { 1290 - struct intel_fbc *fbc = plane->fbc; 1291 - 1292 - if (!fbc) 1293 - continue; 1294 - 1295 - mutex_lock(&fbc->lock); 1296 - 1297 - if (fbc->state.plane == plane) 1298 - __intel_fbc_prepare_dirty_rect(plane_state); 1299 - 1300 - mutex_unlock(&fbc->lock); 1301 - } 1251 + intel_fbc_program_dirty_rect(NULL, fbc, &src); 1302 1252 } 1303 1253 1304 1254 static void intel_fbc_update_state(struct intel_atomic_state *state, ··· 1343 1351 return !plane_state->no_fbc_reason && 1344 1352 intel_fbc_is_fence_ok(plane_state) && 1345 1353 intel_fbc_is_cfb_ok(plane_state); 1354 + } 1355 + 1356 + static void 1357 + __intel_fbc_prepare_dirty_rect(const struct intel_plane_state *plane_state, 1358 + const struct intel_crtc_state *crtc_state) 1359 + { 1360 + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 1361 + struct intel_fbc *fbc = plane->fbc; 1362 + struct drm_rect *fbc_dirty_rect = &fbc->state.dirty_rect; 1363 + int width = drm_rect_width(&plane_state->uapi.src) >> 16; 1364 + const struct drm_rect *damage = &plane_state->damage; 1365 + int y_offset = plane_state->view.color_plane[0].y; 1366 + 1367 + lockdep_assert_held(&fbc->lock); 1368 + 1369 + if (intel_crtc_needs_modeset(crtc_state) || 1370 + !intel_fbc_is_ok(plane_state)) { 1371 + intel_fbc_invalidate_dirty_rect(fbc); 1372 + return; 1373 + } 1374 + 1375 + if (drm_rect_visible(damage)) 1376 + *fbc_dirty_rect = *damage; 1377 + else 1378 + /* dirty rect must cover at least one line */ 1379 + *fbc_dirty_rect = DRM_RECT_INIT(0, y_offset, width, 1); 1380 + } 1381 + 1382 + void 1383 + intel_fbc_prepare_dirty_rect(struct intel_atomic_state *state, 1384 + struct intel_crtc *crtc) 1385 + { 1386 + struct intel_display *display = to_intel_display(state); 1387 + const struct intel_crtc_state *crtc_state = 1388 + intel_atomic_get_new_crtc_state(state, crtc); 1389 + struct intel_plane_state *plane_state; 1390 + struct intel_plane *plane; 1391 + int i; 1392 + 1393 + if (!HAS_FBC_DIRTY_RECT(display)) 1394 + return; 1395 + 1396 + for_each_new_intel_plane_in_state(state, plane, plane_state, i) { 1397 + struct intel_fbc *fbc = plane->fbc; 1398 + 1399 + if (!fbc || plane->pipe != crtc->pipe) 1400 + continue; 1401 + 1402 + mutex_lock(&fbc->lock); 1403 + 1404 + if (fbc->state.plane == plane) 1405 + __intel_fbc_prepare_dirty_rect(plane_state, 1406 + crtc_state); 1407 + 1408 + mutex_unlock(&fbc->lock); 1409 + } 1346 1410 } 1347 1411 1348 1412 static int intel_fbc_check_plane(struct intel_atomic_state *state, ··· 1677 1629 drm_dbg_kms(display->drm, "Disabling FBC on [PLANE:%d:%s]\n", 1678 1630 plane->base.base.id, plane->base.name); 1679 1631 1632 + intel_fbc_invalidate_dirty_rect(fbc); 1633 + 1680 1634 __intel_fbc_cleanup_cfb(fbc); 1681 1635 1682 1636 fbc->state.plane = NULL; ··· 1863 1813 fbc->no_fbc_reason = "FBC enabled but not active yet\n"; 1864 1814 1865 1815 intel_fbc_update_state(state, crtc, plane); 1816 + 1817 + if (HAS_FBC_DIRTY_RECT(display)) 1818 + intel_fbc_hw_intialize_dirty_rect(fbc, plane_state); 1866 1819 1867 1820 intel_fbc_program_workarounds(fbc); 1868 1821 intel_fbc_program_cfb(fbc);
+2 -1
drivers/gpu/drm/i915/display/intel_fbc.h
··· 48 48 void intel_fbc_reset_underrun(struct intel_display *display); 49 49 void intel_fbc_crtc_debugfs_add(struct intel_crtc *crtc); 50 50 void intel_fbc_debugfs_register(struct intel_display *display); 51 - void intel_fbc_prepare_dirty_rect(struct intel_atomic_state *state); 51 + void intel_fbc_prepare_dirty_rect(struct intel_atomic_state *state, 52 + struct intel_crtc *crtc); 52 53 void intel_fbc_dirty_rect_update_noarm(struct intel_dsb *dsb, 53 54 struct intel_plane *plane); 54 55