omapdrm changes for 4.1
* universal plane support * refactoring to prepare work atomic modesetting work * a lot of small fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVHQXYAAoJEPo9qoy8lh71jLUP/jM7MUZNP1uyVLvKX7WbCesT 7hW0ZRWAZUooSlWPiiPucTi23u0O6DmLULj5Vt6UZ6x/qixZAnUUDnjgKTHm6elj upI0DjWbJyi4qk1+enttL+1SgaY9kwT6yyMaWCWOg1MgiSfN3nTwn4xx+zNn/yzP RnP4E9XctoSOSanwqE6sp9sP/sfVCY9v3CJUw2c4LxjcVE1YcKiy3okInPs3cLpi 31P/tjSP2jKhQYkHy0EL2bwwYrbWswZl0v9GqmfNGeRLRFEe1J8BvcLk5X+0P3h4 acn1wog11cavnwyUyzSTJ/eswWi+qRcgl+SQmsoZ/4Y9wNCcpdiFokSVbzLaGE9j fy/rDnjY8Uj9eRbhMNhf3Lzs6aiEcHbmsah1zlH7VLkfEACtEpZAF3az1xVTSiJ1 zMR9l29ZAFe9sq/VDdowNXNYIJxeVXClLetPIr3FKZVYPEOfcaH3mV4xoHTR3Y0C gNCQXa8S9WuXcnPkcdS1shkLMyFppLpng68Ww1H1DemY635RkZGZN2NUvFiJsD46 xmuOyyDReEO1XoHNtk+fum+Ae144Da5YTMtp7IkRXLNu9ajaD4lXurgGHFH2rn/y 3aM/hkzgO/HUyXBkuNX6VkWnpUsT2D/sDACJRRlQt2CEFB/Tt68f48X/FiCh+Mxq w1/1XQD8EZIwIgzW18Bg =81ba -----END PGP SIGNATURE----- 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() ...
This commit is contained in:
commit
67a0375f5e
13 changed files with 678 additions and 682 deletions
|
@ -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 @@
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
* 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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,253 +260,22 @@ 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_destroy(struct drm_crtc *crtc)
|
|
||||||
{
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
|
|
||||||
DBG("%s", omap_crtc->name);
|
|
||||||
|
|
||||||
WARN_ON(omap_crtc->apply_irq.registered);
|
|
||||||
omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
|
|
||||||
|
|
||||||
drm_crtc_cleanup(crtc);
|
|
||||||
|
|
||||||
kfree(omap_crtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|
||||||
{
|
|
||||||
struct omap_drm_private *priv = crtc->dev->dev_private;
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
bool enabled = (mode == DRM_MODE_DPMS_ON);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
DBG("%s: %d", omap_crtc->name, mode);
|
|
||||||
|
|
||||||
if (enabled != omap_crtc->enabled) {
|
|
||||||
omap_crtc->enabled = enabled;
|
|
||||||
omap_crtc->full_update = true;
|
|
||||||
omap_crtc_apply(crtc, &omap_crtc->apply);
|
|
||||||
|
|
||||||
/* also enable our private plane: */
|
|
||||||
WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
|
|
||||||
|
|
||||||
/* and any attached overlay planes: */
|
|
||||||
for (i = 0; i < priv->num_planes; i++) {
|
|
||||||
struct drm_plane *plane = priv->planes[i];
|
|
||||||
if (plane->crtc == crtc)
|
|
||||||
WARN_ON(omap_plane_dpms(plane, mode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
|
|
||||||
const struct drm_display_mode *mode,
|
|
||||||
struct drm_display_mode *adjusted_mode)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int omap_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)
|
|
||||||
{
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
|
|
||||||
mode = adjusted_mode;
|
|
||||||
|
|
||||||
DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
|
||||||
omap_crtc->name, mode->base.id, mode->name,
|
|
||||||
mode->vrefresh, mode->clock,
|
|
||||||
mode->hdisplay, mode->hsync_start,
|
|
||||||
mode->hsync_end, mode->htotal,
|
|
||||||
mode->vdisplay, mode->vsync_start,
|
|
||||||
mode->vsync_end, mode->vtotal,
|
|
||||||
mode->type, mode->flags);
|
|
||||||
|
|
||||||
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,
|
|
||||||
0, 0, mode->hdisplay, mode->vdisplay,
|
|
||||||
x << 16, y << 16,
|
|
||||||
mode->hdisplay << 16, mode->vdisplay << 16,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void omap_crtc_prepare(struct drm_crtc *crtc)
|
|
||||||
{
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
DBG("%s", omap_crtc->name);
|
|
||||||
omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void omap_crtc_commit(struct drm_crtc *crtc)
|
|
||||||
{
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
DBG("%s", omap_crtc->name);
|
|
||||||
omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
|
||||||
struct drm_framebuffer *old_fb)
|
|
||||||
{
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
struct drm_plane *plane = omap_crtc->plane;
|
|
||||||
struct drm_display_mode *mode = &crtc->mode;
|
|
||||||
|
|
||||||
return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
|
|
||||||
0, 0, mode->hdisplay, mode->vdisplay,
|
|
||||||
x << 16, y << 16,
|
|
||||||
mode->hdisplay << 16, mode->vdisplay << 16,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vblank_cb(void *arg)
|
|
||||||
{
|
|
||||||
struct drm_crtc *crtc = arg;
|
|
||||||
struct drm_device *dev = crtc->dev;
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->event_lock, flags);
|
|
||||||
|
|
||||||
/* wakeup userspace */
|
|
||||||
if (omap_crtc->event)
|
|
||||||
drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
|
|
||||||
|
|
||||||
omap_crtc->event = NULL;
|
|
||||||
omap_crtc->old_fb = NULL;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void page_flip_worker(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct omap_crtc *omap_crtc =
|
|
||||||
container_of(work, struct omap_crtc, page_flip_work);
|
|
||||||
struct drm_crtc *crtc = &omap_crtc->base;
|
|
||||||
struct drm_display_mode *mode = &crtc->mode;
|
|
||||||
struct drm_gem_object *bo;
|
|
||||||
|
|
||||||
drm_modeset_lock(&crtc->mutex, NULL);
|
|
||||||
omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
|
|
||||||
0, 0, mode->hdisplay, mode->vdisplay,
|
|
||||||
crtc->x << 16, crtc->y << 16,
|
|
||||||
mode->hdisplay << 16, mode->vdisplay << 16,
|
|
||||||
vblank_cb, crtc);
|
|
||||||
drm_modeset_unlock(&crtc->mutex);
|
|
||||||
|
|
||||||
bo = omap_framebuffer_bo(crtc->primary->fb, 0);
|
|
||||||
drm_gem_object_unreference_unlocked(bo);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void page_flip_cb(void *arg)
|
|
||||||
{
|
|
||||||
struct drm_crtc *crtc = arg;
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
struct omap_drm_private *priv = crtc->dev->dev_private;
|
|
||||||
|
|
||||||
/* avoid assumptions about what ctxt we are called from: */
|
|
||||||
queue_work(priv->wq, &omap_crtc->page_flip_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
|
|
||||||
struct drm_framebuffer *fb,
|
|
||||||
struct drm_pending_vblank_event *event,
|
|
||||||
uint32_t page_flip_flags)
|
|
||||||
{
|
|
||||||
struct drm_device *dev = crtc->dev;
|
|
||||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
|
||||||
struct drm_plane *primary = crtc->primary;
|
|
||||||
struct drm_gem_object *bo;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
|
|
||||||
fb->base.id, event);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->event_lock, flags);
|
|
||||||
|
|
||||||
if (omap_crtc->old_fb) {
|
|
||||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
|
||||||
dev_err(dev->dev, "already a pending flip\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
omap_crtc->event = event;
|
|
||||||
omap_crtc->old_fb = primary->fb = fb;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hold a reference temporarily until the crtc is updated
|
|
||||||
* and takes the reference to the bo. This avoids it
|
|
||||||
* getting freed from under us:
|
|
||||||
*/
|
|
||||||
bo = omap_framebuffer_bo(fb, 0);
|
|
||||||
drm_gem_object_reference(bo);
|
|
||||||
|
|
||||||
omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int omap_crtc_set_property(struct drm_crtc *crtc,
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (property == priv->rotation_prop) {
|
|
||||||
crtc->invert_dimensions =
|
|
||||||
!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return omap_plane_set_property(omap_crtc->plane, property, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct drm_crtc_funcs omap_crtc_funcs = {
|
|
||||||
.set_config = drm_crtc_helper_set_config,
|
|
||||||
.destroy = omap_crtc_destroy,
|
|
||||||
.page_flip = omap_crtc_page_flip_locked,
|
|
||||||
.set_property = omap_crtc_set_property,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
|
|
||||||
.dpms = omap_crtc_dpms,
|
|
||||||
.mode_fixup = omap_crtc_mode_fixup,
|
|
||||||
.mode_set = omap_crtc_mode_set,
|
|
||||||
.prepare = omap_crtc_prepare,
|
|
||||||
.commit = omap_crtc_commit,
|
|
||||||
.mode_set_base = omap_crtc_mode_set_base,
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
||||||
{
|
{
|
||||||
struct omap_crtc *omap_crtc =
|
struct omap_crtc *omap_crtc =
|
||||||
container_of(irq, struct omap_crtc, error_irq);
|
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);
|
if (omap_crtc->ignore_digit_sync_lost) {
|
||||||
/* avoid getting in a flood, unregister the irq until next vblank */
|
irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
|
||||||
__omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
|
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)
|
static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
||||||
|
@ -440,9 +284,6 @@ static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
||||||
container_of(irq, struct omap_crtc, apply_irq);
|
container_of(irq, struct omap_crtc, apply_irq);
|
||||||
struct drm_crtc *crtc = &omap_crtc->base;
|
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)) {
|
if (!dispc_mgr_go_busy(omap_crtc->channel)) {
|
||||||
struct omap_drm_private *priv =
|
struct omap_drm_private *priv =
|
||||||
crtc->dev->dev_private;
|
crtc->dev->dev_private;
|
||||||
|
@ -501,8 +342,8 @@ static void apply_worker(struct work_struct *work)
|
||||||
DBG("%s: GO", omap_crtc->name);
|
DBG("%s: GO", omap_crtc->name);
|
||||||
|
|
||||||
if (dispc_mgr_is_enabled(channel)) {
|
if (dispc_mgr_is_enabled(channel)) {
|
||||||
omap_irq_register(dev, &omap_crtc->apply_irq);
|
|
||||||
dispc_mgr_go(channel);
|
dispc_mgr_go(channel);
|
||||||
|
omap_irq_register(dev, &omap_crtc->apply_irq);
|
||||||
} else {
|
} else {
|
||||||
struct omap_drm_private *priv = dev->dev_private;
|
struct omap_drm_private *priv = dev->dev_private;
|
||||||
queue_work(priv->wq, &omap_crtc->apply_work);
|
queue_work(priv->wq, &omap_crtc->apply_work);
|
||||||
|
@ -541,77 +382,23 @@ int omap_crtc_apply(struct drm_crtc *crtc,
|
||||||
return 0;
|
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)
|
static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
|
||||||
{
|
{
|
||||||
struct omap_crtc *omap_crtc =
|
struct omap_crtc *omap_crtc =
|
||||||
container_of(apply, struct omap_crtc, apply);
|
container_of(apply, struct omap_crtc, apply);
|
||||||
struct drm_crtc *crtc = &omap_crtc->base;
|
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;
|
struct omap_drm_private *priv = crtc->dev->dev_private;
|
||||||
int i;
|
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++) {
|
for (i = 0; i < priv->num_encoders; i++) {
|
||||||
if (priv->encoders[i]->crtc == crtc) {
|
if (priv->encoders[i]->crtc == crtc) {
|
||||||
encoder = priv->encoders[i];
|
encoder = priv->encoders[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
|
if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
|
||||||
omap_encoder_set_enabled(omap_crtc->current_encoder, false);
|
omap_encoder_set_enabled(omap_crtc->current_encoder, false);
|
||||||
|
@ -629,8 +416,6 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
|
||||||
omap_encoder_set_enabled(encoder, true);
|
omap_encoder_set_enabled(encoder, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
omap_crtc->full_update = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_crtc_post_apply(struct omap_drm_apply *apply)
|
static void omap_crtc_post_apply(struct omap_drm_apply *apply)
|
||||||
|
@ -657,6 +442,240 @@ void omap_crtc_flush(struct drm_crtc *crtc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* CRTC Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void omap_crtc_destroy(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
|
||||||
|
DBG("%s", omap_crtc->name);
|
||||||
|
|
||||||
|
WARN_ON(omap_crtc->apply_irq.registered);
|
||||||
|
omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
|
||||||
|
|
||||||
|
drm_crtc_cleanup(crtc);
|
||||||
|
|
||||||
|
kfree(omap_crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||||
|
{
|
||||||
|
struct omap_drm_private *priv = crtc->dev->dev_private;
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
bool enabled = (mode == DRM_MODE_DPMS_ON);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DBG("%s: %d", omap_crtc->name, mode);
|
||||||
|
|
||||||
|
if (enabled != omap_crtc->enabled) {
|
||||||
|
omap_crtc->enabled = enabled;
|
||||||
|
omap_crtc_apply(crtc, &omap_crtc->apply);
|
||||||
|
|
||||||
|
/* Enable/disable all planes associated with the CRTC. */
|
||||||
|
for (i = 0; i < priv->num_planes; i++) {
|
||||||
|
struct drm_plane *plane = priv->planes[i];
|
||||||
|
if (plane->crtc == crtc)
|
||||||
|
WARN_ON(omap_plane_set_enable(plane, enabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||||
|
const struct drm_display_mode *mode,
|
||||||
|
struct drm_display_mode *adjusted_mode)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omap_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)
|
||||||
|
{
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
|
||||||
|
mode = adjusted_mode;
|
||||||
|
|
||||||
|
DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||||
|
omap_crtc->name, mode->base.id, mode->name,
|
||||||
|
mode->vrefresh, mode->clock,
|
||||||
|
mode->hdisplay, mode->hsync_start,
|
||||||
|
mode->hsync_end, mode->htotal,
|
||||||
|
mode->vdisplay, mode->vsync_start,
|
||||||
|
mode->vsync_end, mode->vtotal,
|
||||||
|
mode->type, mode->flags);
|
||||||
|
|
||||||
|
copy_timings_drm_to_omap(&omap_crtc->timings, mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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,
|
||||||
|
x, y, mode->hdisplay, mode->vdisplay,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void omap_crtc_prepare(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
DBG("%s", omap_crtc->name);
|
||||||
|
omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void omap_crtc_commit(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
DBG("%s", omap_crtc->name);
|
||||||
|
omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||||
|
struct drm_framebuffer *old_fb)
|
||||||
|
{
|
||||||
|
struct drm_plane *plane = crtc->primary;
|
||||||
|
struct drm_display_mode *mode = &crtc->mode;
|
||||||
|
|
||||||
|
return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
|
||||||
|
0, 0, mode->hdisplay, mode->vdisplay,
|
||||||
|
x, y, mode->hdisplay, mode->vdisplay,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vblank_cb(void *arg)
|
||||||
|
{
|
||||||
|
struct drm_crtc *crtc = arg;
|
||||||
|
struct drm_device *dev = crtc->dev;
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
unsigned long flags;
|
||||||
|
struct drm_framebuffer *fb;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dev->event_lock, flags);
|
||||||
|
|
||||||
|
/* wakeup userspace */
|
||||||
|
if (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->old_fb = NULL;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||||
|
|
||||||
|
if (fb)
|
||||||
|
drm_framebuffer_unreference(fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void page_flip_worker(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct omap_crtc *omap_crtc =
|
||||||
|
container_of(work, struct omap_crtc, page_flip_work);
|
||||||
|
struct drm_crtc *crtc = &omap_crtc->base;
|
||||||
|
struct drm_display_mode *mode = &crtc->mode;
|
||||||
|
struct drm_gem_object *bo;
|
||||||
|
|
||||||
|
drm_modeset_lock(&crtc->mutex, NULL);
|
||||||
|
omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
|
||||||
|
0, 0, mode->hdisplay, mode->vdisplay,
|
||||||
|
crtc->x, crtc->y, mode->hdisplay, mode->vdisplay,
|
||||||
|
vblank_cb, crtc);
|
||||||
|
drm_modeset_unlock(&crtc->mutex);
|
||||||
|
|
||||||
|
bo = omap_framebuffer_bo(crtc->primary->fb, 0);
|
||||||
|
drm_gem_object_unreference_unlocked(bo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void page_flip_cb(void *arg)
|
||||||
|
{
|
||||||
|
struct drm_crtc *crtc = arg;
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
struct omap_drm_private *priv = crtc->dev->dev_private;
|
||||||
|
|
||||||
|
/* avoid assumptions about what ctxt we are called from: */
|
||||||
|
queue_work(priv->wq, &omap_crtc->page_flip_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
|
||||||
|
struct drm_framebuffer *fb,
|
||||||
|
struct drm_pending_vblank_event *event,
|
||||||
|
uint32_t page_flip_flags)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = crtc->dev;
|
||||||
|
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||||
|
struct drm_plane *primary = crtc->primary;
|
||||||
|
struct drm_gem_object *bo;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
|
||||||
|
fb->base.id, event);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dev->event_lock, flags);
|
||||||
|
|
||||||
|
if (omap_crtc->old_fb) {
|
||||||
|
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||||
|
dev_err(dev->dev, "already a pending flip\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
omap_crtc->event = event;
|
||||||
|
omap_crtc->old_fb = primary->fb = fb;
|
||||||
|
drm_framebuffer_reference(omap_crtc->old_fb);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hold a reference temporarily until the crtc is updated
|
||||||
|
* and takes the reference to the bo. This avoids it
|
||||||
|
* getting freed from under us:
|
||||||
|
*/
|
||||||
|
bo = omap_framebuffer_bo(fb, 0);
|
||||||
|
drm_gem_object_reference(bo);
|
||||||
|
|
||||||
|
omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int omap_crtc_set_property(struct drm_crtc *crtc,
|
||||||
|
struct drm_property *property, uint64_t val)
|
||||||
|
{
|
||||||
|
struct omap_drm_private *priv = crtc->dev->dev_private;
|
||||||
|
|
||||||
|
if (property == priv->rotation_prop) {
|
||||||
|
crtc->invert_dimensions =
|
||||||
|
!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return omap_plane_set_property(crtc->primary, property, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_crtc_funcs omap_crtc_funcs = {
|
||||||
|
.set_config = drm_crtc_helper_set_config,
|
||||||
|
.destroy = omap_crtc_destroy,
|
||||||
|
.page_flip = omap_crtc_page_flip_locked,
|
||||||
|
.set_property = omap_crtc_set_property,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
|
||||||
|
.dpms = omap_crtc_dpms,
|
||||||
|
.mode_fixup = omap_crtc_mode_fixup,
|
||||||
|
.mode_set = omap_crtc_mode_set,
|
||||||
|
.prepare = omap_crtc_prepare,
|
||||||
|
.commit = omap_crtc_commit,
|
||||||
|
.mode_set_base = omap_crtc_mode_set_base,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* Init and Cleanup
|
||||||
|
*/
|
||||||
|
|
||||||
static const char *channel_names[] = {
|
static const char *channel_names[] = {
|
||||||
[OMAP_DSS_CHANNEL_LCD] = "lcd",
|
[OMAP_DSS_CHANNEL_LCD] = "lcd",
|
||||||
[OMAP_DSS_CHANNEL_DIGIT] = "tv",
|
[OMAP_DSS_CHANNEL_DIGIT] = "tv",
|
||||||
|
@ -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,
|
||||||
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,
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
/* 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 @@
|
||||||
#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 @@
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
(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 @@ error:
|
||||||
}
|
}
|
||||||
#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)
|
||||||
|
|
||||||
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 = {
|
||||||
.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);
|
||||||
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 @@ cleanup:
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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,10 +601,12 @@ 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 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
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 = {
|
||||||
.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)
|
||||||
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 {
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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 {
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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(
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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 {
|
||||||
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 = {
|
||||||
* 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)
|
||||||
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)
|
||||||
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 @@ unlock:
|
||||||
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,
|
||||||
/* 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,
|
||||||
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)
|
||||||
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 {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
{
|
{
|
||||||
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[] = {
|
||||||
|
|
||||||
/* 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,
|
||||||
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,
|
||||||
* 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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue