drm/ast: Move mode-setting code into mode_set_nofb CRTC helper
authorThomas Zimmermann <tzimmermann@suse.de>
Thu, 27 Jun 2024 15:27:48 +0000 (17:27 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Wed, 3 Jul 2024 07:38:13 +0000 (09:38 +0200)
Do all mode setting in ast_crtc_helper_mode_set_nofb(), which
always runs after disabling the CRTC and before programming the
planes. Removes implicit synchronization between the CRTC's
atomic disable, enable and the vertical retrace.

Display-mode updates require HW cursors to be disabled. The HW
cursor only picks up changes at vertical retrace periods. So the
CRTC's atomic_disable helper waited for the retrace to delay any
following mode-setting operations, which then happened in
atomic_enable. See [1] for a description of the problem.

With the CRTC helper callback mode_set_nofb, we can now synchronize
and reprogram in the same place. As it always runs before the plane
update, the plane code can be reordered with the CRTC's later
atomic_enable et al.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/series/79914/
Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240627153638.8765-4-tzimmermann@suse.de
drivers/gpu/drm/ast/ast_mode.c

index 421fcdad40e458df601628f5d8000fa89f446f33..e8312b3472ed51251e1ca543a980651027b7ceb2 100644 (file)
@@ -1131,6 +1131,33 @@ ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode
        return status;
 }
 
+static void ast_crtc_helper_mode_set_nofb(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct ast_device *ast = to_ast_device(dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
+       struct ast_vbios_mode_info *vbios_mode_info =
+               &ast_crtc_state->vbios_mode_info;
+       struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+
+       /*
+        * Ensure that no scanout takes place before reprogramming mode
+        * and format registers.
+        *
+        * TODO: Get vblank interrupts working and remove this line.
+        */
+       ast_wait_for_vretrace(ast);
+
+       ast_set_vbios_mode_reg(ast, adjusted_mode, vbios_mode_info);
+       ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x06);
+       ast_set_std_reg(ast, adjusted_mode, vbios_mode_info);
+       ast_set_crtc_reg(ast, adjusted_mode, vbios_mode_info);
+       ast_set_dclk_reg(ast, adjusted_mode, vbios_mode_info);
+       ast_set_crtthd_reg(ast);
+       ast_set_sync_reg(ast, adjusted_mode, vbios_mode_info);
+}
+
 static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
                                        struct drm_atomic_state *state)
 {
@@ -1207,30 +1234,12 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
 
 static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
 {
-       struct drm_device *dev = crtc->dev;
-       struct ast_device *ast = to_ast_device(dev);
-       struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
-       struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
-       struct ast_vbios_mode_info *vbios_mode_info =
-               &ast_crtc_state->vbios_mode_info;
-       struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
-
-       ast_set_vbios_mode_reg(ast, adjusted_mode, vbios_mode_info);
-       ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x06);
-       ast_set_std_reg(ast, adjusted_mode, vbios_mode_info);
-       ast_set_crtc_reg(ast, adjusted_mode, vbios_mode_info);
-       ast_set_dclk_reg(ast, adjusted_mode, vbios_mode_info);
-       ast_set_crtthd_reg(ast);
-       ast_set_sync_reg(ast, adjusted_mode, vbios_mode_info);
-
        ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
 }
 
 static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)
 {
        struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
-       struct drm_device *dev = crtc->dev;
-       struct ast_device *ast = to_ast_device(dev);
 
        ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 
@@ -1245,16 +1254,11 @@ static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_ato
         * simple pageflips on the planes.
         */
        drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
-
-       /*
-        * Ensure that no scanout takes place before reprogramming mode
-        * and format registers.
-        */
-       ast_wait_for_vretrace(ast);
 }
 
 static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
        .mode_valid = ast_crtc_helper_mode_valid,
+       .mode_set_nofb = ast_crtc_helper_mode_set_nofb,
        .atomic_check = ast_crtc_helper_atomic_check,
        .atomic_flush = ast_crtc_helper_atomic_flush,
        .atomic_enable = ast_crtc_helper_atomic_enable,