Skip to content

Commit

Permalink
Merge branch 'drm-st-next-2015-03-19' of git://git.linaro.org/people/…
Browse files Browse the repository at this point in the history
…benjamin.gaignard/kernel into drm-next

This patch makes STI driver use the atomic helpers.
I have fix the comments done by Daniel on the first version and get
his ack with this second version.
* 'drm-st-next-2015-03-19' of git://git.linaro.org/people/benjamin.gaignard/kernel:
  drm: sti: convert driver to atomic modeset
  • Loading branch information
Dave Airlie committed Mar 26, 2015
2 parents 74ccbff + de4b00b commit 517bc04
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 146 deletions.
175 changes: 39 additions & 136 deletions drivers/gpu/drm/sti/sti_drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <linux/clk.h>

#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>

Expand Down Expand Up @@ -77,22 +79,18 @@ static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
}

static int
sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, int x, int y,
struct drm_framebuffer *old_fb)
sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev);
struct sti_layer *layer;
struct clk *clk;
int rate = mode->clock * 1000;
int res;
unsigned int w, h;

DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n",
DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n",
crtc->base.id, sti_mixer_to_str(mixer),
crtc->primary->fb->base.id, mode->base.id, mode->name);
mode->base.id, mode->name);

DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
mode->vrefresh, mode->clock,
Expand Down Expand Up @@ -122,80 +120,20 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
compo->vtg_main : compo->vtg_aux, &crtc->mode);

/* a GDP is reserved to the CRTC FB */
layer = to_sti_layer(crtc->primary);
if (!layer) {
DRM_ERROR("Can not find GDP0)\n");
return -EINVAL;
}

/* copy the mode data adjusted by mode_fixup() into crtc->mode
* so that hardware can be set to proper mode
*/
memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));

res = sti_mixer_set_layer_depth(mixer, layer);
if (res) {
DRM_ERROR("Can not set layer depth\n");
return -EINVAL;
}
res = sti_mixer_active_video_area(mixer, &crtc->mode);
if (res) {
DRM_ERROR("Can not set active video area\n");
return -EINVAL;
}

w = crtc->primary->fb->width - x;
h = crtc->primary->fb->height - y;

return sti_layer_prepare(layer, crtc,
crtc->primary->fb, &crtc->mode,
mixer->id, 0, 0, w, h, x, y, w, h);
}

static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct sti_layer *layer;
unsigned int w, h;
int ret;

DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n",
crtc->base.id, sti_mixer_to_str(mixer),
crtc->primary->fb->base.id, x, y);

/* GDP is reserved to the CRTC FB */
layer = to_sti_layer(crtc->primary);
if (!layer) {
DRM_ERROR("Can not find GDP0)\n");
ret = -EINVAL;
goto out;
}

w = crtc->primary->fb->width - crtc->x;
h = crtc->primary->fb->height - crtc->y;

ret = sti_layer_prepare(layer, crtc,
crtc->primary->fb, &crtc->mode,
mixer->id, 0, 0, w, h,
crtc->x, crtc->y, w, h);
if (ret) {
DRM_ERROR("Can not prepare layer\n");
goto out;
}

sti_drm_crtc_commit(crtc);
out:
return ret;
return res;
}

static void sti_drm_crtc_disable(struct drm_crtc *crtc)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev);
struct sti_layer *layer;

if (!mixer->enabled)
return;
Expand All @@ -205,24 +143,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
/* Disable Background */
sti_mixer_set_background_status(mixer, false);

/* Disable GDP */
layer = to_sti_layer(crtc->primary);
if (!layer) {
DRM_ERROR("Cannot find GDP0\n");
return;
}

/* Disable layer at mixer level */
if (sti_mixer_set_layer_status(mixer, layer, false))
DRM_ERROR("Can not disable %s layer at mixer\n",
sti_layer_to_str(layer));

/* Wait a while to be sure that a Vsync event is received */
msleep(WAIT_NEXT_VSYNC_MS);

/* Then disable layer itself */
sti_layer_disable(layer);

drm_crtc_vblank_off(crtc);

/* Disable pixel clock and compo IP clocks */
Expand All @@ -237,64 +157,44 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc)
mixer->enabled = false;
}

static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
.dpms = sti_drm_crtc_dpms,
.prepare = sti_drm_crtc_prepare,
.commit = sti_drm_crtc_commit,
.mode_fixup = sti_drm_crtc_mode_fixup,
.mode_set = sti_drm_crtc_mode_set,
.mode_set_base = sti_drm_crtc_mode_set_base,
.disable = sti_drm_crtc_disable,
};
static void
sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
sti_drm_crtc_prepare(crtc);
sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
}

static int sti_drm_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags)
static void sti_drm_atomic_begin(struct drm_crtc *crtc)
{
struct drm_device *drm_dev = crtc->dev;
struct drm_framebuffer *old_fb;
struct sti_mixer *mixer = to_sti_mixer(crtc);
unsigned long flags;
int ret;

DRM_DEBUG_KMS("fb %d --> fb %d\n",
crtc->primary->fb->base.id, fb->base.id);
if (crtc->state->event) {
crtc->state->event->pipe = drm_crtc_index(crtc);

mutex_lock(&drm_dev->struct_mutex);
WARN_ON(drm_crtc_vblank_get(crtc) != 0);

old_fb = crtc->primary->fb;
crtc->primary->fb = fb;
ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
if (ret) {
DRM_ERROR("failed\n");
crtc->primary->fb = old_fb;
goto out;
mixer->pending_event = crtc->state->event;
crtc->state->event = NULL;
}
}

if (event) {
event->pipe = mixer->id;

ret = drm_vblank_get(drm_dev, event->pipe);
if (ret) {
DRM_ERROR("Cannot get vblank\n");
goto out;
}

spin_lock_irqsave(&drm_dev->event_lock, flags);
if (mixer->pending_event) {
drm_vblank_put(drm_dev, event->pipe);
ret = -EBUSY;
} else {
mixer->pending_event = event;
}
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
}
out:
mutex_unlock(&drm_dev->struct_mutex);
return ret;
static void sti_drm_atomic_flush(struct drm_crtc *crtc)
{
}

static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
.dpms = sti_drm_crtc_dpms,
.prepare = sti_drm_crtc_prepare,
.commit = sti_drm_crtc_commit,
.mode_fixup = sti_drm_crtc_mode_fixup,
.mode_set = drm_helper_crtc_mode_set,
.mode_set_nofb = sti_drm_crtc_mode_set_nofb,
.mode_set_base = drm_helper_crtc_mode_set_base,
.disable = sti_drm_crtc_disable,
.atomic_begin = sti_drm_atomic_begin,
.atomic_flush = sti_drm_atomic_flush,
};

static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
{
DRM_DEBUG_KMS("\n");
Expand Down Expand Up @@ -380,10 +280,13 @@ void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);

static struct drm_crtc_funcs sti_crtc_funcs = {
.set_config = drm_crtc_helper_set_config,
.page_flip = sti_drm_crtc_page_flip,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.destroy = sti_drm_crtc_destroy,
.set_property = sti_drm_crtc_set_property,
.reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
};

bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
Expand Down
86 changes: 85 additions & 1 deletion drivers/gpu/drm/sti/sti_drm_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <linux/module.h>
#include <linux/of_platform.h>

#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
Expand All @@ -28,8 +30,87 @@
#define STI_MAX_FB_HEIGHT 4096
#define STI_MAX_FB_WIDTH 4096

static void sti_drm_atomic_schedule(struct sti_drm_private *private,
struct drm_atomic_state *state)
{
private->commit.state = state;
schedule_work(&private->commit.work);
}

static void sti_drm_atomic_complete(struct sti_drm_private *private,
struct drm_atomic_state *state)
{
struct drm_device *drm = private->drm_dev;

/*
* Everything below can be run asynchronously without the need to grab
* any modeset locks at all under one condition: It must be guaranteed
* that the asynchronous work has either been cancelled (if the driver
* supports it, which at least requires that the framebuffers get
* cleaned up with drm_atomic_helper_cleanup_planes()) or completed
* before the new state gets committed on the software side with
* drm_atomic_helper_swap_state().
*
* This scheme allows new atomic state updates to be prepared and
* checked in parallel to the asynchronous completion of the previous
* update. Which is important since compositors need to figure out the
* composition of the next frame right after having submitted the
* current layout.
*/

drm_atomic_helper_commit_modeset_disables(drm, state);
drm_atomic_helper_commit_planes(drm, state);
drm_atomic_helper_commit_modeset_enables(drm, state);

drm_atomic_helper_wait_for_vblanks(drm, state);

drm_atomic_helper_cleanup_planes(drm, state);
drm_atomic_state_free(state);
}

static void sti_drm_atomic_work(struct work_struct *work)
{
struct sti_drm_private *private = container_of(work,
struct sti_drm_private, commit.work);

sti_drm_atomic_complete(private, private->commit.state);
}

static int sti_drm_atomic_commit(struct drm_device *drm,
struct drm_atomic_state *state, bool async)
{
struct sti_drm_private *private = drm->dev_private;
int err;

err = drm_atomic_helper_prepare_planes(drm, state);
if (err)
return err;

/* serialize outstanding asynchronous commits */
mutex_lock(&private->commit.lock);
flush_work(&private->commit.work);

/*
* This is the point of no return - everything below never fails except
* when the hw goes bonghits. Which means we can commit the new state on
* the software side now.
*/

drm_atomic_helper_swap_state(drm, state);

if (async)
sti_drm_atomic_schedule(private, state);
else
sti_drm_atomic_complete(private, state);

mutex_unlock(&private->commit.lock);
return 0;
}

static struct drm_mode_config_funcs sti_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = sti_drm_atomic_commit,
};

static void sti_drm_mode_config_init(struct drm_device *dev)
Expand Down Expand Up @@ -61,6 +142,9 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = (void *)private;
private->drm_dev = dev;

mutex_init(&private->commit.lock);
INIT_WORK(&private->commit.work, sti_drm_atomic_work);

drm_mode_config_init(dev);
drm_kms_helper_poll_init(dev);

Expand All @@ -74,7 +158,7 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags)
return ret;
}

drm_helper_disable_unused_functions(dev);
drm_mode_config_reset(dev);

#ifdef CONFIG_DRM_STI_FBDEV
drm_fbdev_cma_init(dev, 32,
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/sti/sti_drm_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ struct sti_drm_private {
struct sti_compositor *compo;
struct drm_property *plane_zorder_property;
struct drm_device *drm_dev;

struct {
struct drm_atomic_state *state;
struct work_struct work;
struct mutex lock;
} commit;
};

#endif
Loading

0 comments on commit 517bc04

Please sign in to comment.