summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c121
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c27
2 files changed, 53 insertions, 95 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index a6ef737c7d35..3257228564d9 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -25,15 +25,12 @@ struct tilcdc_crtc {
struct drm_crtc base;
const struct tilcdc_panel_info *info;
- uint32_t dirty;
- dma_addr_t start, end;
struct drm_pending_vblank_event *event;
int dpms;
wait_queue_head_t frame_done_wq;
bool frame_done;
- /* fb currently set to scanout 0/1: */
- struct drm_framebuffer *scanout[2];
+ struct drm_framebuffer *curr_fb;
/* for deferred fb unref's: */
struct drm_flip_work unref_work;
@@ -54,62 +51,31 @@ static void unref_worker(struct drm_flip_work *work, void *val)
mutex_unlock(&dev->mode_config.mutex);
}
-static void set_scanout(struct drm_crtc *crtc, int n)
-{
- static const uint32_t base_reg[] = {
- LCDC_DMA_FB_BASE_ADDR_0_REG,
- LCDC_DMA_FB_BASE_ADDR_1_REG,
- };
- static const uint32_t ceil_reg[] = {
- LCDC_DMA_FB_CEILING_ADDR_0_REG,
- LCDC_DMA_FB_CEILING_ADDR_1_REG,
- };
- static const uint32_t stat[] = {
- LCDC_END_OF_FRAME0, LCDC_END_OF_FRAME1,
- };
- struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
- struct drm_device *dev = crtc->dev;
- struct tilcdc_drm_private *priv = dev->dev_private;
-
- tilcdc_write(dev, base_reg[n], tilcdc_crtc->start);
- tilcdc_write(dev, ceil_reg[n], tilcdc_crtc->end);
- if (tilcdc_crtc->scanout[n]) {
- drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]);
- drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
- }
- tilcdc_crtc->scanout[n] = crtc->primary->fb;
- drm_framebuffer_reference(tilcdc_crtc->scanout[n]);
- tilcdc_crtc->dirty &= ~stat[n];
-}
-
-static void update_scanout(struct drm_crtc *crtc)
+static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
{
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
struct drm_device *dev = crtc->dev;
- struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_gem_cma_object *gem;
unsigned int depth, bpp;
+ dma_addr_t start, end;
drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
gem = drm_fb_cma_get_gem_obj(fb, 0);
- tilcdc_crtc->start = gem->paddr + fb->offsets[0] +
- (crtc->y * fb->pitches[0]) + (crtc->x * bpp/8);
+ start = gem->paddr + fb->offsets[0] +
+ crtc->y * fb->pitches[0] +
+ crtc->x * bpp / 8;
- tilcdc_crtc->end = tilcdc_crtc->start +
- (crtc->mode.vdisplay * fb->pitches[0]);
+ end = start + (crtc->mode.vdisplay * fb->pitches[0]);
- if (tilcdc_crtc->dpms == DRM_MODE_DPMS_ON) {
- /* already enabled, so just mark the frames that need
- * updating and they will be updated on vblank:
- */
- tilcdc_crtc->dirty |= LCDC_END_OF_FRAME0 | LCDC_END_OF_FRAME1;
- drm_vblank_get(dev, 0);
- } else {
- /* not enabled yet, so update registers immediately: */
- set_scanout(crtc, 0);
- set_scanout(crtc, 1);
- }
+ tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, start);
+ tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG, end);
+
+ if (tilcdc_crtc->curr_fb)
+ drm_flip_work_queue(&tilcdc_crtc->unref_work,
+ tilcdc_crtc->curr_fb);
+
+ tilcdc_crtc->curr_fb = fb;
}
static void reset(struct drm_crtc *crtc)
@@ -131,7 +97,7 @@ static void start(struct drm_crtc *crtc)
reset(crtc);
- tilcdc_set(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE);
+ tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE);
tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_PALETTE_LOAD_MODE(DATA_ONLY));
tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
}
@@ -179,6 +145,7 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
struct drm_device *dev = crtc->dev;
int r;
+ unsigned long flags;
r = tilcdc_verify_fb(crtc, fb);
if (r)
@@ -189,12 +156,18 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
return -EBUSY;
}
+ drm_framebuffer_reference(fb);
+
crtc->primary->fb = fb;
- tilcdc_crtc->event = event;
pm_runtime_get_sync(dev->dev);
- update_scanout(crtc);
+
+ set_scanout(crtc, fb);
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ tilcdc_crtc->event = event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
pm_runtime_put_sync(dev->dev);
@@ -237,6 +210,14 @@ void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode)
}
pm_runtime_put_sync(dev->dev);
+
+ if (tilcdc_crtc->curr_fb) {
+ drm_flip_work_queue(&tilcdc_crtc->unref_work,
+ tilcdc_crtc->curr_fb);
+ tilcdc_crtc->curr_fb = NULL;
+ }
+
+ drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
}
}
@@ -450,8 +431,10 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
else
tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER);
+ drm_framebuffer_reference(crtc->primary->fb);
+
+ set_scanout(crtc, crtc->primary->fb);
- update_scanout(crtc);
tilcdc_crtc_update_clk(crtc);
pm_runtime_put_sync(dev->dev);
@@ -469,9 +452,14 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
if (r)
return r;
+ drm_framebuffer_reference(crtc->primary->fb);
+
pm_runtime_get_sync(dev->dev);
- update_scanout(crtc);
+
+ set_scanout(crtc, crtc->primary->fb);
+
pm_runtime_put_sync(dev->dev);
+
return 0;
}
@@ -661,30 +649,21 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
stat = tilcdc_read_irqstatus(dev);
tilcdc_clear_irqstatus(dev, stat);
- if ((stat & LCDC_END_OF_FRAME0) || (stat & LCDC_END_OF_FRAME1)) {
- struct drm_pending_vblank_event *event;
+ if (stat & LCDC_END_OF_FRAME0) {
unsigned long flags;
- uint32_t dirty = tilcdc_crtc->dirty & stat;
-
- tilcdc_clear_irqstatus(dev, stat);
- if (dirty & LCDC_END_OF_FRAME0)
- set_scanout(crtc, 0);
-
- if (dirty & LCDC_END_OF_FRAME1)
- set_scanout(crtc, 1);
+ drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
drm_handle_vblank(dev, 0);
spin_lock_irqsave(&dev->event_lock, flags);
- event = tilcdc_crtc->event;
- tilcdc_crtc->event = NULL;
- if (event)
- drm_send_vblank_event(dev, 0, event);
- spin_unlock_irqrestore(&dev->event_lock, flags);
- if (dirty && !tilcdc_crtc->dirty)
- drm_vblank_put(dev, 0);
+ if (tilcdc_crtc->event) {
+ drm_send_vblank_event(dev, 0, tilcdc_crtc->event);
+ tilcdc_crtc->event = NULL;
+ }
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
}
if (priv->rev == 2) {
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index e1f697986289..c5d9e3a2f812 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -381,6 +381,7 @@ static int tilcdc_irq_postinstall(struct drm_device *dev)
else
tilcdc_set(dev, LCDC_INT_ENABLE_SET_REG,
LCDC_V2_UNDERFLOW_INT_ENA |
+ LCDC_V2_END_OF_FRAME0_INT_ENA |
LCDC_FRAME_DONE);
return 0;
@@ -398,41 +399,19 @@ static void tilcdc_irq_uninstall(struct drm_device *dev)
} else {
tilcdc_clear(dev, LCDC_INT_ENABLE_SET_REG,
LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA |
- LCDC_V2_END_OF_FRAME0_INT_ENA | LCDC_V2_END_OF_FRAME1_INT_ENA |
+ LCDC_V2_END_OF_FRAME0_INT_ENA |
LCDC_FRAME_DONE);
}
-
-}
-
-static void enable_vblank(struct drm_device *dev, bool enable)
-{
- struct tilcdc_drm_private *priv = dev->dev_private;
- u32 reg, mask;
-
- if (priv->rev == 1) {
- reg = LCDC_DMA_CTRL_REG;
- mask = LCDC_V1_END_OF_FRAME_INT_ENA;
- } else {
- reg = LCDC_INT_ENABLE_SET_REG;
- mask = LCDC_V2_END_OF_FRAME0_INT_ENA |
- LCDC_V2_END_OF_FRAME1_INT_ENA;
- }
-
- if (enable)
- tilcdc_set(dev, reg, mask);
- else
- tilcdc_clear(dev, reg, mask);
}
static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
- enable_vblank(dev, true);
return 0;
}
static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
- enable_vblank(dev, false);
+ return;
}
#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP)
OpenPOWER on IntegriCloud