These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / rcar-du / rcar_du_kms.c
index 93117f1..ca12e8c 100644 (file)
@@ -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;
@@ -405,7 +456,7 @@ static void rcar_du_atomic_complete(struct rcar_du_commit *commit)
        /* Apply the atomic update. */
        drm_atomic_helper_commit_modeset_disables(dev, old_state);
        drm_atomic_helper_commit_modeset_enables(dev, old_state);
-       drm_atomic_helper_commit_planes(dev, old_state);
+       drm_atomic_helper_commit_planes(dev, old_state, false);
 
        drm_atomic_helper_wait_for_vblanks(dev, old_state);
 
@@ -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)