diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index e6a32c4e4040..65d6ba6621ac 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -214,7 +214,7 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) unsigned int i; 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]; unsigned int j; @@ -398,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. @@ -432,7 +445,7 @@ 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); ++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) 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_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h index 7b414b31c3be..d7318e1a6b00 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.h @@ -30,6 +30,7 @@ struct rcar_du_device; * @used_crtcs: number of CRTCs currently in use * @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 { @@ -44,6 +45,7 @@ struct rcar_du_group { struct mutex lock; unsigned int dptsr_planes; + unsigned int num_planes; struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES]; }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 20859aae882e..56518eb1269a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -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", __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_state *plane_state; struct drm_plane_state *s; @@ -495,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; @@ -519,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. */ @@ -531,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; } /* ----------------------------------------------------------------------------- @@ -573,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); @@ -596,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; @@ -625,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 { /* @@ -639,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) @@ -688,12 +699,10 @@ 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; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 3e30d84b798f..c66986414bb4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -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; + 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, ©->state); return ©->state; } @@ -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, struct drm_plane_state *state) { - if (state->fb) - drm_framebuffer_unreference(state->fb); - + __drm_atomic_helper_plane_destroy_state(plane, state); kfree(to_rcar_plane_state(state)); } @@ -390,7 +390,6 @@ static const uint32_t formats[] = { int rcar_du_planes_init(struct rcar_du_group *rgrp) { struct rcar_du_device *rcdu = rgrp->dev; - unsigned int num_planes; unsigned int crtcs; unsigned int i; int ret; @@ -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 * planes. */ - num_planes = rgrp->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) { + 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;