Commit c36045e1 authored by Russell King's avatar Russell King

drm/armada: convert primary plane to atomic state

Convert the primary plane as a whole to use its atomic state and the
transitional helpers.  The CRTC is also switched to use the transitional
helpers for mode_set() and mode_set_base().
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
parent 80c63aee
......@@ -325,38 +325,6 @@ armada_drm_crtc_alloc_plane_work(struct drm_plane *plane)
return work;
}
static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
struct drm_framebuffer *fb, bool force)
{
struct armada_plane_work *work;
if (!fb)
return;
if (force) {
/* Display is disabled, so just drop the old fb */
drm_framebuffer_put(fb);
return;
}
work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary);
if (work) {
work->old_fb = fb;
if (armada_drm_plane_work_queue(dcrtc, work) == 0)
return;
kfree(work);
}
/*
* Oops - just drop the reference immediately and hope for
* the best. The worst that will happen is the buffer gets
* reused before it has finished being displayed.
*/
drm_framebuffer_put(fb);
}
static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
{
/*
......@@ -434,9 +402,6 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc)
dcrtc->dpms = DRM_MODE_DPMS_ON;
armada_drm_crtc_update(dcrtc);
drm_crtc_vblank_on(crtc);
if (dcrtc->old_modeset_fb)
armada_drm_crtc_finish_fb(dcrtc, dcrtc->old_modeset_fb, false);
}
/* The mode_config.mutex will be held for this call */
......@@ -588,27 +553,16 @@ static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc)
return val;
}
static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
/* The mode_config.mutex will be held for this call */
static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *adj,
int x, int y, struct drm_framebuffer *old_fb)
static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct drm_display_mode *adj = &crtc->state->adjusted_mode;
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
struct armada_regs regs[17];
uint32_t lm, rm, tm, bm, val, sclk;
unsigned long flags;
unsigned i;
bool interlaced;
/* Take a reference on the old fb for armada_drm_crtc_commit() */
if (old_fb)
drm_framebuffer_get(old_fb);
dcrtc->old_modeset_fb = old_fb;
interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
bool interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
i = 0;
rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
......@@ -692,35 +646,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
armada_drm_crtc_update_regs(dcrtc, regs);
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
return armada_drm_crtc_mode_set_base(crtc, x, y, old_fb);
}
static int armada_drm_do_primary_update(struct drm_plane *plane,
struct drm_plane_state *state, struct drm_framebuffer *old_fb);
/* The mode_config.mutex will be held for this call */
static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct drm_plane_state state = {
.plane = crtc->primary,
.crtc = crtc,
.fb = crtc->primary->fb,
.crtc_x = 0,
.crtc_y = 0,
.crtc_w = crtc->mode.hdisplay,
.crtc_h = crtc->mode.vdisplay,
.src_x = x << 16,
.src_y = y << 16,
.src_w = crtc->mode.hdisplay << 16,
.src_h = crtc->mode.vdisplay << 16,
.rotation = DRM_MODE_ROTATE_0,
};
armada_drm_do_primary_update(crtc->primary, &state, old_fb);
return 0;
}
/* The mode_config.mutex will be held for this call */
......@@ -732,14 +657,49 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc)
crtc->primary->funcs->disable_plane(crtc->primary, NULL);
}
static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
struct armada_plane *dplane;
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
/* Wait 100ms for any plane works to complete */
dplane = drm_to_armada_plane(crtc->primary);
if (WARN_ON(armada_drm_plane_work_wait(dplane, HZ / 10) == 0))
armada_drm_plane_work_cancel(dcrtc, dplane);
dcrtc->regs_idx = 0;
dcrtc->regs = dcrtc->atomic_regs;
}
static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
unsigned long flags;
DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx);
spin_lock_irqsave(&dcrtc->irq_lock, flags);
armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
}
static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
.dpms = armada_drm_crtc_dpms,
.prepare = armada_drm_crtc_prepare,
.commit = armada_drm_crtc_commit,
.mode_fixup = armada_drm_crtc_mode_fixup,
.mode_set = armada_drm_crtc_mode_set,
.mode_set_base = armada_drm_crtc_mode_set_base,
.mode_set = drm_helper_crtc_mode_set,
.mode_set_nofb = armada_drm_crtc_mode_set_nofb,
.mode_set_base = drm_helper_crtc_mode_set_base,
.disable = armada_drm_crtc_disable,
.atomic_begin = armada_drm_crtc_atomic_begin,
.atomic_flush = armada_drm_crtc_atomic_flush,
};
static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
......@@ -1012,6 +972,12 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
return ret;
}
/*
* We are in transition to atomic modeset: update the atomic modeset
* state with the new framebuffer to keep the state consistent.
*/
drm_framebuffer_assign(&dcrtc->crtc.primary->state->fb, fb);
/*
* Finally, if the display is blanked, we won't receive an
* interrupt, so complete it now.
......@@ -1072,16 +1038,66 @@ static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc)
}
static const struct drm_crtc_funcs armada_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.cursor_set = armada_drm_crtc_cursor_set,
.cursor_move = armada_drm_crtc_cursor_move,
.destroy = armada_drm_crtc_destroy,
.set_config = drm_crtc_helper_set_config,
.page_flip = armada_drm_crtc_page_flip,
.set_property = armada_drm_crtc_set_property,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
.enable_vblank = armada_drm_crtc_enable_vblank,
.disable_vblank = armada_drm_crtc_disable_vblank,
};
static 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;
}
static 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);
if (old_state->fb)
drm_framebuffer_put(old_state->fb);
}
static 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 = {
.crtc = crtc,
.enable = crtc->enabled,
.mode = crtc->mode,
};
return drm_atomic_helper_check_plane_state(state, &crtc_state,
0, INT_MAX,
true, false);
} else {
state->visible = false;
}
return 0;
}
static unsigned int armada_drm_primary_update_state(
struct drm_plane_state *state, struct armada_regs *regs)
{
......@@ -1134,94 +1150,70 @@ static unsigned int armada_drm_primary_update_state(
return idx;
}
static int armada_drm_do_primary_update(struct drm_plane *plane,
struct drm_plane_state *state, struct drm_framebuffer *old_fb)
static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct armada_plane *dplane = drm_to_armada_plane(plane);
struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc);
struct armada_plane_work *work;
struct drm_crtc_state crtc_state = {
.crtc = state->crtc,
.enable = state->crtc->enabled,
.mode = state->crtc->mode,
};
unsigned int idx;
int ret;
struct drm_plane_state *state = plane->state;
struct armada_crtc *dcrtc;
struct armada_regs *regs;
ret = drm_atomic_helper_check_plane_state(state, &crtc_state, 0,
INT_MAX, true, false);
if (ret)
return ret;
DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
work = &dplane->works[dplane->next_work];
work->fn = armada_drm_crtc_complete_frame_work;
if (!state->fb || WARN_ON(!state->crtc))
return;
if (old_fb != state->fb) {
/*
* Take a reference on the new framebuffer - we want to
* hold on to it while the hardware is displaying it.
*/
drm_framebuffer_reference(state->fb);
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);
work->old_fb = old_fb;
} else {
work->old_fb = NULL;
}
dcrtc = drm_to_armada_crtc(state->crtc);
regs = dcrtc->regs + dcrtc->regs_idx;
idx = armada_drm_primary_update_state(state, work->regs);
armada_reg_queue_end(work->regs, idx);
dcrtc->regs_idx += armada_drm_primary_update_state(state, regs);
}
if (!dplane->state.changed)
return 0;
static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct armada_plane *dplane = drm_to_armada_plane(plane);
struct armada_crtc *dcrtc;
struct armada_regs *regs;
unsigned int idx = 0;
/* Wait for pending work to complete */
if (armada_drm_plane_work_wait(dplane, HZ / 10) == 0)
armada_drm_plane_work_cancel(dcrtc, dplane);
DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
if (!dplane->state.vsync_update) {
work->fn(dcrtc, work);
if (work->old_fb)
drm_framebuffer_unreference(work->old_fb);
return 0;
}
if (!old_state->crtc)
return;
/* Queue it for update on the next interrupt if we are enabled */
ret = armada_drm_plane_work_queue(dcrtc, work);
if (ret) {
work->fn(dcrtc, work);
if (work->old_fb)
drm_framebuffer_unreference(work->old_fb);
}
DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
plane->base.id, plane->name,
old_state->crtc->base.id, old_state->crtc->name,
old_state->fb->base.id);
dplane->next_work = !dplane->next_work;
dplane->state.ctrl0 &= ~CFG_GRA_ENA;
return 0;
}
dcrtc = drm_to_armada_crtc(old_state->crtc);
regs = dcrtc->regs + dcrtc->regs_idx;
static int armada_drm_primary_update(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_plane_state state = {
.plane = plane,
.crtc = crtc,
.fb = fb,
.src_x = src_x,
.src_y = src_y,
.src_w = src_w,
.src_h = src_h,
.crtc_x = crtc_x,
.crtc_y = crtc_y,
.crtc_w = crtc_w,
.crtc_h = crtc_h,
.rotation = DRM_MODE_ROTATE_0,
};
return armada_drm_do_primary_update(plane, &state, plane->fb);
/* 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,
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,
};
int armada_drm_plane_disable(struct drm_plane *plane,
struct drm_modeset_acquire_ctx *ctx)
{
......@@ -1283,9 +1275,12 @@ int armada_drm_plane_disable(struct drm_plane *plane,
}
static const struct drm_plane_funcs armada_primary_plane_funcs = {
.update_plane = armada_drm_primary_update,
.disable_plane = armada_drm_plane_disable,
.update_plane = drm_plane_helper_update,
.disable_plane = drm_plane_helper_disable,
.destroy = drm_primary_helper_destroy,
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
int armada_drm_plane_init(struct armada_plane *plane)
......@@ -1414,6 +1409,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
goto err_crtc;
}
drm_plane_helper_add(&primary->base,
&armada_primary_plane_helper_funcs);
ret = drm_universal_plane_init(drm, &primary->base, 0,
&armada_primary_plane_funcs,
armada_primary_formats,
......
......@@ -93,7 +93,6 @@ struct armada_crtc {
uint8_t csc_rgb_mode;
struct drm_plane *plane;
struct drm_framebuffer *old_modeset_fb;
struct armada_gem_object *cursor_obj;
int cursor_x;
......@@ -110,14 +109,15 @@ struct armada_crtc {
spinlock_t irq_lock;
uint32_t irq_ena;
struct armada_regs atomic_regs[32];
struct armada_regs *regs;
unsigned int regs_idx;
};
#define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc)
void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
int armada_drm_plane_disable(struct drm_plane *plane,
struct drm_modeset_acquire_ctx *ctx);
extern struct platform_driver armada_lcd_platform_driver;
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment