summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/rcar-du
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-06-26 13:18:51 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-26 13:18:51 -0700
commit099bfbfc7fbbe22356c02f0caf709ac32e1126ea (patch)
treec2dfe2f9445255d866e9203cff9e9f865ef93513 /drivers/gpu/drm/rcar-du
parent22165fa79814e71e7a5974b3c37a5028ed16c8f9 (diff)
parentc5fd936e992dd2829167d2adc63e151675ca6898 (diff)
downloadlinux-099bfbfc7fbbe22356c02f0caf709ac32e1126ea.tar.bz2
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie: "This is the main drm pull request for v4.2. I've one other new driver from freescale on my radar, it's been posted and reviewed, I'd just like to get someone to give it a last look, so maybe I'll send it or maybe I'll leave it. There is no major nouveau changes in here, Ben was working on something big, and we agreed it was a bit late, there wasn't anything else he considered urgent to merge. There might be another msm pull for some bits that are waiting on arm-soc, I'll see how we time it. This touches some "of" stuff, acks are in place except for the fixes to the build in various configs,t hat I just applied. Summary: New drivers: - virtio-gpu: KMS only pieces of driver for virtio-gpu in qemu. This is just the first part of this driver, enough to run unaccelerated userspace on. As qemu merges more we'll start adding the 3D features for the virgl 3d work. - amdgpu: a new driver from AMD to driver their newer GPUs. (VI+) It contains a new cleaner userspace API, and is a clean break from radeon moving forward, that AMD are going to concentrate on. It also contains a set of register headers auto generated from AMD internal database. core: - atomic modesetting API completed, enabled by default now. - Add support for mode_id blob to atomic ioctl to complete interface. - bunch of Displayport MST fixes - lots of misc fixes. panel: - new simple panels - fix some long-standing build issues with bridge drivers radeon: - VCE1 support - add a GPU reset counter for userspace - lots of fixes. amdkfd: - H/W debugger support module - static user-mode queues - support killing all the waves when a process terminates - use standard DECLARE_BITMAP i915: - Add Broxton support - S3, rotation support for Skylake - RPS booting tuning - CPT modeset sequence fixes - ns2501 dither support - enable cmd parser on haswell - cdclk handling fixes - gen8 dynamic pte allocation - lots of atomic conversion work exynos: - Add atomic modesetting support - Add iommu support - Consolidate drm driver initialization - and MIC, DECON and MIPI-DSI support for exynos5433 omapdrm: - atomic modesetting support (fixes lots of things in rewrite) tegra: - DP aux transaction fixes - iommu support fix msm: - adreno a306 support - various dsi bits - various 64-bit fixes - NV12MT support rcar-du: - atomic and misc fixes sti: - fix HDMI timing complaince tilcdc: - use drm component API to access tda998x driver - fix module unloading qxl: - stability fixes" * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (872 commits) drm/nouveau: Pause between setting gpu to D3hot and cutting the power drm/dp/mst: close deadlock in connector destruction. drm: Always enable atomic API drm/vgem: Set unique to "vgem" of: fix a build error to of_graph_get_endpoint_by_regs function drm/dp/mst: take lock around looking up the branch device on hpd irq drm/dp/mst: make sure mst_primary mstb is valid in work function of: add EXPORT_SYMBOL for of_graph_get_endpoint_by_regs ARM: dts: rename the clock of MIPI DSI 'pll_clk' to 'sclk_mipi' drm/atomic: Don't set crtc_state->enable manually drm/exynos: dsi: do not set TE GPIO direction by input drm/exynos: dsi: add support for MIC driver as a bridge drm/exynos: dsi: add support for Exynos5433 drm/exynos: dsi: make use of array for clock access drm/exynos: dsi: make use of driver data for static values drm/exynos: dsi: add macros for register access drm/exynos: dsi: rename pll_clk to sclk_clk drm/exynos: mic: add MIC driver of: add helper for getting endpoint node of specific identifiers drm/exynos: add Exynos5433 decon driver ...
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 7d0b8ef9bea2..65d6ba6621ac 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 5d9aa9b33769..4b95d9d08c49 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 da1216a73969..780ca11512ba 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 c7c538dd2e68..9f34fc86436a 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 1bdc0ee0c248..7fd39a7d91c8 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 ed36433fbe84..d7318e1a6b00 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 93117f159a3b..56518eb1269a 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 210e5c3fd982..c66986414bb4 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 abff0ebeb195..9732bff1911b 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);
}