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.c112
1 files changed, 75 insertions, 37 deletions
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 62fe682a7de6..bd03a8a67e3a 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);
@@ -721,7 +742,6 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_SUSPEND:
if (ast->tx_chip_type == AST_TX_DP501)
ast_set_dp501_video_output(crtc->dev, 1);
- ast_crtc_load_lut(ast, crtc);
break;
case DRM_MODE_DPMS_OFF:
if (ast->tx_chip_type == AST_TX_DP501)
@@ -733,6 +753,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 +764,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 +776,32 @@ 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)
+static void
+ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state)
{
struct ast_private *ast = to_ast_private(crtc->dev);
+ struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc->state);
+ struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
- ast_open_key(ast);
+ /*
+ * The gamma LUT has to be reloaded after changing the primary
+ * plane's color format.
+ */
+ if (old_ast_crtc_state->format != ast_crtc_state->format)
+ ast_crtc_load_lut(ast, crtc);
}
-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_atomic_state *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,25 +810,42 @@ 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);
}
static void
ast_crtc_helper_atomic_disable(struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state)
+ 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_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 +1085,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 +1129,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,