summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/armada/armada_plane.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/armada/armada_plane.c')
-rw-r--r--drivers/gpu/drm/armada/armada_plane.c221
1 files changed, 120 insertions, 101 deletions
diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c
index 9f36423dd394..a0326b4f568e 100644
--- a/drivers/gpu/drm/armada/armada_plane.c
+++ b/drivers/gpu/drm/armada/armada_plane.c
@@ -1,15 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Russell King
* Rewritten from the dovefb driver, and Armada510 manuals.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
-#include <drm/drmP.h>
+
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_print.h>
+
#include "armada_crtc.h"
#include "armada_drm.h"
#include "armada_fb.h"
@@ -79,74 +79,63 @@ void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
}
}
-static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state,
- struct armada_regs *regs, bool interlaced)
+int armada_drm_plane_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *state)
{
- u16 pitches[3];
- u32 addrs[2][3];
- unsigned i = 0;
-
- armada_drm_plane_calc(state, addrs, pitches, interlaced);
-
- /* write offset, base, and pitch */
- armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0);
- armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1);
- armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH);
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+ plane);
+ struct armada_plane_state *st = to_armada_plane_state(new_plane_state);
+ struct drm_crtc *crtc = new_plane_state->crtc;
+ struct drm_crtc_state *crtc_state;
+ bool interlace;
+ int ret;
- return i;
-}
+ if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) {
+ new_plane_state->visible = false;
+ return 0;
+ }
-int armada_drm_plane_prepare_fb(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
- plane->base.id, plane->name,
- state->fb ? state->fb->base.id : 0);
-
- /*
- * Take a reference on the new framebuffer - we want to
- * hold on to it while the hardware is displaying it.
- */
- if (state->fb)
- drm_framebuffer_get(state->fb);
- return 0;
-}
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
+ 0,
+ INT_MAX, true, false);
+ if (ret)
+ return ret;
+
+ interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
+ if (interlace) {
+ if ((new_plane_state->dst.y1 | new_plane_state->dst.y2) & 1)
+ return -EINVAL;
+ st->src_hw = drm_rect_height(&new_plane_state->src) >> 17;
+ st->dst_yx = new_plane_state->dst.y1 >> 1;
+ st->dst_hw = drm_rect_height(&new_plane_state->dst) >> 1;
+ } else {
+ st->src_hw = drm_rect_height(&new_plane_state->src) >> 16;
+ st->dst_yx = new_plane_state->dst.y1;
+ st->dst_hw = drm_rect_height(&new_plane_state->dst);
+ }
-void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
- struct drm_plane_state *old_state)
-{
- DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
- plane->base.id, plane->name,
- old_state->fb ? old_state->fb->base.id : 0);
+ st->src_hw <<= 16;
+ st->src_hw |= drm_rect_width(&new_plane_state->src) >> 16;
+ st->dst_yx <<= 16;
+ st->dst_yx |= new_plane_state->dst.x1 & 0x0000ffff;
+ st->dst_hw <<= 16;
+ st->dst_hw |= drm_rect_width(&new_plane_state->dst) & 0x0000ffff;
- if (old_state->fb)
- drm_framebuffer_put(old_state->fb);
-}
+ armada_drm_plane_calc(new_plane_state, st->addrs, st->pitches,
+ interlace);
+ st->interlace = interlace;
-int armada_drm_plane_atomic_check(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- if (state->fb && !WARN_ON(!state->crtc)) {
- struct drm_crtc *crtc = state->crtc;
- struct drm_crtc_state *crtc_state;
-
- if (state->state)
- crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
- else
- crtc_state = crtc->state;
- return drm_atomic_helper_check_plane_state(state, crtc_state,
- 0, INT_MAX,
- true, false);
- } else {
- state->visible = false;
- }
return 0;
}
static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
- struct drm_plane_state *old_state)
+ struct drm_atomic_state *state)
{
- struct drm_plane_state *state = plane->state;
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+ plane);
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
+ plane);
struct armada_crtc *dcrtc;
struct armada_regs *regs;
u32 cfg, cfg_mask, val;
@@ -154,67 +143,72 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
- if (!state->fb || WARN_ON(!state->crtc))
+ if (!new_state->fb || WARN_ON(!new_state->crtc))
return;
DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
plane->base.id, plane->name,
- state->crtc->base.id, state->crtc->name,
- state->fb->base.id,
- old_state->visible, state->visible);
+ new_state->crtc->base.id, new_state->crtc->name,
+ new_state->fb->base.id,
+ old_state->visible, new_state->visible);
- dcrtc = drm_to_armada_crtc(state->crtc);
+ dcrtc = drm_to_armada_crtc(new_state->crtc);
regs = dcrtc->regs + dcrtc->regs_idx;
idx = 0;
- if (!old_state->visible && state->visible) {
+ if (!old_state->visible && new_state->visible) {
val = CFG_PDWN64x66;
- if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
+ if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
val |= CFG_PDWN256x24;
armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
}
- val = armada_rect_hw_fp(&state->src);
- if (armada_rect_hw_fp(&old_state->src) != val)
+ val = armada_src_hw(new_state);
+ if (armada_src_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
- val = armada_rect_yx(&state->dst);
- if (armada_rect_yx(&old_state->dst) != val)
+ val = armada_dst_yx(new_state);
+ if (armada_dst_yx(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
- val = armada_rect_hw(&state->dst);
- if (armada_rect_hw(&old_state->dst) != val)
+ val = armada_dst_hw(new_state);
+ if (armada_dst_hw(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
- if (old_state->src.x1 != state->src.x1 ||
- old_state->src.y1 != state->src.y1 ||
- old_state->fb != state->fb ||
- state->crtc->state->mode_changed) {
- idx += armada_drm_crtc_calc_fb(state, regs + idx,
- dcrtc->interlaced);
+ if (old_state->src.x1 != new_state->src.x1 ||
+ old_state->src.y1 != new_state->src.y1 ||
+ old_state->fb != new_state->fb ||
+ new_state->crtc->state->mode_changed) {
+ armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),
+ LCD_CFG_GRA_START_ADDR0);
+ armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),
+ LCD_CFG_GRA_START_ADDR1);
+ armada_reg_queue_mod(regs, idx, armada_pitch(new_state, 0),
+ 0xffff,
+ LCD_CFG_GRA_PITCH);
}
- if (old_state->fb != state->fb ||
- state->crtc->state->mode_changed) {
- cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
- CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod);
- if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
+ if (old_state->fb != new_state->fb ||
+ new_state->crtc->state->mode_changed) {
+ cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |
+ CFG_GRA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod);
+ if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
cfg |= CFG_PALETTE_ENA;
- if (state->visible)
+ if (new_state->visible)
cfg |= CFG_GRA_ENA;
- if (dcrtc->interlaced)
+ if (to_armada_plane_state(new_state)->interlace)
cfg |= CFG_GRA_FTOGGLE;
cfg_mask = CFG_GRAFORMAT |
CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
CFG_SWAPYU | CFG_YUV2RGB) |
CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
CFG_GRA_ENA;
- } else if (old_state->visible != state->visible) {
- cfg = state->visible ? CFG_GRA_ENA : 0;
+ } else if (old_state->visible != new_state->visible) {
+ cfg = new_state->visible ? CFG_GRA_ENA : 0;
cfg_mask = CFG_GRA_ENA;
} else {
cfg = cfg_mask = 0;
}
- if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) ||
- drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) {
+ if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||
+ drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {
cfg_mask |= CFG_GRA_HSMOOTH;
- if (drm_rect_width(&state->src) >> 16 !=
- drm_rect_width(&state->dst))
+ if (drm_rect_width(&new_state->src) >> 16 !=
+ drm_rect_width(&new_state->dst))
cfg |= CFG_GRA_HSMOOTH;
}
@@ -226,8 +220,10 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
}
static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
- struct drm_plane_state *old_state)
+ struct drm_atomic_state *state)
{
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+ plane);
struct armada_crtc *dcrtc;
struct armada_regs *regs;
unsigned int idx = 0;
@@ -248,26 +244,49 @@ static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
/* Disable plane and power down most RAMs and FIFOs */
armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
- CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66,
+ CFG_PDWN32x32 | CFG_PDWN64x66,
0, LCD_SPU_SRAM_PARA1);
dcrtc->regs_idx += idx;
}
static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
- .prepare_fb = armada_drm_plane_prepare_fb,
- .cleanup_fb = armada_drm_plane_cleanup_fb,
.atomic_check = armada_drm_plane_atomic_check,
.atomic_update = armada_drm_primary_plane_atomic_update,
.atomic_disable = armada_drm_primary_plane_atomic_disable,
};
+void armada_plane_reset(struct drm_plane *plane)
+{
+ struct armada_plane_state *st;
+ if (plane->state)
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+ kfree(plane->state);
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st)
+ __drm_atomic_helper_plane_reset(plane, &st->base);
+}
+
+struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct armada_plane_state *st;
+
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
+ if (st)
+ __drm_atomic_helper_plane_duplicate_state(plane, &st->base);
+
+ return &st->base;
+}
+
static const struct drm_plane_funcs armada_primary_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_primary_helper_destroy,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .destroy = drm_plane_helper_destroy,
+ .reset = armada_plane_reset,
+ .atomic_duplicate_state = armada_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};