summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/rcar-du
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/rcar-du
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'drivers/gpu/drm/rcar-du')
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c74
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h14
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.h10
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c136
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c84
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.h21
9 files changed, 237 insertions, 116 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 7d0b8ef9b..65d6ba662 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -195,26 +195,27 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
static unsigned int plane_zpos(struct rcar_du_plane *plane)
{
- return to_rcar_du_plane_state(plane->plane.state)->zpos;
+ return to_rcar_plane_state(plane->plane.state)->zpos;
}
static const struct rcar_du_format_info *
plane_format(struct rcar_du_plane *plane)
{
- return to_rcar_du_plane_state(plane->plane.state)->format;
+ return to_rcar_plane_state(plane->plane.state)->format;
}
static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
{
struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES];
unsigned int num_planes = 0;
+ unsigned int dptsr_planes;
+ unsigned int hwplanes = 0;
unsigned int prio = 0;
unsigned int i;
- u32 dptsr = 0;
u32 dspr = 0;
- for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
- struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
+ for (i = 0; i < rcrtc->group->num_planes; ++i) {
+ struct rcar_du_plane *plane = &rcrtc->group->planes[i];
unsigned int j;
if (plane->plane.state->crtc != &rcrtc->crtc)
@@ -234,41 +235,45 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
for (i = 0; i < num_planes; ++i) {
struct rcar_du_plane *plane = planes[i];
struct drm_plane_state *state = plane->plane.state;
- unsigned int index = to_rcar_du_plane_state(state)->hwindex;
+ unsigned int index = to_rcar_plane_state(state)->hwindex;
prio -= 4;
dspr |= (index + 1) << prio;
- dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
+ hwplanes |= 1 << index;
if (plane_format(plane)->planes == 2) {
index = (index + 1) % 8;
prio -= 4;
dspr |= (index + 1) << prio;
- dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
+ hwplanes |= 1 << index;
}
}
- /* Select display timing and dot clock generator 2 for planes associated
- * with superposition controller 2.
+ /* Update the planes to display timing and dot clock generator
+ * associations.
+ *
+ * Updating the DPTSR register requires restarting the CRTC group,
+ * resulting in visible flicker. To mitigate the issue only update the
+ * association if needed by enabled planes. Planes being disabled will
+ * keep their current association.
*/
- if (rcrtc->index % 2) {
- /* The DPTSR register is updated when the display controller is
- * stopped. We thus need to restart the DU. Once again, sorry
- * for the flicker. One way to mitigate the issue would be to
- * pre-associate planes with CRTCs (either with a fixed 4/4
- * split, or through a module parameter). Flicker would then
- * occur only if we need to break the pre-association.
- */
- mutex_lock(&rcrtc->group->lock);
- if (rcar_du_group_read(rcrtc->group, DPTSR) != dptsr) {
- rcar_du_group_write(rcrtc->group, DPTSR, dptsr);
- if (rcrtc->group->used_crtcs)
- rcar_du_group_restart(rcrtc->group);
- }
- mutex_unlock(&rcrtc->group->lock);
+ mutex_lock(&rcrtc->group->lock);
+
+ dptsr_planes = rcrtc->index % 2 ? rcrtc->group->dptsr_planes | hwplanes
+ : rcrtc->group->dptsr_planes & ~hwplanes;
+
+ if (dptsr_planes != rcrtc->group->dptsr_planes) {
+ rcar_du_group_write(rcrtc->group, DPTSR,
+ (dptsr_planes << 16) | dptsr_planes);
+ rcrtc->group->dptsr_planes = dptsr_planes;
+
+ if (rcrtc->group->used_crtcs)
+ rcar_du_group_restart(rcrtc->group);
}
+ mutex_unlock(&rcrtc->group->lock);
+
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR,
dspr);
}
@@ -393,6 +398,19 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
if (!rcrtc->started)
return;
+ /* Disable all planes and wait for the change to take effect. This is
+ * required as the DSnPR registers are updated on vblank, and no vblank
+ * will occur once the CRTC is stopped. Disabling planes when starting
+ * the CRTC thus wouldn't be enough as it would start scanning out
+ * immediately from old frame buffers until the next vblank.
+ *
+ * This increases the CRTC stop delay, especially when multiple CRTCs
+ * are stopped in one operation as we now wait for one vblank per CRTC.
+ * Whether this can be improved needs to be researched.
+ */
+ rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+ drm_crtc_wait_one_vblank(crtc);
+
/* Disable vertical blanking interrupt reporting. We first need to wait
* for page flip completion before stopping the CRTC as userspace
* expects page flips to eventually complete.
@@ -427,8 +445,8 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
rcar_du_crtc_start(rcrtc);
/* Commit the planes state. */
- for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
- struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
+ for (i = 0; i < rcrtc->group->num_planes; ++i) {
+ struct rcar_du_plane *plane = &rcrtc->group->planes[i];
if (plane->plane.state->crtc != &rcrtc->crtc)
continue;
@@ -592,7 +610,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
rcrtc->enabled = false;
ret = drm_crtc_init_with_planes(rcdu->ddev, crtc,
- &rgrp->planes.planes[index % 2].plane,
+ &rgrp->planes[index % 2].plane,
NULL, &crtc_funcs);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 5d9aa9b33..4b95d9d08 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -22,6 +22,20 @@
struct rcar_du_group;
+/**
+ * struct rcar_du_crtc - the CRTC, representing a DU superposition processor
+ * @crtc: base DRM CRTC
+ * @clock: the CRTC functional clock
+ * @extclock: external pixel dot clock (optional)
+ * @mmio_offset: offset of the CRTC registers in the DU MMIO block
+ * @index: CRTC software and hardware index
+ * @started: whether the CRTC has been started and is running
+ * @event: event to post when the pending page flip completes
+ * @flip_wait: wait queue used to signal page flip completion
+ * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
+ * @enabled: whether the CRTC is enabled, used to control system resume
+ * @group: CRTC group this CRTC belongs to
+ */
struct rcar_du_crtc {
struct drm_crtc crtc;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index da1216a73..780ca1151 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -190,7 +190,7 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
/* DRM/KMS objects */
ret = rcar_du_modeset_init(rcdu);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to initialize DRM/KMS\n");
+ dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret);
goto done;
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index c7c538dd2..9f34fc864 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -83,6 +83,12 @@ struct rcar_du_device {
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
+ struct {
+ struct drm_property *alpha;
+ struct drm_property *colorkey;
+ struct drm_property *zpos;
+ } props;
+
unsigned int dpad0_source;
struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS];
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index 1bdc0ee0c..7fd39a7d9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -85,6 +85,12 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
* superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
*/
rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
+
+ /* Apply planes to CRTCs association. */
+ mutex_lock(&rgrp->lock);
+ rcar_du_group_write(rgrp, DPTSR, (rgrp->dptsr_planes << 16) |
+ rgrp->dptsr_planes);
+ mutex_unlock(&rgrp->lock);
}
/*
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h
index ed36433fb..d7318e1a6 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.h
@@ -25,9 +25,12 @@ struct rcar_du_device;
* @dev: the DU device
* @mmio_offset: registers offset in the device memory map
* @index: group index
+ * @num_crtcs: number of CRTCs in this group (1 or 2)
* @use_count: number of users of the group (rcar_du_group_(get|put))
* @used_crtcs: number of CRTCs currently in use
- * @lock: protects the DPTSR register
+ * @lock: protects the dptsr_planes field and the DPTSR register
+ * @dptsr_planes: bitmask of planes driven by dot-clock and timing generator 1
+ * @num_planes: number of planes in the group
* @planes: planes handled by the group
*/
struct rcar_du_group {
@@ -35,12 +38,15 @@ struct rcar_du_group {
unsigned int mmio_offset;
unsigned int index;
+ unsigned int num_crtcs;
unsigned int use_count;
unsigned int used_crtcs;
struct mutex lock;
+ unsigned int dptsr_planes;
- struct rcar_du_planes planes;
+ unsigned int num_planes;
+ struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
};
u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 93117f159..56518eb12 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -221,7 +221,7 @@ static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane,
{
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
* 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;
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
* the full reallocation procedure. Just mark the hardware
* plane(s) as freed.
*/
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;
plane_state->hwindex = -1;
continue;
@@ -301,10 +306,12 @@ static int rcar_du_atomic_check(struct drm_device *dev,
* mark the hardware plane(s) as free.
*/
if (rcar_du_plane_needs_realloc(plane, plane_state)) {
+ dev_dbg(rcdu->dev, "%s: plane needs reallocation\n",
+ __func__);
groups |= 1 << plane->group->index;
needs_realloc = true;
- index = plane - plane->group->planes.planes;
+ index = plane - plane->group->planes;
group_freed_planes[plane->group->index] |= 1 << index;
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];
unsigned int used_planes = 0;
- for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
- struct rcar_du_plane *plane = &group->planes.planes[i];
+ dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n",
+ __func__, index);
+
+ for (i = 0; i < group->num_planes; ++i) {
+ struct rcar_du_plane *plane = &group->planes[i];
struct rcar_du_plane_state *plane_state;
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
* 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;
+ }
- 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);
+
+ 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;
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. */
for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
struct rcar_du_plane_state *plane_state;
struct rcar_du_plane *plane;
+ unsigned int crtc_planes;
+ unsigned int free;
int idx;
if (!state->planes[i])
continue;
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
* reallocated.
@@ -372,18 +403,38 @@ static int rcar_du_atomic_check(struct drm_device *dev,
!rcar_du_plane_needs_realloc(plane, plane_state))
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,
- 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) {
dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
__func__);
return idx;
}
+ dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n",
+ __func__, plane_state->format->planes, idx);
+
plane_state->hwindex = idx;
group_free_planes[plane->group->index] &=
~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;
@@ -444,8 +495,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
/* Allocate the commit object. */
commit = kzalloc(sizeof(*commit), GFP_KERNEL);
- if (commit == NULL)
- return -ENOMEM;
+ if (commit == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
INIT_WORK(&commit->work, rcar_du_atomic_work);
commit->dev = dev;
@@ -468,7 +521,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
if (ret) {
kfree(commit);
- return ret;
+ goto error;
}
/* Swap the state, this is the point of no return. */
@@ -480,6 +533,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
rcar_du_atomic_complete(commit);
return 0;
+
+error:
+ drm_atomic_helper_cleanup_planes(dev, state);
+ return ret;
}
/* -----------------------------------------------------------------------------
@@ -522,7 +579,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
if (!entity) {
dev_dbg(rcdu->dev, "unconnected endpoint %s, skipping\n",
ep->local_node->full_name);
- return 0;
+ return -ENODEV;
}
entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
@@ -545,7 +602,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
encoder->full_name);
of_node_put(entity_ep_node);
of_node_put(encoder);
- return 0;
+ return -ENODEV;
}
break;
@@ -574,7 +631,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
encoder->full_name);
of_node_put(encoder);
of_node_put(connector);
- return 0;
+ return -EINVAL;
}
} else {
/*
@@ -588,7 +645,12 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
of_node_put(encoder);
of_node_put(connector);
- return ret < 0 ? ret : 1;
+ if (ret && ret != -EPROBE_DEFER)
+ dev_warn(rcdu->dev,
+ "failed to initialize encoder %s (%d), skipping\n",
+ encoder->full_name, ret);
+
+ return ret;
}
static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
@@ -637,17 +699,40 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
return ret;
}
- dev_info(rcdu->dev,
- "encoder initialization failed, skipping\n");
continue;
}
- num_encoders += ret;
+ 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)
{
static const unsigned int mmio_offsets[] = {
@@ -672,6 +757,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
rcdu->num_crtcs = rcdu->info->num_crtcs;
+ ret = rcar_du_properties_init(rcdu);
+ if (ret < 0)
+ return ret;
+
/* Initialize the groups. */
num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
@@ -683,6 +772,13 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
rgrp->dev = rcdu;
rgrp->mmio_offset = mmio_offsets[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);
if (ret < 0)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 210e5c3fd..c66986414 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -45,7 +45,7 @@ static void rcar_du_plane_write(struct rcar_du_group *rgrp,
static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane)
{
struct rcar_du_plane_state *state =
- to_rcar_du_plane_state(plane->plane.state);
+ to_rcar_plane_state(plane->plane.state);
struct drm_framebuffer *fb = plane->plane.state->fb;
struct rcar_du_group *rgrp = plane->group;
unsigned int src_x = state->state.src_x >> 16;
@@ -109,7 +109,7 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
unsigned int index)
{
struct rcar_du_plane_state *state =
- to_rcar_du_plane_state(plane->plane.state);
+ to_rcar_plane_state(plane->plane.state);
struct rcar_du_group *rgrp = plane->group;
u32 colorkey;
u32 pnmr;
@@ -172,7 +172,7 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
unsigned int index)
{
struct rcar_du_plane_state *state =
- to_rcar_du_plane_state(plane->plane.state);
+ to_rcar_plane_state(plane->plane.state);
struct rcar_du_group *rgrp = plane->group;
u32 ddcr2 = PnDDCR2_CODE;
u32 ddcr4;
@@ -222,7 +222,7 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
void rcar_du_plane_setup(struct rcar_du_plane *plane)
{
struct rcar_du_plane_state *state =
- to_rcar_du_plane_state(plane->plane.state);
+ to_rcar_plane_state(plane->plane.state);
__rcar_du_plane_setup(plane, state->hwindex);
if (state->format->planes == 2)
@@ -234,7 +234,7 @@ void rcar_du_plane_setup(struct rcar_du_plane *plane)
static int rcar_du_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
- struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state);
+ struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
struct rcar_du_plane *rplane = to_rcar_plane(plane);
struct rcar_du_device *rcdu = rplane->group->dev;
@@ -302,13 +302,15 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
struct rcar_du_plane_state *state;
struct rcar_du_plane_state *copy;
- state = to_rcar_du_plane_state(plane->state);
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ state = to_rcar_plane_state(plane->state);
copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
if (copy == NULL)
return NULL;
- if (copy->state.fb)
- drm_framebuffer_reference(copy->state.fb);
+ __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
return &copy->state;
}
@@ -316,10 +318,8 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
- if (state->fb)
- drm_framebuffer_unreference(state->fb);
-
- kfree(to_rcar_du_plane_state(state));
+ __drm_atomic_helper_plane_destroy_state(plane, state);
+ kfree(to_rcar_plane_state(state));
}
static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
@@ -327,15 +327,14 @@ static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
struct drm_property *property,
uint64_t val)
{
- struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state);
- struct rcar_du_plane *rplane = to_rcar_plane(plane);
- struct rcar_du_group *rgrp = rplane->group;
+ struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
+ struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
- if (property == rgrp->planes.alpha)
+ if (property == rcdu->props.alpha)
rstate->alpha = val;
- else if (property == rgrp->planes.colorkey)
+ else if (property == rcdu->props.colorkey)
rstate->colorkey = val;
- else if (property == rgrp->planes.zpos)
+ else if (property == rcdu->props.zpos)
rstate->zpos = val;
else
return -EINVAL;
@@ -349,14 +348,13 @@ static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
{
const struct rcar_du_plane_state *rstate =
container_of(state, const struct rcar_du_plane_state, state);
- struct rcar_du_plane *rplane = to_rcar_plane(plane);
- struct rcar_du_group *rgrp = rplane->group;
+ struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
- if (property == rgrp->planes.alpha)
+ if (property == rcdu->props.alpha)
*val = rstate->alpha;
- else if (property == rgrp->planes.colorkey)
+ else if (property == rcdu->props.colorkey)
*val = rstate->colorkey;
- else if (property == rgrp->planes.zpos)
+ else if (property == rcdu->props.zpos)
*val = rstate->zpos;
else
return -EINVAL;
@@ -391,47 +389,23 @@ static const uint32_t formats[] = {
int rcar_du_planes_init(struct rcar_du_group *rgrp)
{
- struct rcar_du_planes *planes = &rgrp->planes;
struct rcar_du_device *rcdu = rgrp->dev;
- unsigned int num_planes;
- unsigned int num_crtcs;
unsigned int crtcs;
unsigned int i;
int ret;
- planes->alpha =
- drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
- if (planes->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).
- */
- planes->colorkey =
- drm_property_create_range(rcdu->ddev, 0, "colorkey",
- 0, 0x01ffffff);
- if (planes->colorkey == NULL)
- return -ENOMEM;
-
- planes->zpos =
- drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
- if (planes->zpos == NULL)
- return -ENOMEM;
-
- /* Create one primary plane per in this group CRTC and seven overlay
+ /* Create one primary plane per CRTC in this group and seven overlay
* planes.
*/
- num_crtcs = min(rcdu->num_crtcs - 2 * rgrp->index, 2U);
- num_planes = num_crtcs + 7;
+ rgrp->num_planes = rgrp->num_crtcs + 7;
crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
- for (i = 0; i < num_planes; ++i) {
- enum drm_plane_type type = i < num_crtcs
+ for (i = 0; i < rgrp->num_planes; ++i) {
+ enum drm_plane_type type = i < rgrp->num_crtcs
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY;
- struct rcar_du_plane *plane = &planes->planes[i];
+ struct rcar_du_plane *plane = &rgrp->planes[i];
plane->group = rgrp;
@@ -448,12 +422,12 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
continue;
drm_object_attach_property(&plane->plane.base,
- planes->alpha, 255);
+ rcdu->props.alpha, 255);
drm_object_attach_property(&plane->plane.base,
- planes->colorkey,
+ rcdu->props.colorkey,
RCAR_DU_COLORKEY_NONE);
drm_object_attach_property(&plane->plane.base,
- planes->zpos, 1);
+ rcdu->props.zpos, 1);
}
return 0;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h
index abff0ebeb..9732bff19 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h
@@ -38,19 +38,20 @@ static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
return container_of(plane, struct rcar_du_plane, plane);
}
-struct rcar_du_planes {
- struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
-
- struct drm_property *alpha;
- struct drm_property *colorkey;
- struct drm_property *zpos;
-};
-
+/**
+ * struct rcar_du_plane_state - Driver-specific plane state
+ * @state: base DRM plane state
+ * @format: information about the pixel format used by the plane
+ * @hwindex: 0-based hardware plane index, -1 means unused
+ * @alpha: value of the plane alpha property
+ * @colorkey: value of the plane colorkey property
+ * @zpos: value of the plane zpos property
+ */
struct rcar_du_plane_state {
struct drm_plane_state state;
const struct rcar_du_format_info *format;
- int hwindex; /* 0-based, -1 means unused */
+ int hwindex;
unsigned int alpha;
unsigned int colorkey;
@@ -58,7 +59,7 @@ struct rcar_du_plane_state {
};
static inline struct rcar_du_plane_state *
-to_rcar_du_plane_state(struct drm_plane_state *state)
+to_rcar_plane_state(struct drm_plane_state *state)
{
return container_of(state, struct rcar_du_plane_state, state);
}