Skip to content

Commit

Permalink
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/daeinki/drm-exynos into drm-next

This is a second pull-request which adds last part of
atomic modeset/pageflip support, render node support,
clean-up, and fix-up.

* 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
  drm/exynos: fix build warning to exynos_drm_gem.c
  drm/exynos: Properly report supported formats for each device
  drm/exynos: add render node support
  drm/exynos: implement atomic_{begin/flush} of DECON
  drm/exynos: remove legacy ->suspend()/resume()
  drm/exynos: Enable atomic modesetting feature
  drm/exynos: remove wait queue for pending page flip
  drm/exynos: wait all planes updates to finish
  drm/exynos: add atomic asynchronous commit
  drm/exynos: fimd: only finish update if START == START_S
  drm/exynos: add macro to get the address of START_S reg
  drm/exynos: check for pending fb before finish update
  drm/exynos: fimd: move window protect code to prepare/cleanup_plane
  drm/exynos: add prepare and cleanup phases for planes
  drm/exynos: fimd: unify call to exynos_drm_crtc_finish_pageflip()
  drm/exynos: don't track enabled state at exynos_crtc
  • Loading branch information
Dave Airlie committed Aug 31, 2015
2 parents 701078d + 50002d4 commit 879a37d
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 153 deletions.
54 changes: 45 additions & 9 deletions drivers/gpu/drm/exynos/exynos5433_drm_decon.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ static const char * const decon_clks_name[] = {
"sclk_decon_eclk",
};

static const uint32_t decon_formats[] = {
DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
};

static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
Expand Down Expand Up @@ -219,6 +226,17 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win,
writel(val, ctx->addr + DECON_SHADOWCON);
}

static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;

if (ctx->suspended)
return;

decon_shadow_protect_win(ctx, plane->zpos, true);
}

static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
Expand All @@ -232,8 +250,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
if (ctx->suspended)
return;

decon_shadow_protect_win(ctx, win, true);

val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y);
writel(val, ctx->addr + DECON_VIDOSDxA(win));

Expand Down Expand Up @@ -265,15 +281,10 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
val |= WINCONx_ENWIN_F;
writel(val, ctx->addr + DECON_WINCONx(win));

decon_shadow_protect_win(ctx, win, false);

/* standalone update */
val = readl(ctx->addr + DECON_UPDATE);
val |= STANDALONE_UPDATE_F;
writel(val, ctx->addr + DECON_UPDATE);

if (ctx->i80_if)
atomic_set(&ctx->win_updated, 1);
}

static void decon_disable_plane(struct exynos_drm_crtc *crtc,
Expand Down Expand Up @@ -301,6 +312,20 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
writel(val, ctx->addr + DECON_UPDATE);
}

static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;

if (ctx->suspended)
return;

decon_shadow_protect_win(ctx, plane->zpos, false);

if (ctx->i80_if)
atomic_set(&ctx->win_updated, 1);
}

static void decon_swreset(struct decon_context *ctx)
{
unsigned int tries;
Expand Down Expand Up @@ -455,8 +480,10 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank,
.commit = decon_commit,
.atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane,
.disable_plane = decon_disable_plane,
.atomic_flush = decon_atomic_flush,
.te_handler = decon_te_irq_handler,
};

Expand All @@ -477,7 +504,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
DRM_PLANE_TYPE_OVERLAY;
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1 << ctx->pipe, type, zpos);
1 << ctx->pipe, type, decon_formats,
ARRAY_SIZE(decon_formats), zpos);
if (ret)
return ret;
}
Expand Down Expand Up @@ -542,13 +570,21 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id)
{
struct decon_context *ctx = dev_id;
u32 val;
int win;

if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled))
goto out;

val = readl(ctx->addr + DECON_VIDINTCON1);
if (val & VIDINTCON1_INTFRMDONEPEND) {
exynos_drm_crtc_finish_pageflip(ctx->crtc);
for (win = 0 ; win < WINDOWS_NR ; win++) {
struct exynos_drm_plane *plane = &ctx->planes[win];

if (!plane->pending_fb)
continue;

exynos_drm_crtc_finish_update(ctx->crtc, plane);
}

/* clear */
writel(VIDINTCON1_INTFRMDONEPEND,
Expand Down
55 changes: 47 additions & 8 deletions drivers/gpu/drm/exynos/exynos7_drm_decon.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ static const struct of_device_id decon_driver_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, decon_driver_dt_match);

static const uint32_t decon_formats[] = {
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_RGBX8888,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_RGBA8888,
DRM_FORMAT_BGRA8888,
};

static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
Expand Down Expand Up @@ -383,6 +395,17 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
writel(val, ctx->regs + SHADOWCON);
}

static void decon_atomic_begin(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;

if (ctx->suspended)
return;

decon_shadow_protect_win(ctx, plane->zpos, true);
}

static void decon_update_plane(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
Expand Down Expand Up @@ -410,9 +433,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
* is set.
*/

/* protect windows */
decon_shadow_protect_win(ctx, win, true);

/* buffer start address */
val = (unsigned long)plane->dma_addr[0];
writel(val, ctx->regs + VIDW_BUF_START(win));
Expand Down Expand Up @@ -510,14 +530,22 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
val &= ~WINCONx_ENWIN;
writel(val, ctx->regs + WINCON(win));

/* unprotect windows */
decon_shadow_protect_win(ctx, win, false);

val = readl(ctx->regs + DECON_UPDATE);
val |= DECON_UPDATE_STANDALONE_F;
writel(val, ctx->regs + DECON_UPDATE);
}

static void decon_atomic_flush(struct exynos_drm_crtc *crtc,
struct exynos_drm_plane *plane)
{
struct decon_context *ctx = crtc->ctx;

if (ctx->suspended)
return;

decon_shadow_protect_win(ctx, plane->zpos, false);
}

static void decon_init(struct decon_context *ctx)
{
u32 val;
Expand Down Expand Up @@ -614,15 +642,18 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = {
.enable_vblank = decon_enable_vblank,
.disable_vblank = decon_disable_vblank,
.wait_for_vblank = decon_wait_for_vblank,
.atomic_begin = decon_atomic_begin,
.update_plane = decon_update_plane,
.disable_plane = decon_disable_plane,
.atomic_flush = decon_atomic_flush,
};


static irqreturn_t decon_irq_handler(int irq, void *dev_id)
{
struct decon_context *ctx = (struct decon_context *)dev_id;
u32 val, clear_bit;
int win;

val = readl(ctx->regs + VIDINTCON1);

Expand All @@ -636,7 +667,14 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)

if (!ctx->i80_if) {
drm_crtc_handle_vblank(&ctx->crtc->base);
exynos_drm_crtc_finish_pageflip(ctx->crtc);
for (win = 0 ; win < WINDOWS_NR ; win++) {
struct exynos_drm_plane *plane = &ctx->planes[win];

if (!plane->pending_fb)
continue;

exynos_drm_crtc_finish_update(ctx->crtc, plane);
}

/* set wait vsync event to zero and wake up queue. */
if (atomic_read(&ctx->wait_vsync_event)) {
Expand Down Expand Up @@ -667,7 +705,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY :
DRM_PLANE_TYPE_OVERLAY;
ret = exynos_plane_init(drm_dev, &ctx->planes[zpos],
1 << ctx->pipe, type, zpos);
1 << ctx->pipe, type, decon_formats,
ARRAY_SIZE(decon_formats), zpos);
if (ret)
return ret;
}
Expand Down
69 changes: 36 additions & 33 deletions drivers/gpu/drm/exynos/exynos_drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,20 @@ static void exynos_drm_crtc_enable(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);

if (exynos_crtc->enabled)
return;

if (exynos_crtc->ops->enable)
exynos_crtc->ops->enable(exynos_crtc);

exynos_crtc->enabled = true;

drm_crtc_vblank_on(crtc);
}

static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);

if (!exynos_crtc->enabled)
return;

/* wait for the completion of page flip. */
if (!wait_event_timeout(exynos_crtc->pending_flip_queue,
(exynos_crtc->event == NULL), HZ/20))
exynos_crtc->event = NULL;

drm_crtc_vblank_off(crtc);

if (exynos_crtc->ops->disable)
exynos_crtc->ops->disable(exynos_crtc);

exynos_crtc->enabled = false;
}

static bool
Expand Down Expand Up @@ -83,16 +68,32 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct drm_plane *plane;

exynos_crtc->event = crtc->state->event;

if (crtc->state->event) {
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
exynos_crtc->event = crtc->state->event;
drm_atomic_crtc_for_each_plane(plane, crtc) {
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);

if (exynos_crtc->ops->atomic_begin)
exynos_crtc->ops->atomic_begin(exynos_crtc,
exynos_plane);
}
}

static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct drm_plane *plane;

drm_atomic_crtc_for_each_plane(plane, crtc) {
struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);

if (exynos_crtc->ops->atomic_flush)
exynos_crtc->ops->atomic_flush(exynos_crtc,
exynos_plane);
}
}

static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
Expand Down Expand Up @@ -140,13 +141,13 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
if (!exynos_crtc)
return ERR_PTR(-ENOMEM);

init_waitqueue_head(&exynos_crtc->pending_flip_queue);

exynos_crtc->pipe = pipe;
exynos_crtc->type = type;
exynos_crtc->ops = ops;
exynos_crtc->ctx = ctx;

init_waitqueue_head(&exynos_crtc->wait_update);

crtc = &exynos_crtc->base;

private->crtc[pipe] = crtc;
Expand All @@ -172,9 +173,6 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);

if (!exynos_crtc->enabled)
return -EPERM;

if (exynos_crtc->ops->enable_vblank)
return exynos_crtc->ops->enable_vblank(exynos_crtc);

Expand All @@ -187,26 +185,31 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);

if (!exynos_crtc->enabled)
return;

if (exynos_crtc->ops->disable_vblank)
exynos_crtc->ops->disable_vblank(exynos_crtc);
}

void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc)
void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc)
{
wait_event_timeout(exynos_crtc->wait_update,
(atomic_read(&exynos_crtc->pending_update) == 0),
msecs_to_jiffies(50));
}

void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
struct exynos_drm_plane *exynos_plane)
{
struct drm_crtc *crtc = &exynos_crtc->base;
unsigned long flags;

spin_lock_irqsave(&crtc->dev->event_lock, flags);
if (exynos_crtc->event) {
exynos_plane->pending_fb = NULL;

drm_crtc_send_vblank_event(crtc, exynos_crtc->event);
drm_crtc_vblank_put(crtc);
wake_up(&exynos_crtc->pending_flip_queue);
if (atomic_dec_and_test(&exynos_crtc->pending_update))
wake_up(&exynos_crtc->wait_update);

}
spin_lock_irqsave(&crtc->dev->event_lock, flags);
if (exynos_crtc->event)
drm_crtc_send_vblank_event(crtc, exynos_crtc->event);

exynos_crtc->event = NULL;
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/exynos/exynos_drm_crtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
void *context);
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc);
void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc);
void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc,
struct exynos_drm_plane *exynos_plane);
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);

/* This function gets pipe value to crtc device matched with out_type. */
Expand Down
Loading

0 comments on commit 879a37d

Please sign in to comment.