Commit 67a0375f authored by Dave Airlie's avatar Dave Airlie

Merge tag 'omapdrm-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next

omapdrm changes for 4.1

* universal plane support
* refactoring to prepare work atomic modesetting work
* a lot of small fixes

* tag 'omapdrm-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (36 commits)
  drm/omap: tiler: add hibernation callback
  drm/omap: add hibernation callbacks
  drm/omap: keep ref to old_fb
  drm/omap: fix race conditon in DMM
  drm/omap: fix race condition with dev->obj_list
  drm/omap: do not use BUG_ON(!spin_is_locked(x))
  drm/omap: only ignore DIGIT SYNC LOST for TV output
  drm/omap: fix race with error_irq
  drm/omap: use DRM_ERROR_RATELIMITED() for error irqs
  drm/omap: stop connector polling during suspend
  drm/omap: remove dummy PM functions
  drm/omap: tiler: fix race condition with engine->async
  drm/omap: fix plane's channel selection
  drm/omap: fix TILER on OMAP5
  drm/omap: handle incompatible buffer stride and pixel size
  drm/omap: fix error handling in omap_framebuffer_create()
  drm/omap: fix operation without fbdev
  drm/omap: add a comment why locking is missing
  drm/omap: add pin refcounting to omap_framebuffer
  drm/omap: clear omap_obj->paddr in omap_gem_put_paddr()
  ...
parents 4d0982c6 1d601da2
...@@ -271,18 +271,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { ...@@ -271,18 +271,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
.best_encoder = omap_connector_attached_encoder, .best_encoder = omap_connector_attached_encoder,
}; };
/* flush an area of the framebuffer (in case of manual update display that
* is not automatically flushed)
*/
void omap_connector_flush(struct drm_connector *connector,
int x, int y, int w, int h)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
/* TODO: enable when supported in dss */
VERB("%s: %d,%d, %dx%d", omap_connector->dssdev->name, x, y, w, h);
}
/* initialize connector */ /* initialize connector */
struct drm_connector *omap_connector_init(struct drm_device *dev, struct drm_connector *omap_connector_init(struct drm_device *dev,
int connector_type, struct omap_dss_device *dssdev, int connector_type, struct omap_dss_device *dssdev,
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
struct omap_crtc { struct omap_crtc {
struct drm_crtc base; struct drm_crtc base;
struct drm_plane *plane;
const char *name; const char *name;
int pipe; int pipe;
...@@ -46,7 +45,6 @@ struct omap_crtc { ...@@ -46,7 +45,6 @@ struct omap_crtc {
struct omap_video_timings timings; struct omap_video_timings timings;
bool enabled; bool enabled;
bool full_update;
struct omap_drm_apply apply; struct omap_drm_apply apply;
...@@ -74,8 +72,14 @@ struct omap_crtc { ...@@ -74,8 +72,14 @@ struct omap_crtc {
* XXX maybe fold into apply_work?? * XXX maybe fold into apply_work??
*/ */
struct work_struct page_flip_work; struct work_struct page_flip_work;
bool ignore_digit_sync_lost;
}; };
/* -----------------------------------------------------------------------------
* Helper Functions
*/
uint32_t pipe2vbl(struct drm_crtc *crtc) uint32_t pipe2vbl(struct drm_crtc *crtc)
{ {
struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
...@@ -83,6 +87,22 @@ uint32_t pipe2vbl(struct drm_crtc *crtc) ...@@ -83,6 +87,22 @@ uint32_t pipe2vbl(struct drm_crtc *crtc)
return dispc_mgr_get_vsync_irq(omap_crtc->channel); return dispc_mgr_get_vsync_irq(omap_crtc->channel);
} }
const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
return &omap_crtc->timings;
}
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
return omap_crtc->channel;
}
/* -----------------------------------------------------------------------------
* DSS Manager Functions
*/
/* /*
* Manager-ops, callbacks from output when they need to configure * Manager-ops, callbacks from output when they need to configure
* the upstream part of the video pipe. * the upstream part of the video pipe.
...@@ -122,7 +142,63 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr) ...@@ -122,7 +142,63 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
{ {
} }
static void set_enabled(struct drm_crtc *crtc, bool enable); /* Called only from CRTC pre_apply and suspend/resume handlers. */
static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
{
struct drm_device *dev = crtc->dev;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
enum omap_channel channel = omap_crtc->channel;
struct omap_irq_wait *wait;
u32 framedone_irq, vsync_irq;
int ret;
if (dispc_mgr_is_enabled(channel) == enable)
return;
if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
/*
* Digit output produces some sync lost interrupts during the
* first frame when enabling, so we need to ignore those.
*/
omap_crtc->ignore_digit_sync_lost = true;
}
framedone_irq = dispc_mgr_get_framedone_irq(channel);
vsync_irq = dispc_mgr_get_vsync_irq(channel);
if (enable) {
wait = omap_irq_wait_init(dev, vsync_irq, 1);
} else {
/*
* When we disable the digit output, we need to wait for
* FRAMEDONE to know that DISPC has finished with the output.
*
* OMAP2/3 does not have FRAMEDONE irq for digit output, and in
* that case we need to use vsync interrupt, and wait for both
* even and odd frames.
*/
if (framedone_irq)
wait = omap_irq_wait_init(dev, framedone_irq, 1);
else
wait = omap_irq_wait_init(dev, vsync_irq, 2);
}
dispc_mgr_enable(channel, enable);
ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
if (ret) {
dev_err(dev->dev, "%s: timeout waiting for %s\n",
omap_crtc->name, enable ? "enable" : "disable");
}
if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
omap_crtc->ignore_digit_sync_lost = false;
/* make sure the irq handler sees the value above */
mb();
}
}
static int omap_crtc_enable(struct omap_overlay_manager *mgr) static int omap_crtc_enable(struct omap_overlay_manager *mgr)
{ {
...@@ -131,7 +207,7 @@ static int omap_crtc_enable(struct omap_overlay_manager *mgr) ...@@ -131,7 +207,7 @@ static int omap_crtc_enable(struct omap_overlay_manager *mgr)
dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
dispc_mgr_set_timings(omap_crtc->channel, dispc_mgr_set_timings(omap_crtc->channel,
&omap_crtc->timings); &omap_crtc->timings);
set_enabled(&omap_crtc->base, true); omap_crtc_set_enabled(&omap_crtc->base, true);
return 0; return 0;
} }
...@@ -140,7 +216,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr) ...@@ -140,7 +216,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr)
{ {
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
set_enabled(&omap_crtc->base, false); omap_crtc_set_enabled(&omap_crtc->base, false);
} }
static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
...@@ -149,7 +225,6 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, ...@@ -149,7 +225,6 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
DBG("%s", omap_crtc->name); DBG("%s", omap_crtc->name);
omap_crtc->timings = *timings; omap_crtc->timings = *timings;
omap_crtc->full_update = true;
} }
static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
...@@ -185,8 +260,190 @@ static const struct dss_mgr_ops mgr_ops = { ...@@ -185,8 +260,190 @@ static const struct dss_mgr_ops mgr_ops = {
.unregister_framedone_handler = omap_crtc_unregister_framedone_handler, .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
}; };
/* /* -----------------------------------------------------------------------------
* CRTC funcs: * Apply Logic
*/
static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{
struct omap_crtc *omap_crtc =
container_of(irq, struct omap_crtc, error_irq);
if (omap_crtc->ignore_digit_sync_lost) {
irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
if (!irqstatus)
return;
}
DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
}
static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{
struct omap_crtc *omap_crtc =
container_of(irq, struct omap_crtc, apply_irq);
struct drm_crtc *crtc = &omap_crtc->base;
if (!dispc_mgr_go_busy(omap_crtc->channel)) {
struct omap_drm_private *priv =
crtc->dev->dev_private;
DBG("%s: apply done", omap_crtc->name);
__omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
queue_work(priv->wq, &omap_crtc->apply_work);
}
}
static void apply_worker(struct work_struct *work)
{
struct omap_crtc *omap_crtc =
container_of(work, struct omap_crtc, apply_work);
struct drm_crtc *crtc = &omap_crtc->base;
struct drm_device *dev = crtc->dev;
struct omap_drm_apply *apply, *n;
bool need_apply;
/*
* Synchronize everything on mode_config.mutex, to keep
* the callbacks and list modification all serialized
* with respect to modesetting ioctls from userspace.
*/
drm_modeset_lock(&crtc->mutex, NULL);
dispc_runtime_get();
/*
* If we are still pending a previous update, wait.. when the
* pending update completes, we get kicked again.
*/
if (omap_crtc->apply_irq.registered)
goto out;
/* finish up previous apply's: */
list_for_each_entry_safe(apply, n,
&omap_crtc->pending_applies, pending_node) {
apply->post_apply(apply);
list_del(&apply->pending_node);
}
need_apply = !list_empty(&omap_crtc->queued_applies);
/* then handle the next round of of queued apply's: */
list_for_each_entry_safe(apply, n,
&omap_crtc->queued_applies, queued_node) {
apply->pre_apply(apply);
list_del(&apply->queued_node);
apply->queued = false;
list_add_tail(&apply->pending_node,
&omap_crtc->pending_applies);
}
if (need_apply) {
enum omap_channel channel = omap_crtc->channel;
DBG("%s: GO", omap_crtc->name);
if (dispc_mgr_is_enabled(channel)) {
dispc_mgr_go(channel);
omap_irq_register(dev, &omap_crtc->apply_irq);
} else {
struct omap_drm_private *priv = dev->dev_private;
queue_work(priv->wq, &omap_crtc->apply_work);
}
}
out:
dispc_runtime_put();
drm_modeset_unlock(&crtc->mutex);
}
int omap_crtc_apply(struct drm_crtc *crtc,
struct omap_drm_apply *apply)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
/* no need to queue it again if it is already queued: */
if (apply->queued)
return 0;
apply->queued = true;
list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
/*
* If there are no currently pending updates, then go ahead and
* kick the worker immediately, otherwise it will run again when
* the current update finishes.
*/
if (list_empty(&omap_crtc->pending_applies)) {
struct omap_drm_private *priv = crtc->dev->dev_private;
queue_work(priv->wq, &omap_crtc->apply_work);
}
return 0;
}
static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
{
struct omap_crtc *omap_crtc =
container_of(apply, struct omap_crtc, apply);
struct drm_crtc *crtc = &omap_crtc->base;
struct omap_drm_private *priv = crtc->dev->dev_private;
struct drm_encoder *encoder = NULL;
unsigned int i;
DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled);
for (i = 0; i < priv->num_encoders; i++) {
if (priv->encoders[i]->crtc == crtc) {
encoder = priv->encoders[i];
break;
}
}
if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
omap_encoder_set_enabled(omap_crtc->current_encoder, false);
omap_crtc->current_encoder = encoder;
if (!omap_crtc->enabled) {
if (encoder)
omap_encoder_set_enabled(encoder, false);
} else {
if (encoder) {
omap_encoder_set_enabled(encoder, false);
omap_encoder_update(encoder, omap_crtc->mgr,
&omap_crtc->timings);
omap_encoder_set_enabled(encoder, true);
}
}
}
static void omap_crtc_post_apply(struct omap_drm_apply *apply)
{
/* nothing needed for post-apply */
}
void omap_crtc_flush(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
int loops = 0;
while (!list_empty(&omap_crtc->pending_applies) ||
!list_empty(&omap_crtc->queued_applies) ||
omap_crtc->event || omap_crtc->old_fb) {
if (++loops > 10) {
dev_err(crtc->dev->dev,
"omap_crtc_flush() timeout\n");
break;
}
schedule_timeout_uninterruptible(msecs_to_jiffies(20));
}
}
/* -----------------------------------------------------------------------------
* CRTC Functions
*/ */
static void omap_crtc_destroy(struct drm_crtc *crtc) static void omap_crtc_destroy(struct drm_crtc *crtc)
...@@ -214,17 +471,13 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -214,17 +471,13 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
if (enabled != omap_crtc->enabled) { if (enabled != omap_crtc->enabled) {
omap_crtc->enabled = enabled; omap_crtc->enabled = enabled;
omap_crtc->full_update = true;
omap_crtc_apply(crtc, &omap_crtc->apply); omap_crtc_apply(crtc, &omap_crtc->apply);
/* also enable our private plane: */ /* Enable/disable all planes associated with the CRTC. */
WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
/* and any attached overlay planes: */
for (i = 0; i < priv->num_planes; i++) { for (i = 0; i < priv->num_planes; i++) {
struct drm_plane *plane = priv->planes[i]; struct drm_plane *plane = priv->planes[i];
if (plane->crtc == crtc) if (plane->crtc == crtc)
WARN_ON(omap_plane_dpms(plane, mode)); WARN_ON(omap_plane_set_enable(plane, enabled));
} }
} }
} }
...@@ -256,12 +509,16 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, ...@@ -256,12 +509,16 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
mode->type, mode->flags); mode->type, mode->flags);
copy_timings_drm_to_omap(&omap_crtc->timings, mode); copy_timings_drm_to_omap(&omap_crtc->timings, mode);
omap_crtc->full_update = true;
return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb, /*
* The primary plane CRTC can be reset if the plane is disabled directly
* through the universal plane API. Set it again here.
*/
crtc->primary->crtc = crtc;
return omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
0, 0, mode->hdisplay, mode->vdisplay, 0, 0, mode->hdisplay, mode->vdisplay,
x << 16, y << 16, x, y, mode->hdisplay, mode->vdisplay,
mode->hdisplay << 16, mode->vdisplay << 16,
NULL, NULL); NULL, NULL);
} }
...@@ -282,14 +539,12 @@ static void omap_crtc_commit(struct drm_crtc *crtc) ...@@ -282,14 +539,12 @@ static void omap_crtc_commit(struct drm_crtc *crtc)
static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_plane *plane = crtc->primary;
struct drm_plane *plane = omap_crtc->plane;
struct drm_display_mode *mode = &crtc->mode; struct drm_display_mode *mode = &crtc->mode;
return omap_plane_mode_set(plane, crtc, crtc->primary->fb, return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
0, 0, mode->hdisplay, mode->vdisplay, 0, 0, mode->hdisplay, mode->vdisplay,
x << 16, y << 16, x, y, mode->hdisplay, mode->vdisplay,
mode->hdisplay << 16, mode->vdisplay << 16,
NULL, NULL); NULL, NULL);
} }
...@@ -299,6 +554,7 @@ static void vblank_cb(void *arg) ...@@ -299,6 +554,7 @@ static void vblank_cb(void *arg)
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
unsigned long flags; unsigned long flags;
struct drm_framebuffer *fb;
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
...@@ -306,10 +562,15 @@ static void vblank_cb(void *arg) ...@@ -306,10 +562,15 @@ static void vblank_cb(void *arg)
if (omap_crtc->event) if (omap_crtc->event)
drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
fb = omap_crtc->old_fb;
omap_crtc->event = NULL; omap_crtc->event = NULL;
omap_crtc->old_fb = NULL; omap_crtc->old_fb = NULL;
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
if (fb)
drm_framebuffer_unreference(fb);
} }
static void page_flip_worker(struct work_struct *work) static void page_flip_worker(struct work_struct *work)
...@@ -321,10 +582,9 @@ static void page_flip_worker(struct work_struct *work) ...@@ -321,10 +582,9 @@ static void page_flip_worker(struct work_struct *work)
struct drm_gem_object *bo; struct drm_gem_object *bo;
drm_modeset_lock(&crtc->mutex, NULL); drm_modeset_lock(&crtc->mutex, NULL);
omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb, omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
0, 0, mode->hdisplay, mode->vdisplay, 0, 0, mode->hdisplay, mode->vdisplay,
crtc->x << 16, crtc->y << 16, crtc->x, crtc->y, mode->hdisplay, mode->vdisplay,
mode->hdisplay << 16, mode->vdisplay << 16,
vblank_cb, crtc); vblank_cb, crtc);
drm_modeset_unlock(&crtc->mutex); drm_modeset_unlock(&crtc->mutex);
...@@ -361,11 +621,12 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, ...@@ -361,11 +621,12 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
if (omap_crtc->old_fb) { if (omap_crtc->old_fb) {
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
dev_err(dev->dev, "already a pending flip\n"); dev_err(dev->dev, "already a pending flip\n");
return -EINVAL; return -EBUSY;
} }
omap_crtc->event = event; omap_crtc->event = event;
omap_crtc->old_fb = primary->fb = fb; omap_crtc->old_fb = primary->fb = fb;
drm_framebuffer_reference(omap_crtc->old_fb);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
...@@ -385,7 +646,6 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, ...@@ -385,7 +646,6 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
static int omap_crtc_set_property(struct drm_crtc *crtc, static int omap_crtc_set_property(struct drm_crtc *crtc,
struct drm_property *property, uint64_t val) struct drm_property *property, uint64_t val)
{ {
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_drm_private *priv = crtc->dev->dev_private; struct omap_drm_private *priv = crtc->dev->dev_private;
if (property == priv->rotation_prop) { if (property == priv->rotation_prop) {
...@@ -393,7 +653,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, ...@@ -393,7 +653,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270))); !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
} }
return omap_plane_set_property(omap_crtc->plane, property, val); return omap_plane_set_property(crtc->primary, property, val);
} }
static const struct drm_crtc_funcs omap_crtc_funcs = { static const struct drm_crtc_funcs omap_crtc_funcs = {
...@@ -412,250 +672,9 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { ...@@ -412,250 +672,9 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
.mode_set_base = omap_crtc_mode_set_base, .mode_set_base = omap_crtc_mode_set_base,
}; };
const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc) /* -----------------------------------------------------------------------------
{ * Init and Cleanup
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
return &omap_crtc->timings;
}
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
return omap_crtc->channel;
}
static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{
struct omap_crtc *omap_crtc =
container_of(irq, struct omap_crtc, error_irq);
struct drm_crtc *crtc = &omap_crtc->base;
DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
/* avoid getting in a flood, unregister the irq until next vblank */
__omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
}
static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{
struct omap_crtc *omap_crtc =
container_of(irq, struct omap_crtc, apply_irq);
struct drm_crtc *crtc = &omap_crtc->base;
if (!omap_crtc->error_irq.registered)
__omap_irq_register(crtc->dev, &omap_crtc->error_irq);
if (!dispc_mgr_go_busy(omap_crtc->channel)) {
struct omap_drm_private *priv =
crtc->dev->dev_private;
DBG("%s: apply done", omap_crtc->name);
__omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
queue_work(priv->wq, &omap_crtc->apply_work);
}
}
static void apply_worker(struct work_struct *work)
{
struct omap_crtc *omap_crtc =
container_of(work, struct omap_crtc, apply_work);
struct drm_crtc *crtc = &omap_crtc->base;
struct drm_device *dev = crtc->dev;
struct omap_drm_apply *apply, *n;
bool need_apply;
/*
* Synchronize everything on mode_config.mutex, to keep
* the callbacks and list modification all serialized
* with respect to modesetting ioctls from userspace.
*/ */
drm_modeset_lock(&crtc->mutex, NULL);
dispc_runtime_get();
/*
* If we are still pending a previous update, wait.. when the
* pending update completes, we get kicked again.
*/
if (omap_crtc->apply_irq.registered)
goto out;
/* finish up previous apply's: */
list_for_each_entry_safe(apply, n,
&omap_crtc->pending_applies, pending_node) {
apply->post_apply(apply);
list_del(&apply->pending_node);
}
need_apply = !list_empty(&omap_crtc->queued_applies);
/* then handle the next round of of queued apply's: */
list_for_each_entry_safe(apply, n,
&omap_crtc->queued_applies, queued_node) {
apply->pre_apply(apply);
list_del(&apply->queued_node);
apply->queued = false;
list_add_tail(&apply->pending_node,
&omap_crtc->pending_applies);
}
if (need_apply) {
enum omap_channel channel = omap_crtc->channel;
DBG("%s: GO", omap_crtc->name);
if (dispc_mgr_is_enabled(channel)) {
omap_irq_register(dev, &omap_crtc->apply_irq);
dispc_mgr_go(channel);
} else {
struct omap_drm_private *priv = dev->dev_private;
queue_work(priv->wq, &omap_crtc->apply_work);
}
}
out:
dispc_runtime_put();
drm_modeset_unlock(&crtc->mutex);
}
int omap_crtc_apply(struct drm_crtc *crtc,
struct omap_drm_apply *apply)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
/* no need to queue it again if it is already queued: */
if (apply->queued)
return 0;
apply->queued = true;
list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
/*
* If there are no currently pending updates, then go ahead and
* kick the worker immediately, otherwise it will run again when
* the current update finishes.
*/
if (list_empty(&omap_crtc->pending_applies)) {
struct omap_drm_private *priv = crtc->dev->dev_private;
queue_work(priv->wq, &omap_crtc->apply_work);
}
return 0;
}
/* called only from apply */
static void set_enabled(struct drm_crtc *crtc, bool enable)
{
struct drm_device *dev = crtc->dev;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
enum omap_channel channel = omap_crtc->channel;
struct omap_irq_wait *wait;
u32 framedone_irq, vsync_irq;
int ret;
if (dispc_mgr_is_enabled(channel) == enable)
return;
/*
* Digit output produces some sync lost interrupts during the first
* frame when enabling, so we need to ignore those.
*/
omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
framedone_irq = dispc_mgr_get_framedone_irq(channel);
vsync_irq = dispc_mgr_get_vsync_irq(channel);
if (enable) {
wait = omap_irq_wait_init(dev, vsync_irq, 1);
} else {
/*
* When we disable the digit output, we need to wait for
* FRAMEDONE to know that DISPC has finished with the output.
*
* OMAP2/3 does not have FRAMEDONE irq for digit output, and in
* that case we need to use vsync interrupt, and wait for both
* even and odd frames.
*/
if (framedone_irq)
wait = omap_irq_wait_init(dev, framedone_irq, 1);
else
wait = omap_irq_wait_init(dev, vsync_irq, 2);
}
dispc_mgr_enable(channel, enable);
ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
if (ret) {
dev_err(dev->dev, "%s: timeout waiting for %s\n",
omap_crtc->name, enable ? "enable" : "disable");
}
omap_irq_register(crtc->dev, &omap_crtc->error_irq);
}
static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
{
struct omap_crtc *omap_crtc =
container_of(apply, struct omap_crtc, apply);
struct drm_crtc *crtc = &omap_crtc->base;
struct drm_encoder *encoder = NULL;
DBG("%s: enabled=%d, full=%d", omap_crtc->name,
omap_crtc->enabled, omap_crtc->full_update);
if (omap_crtc->full_update) {
struct omap_drm_private *priv = crtc->dev->dev_private;
int i;
for (i = 0; i < priv->num_encoders; i++) {
if (priv->encoders[i]->crtc == crtc) {
encoder = priv->encoders[i];
break;
}
}
}
if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
omap_encoder_set_enabled(omap_crtc->current_encoder, false);
omap_crtc->current_encoder = encoder;
if (!omap_crtc->enabled) {
if (encoder)
omap_encoder_set_enabled(encoder, false);
} else {
if (encoder) {
omap_encoder_set_enabled(encoder, false);
omap_encoder_update(encoder, omap_crtc->mgr,
&omap_crtc->timings);
omap_encoder_set_enabled(encoder, true);
}
}
omap_crtc->full_update = false;
}
static void omap_crtc_post_apply(struct omap_drm_apply *apply)
{
/* nothing needed for post-apply */
}
void omap_crtc_flush(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
int loops = 0;
while (!list_empty(&omap_crtc->pending_applies) ||
!list_empty(&omap_crtc->queued_applies) ||
omap_crtc->event || omap_crtc->old_fb) {
if (++loops > 10) {
dev_err(crtc->dev->dev,
"omap_crtc_flush() timeout\n");
break;
}
schedule_timeout_uninterruptible(msecs_to_jiffies(20));
}
}
static const char *channel_names[] = { static const char *channel_names[] = {
[OMAP_DSS_CHANNEL_LCD] = "lcd", [OMAP_DSS_CHANNEL_LCD] = "lcd",
...@@ -681,12 +700,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -681,12 +700,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_crtc *crtc = NULL; struct drm_crtc *crtc = NULL;
struct omap_crtc *omap_crtc; struct omap_crtc *omap_crtc;
struct omap_overlay_manager_info *info; struct omap_overlay_manager_info *info;
int ret;
DBG("%s", channel_names[channel]); DBG("%s", channel_names[channel]);
omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
if (!omap_crtc) if (!omap_crtc)
goto fail; return NULL;
crtc = &omap_crtc->base; crtc = &omap_crtc->base;
...@@ -700,8 +720,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -700,8 +720,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc->apply.post_apply = omap_crtc_post_apply; omap_crtc->apply.post_apply = omap_crtc_post_apply;
omap_crtc->channel = channel; omap_crtc->channel = channel;
omap_crtc->plane = plane;
omap_crtc->plane->crtc = crtc;
omap_crtc->name = channel_names[channel]; omap_crtc->name = channel_names[channel];
omap_crtc->pipe = id; omap_crtc->pipe = id;
...@@ -723,18 +741,18 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -723,18 +741,18 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
info->trans_enabled = false; info->trans_enabled = false;
drm_crtc_init(dev, crtc, &omap_crtc_funcs); ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
&omap_crtc_funcs);
if (ret < 0) {
kfree(omap_crtc);
return NULL;
}
drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
omap_plane_install_properties(omap_crtc->plane, &crtc->base); omap_plane_install_properties(crtc->primary, &crtc->base);
omap_crtcs[channel] = omap_crtc; omap_crtcs[channel] = omap_crtc;
return crtc; return crtc;
fail:
if (crtc)
omap_crtc_destroy(crtc);
return NULL;
} }
...@@ -148,11 +148,15 @@ struct refill_engine { ...@@ -148,11 +148,15 @@ struct refill_engine {
bool async; bool async;
wait_queue_head_t wait_for_refill; struct completion compl;
struct list_head idle_node; struct list_head idle_node;
}; };
struct dmm_platform_data {
uint32_t cpu_cache_flags;
};
struct dmm { struct dmm {
struct device *dev; struct device *dev;
void __iomem *base; void __iomem *base;
...@@ -183,6 +187,8 @@ struct dmm { ...@@ -183,6 +187,8 @@ struct dmm {
/* allocation list and lock */ /* allocation list and lock */
struct list_head alloc_head; struct list_head alloc_head;
const struct dmm_platform_data *plat_data;
}; };
#endif #endif
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/completion.h>
#include "omap_dmm_tiler.h" #include "omap_dmm_tiler.h"
#include "omap_dmm_priv.h" #include "omap_dmm_priv.h"
...@@ -39,6 +40,10 @@ ...@@ -39,6 +40,10 @@
static struct tcm *containers[TILFMT_NFORMATS]; static struct tcm *containers[TILFMT_NFORMATS];
static struct dmm *omap_dmm; static struct dmm *omap_dmm;
#if defined(CONFIG_OF)
static const struct of_device_id dmm_of_match[];
#endif
/* global spinlock for protecting lists */ /* global spinlock for protecting lists */
static DEFINE_SPINLOCK(list_lock); static DEFINE_SPINLOCK(list_lock);
...@@ -142,10 +147,10 @@ static irqreturn_t omap_dmm_irq_handler(int irq, void *arg) ...@@ -142,10 +147,10 @@ static irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
for (i = 0; i < dmm->num_engines; i++) { for (i = 0; i < dmm->num_engines; i++) {
if (status & DMM_IRQSTAT_LST) { if (status & DMM_IRQSTAT_LST) {
wake_up_interruptible(&dmm->engines[i].wait_for_refill);
if (dmm->engines[i].async) if (dmm->engines[i].async)
release_engine(&dmm->engines[i]); release_engine(&dmm->engines[i]);
complete(&dmm->engines[i].compl);
} }
status >>= 8; status >>= 8;
...@@ -269,15 +274,17 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait) ...@@ -269,15 +274,17 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
/* mark whether it is async to denote list management in IRQ handler */ /* mark whether it is async to denote list management in IRQ handler */
engine->async = wait ? false : true; engine->async = wait ? false : true;
reinit_completion(&engine->compl);
/* verify that the irq handler sees the 'async' and completion value */
smp_mb();
/* kick reload */ /* kick reload */
writel(engine->refill_pa, writel(engine->refill_pa,
dmm->base + reg[PAT_DESCR][engine->id]); dmm->base + reg[PAT_DESCR][engine->id]);
if (wait) { if (wait) {
if (wait_event_interruptible_timeout(engine->wait_for_refill, if (!wait_for_completion_timeout(&engine->compl,
wait_status(engine, DMM_PATSTATUS_READY) == 0, msecs_to_jiffies(1))) {
msecs_to_jiffies(1)) <= 0) {
dev_err(dmm->dev, "timed out waiting for done\n"); dev_err(dmm->dev, "timed out waiting for done\n");
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} }
...@@ -529,6 +536,11 @@ size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h) ...@@ -529,6 +536,11 @@ size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h)
return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h; return round_up(geom[fmt].cpp * w, PAGE_SIZE) * h;
} }
uint32_t tiler_get_cpu_cache_flags(void)
{
return omap_dmm->plat_data->cpu_cache_flags;
}
bool dmm_is_available(void) bool dmm_is_available(void)
{ {
return omap_dmm ? true : false; return omap_dmm ? true : false;
...@@ -592,6 +604,18 @@ static int omap_dmm_probe(struct platform_device *dev) ...@@ -592,6 +604,18 @@ static int omap_dmm_probe(struct platform_device *dev)
init_waitqueue_head(&omap_dmm->engine_queue); init_waitqueue_head(&omap_dmm->engine_queue);
if (dev->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(dmm_of_match, dev->dev.of_node);
if (!match) {
dev_err(&dev->dev, "failed to find matching device node\n");
return -ENODEV;
}
omap_dmm->plat_data = match->data;
}
/* lookup hwmod data - base address and irq */ /* lookup hwmod data - base address and irq */
mem = platform_get_resource(dev, IORESOURCE_MEM, 0); mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!mem) { if (!mem) {
...@@ -696,7 +720,7 @@ static int omap_dmm_probe(struct platform_device *dev) ...@@ -696,7 +720,7 @@ static int omap_dmm_probe(struct platform_device *dev)
(REFILL_BUFFER_SIZE * i); (REFILL_BUFFER_SIZE * i);
omap_dmm->engines[i].refill_pa = omap_dmm->refill_pa + omap_dmm->engines[i].refill_pa = omap_dmm->refill_pa +
(REFILL_BUFFER_SIZE * i); (REFILL_BUFFER_SIZE * i);
init_waitqueue_head(&omap_dmm->engines[i].wait_for_refill); init_completion(&omap_dmm->engines[i].compl);
list_add(&omap_dmm->engines[i].idle_node, &omap_dmm->idle_head); list_add(&omap_dmm->engines[i].idle_node, &omap_dmm->idle_head);
} }
...@@ -941,7 +965,7 @@ int tiler_map_show(struct seq_file *s, void *arg) ...@@ -941,7 +965,7 @@ int tiler_map_show(struct seq_file *s, void *arg)
} }
#endif #endif
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int omap_dmm_resume(struct device *dev) static int omap_dmm_resume(struct device *dev)
{ {
struct tcm_area area; struct tcm_area area;
...@@ -965,16 +989,28 @@ static int omap_dmm_resume(struct device *dev) ...@@ -965,16 +989,28 @@ static int omap_dmm_resume(struct device *dev)
return 0; return 0;
} }
static const struct dev_pm_ops omap_dmm_pm_ops = {
.resume = omap_dmm_resume,
};
#endif #endif
static SIMPLE_DEV_PM_OPS(omap_dmm_pm_ops, NULL, omap_dmm_resume);
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
static const struct dmm_platform_data dmm_omap4_platform_data = {
.cpu_cache_flags = OMAP_BO_WC,
};
static const struct dmm_platform_data dmm_omap5_platform_data = {
.cpu_cache_flags = OMAP_BO_UNCACHED,
};
static const struct of_device_id dmm_of_match[] = { static const struct of_device_id dmm_of_match[] = {
{ .compatible = "ti,omap4-dmm", }, {
{ .compatible = "ti,omap5-dmm", }, .compatible = "ti,omap4-dmm",
.data = &dmm_omap4_platform_data,
},
{
.compatible = "ti,omap5-dmm",
.data = &dmm_omap5_platform_data,
},
{}, {},
}; };
#endif #endif
...@@ -986,9 +1022,7 @@ struct platform_driver omap_dmm_driver = { ...@@ -986,9 +1022,7 @@ struct platform_driver omap_dmm_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = DMM_DRIVER_NAME, .name = DMM_DRIVER_NAME,
.of_match_table = of_match_ptr(dmm_of_match), .of_match_table = of_match_ptr(dmm_of_match),
#ifdef CONFIG_PM
.pm = &omap_dmm_pm_ops, .pm = &omap_dmm_pm_ops,
#endif
}, },
}; };
......
...@@ -106,6 +106,7 @@ uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient); ...@@ -106,6 +106,7 @@ uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient);
size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h); size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h); size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h); void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
uint32_t tiler_get_cpu_cache_flags(void);
bool dmm_is_available(void); bool dmm_is_available(void);
extern struct platform_driver omap_dmm_driver; extern struct platform_driver omap_dmm_driver;
......
...@@ -128,6 +128,29 @@ static int omap_connect_dssdevs(void) ...@@ -128,6 +128,29 @@ static int omap_connect_dssdevs(void)
return r; return r;
} }
static int omap_modeset_create_crtc(struct drm_device *dev, int id,
enum omap_channel channel)
{
struct omap_drm_private *priv = dev->dev_private;
struct drm_plane *plane;
struct drm_crtc *crtc;
plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_PRIMARY);
if (IS_ERR(plane))
return PTR_ERR(plane);
crtc = omap_crtc_init(dev, plane, channel, id);
BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
priv->crtcs[id] = crtc;
priv->num_crtcs++;
priv->planes[id] = plane;
priv->num_planes++;
return 0;
}
static int omap_modeset_init(struct drm_device *dev) static int omap_modeset_init(struct drm_device *dev)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
...@@ -136,6 +159,7 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -136,6 +159,7 @@ static int omap_modeset_init(struct drm_device *dev)
int num_mgrs = dss_feat_get_num_mgrs(); int num_mgrs = dss_feat_get_num_mgrs();
int num_crtcs; int num_crtcs;
int i, id = 0; int i, id = 0;
int ret;
drm_mode_config_init(dev); drm_mode_config_init(dev);
...@@ -209,18 +233,13 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -209,18 +233,13 @@ static int omap_modeset_init(struct drm_device *dev)
* allocated crtc, we create a new crtc for it * allocated crtc, we create a new crtc for it
*/ */
if (!channel_used(dev, channel)) { if (!channel_used(dev, channel)) {
struct drm_plane *plane; ret = omap_modeset_create_crtc(dev, id, channel);
struct drm_crtc *crtc; if (ret < 0) {
dev_err(dev->dev,
plane = omap_plane_init(dev, id, true); "could not create CRTC (channel %u)\n",
crtc = omap_crtc_init(dev, plane, channel, id); channel);
return ret;
BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); }
priv->crtcs[id] = crtc;
priv->num_crtcs++;
priv->planes[id] = plane;
priv->num_planes++;
id++; id++;
} }
...@@ -234,26 +253,8 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -234,26 +253,8 @@ static int omap_modeset_init(struct drm_device *dev)
/* find a free manager for this crtc */ /* find a free manager for this crtc */
for (i = 0; i < num_mgrs; i++) { for (i = 0; i < num_mgrs; i++) {
if (!channel_used(dev, i)) { if (!channel_used(dev, i))
struct drm_plane *plane;
struct drm_crtc *crtc;
plane = omap_plane_init(dev, id, true);
crtc = omap_crtc_init(dev, plane, i, id);
BUG_ON(priv->num_crtcs >=
ARRAY_SIZE(priv->crtcs));
priv->crtcs[id] = crtc;
priv->num_crtcs++;
priv->planes[id] = plane;
priv->num_planes++;
break; break;
} else {
continue;
}
} }
if (i == num_mgrs) { if (i == num_mgrs) {
...@@ -261,13 +262,24 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -261,13 +262,24 @@ static int omap_modeset_init(struct drm_device *dev)
dev_err(dev->dev, "no managers left for crtc\n"); dev_err(dev->dev, "no managers left for crtc\n");
return -ENOMEM; return -ENOMEM;
} }
ret = omap_modeset_create_crtc(dev, id, i);
if (ret < 0) {
dev_err(dev->dev,
"could not create CRTC (channel %u)\n", i);
return ret;
}
} }
/* /*
* Create normal planes for the remaining overlays: * Create normal planes for the remaining overlays:
*/ */
for (; id < num_ovls; id++) { for (; id < num_ovls; id++) {
struct drm_plane *plane = omap_plane_init(dev, id, false); struct drm_plane *plane;
plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY);
if (IS_ERR(plane))
return PTR_ERR(plane);
BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
priv->planes[priv->num_planes++] = plane; priv->planes[priv->num_planes++] = plane;
...@@ -286,14 +298,13 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -286,14 +298,13 @@ static int omap_modeset_init(struct drm_device *dev)
for (id = 0; id < priv->num_crtcs; id++) { for (id = 0; id < priv->num_crtcs; id++) {
struct drm_crtc *crtc = priv->crtcs[id]; struct drm_crtc *crtc = priv->crtcs[id];
enum omap_channel crtc_channel; enum omap_channel crtc_channel;
enum omap_dss_output_id supported_outputs;
crtc_channel = omap_crtc_channel(crtc); crtc_channel = omap_crtc_channel(crtc);
supported_outputs =
dss_feat_get_supported_outputs(crtc_channel);
if (supported_outputs & output->id) if (output->dispc_channel == crtc_channel) {
encoder->possible_crtcs |= (1 << id); encoder->possible_crtcs |= (1 << id);
break;
}
} }
omap_dss_put_device(output); omap_dss_put_device(output);
...@@ -480,6 +491,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags) ...@@ -480,6 +491,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
priv->wq = alloc_ordered_workqueue("omapdrm", 0); priv->wq = alloc_ordered_workqueue("omapdrm", 0);
spin_lock_init(&priv->list_lock);
INIT_LIST_HEAD(&priv->obj_list); INIT_LIST_HEAD(&priv->obj_list);
omap_gem_init(dev); omap_gem_init(dev);
...@@ -519,6 +531,7 @@ static int dev_unload(struct drm_device *dev) ...@@ -519,6 +531,7 @@ static int dev_unload(struct drm_device *dev)
drm_kms_helper_poll_fini(dev); drm_kms_helper_poll_fini(dev);
if (priv->fbdev)
omap_fbdev_free(dev); omap_fbdev_free(dev);
/* flush crtcs so the fbs get released */ /* flush crtcs so the fbs get released */
...@@ -588,9 +601,11 @@ static void dev_lastclose(struct drm_device *dev) ...@@ -588,9 +601,11 @@ static void dev_lastclose(struct drm_device *dev)
} }
} }
if (priv->fbdev) {
ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev); ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
if (ret) if (ret)
DBG("failed to restore crtc mode"); DBG("failed to restore crtc mode");
}
} }
static void dev_preclose(struct drm_device *dev, struct drm_file *file) static void dev_preclose(struct drm_device *dev, struct drm_file *file)
...@@ -621,8 +636,8 @@ static const struct file_operations omapdriver_fops = { ...@@ -621,8 +636,8 @@ static const struct file_operations omapdriver_fops = {
}; };
static struct drm_driver omap_drm_driver = { static struct drm_driver omap_drm_driver = {
.driver_features = .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM
DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, | DRIVER_PRIME,
.load = dev_load, .load = dev_load,
.unload = dev_unload, .unload = dev_unload,
.open = dev_open, .open = dev_open,
...@@ -661,23 +676,6 @@ static struct drm_driver omap_drm_driver = { ...@@ -661,23 +676,6 @@ static struct drm_driver omap_drm_driver = {
.patchlevel = DRIVER_PATCHLEVEL, .patchlevel = DRIVER_PATCHLEVEL,
}; };
static int pdev_suspend(struct platform_device *pDevice, pm_message_t state)
{
DBG("");
return 0;
}
static int pdev_resume(struct platform_device *device)
{
DBG("");
return 0;
}
static void pdev_shutdown(struct platform_device *device)
{
DBG("");
}
static int pdev_probe(struct platform_device *device) static int pdev_probe(struct platform_device *device)
{ {
int r; int r;
...@@ -709,24 +707,35 @@ static int pdev_remove(struct platform_device *device) ...@@ -709,24 +707,35 @@ static int pdev_remove(struct platform_device *device)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static const struct dev_pm_ops omapdrm_pm_ops = { static int omap_drm_suspend(struct device *dev)
.resume = omap_gem_resume, {
}; struct drm_device *drm_dev = dev_get_drvdata(dev);
drm_kms_helper_poll_disable(drm_dev);
return 0;
}
static int omap_drm_resume(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
drm_kms_helper_poll_enable(drm_dev);
return omap_gem_resume(dev);
}
#endif #endif
static SIMPLE_DEV_PM_OPS(omapdrm_pm_ops, omap_drm_suspend, omap_drm_resume);
static struct platform_driver pdev = { static struct platform_driver pdev = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
#ifdef CONFIG_PM
.pm = &omapdrm_pm_ops, .pm = &omapdrm_pm_ops,
#endif
}, },
.probe = pdev_probe, .probe = pdev_probe,
.remove = pdev_remove, .remove = pdev_remove,
.suspend = pdev_suspend,
.resume = pdev_resume,
.shutdown = pdev_shutdown,
}; };
static int __init omap_drm_init(void) static int __init omap_drm_init(void)
......
...@@ -105,6 +105,9 @@ struct omap_drm_private { ...@@ -105,6 +105,9 @@ struct omap_drm_private {
struct workqueue_struct *wq; struct workqueue_struct *wq;
/* lock for obj_list below */
spinlock_t list_lock;
/* list of GEM objects: */ /* list of GEM objects: */
struct list_head obj_list; struct list_head obj_list;
...@@ -160,14 +163,14 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -160,14 +163,14 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
void omap_crtc_flush(struct drm_crtc *crtc); void omap_crtc_flush(struct drm_crtc *crtc);
struct drm_plane *omap_plane_init(struct drm_device *dev, struct drm_plane *omap_plane_init(struct drm_device *dev,
int plane_id, bool private_plane); int id, enum drm_plane_type type);
int omap_plane_dpms(struct drm_plane *plane, int mode); int omap_plane_set_enable(struct drm_plane *plane, bool enable);
int omap_plane_mode_set(struct drm_plane *plane, int omap_plane_mode_set(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h, unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y, unsigned int src_x, unsigned int src_y,
uint32_t src_w, uint32_t src_h, unsigned int src_w, unsigned int src_h,
void (*fxn)(void *), void *arg); void (*fxn)(void *), void *arg);
void omap_plane_install_properties(struct drm_plane *plane, void omap_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj); struct drm_mode_object *obj);
...@@ -186,8 +189,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, ...@@ -186,8 +189,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
struct drm_encoder *encoder); struct drm_encoder *encoder);
struct drm_encoder *omap_connector_attached_encoder( struct drm_encoder *omap_connector_attached_encoder(
struct drm_connector *connector); struct drm_connector *connector);
void omap_connector_flush(struct drm_connector *connector,
int x, int y, int w, int h);
bool omap_connector_get_hdmi_mode(struct drm_connector *connector); bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
void copy_timings_omap_to_drm(struct drm_display_mode *mode, void copy_timings_omap_to_drm(struct drm_display_mode *mode,
...@@ -208,8 +209,6 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, ...@@ -208,8 +209,6 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
struct omap_drm_window *win, struct omap_overlay_info *info); struct omap_drm_window *win, struct omap_overlay_info *info);
struct drm_connector *omap_framebuffer_get_next_connector( struct drm_connector *omap_framebuffer_get_next_connector(
struct drm_framebuffer *fb, struct drm_connector *from); struct drm_framebuffer *fb, struct drm_connector *from);
void omap_framebuffer_flush(struct drm_framebuffer *fb,
int x, int y, int w, int h);
void omap_gem_init(struct drm_device *dev); void omap_gem_init(struct drm_device *dev);
void omap_gem_deinit(struct drm_device *dev); void omap_gem_deinit(struct drm_device *dev);
......
...@@ -86,6 +86,7 @@ struct plane { ...@@ -86,6 +86,7 @@ struct plane {
struct omap_framebuffer { struct omap_framebuffer {
struct drm_framebuffer base; struct drm_framebuffer base;
int pin_count;
const struct format *format; const struct format *format;
struct plane planes[4]; struct plane planes[4];
}; };
...@@ -121,18 +122,6 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb, ...@@ -121,18 +122,6 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_file *file_priv, unsigned flags, unsigned color,
struct drm_clip_rect *clips, unsigned num_clips) struct drm_clip_rect *clips, unsigned num_clips)
{ {
int i;
drm_modeset_lock_all(fb->dev);
for (i = 0; i < num_clips; i++) {
omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1,
clips[i].x2 - clips[i].x1,
clips[i].y2 - clips[i].y1);
}
drm_modeset_unlock_all(fb->dev);
return 0; return 0;
} }
...@@ -261,6 +250,11 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb) ...@@ -261,6 +250,11 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
int ret, i, n = drm_format_num_planes(fb->pixel_format); int ret, i, n = drm_format_num_planes(fb->pixel_format);
if (omap_fb->pin_count > 0) {
omap_fb->pin_count++;
return 0;
}
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
struct plane *plane = &omap_fb->planes[i]; struct plane *plane = &omap_fb->planes[i];
ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true); ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
...@@ -269,6 +263,8 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb) ...@@ -269,6 +263,8 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE); omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE);
} }
omap_fb->pin_count++;
return 0; return 0;
fail: fail:
...@@ -287,6 +283,11 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb) ...@@ -287,6 +283,11 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb)
struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
int ret, i, n = drm_format_num_planes(fb->pixel_format); int ret, i, n = drm_format_num_planes(fb->pixel_format);
omap_fb->pin_count--;
if (omap_fb->pin_count > 0)
return 0;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
struct plane *plane = &omap_fb->planes[i]; struct plane *plane = &omap_fb->planes[i];
ret = omap_gem_put_paddr(plane->bo); ret = omap_gem_put_paddr(plane->bo);
...@@ -336,34 +337,6 @@ struct drm_connector *omap_framebuffer_get_next_connector( ...@@ -336,34 +337,6 @@ struct drm_connector *omap_framebuffer_get_next_connector(
return NULL; return NULL;
} }
/* flush an area of the framebuffer (in case of manual update display that
* is not automatically flushed)
*/
void omap_framebuffer_flush(struct drm_framebuffer *fb,
int x, int y, int w, int h)
{
struct drm_connector *connector = NULL;
VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb);
/* FIXME: This is racy - no protection against modeset config changes. */
while ((connector = omap_framebuffer_get_next_connector(fb, connector))) {
/* only consider connectors that are part of a chain */
if (connector->encoder && connector->encoder->crtc) {
/* TODO: maybe this should propagate thru the crtc who
* could do the coordinate translation..
*/
struct drm_crtc *crtc = connector->encoder->crtc;
int cx = max(0, x - crtc->x);
int cy = max(0, y - crtc->y);
int cw = w + (x - crtc->x) - cx;
int ch = h + (y - crtc->y) - cy;
omap_connector_flush(connector, cx, cy, cw, ch);
}
}
}
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
{ {
...@@ -407,7 +380,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, ...@@ -407,7 +380,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
{ {
struct omap_framebuffer *omap_fb; struct omap_framebuffer *omap_fb = NULL;
struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fb = NULL;
const struct format *format = NULL; const struct format *format = NULL;
int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
...@@ -450,6 +423,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, ...@@ -450,6 +423,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
goto fail; goto fail;
} }
if (pitch % format->planes[i].stride_bpp != 0) {
dev_err(dev->dev,
"buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n",
pitch, format->planes[i].stride_bpp);
ret = -EINVAL;
goto fail;
}
size = pitch * mode_cmd->height / format->planes[i].sub_y; size = pitch * mode_cmd->height / format->planes[i].sub_y;
if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) { if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
...@@ -478,8 +459,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, ...@@ -478,8 +459,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
return fb; return fb;
fail: fail:
if (fb) kfree(omap_fb);
omap_framebuffer_destroy(fb);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
...@@ -42,42 +42,8 @@ struct omap_fbdev { ...@@ -42,42 +42,8 @@ struct omap_fbdev {
struct work_struct work; struct work_struct work;
}; };
static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h);
static struct drm_fb_helper *get_fb(struct fb_info *fbi); static struct drm_fb_helper *get_fb(struct fb_info *fbi);
static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf,
size_t count, loff_t *ppos)
{
ssize_t res;
res = fb_sys_write(fbi, buf, count, ppos);
omap_fbdev_flush(fbi, 0, 0, fbi->var.xres, fbi->var.yres);
return res;
}
static void omap_fbdev_fillrect(struct fb_info *fbi,
const struct fb_fillrect *rect)
{
sys_fillrect(fbi, rect);
omap_fbdev_flush(fbi, rect->dx, rect->dy, rect->width, rect->height);
}
static void omap_fbdev_copyarea(struct fb_info *fbi,
const struct fb_copyarea *area)
{
sys_copyarea(fbi, area);
omap_fbdev_flush(fbi, area->dx, area->dy, area->width, area->height);
}
static void omap_fbdev_imageblit(struct fb_info *fbi,
const struct fb_image *image)
{
sys_imageblit(fbi, image);
omap_fbdev_flush(fbi, image->dx, image->dy,
image->width, image->height);
}
static void pan_worker(struct work_struct *work) static void pan_worker(struct work_struct *work)
{ {
struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work); struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work);
...@@ -121,10 +87,10 @@ static struct fb_ops omap_fb_ops = { ...@@ -121,10 +87,10 @@ static struct fb_ops omap_fb_ops = {
* basic fbdev ops which write to the framebuffer * basic fbdev ops which write to the framebuffer
*/ */
.fb_read = fb_sys_read, .fb_read = fb_sys_read,
.fb_write = omap_fbdev_write, .fb_write = fb_sys_write,
.fb_fillrect = omap_fbdev_fillrect, .fb_fillrect = sys_fillrect,
.fb_copyarea = omap_fbdev_copyarea, .fb_copyarea = sys_copyarea,
.fb_imageblit = omap_fbdev_imageblit, .fb_imageblit = sys_imageblit,
.fb_check_var = drm_fb_helper_check_var, .fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par, .fb_set_par = drm_fb_helper_set_par,
...@@ -294,21 +260,6 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi) ...@@ -294,21 +260,6 @@ static struct drm_fb_helper *get_fb(struct fb_info *fbi)
return fbi->par; return fbi->par;
} }
/* flush an area of the framebuffer (in case of manual update display that
* is not automatically flushed)
*/
static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h)
{
struct drm_fb_helper *helper = get_fb(fbi);
if (!helper)
return;
VERB("flush fbdev: %d,%d %dx%d, fbi=%p", x, y, w, h, fbi);
omap_framebuffer_flush(helper->fb, x, y, w, h);
}
/* initialize fbdev helper */ /* initialize fbdev helper */
struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
{ {
......
...@@ -828,6 +828,7 @@ int omap_gem_put_paddr(struct drm_gem_object *obj) ...@@ -828,6 +828,7 @@ int omap_gem_put_paddr(struct drm_gem_object *obj)
dev_err(obj->dev->dev, dev_err(obj->dev->dev,
"could not release unmap: %d\n", ret); "could not release unmap: %d\n", ret);
} }
omap_obj->paddr = 0;
omap_obj->block = NULL; omap_obj->block = NULL;
} }
} }
...@@ -1272,13 +1273,16 @@ int omap_gem_set_sync_object(struct drm_gem_object *obj, void *syncobj) ...@@ -1272,13 +1273,16 @@ int omap_gem_set_sync_object(struct drm_gem_object *obj, void *syncobj)
void omap_gem_free_object(struct drm_gem_object *obj) void omap_gem_free_object(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
struct omap_drm_private *priv = dev->dev_private;
struct omap_gem_object *omap_obj = to_omap_bo(obj); struct omap_gem_object *omap_obj = to_omap_bo(obj);
evict(obj); evict(obj);
WARN_ON(!mutex_is_locked(&dev->struct_mutex)); WARN_ON(!mutex_is_locked(&dev->struct_mutex));
spin_lock(&priv->list_lock);
list_del(&omap_obj->mm_list); list_del(&omap_obj->mm_list);
spin_unlock(&priv->list_lock);
drm_gem_free_mmap_offset(obj); drm_gem_free_mmap_offset(obj);
...@@ -1358,8 +1362,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, ...@@ -1358,8 +1362,8 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
/* currently don't allow cached buffers.. there is some caching /* currently don't allow cached buffers.. there is some caching
* stuff that needs to be handled better * stuff that needs to be handled better
*/ */
flags &= ~(OMAP_BO_CACHED|OMAP_BO_UNCACHED); flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED);
flags |= OMAP_BO_WC; flags |= tiler_get_cpu_cache_flags();
/* align dimensions to slot boundaries... */ /* align dimensions to slot boundaries... */
tiler_align(gem2fmt(flags), tiler_align(gem2fmt(flags),
...@@ -1376,7 +1380,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, ...@@ -1376,7 +1380,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
if (!omap_obj) if (!omap_obj)
goto fail; goto fail;
spin_lock(&priv->list_lock);
list_add(&omap_obj->mm_list, &priv->obj_list); list_add(&omap_obj->mm_list, &priv->obj_list);
spin_unlock(&priv->list_lock);
obj = &omap_obj->base; obj = &omap_obj->base;
......
...@@ -34,7 +34,7 @@ static void omap_irq_update(struct drm_device *dev) ...@@ -34,7 +34,7 @@ static void omap_irq_update(struct drm_device *dev)
struct omap_drm_irq *irq; struct omap_drm_irq *irq;
uint32_t irqmask = priv->vblank_mask; uint32_t irqmask = priv->vblank_mask;
BUG_ON(!spin_is_locked(&list_lock)); assert_spin_locked(&list_lock);
list_for_each_entry(irq, &priv->irq_list, node) list_for_each_entry(irq, &priv->irq_list, node)
irqmask |= irq->irqmask; irqmask |= irq->irqmask;
......
...@@ -65,12 +65,16 @@ struct omap_plane { ...@@ -65,12 +65,16 @@ struct omap_plane {
struct callback apply_done_cb; struct callback apply_done_cb;
}; };
static void unpin_worker(struct drm_flip_work *work, void *val) static void omap_plane_unpin_worker(struct drm_flip_work *work, void *val)
{ {
struct omap_plane *omap_plane = struct omap_plane *omap_plane =
container_of(work, struct omap_plane, unpin_work); container_of(work, struct omap_plane, unpin_work);
struct drm_device *dev = omap_plane->base.dev; struct drm_device *dev = omap_plane->base.dev;
/*
* omap_framebuffer_pin/unpin are always called from priv->wq,
* so there's no need for locking here.
*/
omap_framebuffer_unpin(val); omap_framebuffer_unpin(val);
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
drm_framebuffer_unreference(val); drm_framebuffer_unreference(val);
...@@ -78,7 +82,8 @@ static void unpin_worker(struct drm_flip_work *work, void *val) ...@@ -78,7 +82,8 @@ static void unpin_worker(struct drm_flip_work *work, void *val)
} }
/* update which fb (if any) is pinned for scanout */ /* update which fb (if any) is pinned for scanout */
static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) static int omap_plane_update_pin(struct drm_plane *plane,
struct drm_framebuffer *fb)
{ {
struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_plane *omap_plane = to_omap_plane(plane);
struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb; struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb;
...@@ -121,13 +126,12 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply) ...@@ -121,13 +126,12 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
struct drm_crtc *crtc = plane->crtc; struct drm_crtc *crtc = plane->crtc;
enum omap_channel channel; enum omap_channel channel;
bool enabled = omap_plane->enabled && crtc; bool enabled = omap_plane->enabled && crtc;
bool ilace, replication;
int ret; int ret;
DBG("%s, enabled=%d", omap_plane->name, enabled); DBG("%s, enabled=%d", omap_plane->name, enabled);
/* if fb has changed, pin new fb: */ /* if fb has changed, pin new fb: */
update_pin(plane, enabled ? plane->fb : NULL); omap_plane_update_pin(plane, enabled ? plane->fb : NULL);
if (!enabled) { if (!enabled) {
dispc_ovl_enable(omap_plane->id, false); dispc_ovl_enable(omap_plane->id, false);
...@@ -145,20 +149,17 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply) ...@@ -145,20 +149,17 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
DBG("%d,%d %pad %pad", info->pos_x, info->pos_y, DBG("%d,%d %pad %pad", info->pos_x, info->pos_y,
&info->paddr, &info->p_uv_addr); &info->paddr, &info->p_uv_addr);
/* TODO: */ dispc_ovl_set_channel_out(omap_plane->id, channel);
ilace = false;
replication = false;
/* and finally, update omapdss: */ /* and finally, update omapdss: */
ret = dispc_ovl_setup(omap_plane->id, info, ret = dispc_ovl_setup(omap_plane->id, info, false,
replication, omap_crtc_timings(crtc), false); omap_crtc_timings(crtc), false);
if (ret) { if (ret) {
dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret); dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
return; return;
} }
dispc_ovl_enable(omap_plane->id, true); dispc_ovl_enable(omap_plane->id, true);
dispc_ovl_set_channel_out(omap_plane->id, channel);
} }
static void omap_plane_post_apply(struct omap_drm_apply *apply) static void omap_plane_post_apply(struct omap_drm_apply *apply)
...@@ -167,7 +168,6 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply) ...@@ -167,7 +168,6 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
container_of(apply, struct omap_plane, apply); container_of(apply, struct omap_plane, apply);
struct drm_plane *plane = &omap_plane->base; struct drm_plane *plane = &omap_plane->base;
struct omap_drm_private *priv = plane->dev->dev_private; struct omap_drm_private *priv = plane->dev->dev_private;
struct omap_overlay_info *info = &omap_plane->info;
struct callback cb; struct callback cb;
cb = omap_plane->apply_done_cb; cb = omap_plane->apply_done_cb;
...@@ -177,14 +177,9 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply) ...@@ -177,14 +177,9 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
if (cb.fxn) if (cb.fxn)
cb.fxn(cb.arg); cb.fxn(cb.arg);
if (omap_plane->enabled) {
omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
info->out_width, info->out_height);
}
} }
static int apply(struct drm_plane *plane) static int omap_plane_apply(struct drm_plane *plane)
{ {
if (plane->crtc) { if (plane->crtc) {
struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_plane *omap_plane = to_omap_plane(plane);
...@@ -197,8 +192,8 @@ int omap_plane_mode_set(struct drm_plane *plane, ...@@ -197,8 +192,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h, unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y, unsigned int src_x, unsigned int src_y,
uint32_t src_w, uint32_t src_h, unsigned int src_w, unsigned int src_h,
void (*fxn)(void *), void *arg) void (*fxn)(void *), void *arg)
{ {
struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_plane *omap_plane = to_omap_plane(plane);
...@@ -209,11 +204,10 @@ int omap_plane_mode_set(struct drm_plane *plane, ...@@ -209,11 +204,10 @@ int omap_plane_mode_set(struct drm_plane *plane,
win->crtc_w = crtc_w; win->crtc_w = crtc_w;
win->crtc_h = crtc_h; win->crtc_h = crtc_h;
/* src values are in Q16 fixed point, convert to integer: */ win->src_x = src_x;
win->src_x = src_x >> 16; win->src_y = src_y;
win->src_y = src_y >> 16; win->src_w = src_w;
win->src_w = src_w >> 16; win->src_h = src_h;
win->src_h = src_h >> 16;
if (fxn) { if (fxn) {
/* omap_crtc should ensure that a new page flip /* omap_crtc should ensure that a new page flip
...@@ -225,15 +219,7 @@ int omap_plane_mode_set(struct drm_plane *plane, ...@@ -225,15 +219,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
omap_plane->apply_done_cb.arg = arg; omap_plane->apply_done_cb.arg = arg;
} }
if (plane->fb) return omap_plane_apply(plane);
drm_framebuffer_unreference(plane->fb);
drm_framebuffer_reference(fb);
plane->fb = fb;
plane->crtc = crtc;
return apply(plane);
} }
static int omap_plane_update(struct drm_plane *plane, static int omap_plane_update(struct drm_plane *plane,
...@@ -254,17 +240,29 @@ static int omap_plane_update(struct drm_plane *plane, ...@@ -254,17 +240,29 @@ static int omap_plane_update(struct drm_plane *plane,
break; break;
} }
/*
* We don't need to take a reference to the framebuffer as the DRM core
* has already done so for the purpose of setting plane->fb.
*/
plane->fb = fb;
plane->crtc = crtc;
/* src values are in Q16 fixed point, convert to integer: */
return omap_plane_mode_set(plane, crtc, fb, return omap_plane_mode_set(plane, crtc, fb,
crtc_x, crtc_y, crtc_w, crtc_h, crtc_x, crtc_y, crtc_w, crtc_h,
src_x, src_y, src_w, src_h, src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
NULL, NULL); NULL, NULL);
} }
static int omap_plane_disable(struct drm_plane *plane) static int omap_plane_disable(struct drm_plane *plane)
{ {
struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_plane *omap_plane = to_omap_plane(plane);
omap_plane->win.rotation = BIT(DRM_ROTATE_0); omap_plane->win.rotation = BIT(DRM_ROTATE_0);
return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); omap_plane->info.zorder = plane->type == DRM_PLANE_TYPE_PRIMARY
? 0 : omap_plane->id;
return omap_plane_set_enable(plane, false);
} }
static void omap_plane_destroy(struct drm_plane *plane) static void omap_plane_destroy(struct drm_plane *plane)
...@@ -275,7 +273,6 @@ static void omap_plane_destroy(struct drm_plane *plane) ...@@ -275,7 +273,6 @@ static void omap_plane_destroy(struct drm_plane *plane)
omap_irq_unregister(plane->dev, &omap_plane->error_irq); omap_irq_unregister(plane->dev, &omap_plane->error_irq);
omap_plane_disable(plane);
drm_plane_cleanup(plane); drm_plane_cleanup(plane);
drm_flip_work_cleanup(&omap_plane->unpin_work); drm_flip_work_cleanup(&omap_plane->unpin_work);
...@@ -283,18 +280,15 @@ static void omap_plane_destroy(struct drm_plane *plane) ...@@ -283,18 +280,15 @@ static void omap_plane_destroy(struct drm_plane *plane)
kfree(omap_plane); kfree(omap_plane);
} }
int omap_plane_dpms(struct drm_plane *plane, int mode) int omap_plane_set_enable(struct drm_plane *plane, bool enable)
{ {
struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_plane *omap_plane = to_omap_plane(plane);
bool enabled = (mode == DRM_MODE_DPMS_ON);
int ret = 0;
if (enabled != omap_plane->enabled) { if (enable == omap_plane->enabled)
omap_plane->enabled = enabled; return 0;
ret = apply(plane);
}
return ret; omap_plane->enabled = enable;
return omap_plane_apply(plane);
} }
/* helper to install properties which are common to planes and crtcs */ /* helper to install properties which are common to planes and crtcs */
...@@ -342,11 +336,11 @@ int omap_plane_set_property(struct drm_plane *plane, ...@@ -342,11 +336,11 @@ int omap_plane_set_property(struct drm_plane *plane,
if (property == priv->rotation_prop) { if (property == priv->rotation_prop) {
DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val); DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
omap_plane->win.rotation = val; omap_plane->win.rotation = val;
ret = apply(plane); ret = omap_plane_apply(plane);
} else if (property == priv->zorder_prop) { } else if (property == priv->zorder_prop) {
DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val); DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
omap_plane->info.zorder = val; omap_plane->info.zorder = val;
ret = apply(plane); ret = omap_plane_apply(plane);
} }
return ret; return ret;
...@@ -363,7 +357,8 @@ static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) ...@@ -363,7 +357,8 @@ static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{ {
struct omap_plane *omap_plane = struct omap_plane *omap_plane =
container_of(irq, struct omap_plane, error_irq); container_of(irq, struct omap_plane, error_irq);
DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus); DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
irqstatus);
} }
static const char *plane_names[] = { static const char *plane_names[] = {
...@@ -382,21 +377,22 @@ static const uint32_t error_irqs[] = { ...@@ -382,21 +377,22 @@ static const uint32_t error_irqs[] = {
/* initialize plane */ /* initialize plane */
struct drm_plane *omap_plane_init(struct drm_device *dev, struct drm_plane *omap_plane_init(struct drm_device *dev,
int id, bool private_plane) int id, enum drm_plane_type type)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
struct drm_plane *plane = NULL; struct drm_plane *plane;
struct omap_plane *omap_plane; struct omap_plane *omap_plane;
struct omap_overlay_info *info; struct omap_overlay_info *info;
int ret;
DBG("%s: priv=%d", plane_names[id], private_plane); DBG("%s: type=%d", plane_names[id], type);
omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
if (!omap_plane) if (!omap_plane)
return NULL; return ERR_PTR(-ENOMEM);
drm_flip_work_init(&omap_plane->unpin_work, drm_flip_work_init(&omap_plane->unpin_work,
"unpin", unpin_worker); "unpin", omap_plane_unpin_worker);
omap_plane->nformats = omap_framebuffer_get_formats( omap_plane->nformats = omap_framebuffer_get_formats(
omap_plane->formats, ARRAY_SIZE(omap_plane->formats), omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
...@@ -413,8 +409,11 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, ...@@ -413,8 +409,11 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
omap_plane->error_irq.irq = omap_plane_error_irq; omap_plane->error_irq.irq = omap_plane_error_irq;
omap_irq_register(dev, &omap_plane->error_irq); omap_irq_register(dev, &omap_plane->error_irq);
drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs, ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
omap_plane->formats, omap_plane->nformats, private_plane); &omap_plane_funcs, omap_plane->formats,
omap_plane->nformats, type);
if (ret < 0)
goto error;
omap_plane_install_properties(plane, &plane->base); omap_plane_install_properties(plane, &plane->base);
...@@ -432,10 +431,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, ...@@ -432,10 +431,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
* TODO add ioctl to give userspace an API to change this.. this * TODO add ioctl to give userspace an API to change this.. this
* will come in a subsequent patch. * will come in a subsequent patch.
*/ */
if (private_plane) if (type == DRM_PLANE_TYPE_PRIMARY)
omap_plane->info.zorder = 0; omap_plane->info.zorder = 0;
else else
omap_plane->info.zorder = id; omap_plane->info.zorder = id;
return plane; return plane;
error:
omap_irq_unregister(plane->dev, &omap_plane->error_irq);
kfree(omap_plane);
return NULL;
} }
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