Commit a21be4ec authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev into drm-next

rcar-du fixes

* 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev:
  drm: rcar-du: Use the drm atomic state duplication helpers for planes
  drm: rcar-du: Clean up planes in the error paths of .atomic_commit()
  drm: rcar-du: Convert rcar_du_encoders_init_one() return value to 0/<0
  drm: rcar-du: Clarify error message when encoder initialization fails
  drm: rcar-du: Fix crash with groups that have less than 9 planes
  drm: rcar-du: Disable all planes when stopping the CRTC
  drm: rcar-du: Print the error value when DRM/KMS init fails
parents c90a95bf 263b39fe
...@@ -214,7 +214,7 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) ...@@ -214,7 +214,7 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
unsigned int i; unsigned int i;
u32 dspr = 0; u32 dspr = 0;
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) { for (i = 0; i < rcrtc->group->num_planes; ++i) {
struct rcar_du_plane *plane = &rcrtc->group->planes[i]; struct rcar_du_plane *plane = &rcrtc->group->planes[i];
unsigned int j; unsigned int j;
...@@ -398,6 +398,19 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) ...@@ -398,6 +398,19 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
if (!rcrtc->started) if (!rcrtc->started)
return; 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 /* Disable vertical blanking interrupt reporting. We first need to wait
* for page flip completion before stopping the CRTC as userspace * for page flip completion before stopping the CRTC as userspace
* expects page flips to eventually complete. * expects page flips to eventually complete.
...@@ -432,7 +445,7 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc) ...@@ -432,7 +445,7 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
rcar_du_crtc_start(rcrtc); rcar_du_crtc_start(rcrtc);
/* Commit the planes state. */ /* Commit the planes state. */
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) { for (i = 0; i < rcrtc->group->num_planes; ++i) {
struct rcar_du_plane *plane = &rcrtc->group->planes[i]; struct rcar_du_plane *plane = &rcrtc->group->planes[i];
if (plane->plane.state->crtc != &rcrtc->crtc) if (plane->plane.state->crtc != &rcrtc->crtc)
......
...@@ -190,7 +190,7 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags) ...@@ -190,7 +190,7 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags)
/* DRM/KMS objects */ /* DRM/KMS objects */
ret = rcar_du_modeset_init(rcdu); ret = rcar_du_modeset_init(rcdu);
if (ret < 0) { 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; goto done;
} }
......
...@@ -30,6 +30,7 @@ struct rcar_du_device; ...@@ -30,6 +30,7 @@ struct rcar_du_device;
* @used_crtcs: number of CRTCs currently in use * @used_crtcs: number of CRTCs currently in use
* @lock: protects the dptsr_planes field and 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 * @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 * @planes: planes handled by the group
*/ */
struct rcar_du_group { struct rcar_du_group {
...@@ -44,6 +45,7 @@ struct rcar_du_group { ...@@ -44,6 +45,7 @@ struct rcar_du_group {
struct mutex lock; struct mutex lock;
unsigned int dptsr_planes; unsigned int dptsr_planes;
unsigned int num_planes;
struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES]; struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
}; };
......
...@@ -336,7 +336,7 @@ static int rcar_du_atomic_check(struct drm_device *dev, ...@@ -336,7 +336,7 @@ static int rcar_du_atomic_check(struct drm_device *dev,
dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n", dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n",
__func__, index); __func__, index);
for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) { for (i = 0; i < group->num_planes; ++i) {
struct rcar_du_plane *plane = &group->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;
...@@ -495,8 +495,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev, ...@@ -495,8 +495,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
/* Allocate the commit object. */ /* Allocate the commit object. */
commit = kzalloc(sizeof(*commit), GFP_KERNEL); commit = kzalloc(sizeof(*commit), GFP_KERNEL);
if (commit == NULL) if (commit == NULL) {
return -ENOMEM; ret = -ENOMEM;
goto error;
}
INIT_WORK(&commit->work, rcar_du_atomic_work); INIT_WORK(&commit->work, rcar_du_atomic_work);
commit->dev = dev; commit->dev = dev;
...@@ -519,7 +521,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev, ...@@ -519,7 +521,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
if (ret) { if (ret) {
kfree(commit); kfree(commit);
return ret; goto error;
} }
/* Swap the state, this is the point of no return. */ /* Swap the state, this is the point of no return. */
...@@ -531,6 +533,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev, ...@@ -531,6 +533,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev,
rcar_du_atomic_complete(commit); rcar_du_atomic_complete(commit);
return 0; return 0;
error:
drm_atomic_helper_cleanup_planes(dev, state);
return ret;
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
...@@ -573,7 +579,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, ...@@ -573,7 +579,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
if (!entity) { if (!entity) {
dev_dbg(rcdu->dev, "unconnected endpoint %s, skipping\n", dev_dbg(rcdu->dev, "unconnected endpoint %s, skipping\n",
ep->local_node->full_name); ep->local_node->full_name);
return 0; return -ENODEV;
} }
entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0); entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
...@@ -596,7 +602,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, ...@@ -596,7 +602,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
encoder->full_name); encoder->full_name);
of_node_put(entity_ep_node); of_node_put(entity_ep_node);
of_node_put(encoder); of_node_put(encoder);
return 0; return -ENODEV;
} }
break; break;
...@@ -625,7 +631,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, ...@@ -625,7 +631,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
encoder->full_name); encoder->full_name);
of_node_put(encoder); of_node_put(encoder);
of_node_put(connector); of_node_put(connector);
return 0; return -EINVAL;
} }
} else { } else {
/* /*
...@@ -639,7 +645,12 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, ...@@ -639,7 +645,12 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
of_node_put(encoder); of_node_put(encoder);
of_node_put(connector); 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) static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
...@@ -688,12 +699,10 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu) ...@@ -688,12 +699,10 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
return ret; return ret;
} }
dev_info(rcdu->dev,
"encoder initialization failed, skipping\n");
continue; continue;
} }
num_encoders += ret; num_encoders++;
} }
return num_encoders; return num_encoders;
......
...@@ -302,13 +302,15 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) ...@@ -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 *state;
struct rcar_du_plane_state *copy; struct rcar_du_plane_state *copy;
if (WARN_ON(!plane->state))
return NULL;
state = to_rcar_plane_state(plane->state); state = to_rcar_plane_state(plane->state);
copy = kmemdup(state, sizeof(*state), GFP_KERNEL); copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
if (copy == NULL) if (copy == NULL)
return NULL; return NULL;
if (copy->state.fb) __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
drm_framebuffer_reference(copy->state.fb);
return &copy->state; return &copy->state;
} }
...@@ -316,9 +318,7 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) ...@@ -316,9 +318,7 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane, static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
if (state->fb) __drm_atomic_helper_plane_destroy_state(plane, state);
drm_framebuffer_unreference(state->fb);
kfree(to_rcar_plane_state(state)); kfree(to_rcar_plane_state(state));
} }
...@@ -390,7 +390,6 @@ static const uint32_t formats[] = { ...@@ -390,7 +390,6 @@ static const uint32_t formats[] = {
int rcar_du_planes_init(struct rcar_du_group *rgrp) int rcar_du_planes_init(struct rcar_du_group *rgrp)
{ {
struct rcar_du_device *rcdu = rgrp->dev; struct rcar_du_device *rcdu = rgrp->dev;
unsigned int num_planes;
unsigned int crtcs; unsigned int crtcs;
unsigned int i; unsigned int i;
int ret; int ret;
...@@ -398,11 +397,11 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp) ...@@ -398,11 +397,11 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
/* Create one primary plane per CRTC in this group and seven overlay /* Create one primary plane per CRTC in this group and seven overlay
* planes. * planes.
*/ */
num_planes = rgrp->num_crtcs + 7; rgrp->num_planes = rgrp->num_crtcs + 7;
crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index)); crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
for (i = 0; i < num_planes; ++i) { for (i = 0; i < rgrp->num_planes; ++i) {
enum drm_plane_type type = i < rgrp->num_crtcs enum drm_plane_type type = i < rgrp->num_crtcs
? DRM_PLANE_TYPE_PRIMARY ? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY; : DRM_PLANE_TYPE_OVERLAY;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment