summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/armada
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
commite5fd91f1ef340da553f7a79da9540c3db711c937 (patch)
treeb11842027dc6641da63f4bcc524f8678263304a3 /drivers/gpu/drm/armada
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'drivers/gpu/drm/armada')
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c2
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h2
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c10
-rw-r--r--drivers/gpu/drm/armada/armada_gem.c5
-rw-r--r--drivers/gpu/drm/armada/armada_output.c16
-rw-r--r--drivers/gpu/drm/armada/armada_output.h6
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c121
7 files changed, 78 insertions, 84 deletions
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 42d2ffa08..01ffe9bff 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -531,8 +531,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
drm_crtc_vblank_off(crtc);
- crtc->mode = *adj;
-
val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA;
if (val != dcrtc->dumb_ctrl) {
dcrtc->dumb_ctrl = val;
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index ea63c6c7c..5f6aef0dc 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -46,8 +46,6 @@ void armada_drm_vbl_event_add(struct armada_crtc *,
struct armada_vbl_event *);
void armada_drm_vbl_event_remove(struct armada_crtc *,
struct armada_vbl_event *);
-void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *,
- struct armada_vbl_event *);
#define armada_drm_vbl_event_init(_e, _f, _d) do { \
struct armada_vbl_event *__e = _e; \
INIT_LIST_HEAD(&__e->node); \
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index b01420c84..225034b74 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -253,16 +253,6 @@ void armada_drm_vbl_event_remove(struct armada_crtc *dcrtc,
}
}
-void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *dcrtc,
- struct armada_vbl_event *evt)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dcrtc->irq_lock, flags);
- armada_drm_vbl_event_remove(dcrtc, evt);
- spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
-}
-
/* These are called under the vbl_lock. */
static int armada_drm_enable_vblank(struct drm_device *dev, int crtc)
{
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
index 580e10aca..60a688ef8 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -69,8 +69,9 @@ void armada_gem_free_object(struct drm_gem_object *obj)
if (dobj->obj.import_attach) {
/* We only ever display imported data */
- dma_buf_unmap_attachment(dobj->obj.import_attach, dobj->sgt,
- DMA_TO_DEVICE);
+ if (dobj->sgt)
+ dma_buf_unmap_attachment(dobj->obj.import_attach,
+ dobj->sgt, DMA_TO_DEVICE);
drm_prime_gem_destroy(&dobj->obj, NULL);
}
diff --git a/drivers/gpu/drm/armada/armada_output.c b/drivers/gpu/drm/armada/armada_output.c
index abbc309fe..5a9823178 100644
--- a/drivers/gpu/drm/armada/armada_output.c
+++ b/drivers/gpu/drm/armada/armada_output.c
@@ -72,22 +72,6 @@ static const struct drm_connector_funcs armada_drm_conn_funcs = {
.set_property = armada_drm_connector_set_property,
};
-void armada_drm_encoder_prepare(struct drm_encoder *encoder)
-{
- encoder_helper_funcs(encoder)->dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-void armada_drm_encoder_commit(struct drm_encoder *encoder)
-{
- encoder_helper_funcs(encoder)->dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
-bool armada_drm_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode, struct drm_display_mode *adjusted)
-{
- return true;
-}
-
/* Shouldn't this be a generic helper function? */
int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn,
struct drm_display_mode *mode)
diff --git a/drivers/gpu/drm/armada/armada_output.h b/drivers/gpu/drm/armada/armada_output.h
index 3c4023e14..f44878575 100644
--- a/drivers/gpu/drm/armada/armada_output.h
+++ b/drivers/gpu/drm/armada/armada_output.h
@@ -21,12 +21,6 @@ struct armada_output_type {
struct drm_encoder *armada_drm_connector_encoder(struct drm_connector *conn);
-void armada_drm_encoder_prepare(struct drm_encoder *encoder);
-void armada_drm_encoder_commit(struct drm_encoder *encoder);
-
-bool armada_drm_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode, struct drm_display_mode *adj);
-
int armada_drm_slave_encoder_mode_valid(struct drm_connector *conn,
struct drm_display_mode *mode);
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index c5b06fdb4..e939faba7 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -7,6 +7,7 @@
* published by the Free Software Foundation.
*/
#include <drm/drmP.h>
+#include <drm/drm_plane_helper.h>
#include "armada_crtc.h"
#include "armada_drm.h"
#include "armada_fb.h"
@@ -85,16 +86,8 @@ static void armada_plane_vbl(struct armada_crtc *dcrtc, void *data)
if (fb)
armada_drm_queue_unref_work(dcrtc->crtc.dev, fb);
-}
-static unsigned armada_limit(int start, unsigned size, unsigned max)
-{
- int end = start + size;
- if (end < 0)
- return 0;
- if (start < 0)
- start = 0;
- return (unsigned)end > max ? max - start : end - start;
+ wake_up(&dplane->vbl.wait);
}
static int
@@ -105,26 +98,39 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
{
struct armada_plane *dplane = drm_to_armada_plane(plane);
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
+ struct drm_rect src = {
+ .x1 = src_x,
+ .y1 = src_y,
+ .x2 = src_x + src_w,
+ .y2 = src_y + src_h,
+ };
+ struct drm_rect dest = {
+ .x1 = crtc_x,
+ .y1 = crtc_y,
+ .x2 = crtc_x + crtc_w,
+ .y2 = crtc_y + crtc_h,
+ };
+ const struct drm_rect clip = {
+ .x2 = crtc->mode.hdisplay,
+ .y2 = crtc->mode.vdisplay,
+ };
uint32_t val, ctrl0;
unsigned idx = 0;
+ bool visible;
int ret;
- crtc_w = armada_limit(crtc_x, crtc_w, dcrtc->crtc.mode.hdisplay);
- crtc_h = armada_limit(crtc_y, crtc_h, dcrtc->crtc.mode.vdisplay);
+ ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, &clip,
+ 0, INT_MAX, true, false, &visible);
+ if (ret)
+ return ret;
+
ctrl0 = CFG_DMA_FMT(drm_fb_to_armada_fb(fb)->fmt) |
CFG_DMA_MOD(drm_fb_to_armada_fb(fb)->mod) |
CFG_CBSH_ENA | CFG_DMA_HSMOOTH | CFG_DMA_ENA;
/* Does the position/size result in nothing to display? */
- if (crtc_w == 0 || crtc_h == 0) {
+ if (!visible)
ctrl0 &= ~CFG_DMA_ENA;
- }
-
- /*
- * FIXME: if the starting point is off screen, we need to
- * adjust src_x, src_y, src_w, src_h appropriately, and
- * according to the scale.
- */
if (!dcrtc->plane) {
dcrtc->plane = plane;
@@ -134,15 +140,19 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
/* FIXME: overlay on an interlaced display */
/* Just updating the position/size? */
if (plane->fb == fb && dplane->ctrl0 == ctrl0) {
- val = (src_h & 0xffff0000) | src_w >> 16;
+ val = (drm_rect_height(&src) & 0xffff0000) |
+ drm_rect_width(&src) >> 16;
dplane->src_hw = val;
writel_relaxed(val, dcrtc->base + LCD_SPU_DMA_HPXL_VLN);
- val = crtc_h << 16 | crtc_w;
+
+ val = drm_rect_height(&dest) << 16 | drm_rect_width(&dest);
dplane->dst_hw = val;
writel_relaxed(val, dcrtc->base + LCD_SPU_DZM_HPXL_VLN);
- val = crtc_y << 16 | crtc_x;
+
+ val = dest.y1 << 16 | dest.x1;
dplane->dst_yx = val;
writel_relaxed(val, dcrtc->base + LCD_SPU_DMA_OVSA_HPXL_VLN);
+
return 0;
} else if (~dplane->ctrl0 & ctrl0 & CFG_DMA_ENA) {
/* Power up the Y/U/V FIFOs on ENA 0->1 transitions */
@@ -150,15 +160,14 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
dcrtc->base + LCD_SPU_SRAM_PARA1);
}
- ret = wait_event_timeout(dplane->vbl.wait,
- list_empty(&dplane->vbl.update.node),
- HZ/25);
- if (ret < 0)
- return ret;
+ wait_event_timeout(dplane->vbl.wait,
+ list_empty(&dplane->vbl.update.node),
+ HZ/25);
if (plane->fb != fb) {
struct armada_gem_object *obj = drm_fb_obj(fb);
- uint32_t sy, su, sv;
+ uint32_t addr[3], pixel_format;
+ int i, num_planes, hsub;
/*
* Take a reference on the new framebuffer - we want to
@@ -178,26 +187,39 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
older_fb);
}
- src_y >>= 16;
- src_x >>= 16;
- sy = obj->dev_addr + fb->offsets[0] + src_y * fb->pitches[0] +
- src_x * fb->bits_per_pixel / 8;
- su = obj->dev_addr + fb->offsets[1] + src_y * fb->pitches[1] +
- src_x;
- sv = obj->dev_addr + fb->offsets[2] + src_y * fb->pitches[2] +
- src_x;
+ src_y = src.y1 >> 16;
+ src_x = src.x1 >> 16;
- armada_reg_queue_set(dplane->vbl.regs, idx, sy,
+ pixel_format = fb->pixel_format;
+ hsub = drm_format_horz_chroma_subsampling(pixel_format);
+ num_planes = drm_format_num_planes(pixel_format);
+
+ /*
+ * Annoyingly, shifting a YUYV-format image by one pixel
+ * causes the U/V planes to toggle. Toggle the UV swap.
+ * (Unfortunately, this causes momentary colour flickering.)
+ */
+ if (src_x & (hsub - 1) && num_planes == 1)
+ ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV);
+
+ for (i = 0; i < num_planes; i++)
+ addr[i] = obj->dev_addr + fb->offsets[i] +
+ src_y * fb->pitches[i] +
+ src_x * drm_format_plane_cpp(pixel_format, i);
+ for (; i < ARRAY_SIZE(addr); i++)
+ addr[i] = 0;
+
+ armada_reg_queue_set(dplane->vbl.regs, idx, addr[0],
LCD_SPU_DMA_START_ADDR_Y0);
- armada_reg_queue_set(dplane->vbl.regs, idx, su,
+ armada_reg_queue_set(dplane->vbl.regs, idx, addr[1],
LCD_SPU_DMA_START_ADDR_U0);
- armada_reg_queue_set(dplane->vbl.regs, idx, sv,
+ armada_reg_queue_set(dplane->vbl.regs, idx, addr[2],
LCD_SPU_DMA_START_ADDR_V0);
- armada_reg_queue_set(dplane->vbl.regs, idx, sy,
+ armada_reg_queue_set(dplane->vbl.regs, idx, addr[0],
LCD_SPU_DMA_START_ADDR_Y1);
- armada_reg_queue_set(dplane->vbl.regs, idx, su,
+ armada_reg_queue_set(dplane->vbl.regs, idx, addr[1],
LCD_SPU_DMA_START_ADDR_U1);
- armada_reg_queue_set(dplane->vbl.regs, idx, sv,
+ armada_reg_queue_set(dplane->vbl.regs, idx, addr[2],
LCD_SPU_DMA_START_ADDR_V1);
val = fb->pitches[0] << 16 | fb->pitches[0];
@@ -208,24 +230,27 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
LCD_SPU_DMA_PITCH_UV);
}
- val = (src_h & 0xffff0000) | src_w >> 16;
+ val = (drm_rect_height(&src) & 0xffff0000) | drm_rect_width(&src) >> 16;
if (dplane->src_hw != val) {
dplane->src_hw = val;
armada_reg_queue_set(dplane->vbl.regs, idx, val,
LCD_SPU_DMA_HPXL_VLN);
}
- val = crtc_h << 16 | crtc_w;
+
+ val = drm_rect_height(&dest) << 16 | drm_rect_width(&dest);
if (dplane->dst_hw != val) {
dplane->dst_hw = val;
armada_reg_queue_set(dplane->vbl.regs, idx, val,
LCD_SPU_DZM_HPXL_VLN);
}
- val = crtc_y << 16 | crtc_x;
+
+ val = dest.y1 << 16 | dest.x1;
if (dplane->dst_yx != val) {
dplane->dst_yx = val;
armada_reg_queue_set(dplane->vbl.regs, idx, val,
LCD_SPU_DMA_OVSA_HPXL_VLN);
}
+
if (dplane->ctrl0 != ctrl0) {
dplane->ctrl0 = ctrl0;
armada_reg_queue_mod(dplane->vbl.regs, idx, ctrl0,
@@ -279,7 +304,11 @@ static int armada_plane_disable(struct drm_plane *plane)
static void armada_plane_destroy(struct drm_plane *plane)
{
- kfree(plane);
+ struct armada_plane *dplane = drm_to_armada_plane(plane);
+
+ drm_plane_cleanup(plane);
+
+ kfree(dplane);
}
static int armada_plane_set_property(struct drm_plane *plane,