summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/sti
diff options
context:
space:
mode:
authorVincent Abriou <vincent.abriou@st.com>2015-08-03 14:22:16 +0200
committerBenjamin Gaignard <benjamin.gaignard@linaro.org>2015-08-03 14:26:05 +0200
commit29d1dc62e1618192a25bd2eae9617529b9930cfc (patch)
tree67e0151ceaad7b164d1f2b7accc7d6f21f377299 /drivers/gpu/drm/sti
parent9e1f05b28009ca7de50fb92c227c8046f686e2c5 (diff)
drm/sti: atomic crtc/plane update
Better fit STI hardware structure. Planes are no more responsible of updating mixer information such as z-order and status. It is now up to the CRTC atomic flush to do it. Plane actions (enable or disable) are performed atomically. Disabling of a plane is synchronize with the vsync event. Signed-off-by: Vincent Abriou <vincent.abriou@st.com> Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Diffstat (limited to 'drivers/gpu/drm/sti')
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c32
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c133
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c211
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.h6
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c493
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.h8
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c429
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c10
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.h11
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c253
-rw-r--r--drivers/gpu/drm/sti/sti_plane.h66
-rw-r--r--drivers/gpu/drm/sti/sti_vid.c29
-rw-r--r--drivers/gpu/drm/sti/sti_vid.h5
13 files changed, 809 insertions, 877 deletions
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index d62ed7f4cb2c..c652627b1bca 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -61,15 +61,13 @@ static int sti_compositor_bind(struct device *dev,
{
struct sti_compositor *compo = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
- unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0;
+ unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0;
struct sti_private *dev_priv = drm_dev->dev_private;
struct drm_plane *cursor = NULL;
struct drm_plane *primary = NULL;
struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc;
unsigned int array_size = compo->data.nb_subdev;
- struct sti_plane *plane;
-
dev_priv->compo = compo;
/* Register mixer subdev and video subdev first */
@@ -110,27 +108,25 @@ static int sti_compositor_bind(struct device *dev,
/* Nothing to do, already done at the first round */
break;
case STI_CURSOR_SUBDEV:
- plane = sti_cursor_create(compo->dev, desc[i].id,
- compo->regs + desc[i].offset);
- if (!plane) {
+ cursor = sti_cursor_create(drm_dev, compo->dev,
+ desc[i].id,
+ compo->regs + desc[i].offset,
+ 1);
+ if (!cursor) {
DRM_ERROR("Can't create CURSOR plane\n");
break;
}
- cursor = sti_plane_init(drm_dev, plane, 1,
- DRM_PLANE_TYPE_CURSOR);
- plane_id++;
break;
case STI_GPD_SUBDEV:
- plane = sti_gdp_create(compo->dev, desc[i].id,
- compo->regs + desc[i].offset);
- if (!plane) {
+ primary = sti_gdp_create(drm_dev, compo->dev,
+ desc[i].id,
+ compo->regs + desc[i].offset,
+ (1 << mixer_id) - 1,
+ plane_type);
+ if (!primary) {
DRM_ERROR("Can't create GDP plane\n");
break;
}
- primary = sti_plane_init(drm_dev, plane,
- (1 << mixer_id) - 1,
- plane_type);
- plane_id++;
break;
default:
DRM_ERROR("Unknown subdev compoment type\n");
@@ -151,10 +147,6 @@ static int sti_compositor_bind(struct device *dev,
/* Allow usage of vblank without having to call drm_irq_install */
drm_dev->irq_enabled = 1;
- DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
- crtc_id, plane_id);
- DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");
-
return 0;
}
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index 27b3ef207617..23fc2db50d17 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -17,20 +17,18 @@
#include "sti_compositor.h"
#include "sti_crtc.h"
#include "sti_drv.h"
+#include "sti_vid.h"
#include "sti_vtg.h"
-static void sti_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
- DRM_DEBUG_KMS("\n");
-}
-
-static void sti_crtc_prepare(struct drm_crtc *crtc)
+static void sti_crtc_enable(struct drm_crtc *crtc)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev);
- mixer->enabled = true;
+ DRM_DEBUG_DRIVER("\n");
+
+ mixer->status = STI_MIXER_READY;
/* Prepare and enable the compo IP clock */
if (mixer->id == STI_MIXER_MAIN) {
@@ -41,31 +39,16 @@ static void sti_crtc_prepare(struct drm_crtc *crtc)
DRM_INFO("Failed to prepare/enable compo_aux clk\n");
}
- sti_mixer_clear_all_planes(mixer);
+ drm_crtc_vblank_on(crtc);
}
-static void sti_crtc_commit(struct drm_crtc *crtc)
+static void sti_crtc_disabling(struct drm_crtc *crtc)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
- struct device *dev = mixer->dev;
- struct sti_compositor *compo = dev_get_drvdata(dev);
- struct sti_plane *plane;
-
- if ((!mixer || !compo)) {
- DRM_ERROR("Can't find mixer or compositor)\n");
- return;
- }
-
- /* get GDP which is reserved to the CRTC FB */
- plane = to_sti_plane(crtc->primary);
- if (!plane)
- DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n");
- /* Enable plane on mixer */
- if (sti_mixer_set_plane_status(mixer, plane, true))
- DRM_ERROR("Cannot enable plane at mixer\n");
+ DRM_DEBUG_DRIVER("\n");
- drm_crtc_vblank_on(crtc);
+ mixer->status = STI_MIXER_DISABLING;
}
static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -133,9 +116,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
struct device *dev = mixer->dev;
struct sti_compositor *compo = dev_get_drvdata(dev);
- if (!mixer->enabled)
- return;
-
DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
/* Disable Background */
@@ -152,13 +132,13 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
clk_disable_unprepare(compo->clk_compo_aux);
}
- mixer->enabled = false;
+ mixer->status = STI_MIXER_DISABLED;
}
static void
sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
- sti_crtc_prepare(crtc);
+ sti_crtc_enable(crtc);
sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
}
@@ -178,17 +158,79 @@ static void sti_crtc_atomic_begin(struct drm_crtc *crtc)
static void sti_crtc_atomic_flush(struct drm_crtc *crtc)
{
+ struct drm_device *drm_dev = crtc->dev;
+ struct sti_mixer *mixer = to_sti_mixer(crtc);
+ struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
+ struct drm_plane *p;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ /* perform plane actions */
+ list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
+ struct sti_plane *plane = to_sti_plane(p);
+
+ switch (plane->status) {
+ case STI_PLANE_UPDATED:
+ /* update planes tag as updated */
+ DRM_DEBUG_DRIVER("update plane %s\n",
+ sti_plane_to_str(plane));
+
+ if (sti_mixer_set_plane_depth(mixer, plane)) {
+ DRM_ERROR("Cannot set plane %s depth\n",
+ sti_plane_to_str(plane));
+ break;
+ }
+
+ if (sti_mixer_set_plane_status(mixer, plane, true)) {
+ DRM_ERROR("Cannot enable plane %s at mixer\n",
+ sti_plane_to_str(plane));
+ break;
+ }
+
+ /* if plane is HQVDP_0 then commit the vid[0] */
+ if (plane->desc == STI_HQVDP_0)
+ sti_vid_commit(compo->vid[0], p->state);
+
+ plane->status = STI_PLANE_READY;
+
+ break;
+ case STI_PLANE_DISABLING:
+ /* disabling sequence for planes tag as disabling */
+ DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
+ sti_plane_to_str(plane));
+
+ if (sti_mixer_set_plane_status(mixer, plane, false)) {
+ DRM_ERROR("Cannot disable plane %s at mixer\n",
+ sti_plane_to_str(plane));
+ continue;
+ }
+
+ if (plane->desc == STI_CURSOR)
+ /* tag plane status for disabled */
+ plane->status = STI_PLANE_DISABLED;
+ else
+ /* tag plane status for flushing */
+ plane->status = STI_PLANE_FLUSHING;
+
+ /* if plane is HQVDP_0 then disable the vid[0] */
+ if (plane->desc == STI_HQVDP_0)
+ sti_vid_disable(compo->vid[0]);
+
+ break;
+ default:
+ /* Other status case are not handled */
+ break;
+ }
+ }
}
static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
- .dpms = sti_crtc_dpms,
- .prepare = sti_crtc_prepare,
- .commit = sti_crtc_commit,
+ .enable = sti_crtc_enable,
+ .disable = sti_crtc_disabling,
.mode_fixup = sti_crtc_mode_fixup,
.mode_set = drm_helper_crtc_mode_set,
.mode_set_nofb = sti_crtc_mode_set_nofb,
.mode_set_base = drm_helper_crtc_mode_set_base,
- .disable = sti_crtc_disable,
.atomic_begin = sti_crtc_atomic_begin,
.atomic_flush = sti_crtc_atomic_flush,
};
@@ -237,6 +279,21 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
}
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+ if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
+ struct drm_plane *p;
+
+ /* Disable mixer only if all overlay planes (GDP and VDP)
+ * are disabled */
+ list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
+ struct sti_plane *plane = to_sti_plane(p);
+
+ if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
+ if (plane->status != STI_PLANE_DISABLED)
+ return 0;
+ }
+ sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
+ }
+
return 0;
}
@@ -259,9 +316,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc)
}
EXPORT_SYMBOL(sti_crtc_enable_vblank);
-void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)
+void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc)
{
- struct sti_private *priv = dev->dev_private;
+ struct sti_private *priv = drm_dev->dev_private;
struct sti_compositor *compo = priv->compo;
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
@@ -273,7 +330,7 @@ void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)
/* free the resources of the pending requests */
if (compo->mixer[crtc]->pending_event) {
- drm_vblank_put(dev, crtc);
+ drm_vblank_put(drm_dev, crtc);
compo->mixer[crtc]->pending_event = NULL;
}
}
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 2868909aa926..dd1032195051 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -7,6 +7,12 @@
*/
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "sti_compositor.h"
#include "sti_cursor.h"
#include "sti_plane.h"
#include "sti_vtg.h"
@@ -42,14 +48,14 @@ struct dma_pixmap {
/**
* STI Cursor structure
*
- * @sti_plane: sti_plane structure
- * @dev: driver device
- * @regs: cursor registers
- * @width: cursor width
- * @height: cursor height
- * @clut: color look up table
- * @clut_paddr: color look up table physical address
- * @pixmap: pixmap dma buffer (clut8-format cursor)
+ * @sti_plane: sti_plane structure
+ * @dev: driver device
+ * @regs: cursor registers
+ * @width: cursor width
+ * @height: cursor height
+ * @clut: color look up table
+ * @clut_paddr: color look up table physical address
+ * @pixmap: pixmap dma buffer (clut8-format cursor)
*/
struct sti_cursor {
struct sti_plane plane;
@@ -68,20 +74,8 @@ static const uint32_t cursor_supported_formats[] = {
#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
-static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane)
-{
- return cursor_supported_formats;
-}
-
-static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane)
-{
- return ARRAY_SIZE(cursor_supported_formats);
-}
-
-static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
+static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
{
- struct sti_cursor *cursor = to_sti_cursor(plane);
- u32 *src = plane->vaddr;
u8 *dst = cursor->pixmap.base;
unsigned int i, j;
u32 a, r, g, b;
@@ -100,32 +94,67 @@ static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
}
}
-static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
+static void sti_cursor_init(struct sti_cursor *cursor)
+{
+ unsigned short *base = cursor->clut;
+ unsigned int a, r, g, b;
+
+ /* Assign CLUT values, ARGB444 format */
+ for (a = 0; a < 4; a++)
+ for (r = 0; r < 4; r++)
+ for (g = 0; g < 4; g++)
+ for (b = 0; b < 4; b++)
+ *base++ = (a * 5) << 12 |
+ (r * 5) << 8 |
+ (g * 5) << 4 |
+ (b * 5);
+}
+
+static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
+ struct drm_plane_state *oldstate)
{
+ struct drm_plane_state *state = drm_plane->state;
+ struct sti_plane *plane = to_sti_plane(drm_plane);
struct sti_cursor *cursor = to_sti_cursor(plane);
- struct drm_display_mode *mode = plane->mode;
+ struct drm_crtc *crtc = state->crtc;
+ struct sti_mixer *mixer = to_sti_mixer(crtc);
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_display_mode *mode = &crtc->mode;
+ int dst_x = state->crtc_x;
+ int dst_y = state->crtc_y;
+ int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+ int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+ /* src_x are in 16.16 format */
+ int src_w = state->src_w >> 16;
+ int src_h = state->src_h >> 16;
+ bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
+ struct drm_gem_cma_object *cma_obj;
u32 y, x;
u32 val;
- DRM_DEBUG_DRIVER("\n");
+ DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
+ crtc->base.id, sti_mixer_to_str(mixer),
+ drm_plane->base.id, sti_plane_to_str(plane));
+ DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
- dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
+ dev_dbg(cursor->dev, "%s %s\n", __func__,
+ sti_plane_to_str(plane));
- if (plane->src_w < STI_CURS_MIN_SIZE ||
- plane->src_h < STI_CURS_MIN_SIZE ||
- plane->src_w > STI_CURS_MAX_SIZE ||
- plane->src_h > STI_CURS_MAX_SIZE) {
+ if (src_w < STI_CURS_MIN_SIZE ||
+ src_h < STI_CURS_MIN_SIZE ||
+ src_w > STI_CURS_MAX_SIZE ||
+ src_h > STI_CURS_MAX_SIZE) {
DRM_ERROR("Invalid cursor size (%dx%d)\n",
- plane->src_w, plane->src_h);
- return -EINVAL;
+ src_w, src_h);
+ return;
}
/* If the cursor size has changed, re-allocated the pixmap */
if (!cursor->pixmap.base ||
- (cursor->width != plane->src_w) ||
- (cursor->height != plane->src_h)) {
- cursor->width = plane->src_w;
- cursor->height = plane->src_h;
+ (cursor->width != src_w) ||
+ (cursor->height != src_h)) {
+ cursor->width = src_w;
+ cursor->height = src_h;
if (cursor->pixmap.base)
dma_free_writecombine(cursor->dev,
@@ -141,12 +170,18 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
GFP_KERNEL | GFP_DMA);
if (!cursor->pixmap.base) {
DRM_ERROR("Failed to allocate memory for pixmap\n");
- return -ENOMEM;
+ return;
}
}
+ cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ if (!cma_obj) {
+ DRM_ERROR("Can't get CMA GEM object for fb\n");
+ return;
+ }
+
/* Convert ARGB8888 to CLUT8 */
- sti_cursor_argb8888_to_clut8(plane);
+ sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
/* AWS and AWE depend on the mode */
y = sti_vtg_get_line_number(*mode, 0);
@@ -164,62 +199,50 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
}
- return 0;
-}
-
-static int sti_cursor_commit_plane(struct sti_plane *plane)
-{
- struct sti_cursor *cursor = to_sti_cursor(plane);
- struct drm_display_mode *mode = plane->mode;
- u32 ydo, xdo;
-
- dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
-
/* Set memory location, size, and position */
writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
writel(cursor->width, cursor->regs + CUR_PMP);
writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);
- ydo = sti_vtg_get_line_number(*mode, plane->dst_y);
- xdo = sti_vtg_get_pixel_number(*mode, plane->dst_y);
- writel((ydo << 16) | xdo, cursor->regs + CUR_VPO);
+ y = sti_vtg_get_line_number(*mode, dst_y);
+ x = sti_vtg_get_pixel_number(*mode, dst_y);
+ writel((y << 16) | x, cursor->regs + CUR_VPO);
- return 0;
+ plane->status = STI_PLANE_UPDATED;
}
-static int sti_cursor_disable_plane(struct sti_plane *plane)
+static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
+ struct drm_plane_state *oldstate)
{
- return 0;
-}
+ struct sti_plane *plane = to_sti_plane(drm_plane);
+ struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
-static void sti_cursor_init(struct sti_cursor *cursor)
-{
- unsigned short *base = cursor->clut;
- unsigned int a, r, g, b;
+ if (!drm_plane->crtc) {
+ DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
+ drm_plane->base.id);
+ return;
+ }
- /* Assign CLUT values, ARGB444 format */
- for (a = 0; a < 4; a++)
- for (r = 0; r < 4; r++)
- for (g = 0; g < 4; g++)
- for (b = 0; b < 4; b++)
- *base++ = (a * 5) << 12 |
- (r * 5) << 8 |
- (g * 5) << 4 |
- (b * 5);
+ DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
+ drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
+ drm_plane->base.id, sti_plane_to_str(plane));
+
+ plane->status = STI_PLANE_DISABLING;
}
-static const struct sti_plane_funcs cursor_plane_ops = {
- .get_formats = sti_cursor_get_formats,
- .get_nb_formats = sti_cursor_get_nb_formats,
- .prepare = sti_cursor_prepare_plane,
- .commit = sti_cursor_commit_plane,
- .disable = sti_cursor_disable_plane,
+static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
+ .atomic_update = sti_cursor_atomic_update,
+ .atomic_disable = sti_cursor_atomic_disable,
};
-struct sti_plane *sti_cursor_create(struct device *dev, int desc,
- void __iomem *baseaddr)
+struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
+ struct device *dev, int desc,
+ void __iomem *baseaddr,
+ unsigned int possible_crtcs)
{
struct sti_cursor *cursor;
+ size_t size;
+ int res;
cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
if (!cursor) {
@@ -228,23 +251,43 @@ struct sti_plane *sti_cursor_create(struct device *dev, int desc,
}
/* Allocate clut buffer */
- cursor->clut = dma_alloc_writecombine(dev,
- 0x100 * sizeof(unsigned short),
- &cursor->clut_paddr,
- GFP_KERNEL | GFP_DMA);
+ size = 0x100 * sizeof(unsigned short);
+ cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr,
+ GFP_KERNEL | GFP_DMA);
if (!cursor->clut) {
DRM_ERROR("Failed to allocate memory for cursor clut\n");
- devm_kfree(dev, cursor);
- return NULL;
+ goto err_clut;
}
cursor->dev = dev;
cursor->regs = baseaddr;
cursor->plane.desc = desc;
- cursor->plane.ops = &cursor_plane_ops;
+ cursor->plane.status = STI_PLANE_DISABLED;
sti_cursor_init(cursor);
- return &cursor->plane;
+ res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane,
+ possible_crtcs,
+ &sti_plane_helpers_funcs,
+ cursor_supported_formats,
+ ARRAY_SIZE(cursor_supported_formats),
+ DRM_PLANE_TYPE_CURSOR);
+ if (res) {
+ DRM_ERROR("Failed to initialize universal plane\n");
+ goto err_plane;
+ }
+
+ drm_plane_helper_add(&cursor->plane.drm_plane,
+ &sti_cursor_helpers_funcs);
+
+ sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
+
+ return &cursor->plane.drm_plane;
+
+err_plane:
+ dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr);
+err_clut:
+ devm_kfree(dev, cursor);
+ return NULL;
}
diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h
index db973b705d92..2ee5c10e8b33 100644
--- a/drivers/gpu/drm/sti/sti_cursor.h
+++ b/drivers/gpu/drm/sti/sti_cursor.h
@@ -7,7 +7,9 @@
#ifndef _STI_CURSOR_H_
#define _STI_CURSOR_H_
-struct sti_plane *sti_cursor_create(struct device *dev, int desc,
- void __iomem *baseaddr);
+struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
+ struct device *dev, int desc,
+ void __iomem *baseaddr,
+ unsigned int possible_crtcs);
#endif
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index e323310bfa73..9365670427ad 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -9,6 +9,9 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
#include "sti_compositor.h"
#include "sti_gdp.h"
#include "sti_plane.h"
@@ -26,7 +29,7 @@
#define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
#define GDP_ARGB8565 0x04
#define GDP_ARGB8888 0x05
-#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
+#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
#define GDP_ARGB1555 0x06
#define GDP_ARGB4444 0x07
#define GDP_CLUT8 0x0B
@@ -53,8 +56,8 @@
#define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0))
#define GAM_GDP_SIZE_MAX 0x7FF
-#define GDP_NODE_NB_BANK 2
-#define GDP_NODE_PER_FIELD 2
+#define GDP_NODE_NB_BANK 2
+#define GDP_NODE_PER_FIELD 2
struct sti_gdp_node {
u32 gam_gdp_ctl;
@@ -124,16 +127,6 @@ static const uint32_t gdp_supported_formats[] = {
DRM_FORMAT_C8,
};
-static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane)
-{
- return gdp_supported_formats;
-}
-
-static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane)
-{
- return ARRAY_SIZE(gdp_supported_formats);
-}
-
static int sti_gdp_fourcc2format(int fourcc)
{
switch (fourcc) {
@@ -179,17 +172,16 @@ static int sti_gdp_get_alpharange(int format)
/**
* sti_gdp_get_free_nodes
- * @plane: gdp plane
+ * @gdp: gdp pointer
*
* Look for a GDP node list that is not currently read by the HW.
*
* RETURNS:
* Pointer to the free GDP node list
*/
-static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane)
+static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_gdp *gdp)
{
int hw_nvn;
- struct sti_gdp *gdp = to_sti_gdp(plane);
unsigned int i;
hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
@@ -203,7 +195,7 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane)
/* in hazardious cases restart with the first node */
DRM_ERROR("inconsistent NVN for %s: 0x%08X\n",
- sti_plane_to_str(plane), hw_nvn);
+ sti_plane_to_str(&gdp->plane), hw_nvn);
end:
return &gdp->node_list[0];
@@ -211,7 +203,7 @@ end:
/**
* sti_gdp_get_current_nodes
- * @plane: GDP plane
+ * @gdp: gdp pointer
*
* Look for GDP nodes that are currently read by the HW.
*
@@ -219,10 +211,9 @@ end:
* Pointer to the current GDP node list
*/
static
-struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane)
+struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_gdp *gdp)
{
int hw_nvn;
- struct sti_gdp *gdp = to_sti_gdp(plane);
unsigned int i;
hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
@@ -236,205 +227,25 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane)
end:
DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n",
- hw_nvn, sti_plane_to_str(plane));
+ hw_nvn, sti_plane_to_str(&gdp->plane));
return NULL;
}
/**
- * sti_gdp_prepare
- * @plane: gdp plane
- * @first_prepare: true if it is the first time this function is called
- *
- * Update the free GDP node list according to the plane properties.
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_gdp_prepare(struct sti_plane *plane, bool first_prepare)
-{
- struct sti_gdp_node_list *list;
- struct sti_gdp_node *top_field, *btm_field;
- struct drm_display_mode *mode = plane->mode;
- struct sti_gdp *gdp = to_sti_gdp(plane);
- struct device *dev = gdp->dev;
- struct sti_compositor *compo = dev_get_drvdata(dev);
- int format;
- unsigned int depth, bpp;
- int rate = mode->clock * 1000;
- int res;
- u32 ydo, xdo, yds, xds;
-
- list = sti_gdp_get_free_nodes(plane);
- top_field = list->top_field;
- btm_field = list->btm_field;
-
- dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
- sti_plane_to_str(plane), top_field, btm_field);
-
- /* Build the top field from plane params */
- top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
- top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
- format = sti_gdp_fourcc2format(plane->format);
- if (format == -1) {
- DRM_ERROR("Format not supported by GDP %.4s\n",
- (char *)&plane->format);
- return 1;
- }
- top_field->gam_gdp_ctl |= format;
- top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
- top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
-
- /* pixel memory location */
- drm_fb_get_bpp_depth(plane->format, &depth, &bpp);
- top_field->gam_gdp_pml = (u32)plane->paddr + plane->offsets[0];
- top_field->gam_gdp_pml += plane->src_x * (bpp >> 3);
- top_field->gam_gdp_pml += plane->src_y * plane->pitches[0];
-
- /* input parameters */
- top_field->gam_gdp_pmp = plane->pitches[0];
- top_field->gam_gdp_size =
- clamp_val(plane->src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
- clamp_val(plane->src_w, 0, GAM_GDP_SIZE_MAX);
-
- /* output parameters */
- ydo = sti_vtg_get_line_number(*mode, plane->dst_y);
- yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1);
- xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x);
- xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1);
- top_field->gam_gdp_vpo = (ydo << 16) | xdo;
- top_field->gam_gdp_vps = (yds << 16) | xds;
-
- /* Same content and chained together */
- memcpy(btm_field, top_field, sizeof(*btm_field));
- top_field->gam_gdp_nvn = list->btm_field_paddr;
- btm_field->gam_gdp_nvn = list->top_field_paddr;
-
- /* Interlaced mode */
- if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE)
- btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
- plane->pitches[0];
-
- if (first_prepare) {
- /* Register gdp callback */
- if (sti_vtg_register_client(plane->mixer_id == STI_MIXER_MAIN ?
- compo->vtg_main : compo->vtg_aux,
- &gdp->vtg_field_nb, plane->mixer_id)) {
- DRM_ERROR("Cannot register VTG notifier\n");
- return 1;
- }
-
- /* Set and enable gdp clock */
- if (gdp->clk_pix) {
- struct clk *clkp;
- /* According to the mixer used, the gdp pixel clock
- * should have a different parent clock. */
- if (plane->mixer_id == STI_MIXER_MAIN)
- clkp = gdp->clk_main_parent;
- else
- clkp = gdp->clk_aux_parent;
-
- if (clkp)
- clk_set_parent(gdp->clk_pix, clkp);
-
- res = clk_set_rate(gdp->clk_pix, rate);
- if (res < 0) {
- DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
- rate);
- return 1;
- }
-
- if (clk_prepare_enable(gdp->clk_pix)) {
- DRM_ERROR("Failed to prepare/enable gdp\n");
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-/**
- * sti_gdp_commit
- * @plane: gdp plane
- *
- * Update the NVN field of the 'right' field of the current GDP node (being
- * used by the HW) with the address of the updated ('free') top field GDP node.
- * - In interlaced mode the 'right' field is the bottom field as we update
- * frames starting from their top field
- * - In progressive mode, we update both bottom and top fields which are
- * equal nodes.
- * At the next VSYNC, the updated node list will be used by the HW.
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_gdp_commit(struct sti_plane *plane)
-{
- struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(plane);
- struct sti_gdp_node *updated_top_node = updated_list->top_field;
- struct sti_gdp_node *updated_btm_node = updated_list->btm_field;
- struct sti_gdp *gdp = to_sti_gdp(plane);
- u32 dma_updated_top = updated_list->top_field_paddr;
- u32 dma_updated_btm = updated_list->btm_field_paddr;
- struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(plane);
-
- dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__,
- sti_plane_to_str(plane),
- updated_top_node, updated_btm_node);
- dev_dbg(gdp->dev, "Current NVN:0x%X\n",
- readl(gdp->regs + GAM_GDP_NVN_OFFSET));
- dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
- (unsigned long)plane->paddr,
- readl(gdp->regs + GAM_GDP_PML_OFFSET));
-
- if (curr_list == NULL) {
- /* First update or invalid node should directly write in the
- * hw register */
- DRM_DEBUG_DRIVER("%s first update (or invalid node)",
- sti_plane_to_str(plane));
-
- writel(gdp->is_curr_top == true ?
- dma_updated_btm : dma_updated_top,
- gdp->regs + GAM_GDP_NVN_OFFSET);
- return 0;
- }
-
- if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) {
- if (gdp->is_curr_top == true) {
- /* Do not update in the middle of the frame, but
- * postpone the update after the bottom field has
- * been displayed */
- curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
- } else {
- /* Direct update to avoid one frame delay */
- writel(dma_updated_top,
- gdp->regs + GAM_GDP_NVN_OFFSET);
- }
- } else {
- /* Direct update for progressive to avoid one frame delay */
- writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET);
- }
-
- return 0;
-}
-
-/**
* sti_gdp_disable
- * @plane: gdp plane
+ * @gdp: gdp pointer
*
* Disable a GDP.
- *
- * RETURNS:
- * 0 on success.
*/
-static int sti_gdp_disable(struct sti_plane *plane)
+static void sti_gdp_disable(struct sti_gdp *gdp)
{
- unsigned int i;
- struct sti_gdp *gdp = to_sti_gdp(plane);
+ struct drm_plane *drm_plane = &gdp->plane.drm_plane;
+ struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
+ unsigned int i;
- DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane));
+ DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane));
/* Set the nodes as 'to be ignored on mixer' */
for (i = 0; i < GDP_NODE_NB_BANK; i++) {
@@ -442,14 +253,14 @@ static int sti_gdp_disable(struct sti_plane *plane)
gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
}
- if (sti_vtg_unregister_client(plane->mixer_id == STI_MIXER_MAIN ?
+ if (sti_vtg_unregister_client(mixer->id == STI_MIXER_MAIN ?
compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb))
DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
if (gdp->clk_pix)
clk_disable_unprepare(gdp->clk_pix);
- return 0;
+ gdp->plane.status = STI_PLANE_DISABLED;
}
/**
@@ -468,6 +279,14 @@ int sti_gdp_field_cb(struct notifier_block *nb,
{
struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb);
+ if (gdp->plane.status == STI_PLANE_FLUSHING) {
+ /* disable need to be synchronize on vsync event */
+ DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
+ sti_plane_to_str(&gdp->plane));
+
+ sti_gdp_disable(gdp);
+ }
+
switch (event) {
case VTG_TOP_FIELD_EVENT:
gdp->is_curr_top = true;
@@ -561,18 +380,235 @@ static void sti_gdp_init(struct sti_gdp *gdp)
}
}
-static const struct sti_plane_funcs gdp_plane_ops = {
- .get_formats = sti_gdp_get_formats,
- .get_nb_formats = sti_gdp_get_nb_formats,
- .prepare = sti_gdp_prepare,
- .commit = sti_gdp_commit,
- .disable = sti_gdp_disable,
+static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
+ struct drm_plane_state *oldstate)
+{
+ struct drm_plane_state *state = drm_plane->state;
+ struct sti_plane *plane = to_sti_plane(drm_plane);
+ struct sti_gdp *gdp = to_sti_gdp(plane