@@ -111,36 +111,47 @@ static void rcar_du_crtc_start_stop(struct rcar_du_crtc *rcrtc, bool start)
rcar_du_crtc_write(rcrtc, DSYSR, value | DSYSR_DRES);
}
-void rcar_du_crtc_enable_plane(struct rcar_du_plane *rplane, bool enable)
+void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
{
- struct rcar_du_crtc *rcrtc = to_rcar_crtc(rplane->crtc);
- struct rcar_du_device *rcdu = rplane->crtc->dev->dev_private;
- unsigned int prio;
+ struct rcar_du_device *rcdu = crtc->dev->dev_private;
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ struct rcar_du_plane *planes[ARRAY_SIZE(rcdu->planes.planes)];
+ unsigned int num_planes = 0;
+ unsigned int prio = 0;
unsigned int i;
u32 dspr = 0;
- mutex_lock(&rcdu->planes.lock);
-
- rplane->enabled = enable;
-
- for (i = 0, prio = 28; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
+ for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
struct rcar_du_plane *plane = &rcdu->planes.planes[i];
+ unsigned int j;
if (plane->crtc != &rcrtc->crtc || !plane->enabled)
continue;
- dspr |= (plane->hwindex + 1) << prio;
+ /* Insert the plane in the sorted planes array. */
+ for (j = num_planes++; j > 0; --j) {
+ if (planes[j-1]->zpos <= plane->zpos)
+ break;
+ planes[j] = planes[j-1];
+ }
+
+ planes[j] = plane;
+ prio += plane->format->planes * 4;
+ }
+
+ for (i = 0; i < num_planes; ++i) {
+ struct rcar_du_plane *plane = planes[i];
+
prio -= 4;
+ dspr |= (plane->hwindex + 1) << prio;
if (plane->format->planes == 2) {
- dspr |= (plane->hwindex + 2) << prio;
prio -= 4;
+ dspr |= (plane->hwindex + 2) << prio;
}
}
rcar_du_crtc_write(rcrtc, DS1PR, dspr);
-
- mutex_unlock(&rcdu->planes.lock);
}
/*
@@ -180,7 +191,11 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
rcar_du_crtc_set_display_timing(rcrtc);
rcar_du_plane_setup(rcrtc->plane);
- rcar_du_crtc_enable_plane(rcrtc->plane, true);
+
+ mutex_lock(&rcdu->planes.lock);
+ rcrtc->plane->enabled = true;
+ rcar_du_crtc_update_planes(crtc);
+ mutex_unlock(&rcdu->planes.lock);
/* Setup planes. */
list_for_each_entry(plane, &rcdu->ddev->mode_config.plane_list, head) {
@@ -205,7 +220,11 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
if (!rcrtc->started)
return;
- rcar_du_crtc_enable_plane(rcrtc->plane, false);
+ mutex_lock(&rcdu->planes.lock);
+ rcrtc->plane->enabled = false;
+ rcar_du_crtc_update_planes(crtc);
+ mutex_unlock(&rcdu->planes.lock);
+
rcar_du_crtc_start_stop(rcrtc, false);
clk_disable(rcdu->clock);
@@ -42,6 +42,7 @@ void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
struct drm_file *file);
void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc);
void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
-void rcar_du_crtc_enable_plane(struct rcar_du_plane *plane, bool enable);
+
+void rcar_du_crtc_update_planes(struct drm_crtc *crtc);
#endif /* __RCAR_DU_CRTC_H__ */
@@ -40,6 +40,8 @@ struct rcar_du_device {
struct rcar_du_plane planes[8];
unsigned int free;
struct mutex lock;
+
+ struct drm_property *zpos;
} planes;
};
@@ -245,15 +245,24 @@ rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
rcar_du_plane_compute_base(rplane, fb);
rcar_du_plane_setup(rplane);
- rcar_du_crtc_enable_plane(rplane, true);
+ mutex_lock(&rcdu->planes.lock);
+ rplane->enabled = true;
+ rcar_du_crtc_update_planes(rplane->crtc);
+ mutex_unlock(&rcdu->planes.lock);
+
return 0;
}
static int rcar_du_plane_disable(struct drm_plane *plane)
{
+ struct rcar_du_device *rcdu = plane->dev->dev_private;
struct rcar_du_plane *rplane = to_rcar_plane(plane);
- rcar_du_crtc_enable_plane(rplane, false);
+ mutex_lock(&rcdu->planes.lock);
+ rplane->enabled = false;
+ rcar_du_crtc_update_planes(rplane->crtc);
+ mutex_unlock(&rcdu->planes.lock);
+
rcar_du_plane_release(rplane);
rplane->crtc = NULL;
@@ -262,9 +271,35 @@ static int rcar_du_plane_disable(struct drm_plane *plane)
return 0;
}
+static int rcar_du_plane_set_property(struct drm_plane *plane,
+ struct drm_property *property,
+ uint64_t value)
+{
+ struct rcar_du_device *rcdu = plane->dev->dev_private;
+ struct rcar_du_plane *rplane = to_rcar_plane(plane);
+
+ if (property != rcdu->planes.zpos)
+ return -EINVAL;
+
+ mutex_lock(&rcdu->planes.lock);
+ if (rplane->zpos == value)
+ goto done;
+
+ rplane->zpos = value;
+ if (!rplane->enabled)
+ goto done;
+
+ rcar_du_crtc_update_planes(rplane->crtc);
+
+done:
+ mutex_unlock(&rcdu->planes.lock);
+ return 0;
+}
+
static const struct drm_plane_funcs rcar_du_plane_funcs = {
.update_plane = rcar_du_plane_update,
.disable_plane = rcar_du_plane_disable,
+ .set_property = rcar_du_plane_set_property,
.destroy = drm_plane_cleanup,
};
@@ -288,21 +323,35 @@ int rcar_du_plane_init(struct rcar_du_device *rcdu)
mutex_init(&rcdu->planes.lock);
rcdu->planes.free = 0xff;
+ rcdu->planes.zpos =
+ drm_property_create_range(rcdu->ddev, 0, "zpos",
+ ARRAY_SIZE(rcdu->crtc),
+ ARRAY_SIZE(rcdu->planes.planes) - 1);
+ if (rcdu->planes.zpos == NULL)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
struct rcar_du_plane *plane = &rcdu->planes.planes[i];
plane->dev = rcdu;
plane->hwindex = -1;
+ plane->zpos = 1;
/* Reserve one plane per CRTC */
- if (i < ARRAY_SIZE(rcdu->crtc))
+ if (i < ARRAY_SIZE(rcdu->crtc)) {
+ plane->zpos = 0;
continue;
+ }
ret = drm_plane_init(rcdu->ddev, &plane->plane, 1,
&rcar_du_plane_funcs, formats,
ARRAY_SIZE(formats), false);
if (ret < 0)
return ret;
+
+ drm_object_attach_property(&plane->plane.base,
+ rcdu->planes.zpos, 1);
+
}
return 0;
@@ -29,6 +29,7 @@ struct rcar_du_plane {
bool enabled;
int hwindex; /* 0-based, -1 means unused */
+ unsigned int zpos;
const struct rcar_du_format_info *format;