|
@@ -221,7 +221,7 @@ static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane,
|
|
{
|
|
{
|
|
const struct rcar_du_format_info *cur_format;
|
|
const struct rcar_du_format_info *cur_format;
|
|
|
|
|
|
- cur_format = to_rcar_du_plane_state(plane->plane.state)->format;
|
|
|
|
|
|
+ cur_format = to_rcar_plane_state(plane->plane.state)->format;
|
|
|
|
|
|
/* Lowering the number of planes doesn't strictly require reallocation
|
|
/* Lowering the number of planes doesn't strictly require reallocation
|
|
* as the extra hardware plane will be freed when committing, but doing
|
|
* as the extra hardware plane will be freed when committing, but doing
|
|
@@ -284,14 +284,19 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|
continue;
|
|
continue;
|
|
|
|
|
|
plane = to_rcar_plane(state->planes[i]);
|
|
plane = to_rcar_plane(state->planes[i]);
|
|
- plane_state = to_rcar_du_plane_state(state->plane_states[i]);
|
|
|
|
|
|
+ plane_state = to_rcar_plane_state(state->plane_states[i]);
|
|
|
|
+
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: checking plane (%u,%u)\n", __func__,
|
|
|
|
+ plane->group->index, plane - plane->group->planes);
|
|
|
|
|
|
/* If the plane is being disabled we don't need to go through
|
|
/* If the plane is being disabled we don't need to go through
|
|
* the full reallocation procedure. Just mark the hardware
|
|
* the full reallocation procedure. Just mark the hardware
|
|
* plane(s) as freed.
|
|
* plane(s) as freed.
|
|
*/
|
|
*/
|
|
if (!plane_state->format) {
|
|
if (!plane_state->format) {
|
|
- index = plane - plane->group->planes.planes;
|
|
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: plane is being disabled\n",
|
|
|
|
+ __func__);
|
|
|
|
+ index = plane - plane->group->planes;
|
|
group_freed_planes[plane->group->index] |= 1 << index;
|
|
group_freed_planes[plane->group->index] |= 1 << index;
|
|
plane_state->hwindex = -1;
|
|
plane_state->hwindex = -1;
|
|
continue;
|
|
continue;
|
|
@@ -301,10 +306,12 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|
* mark the hardware plane(s) as free.
|
|
* mark the hardware plane(s) as free.
|
|
*/
|
|
*/
|
|
if (rcar_du_plane_needs_realloc(plane, plane_state)) {
|
|
if (rcar_du_plane_needs_realloc(plane, plane_state)) {
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: plane needs reallocation\n",
|
|
|
|
+ __func__);
|
|
groups |= 1 << plane->group->index;
|
|
groups |= 1 << plane->group->index;
|
|
needs_realloc = true;
|
|
needs_realloc = true;
|
|
|
|
|
|
- index = plane - plane->group->planes.planes;
|
|
|
|
|
|
+ index = plane - plane->group->planes;
|
|
group_freed_planes[plane->group->index] |= 1 << index;
|
|
group_freed_planes[plane->group->index] |= 1 << index;
|
|
plane_state->hwindex = -1;
|
|
plane_state->hwindex = -1;
|
|
}
|
|
}
|
|
@@ -326,8 +333,11 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|
struct rcar_du_group *group = &rcdu->groups[index];
|
|
struct rcar_du_group *group = &rcdu->groups[index];
|
|
unsigned int used_planes = 0;
|
|
unsigned int used_planes = 0;
|
|
|
|
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n",
|
|
|
|
+ __func__, index);
|
|
|
|
+
|
|
for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
|
|
for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
|
|
- struct rcar_du_plane *plane = &group->planes.planes[i];
|
|
|
|
|
|
+ struct rcar_du_plane *plane = &group->planes[i];
|
|
struct rcar_du_plane_state *plane_state;
|
|
struct rcar_du_plane_state *plane_state;
|
|
struct drm_plane_state *s;
|
|
struct drm_plane_state *s;
|
|
|
|
|
|
@@ -342,28 +352,49 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|
* above. Use the local freed planes list to check for
|
|
* above. Use the local freed planes list to check for
|
|
* that condition instead.
|
|
* that condition instead.
|
|
*/
|
|
*/
|
|
- if (group_freed_planes[index] & (1 << i))
|
|
|
|
|
|
+ if (group_freed_planes[index] & (1 << i)) {
|
|
|
|
+ dev_dbg(rcdu->dev,
|
|
|
|
+ "%s: plane (%u,%u) has been freed, skipping\n",
|
|
|
|
+ __func__, plane->group->index,
|
|
|
|
+ plane - plane->group->planes);
|
|
continue;
|
|
continue;
|
|
|
|
+ }
|
|
|
|
|
|
- plane_state = to_rcar_du_plane_state(plane->plane.state);
|
|
|
|
|
|
+ plane_state = to_rcar_plane_state(plane->plane.state);
|
|
used_planes |= rcar_du_plane_hwmask(plane_state);
|
|
used_planes |= rcar_du_plane_hwmask(plane_state);
|
|
|
|
+
|
|
|
|
+ dev_dbg(rcdu->dev,
|
|
|
|
+ "%s: plane (%u,%u) uses %u hwplanes (index %d)\n",
|
|
|
|
+ __func__, plane->group->index,
|
|
|
|
+ plane - plane->group->planes,
|
|
|
|
+ plane_state->format ?
|
|
|
|
+ plane_state->format->planes : 0,
|
|
|
|
+ plane_state->hwindex);
|
|
}
|
|
}
|
|
|
|
|
|
group_free_planes[index] = 0xff & ~used_planes;
|
|
group_free_planes[index] = 0xff & ~used_planes;
|
|
groups &= ~(1 << index);
|
|
groups &= ~(1 << index);
|
|
|
|
+
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n",
|
|
|
|
+ __func__, index, group_free_planes[index]);
|
|
}
|
|
}
|
|
|
|
|
|
/* Reallocate hardware planes for each plane that needs it. */
|
|
/* Reallocate hardware planes for each plane that needs it. */
|
|
for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
|
|
for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
|
|
struct rcar_du_plane_state *plane_state;
|
|
struct rcar_du_plane_state *plane_state;
|
|
struct rcar_du_plane *plane;
|
|
struct rcar_du_plane *plane;
|
|
|
|
+ unsigned int crtc_planes;
|
|
|
|
+ unsigned int free;
|
|
int idx;
|
|
int idx;
|
|
|
|
|
|
if (!state->planes[i])
|
|
if (!state->planes[i])
|
|
continue;
|
|
continue;
|
|
|
|
|
|
plane = to_rcar_plane(state->planes[i]);
|
|
plane = to_rcar_plane(state->planes[i]);
|
|
- plane_state = to_rcar_du_plane_state(state->plane_states[i]);
|
|
|
|
|
|
+ plane_state = to_rcar_plane_state(state->plane_states[i]);
|
|
|
|
+
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: allocating plane (%u,%u)\n", __func__,
|
|
|
|
+ plane->group->index, plane - plane->group->planes);
|
|
|
|
|
|
/* Skip planes that are being disabled or don't need to be
|
|
/* Skip planes that are being disabled or don't need to be
|
|
* reallocated.
|
|
* reallocated.
|
|
@@ -372,18 +403,38 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|
!rcar_du_plane_needs_realloc(plane, plane_state))
|
|
!rcar_du_plane_needs_realloc(plane, plane_state))
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ /* Try to allocate the plane from the free planes currently
|
|
|
|
+ * associated with the target CRTC to avoid restarting the CRTC
|
|
|
|
+ * group and thus minimize flicker. If it fails fall back to
|
|
|
|
+ * allocating from all free planes.
|
|
|
|
+ */
|
|
|
|
+ crtc_planes = to_rcar_crtc(plane_state->state.crtc)->index % 2
|
|
|
|
+ ? plane->group->dptsr_planes
|
|
|
|
+ : ~plane->group->dptsr_planes;
|
|
|
|
+ free = group_free_planes[plane->group->index];
|
|
|
|
+
|
|
idx = rcar_du_plane_hwalloc(plane_state->format->planes,
|
|
idx = rcar_du_plane_hwalloc(plane_state->format->planes,
|
|
- group_free_planes[plane->group->index]);
|
|
|
|
|
|
+ free & crtc_planes);
|
|
|
|
+ if (idx < 0)
|
|
|
|
+ idx = rcar_du_plane_hwalloc(plane_state->format->planes,
|
|
|
|
+ free);
|
|
if (idx < 0) {
|
|
if (idx < 0) {
|
|
dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
|
|
dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
|
|
__func__);
|
|
__func__);
|
|
return idx;
|
|
return idx;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n",
|
|
|
|
+ __func__, plane_state->format->planes, idx);
|
|
|
|
+
|
|
plane_state->hwindex = idx;
|
|
plane_state->hwindex = idx;
|
|
|
|
|
|
group_free_planes[plane->group->index] &=
|
|
group_free_planes[plane->group->index] &=
|
|
~rcar_du_plane_hwmask(plane_state);
|
|
~rcar_du_plane_hwmask(plane_state);
|
|
|
|
+
|
|
|
|
+ dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n",
|
|
|
|
+ __func__, plane->group->index,
|
|
|
|
+ group_free_planes[plane->group->index]);
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -648,6 +699,31 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
|
|
return num_encoders;
|
|
return num_encoders;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int rcar_du_properties_init(struct rcar_du_device *rcdu)
|
|
|
|
+{
|
|
|
|
+ rcdu->props.alpha =
|
|
|
|
+ drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
|
|
|
|
+ if (rcdu->props.alpha == NULL)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ /* The color key is expressed as an RGB888 triplet stored in a 32-bit
|
|
|
|
+ * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
|
|
|
|
+ * or enable source color keying (1).
|
|
|
|
+ */
|
|
|
|
+ rcdu->props.colorkey =
|
|
|
|
+ drm_property_create_range(rcdu->ddev, 0, "colorkey",
|
|
|
|
+ 0, 0x01ffffff);
|
|
|
|
+ if (rcdu->props.colorkey == NULL)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ rcdu->props.zpos =
|
|
|
|
+ drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
|
|
|
|
+ if (rcdu->props.zpos == NULL)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
|
int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
|
{
|
|
{
|
|
static const unsigned int mmio_offsets[] = {
|
|
static const unsigned int mmio_offsets[] = {
|
|
@@ -672,6 +748,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
|
|
|
|
|
rcdu->num_crtcs = rcdu->info->num_crtcs;
|
|
rcdu->num_crtcs = rcdu->info->num_crtcs;
|
|
|
|
|
|
|
|
+ ret = rcar_du_properties_init(rcdu);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
/* Initialize the groups. */
|
|
/* Initialize the groups. */
|
|
num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
|
|
num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
|
|
|
|
|
|
@@ -683,6 +763,13 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
|
rgrp->dev = rcdu;
|
|
rgrp->dev = rcdu;
|
|
rgrp->mmio_offset = mmio_offsets[i];
|
|
rgrp->mmio_offset = mmio_offsets[i];
|
|
rgrp->index = i;
|
|
rgrp->index = i;
|
|
|
|
+ rgrp->num_crtcs = min(rcdu->num_crtcs - 2 * i, 2U);
|
|
|
|
+
|
|
|
|
+ /* If we have more than one CRTCs in this group pre-associate
|
|
|
|
+ * planes 0-3 with CRTC 0 and planes 4-7 with CRTC 1 to minimize
|
|
|
|
+ * flicker occurring when the association is changed.
|
|
|
|
+ */
|
|
|
|
+ rgrp->dptsr_planes = rgrp->num_crtcs > 1 ? 0xf0 : 0;
|
|
|
|
|
|
ret = rcar_du_planes_init(rgrp);
|
|
ret = rcar_du_planes_init(rgrp);
|
|
if (ret < 0)
|
|
if (ret < 0)
|