summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/ast/ast_mode.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/ast/ast_mode.c')
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c103
1 files changed, 62 insertions, 41 deletions
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 62fe682a7de6..834a156e3a75 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -514,6 +514,16 @@ static void ast_set_start_address_crt1(struct ast_private *ast,
}
+static void ast_wait_for_vretrace(struct ast_private *ast)
+{
+ unsigned long timeout = jiffies + HZ;
+ u8 vgair1;
+
+ do {
+ vgair1 = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ);
+ } while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && time_before(jiffies, timeout));
+}
+
/*
* Primary plane
*/
@@ -562,13 +572,24 @@ ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_plane_state *state = plane->state;
struct drm_gem_vram_object *gbo;
s64 gpu_addr;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_framebuffer *old_fb = old_state->fb;
- gbo = drm_gem_vram_of_gem(state->fb->obj[0]);
+ if (!old_fb || (fb->format != old_fb->format)) {
+ struct drm_crtc_state *crtc_state = 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;
+
+ ast_set_color_reg(ast, fb->format);
+ ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info);
+ }
+
+ gbo = drm_gem_vram_of_gem(fb->obj[0]);
gpu_addr = drm_gem_vram_offset(gbo);
if (drm_WARN_ON_ONCE(dev, gpu_addr < 0))
return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */
- ast_set_offset_reg(ast, state->fb);
+ ast_set_offset_reg(ast, fb);
ast_set_start_address_crt1(ast, (u32)gpu_addr);
ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00);
@@ -733,6 +754,7 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
+ struct drm_device *dev = crtc->dev;
struct ast_crtc_state *ast_state;
const struct drm_format_info *format;
bool succ;
@@ -743,8 +765,8 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
ast_state = to_ast_crtc_state(state);
format = ast_state->format;
- if (!format)
- return 0;
+ if (drm_WARN_ON_ONCE(dev, !format))
+ return -EINVAL; /* BUG: We didn't set format in primary check(). */
succ = ast_get_vbios_mode_info(format, &state->mode,
&state->adjusted_mode,
@@ -755,39 +777,17 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
return 0;
}
-static void ast_crtc_helper_atomic_begin(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state)
-{
- struct ast_private *ast = to_ast_private(crtc->dev);
-
- ast_open_key(ast);
-}
-
-static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state)
+static void
+ast_crtc_helper_atomic_enable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
{
struct drm_device *dev = crtc->dev;
struct ast_private *ast = to_ast_private(dev);
- struct ast_crtc_state *ast_state;
- const struct drm_format_info *format;
- struct ast_vbios_mode_info *vbios_mode_info;
- struct drm_display_mode *adjusted_mode;
-
- ast_state = to_ast_crtc_state(crtc->state);
-
- format = ast_state->format;
- if (!format)
- return;
-
- vbios_mode_info = &ast_state->vbios_mode_info;
-
- ast_set_color_reg(ast, format);
- ast_set_vbios_color_reg(ast, format, vbios_mode_info);
-
- if (!crtc->state->mode_changed)
- return;
-
- adjusted_mode = &crtc->state->adjusted_mode;
+ 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;
ast_set_vbios_mode_reg(ast, adjusted_mode, vbios_mode_info);
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06);
@@ -796,12 +796,7 @@ static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
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 void
-ast_crtc_helper_atomic_enable(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state)
-{
ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
}
@@ -809,13 +804,32 @@ static void
ast_crtc_helper_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
+ struct drm_device *dev = crtc->dev;
+ struct ast_private *ast = to_ast_private(dev);
+
ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ /*
+ * HW cursors require the underlying primary plane and CRTC to
+ * display a valid mode and image. This is not the case during
+ * full modeset operations. So we temporarily disable any active
+ * plane, including the HW cursor. Each plane's atomic_update()
+ * helper will re-enable it if necessary.
+ *
+ * We only do this during *full* modesets. It does not affect
+ * 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 = {
.atomic_check = ast_crtc_helper_atomic_check,
- .atomic_begin = ast_crtc_helper_atomic_begin,
- .atomic_flush = ast_crtc_helper_atomic_flush,
.atomic_enable = ast_crtc_helper_atomic_enable,
.atomic_disable = ast_crtc_helper_atomic_disable,
};
@@ -1054,6 +1068,11 @@ static int ast_connector_init(struct drm_device *dev)
* Mode config
*/
+static const struct drm_mode_config_helper_funcs
+ast_mode_config_helper_funcs = {
+ .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+};
+
static const struct drm_mode_config_funcs ast_mode_config_funcs = {
.fb_create = drm_gem_fb_create,
.mode_valid = drm_vram_helper_mode_valid,
@@ -1093,6 +1112,8 @@ int ast_mode_config_init(struct ast_private *ast)
dev->mode_config.max_height = 1200;
}
+ dev->mode_config.helper_private = &ast_mode_config_helper_funcs;
+
memset(&ast->primary_plane, 0, sizeof(ast->primary_plane));
ret = drm_universal_plane_init(dev, &ast->primary_plane, 0x01,
&ast_primary_plane_funcs,