root/drivers/gpu/drm/i915/display/intel_atomic_plane.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intel_plane_alloc
  2. intel_plane_free
  3. intel_plane_duplicate_state
  4. intel_plane_destroy_state
  5. intel_plane_data_rate
  6. intel_plane_atomic_check_with_state
  7. get_crtc_from_states
  8. intel_plane_atomic_check
  9. skl_next_plane_to_commit
  10. intel_update_plane
  11. intel_update_slave
  12. intel_disable_plane
  13. skl_update_planes_on_crtc
  14. i9xx_update_planes_on_crtc

   1 /*
   2  * Copyright © 2014 Intel Corporation
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice (including the next
  12  * paragraph) shall be included in all copies or substantial portions of the
  13  * Software.
  14  *
  15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21  * DEALINGS IN THE SOFTWARE.
  22  */
  23 
  24 /**
  25  * DOC: atomic plane helpers
  26  *
  27  * The functions here are used by the atomic plane helper functions to
  28  * implement legacy plane updates (i.e., drm_plane->update_plane() and
  29  * drm_plane->disable_plane()).  This allows plane updates to use the
  30  * atomic state infrastructure and perform plane updates as separate
  31  * prepare/check/commit/cleanup steps.
  32  */
  33 
  34 #include <drm/drm_atomic_helper.h>
  35 #include <drm/drm_fourcc.h>
  36 #include <drm/drm_plane_helper.h>
  37 
  38 #include "i915_trace.h"
  39 #include "intel_atomic_plane.h"
  40 #include "intel_display_types.h"
  41 #include "intel_pm.h"
  42 #include "intel_sprite.h"
  43 
  44 struct intel_plane *intel_plane_alloc(void)
  45 {
  46         struct intel_plane_state *plane_state;
  47         struct intel_plane *plane;
  48 
  49         plane = kzalloc(sizeof(*plane), GFP_KERNEL);
  50         if (!plane)
  51                 return ERR_PTR(-ENOMEM);
  52 
  53         plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
  54         if (!plane_state) {
  55                 kfree(plane);
  56                 return ERR_PTR(-ENOMEM);
  57         }
  58 
  59         __drm_atomic_helper_plane_reset(&plane->base, &plane_state->base);
  60         plane_state->scaler_id = -1;
  61 
  62         return plane;
  63 }
  64 
  65 void intel_plane_free(struct intel_plane *plane)
  66 {
  67         intel_plane_destroy_state(&plane->base, plane->base.state);
  68         kfree(plane);
  69 }
  70 
  71 /**
  72  * intel_plane_duplicate_state - duplicate plane state
  73  * @plane: drm plane
  74  *
  75  * Allocates and returns a copy of the plane state (both common and
  76  * Intel-specific) for the specified plane.
  77  *
  78  * Returns: The newly allocated plane state, or NULL on failure.
  79  */
  80 struct drm_plane_state *
  81 intel_plane_duplicate_state(struct drm_plane *plane)
  82 {
  83         struct drm_plane_state *state;
  84         struct intel_plane_state *intel_state;
  85 
  86         intel_state = kmemdup(plane->state, sizeof(*intel_state), GFP_KERNEL);
  87 
  88         if (!intel_state)
  89                 return NULL;
  90 
  91         state = &intel_state->base;
  92 
  93         __drm_atomic_helper_plane_duplicate_state(plane, state);
  94 
  95         intel_state->vma = NULL;
  96         intel_state->flags = 0;
  97 
  98         return state;
  99 }
 100 
 101 /**
 102  * intel_plane_destroy_state - destroy plane state
 103  * @plane: drm plane
 104  * @state: state object to destroy
 105  *
 106  * Destroys the plane state (both common and Intel-specific) for the
 107  * specified plane.
 108  */
 109 void
 110 intel_plane_destroy_state(struct drm_plane *plane,
 111                           struct drm_plane_state *state)
 112 {
 113         WARN_ON(to_intel_plane_state(state)->vma);
 114 
 115         drm_atomic_helper_plane_destroy_state(plane, state);
 116 }
 117 
 118 unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
 119                                    const struct intel_plane_state *plane_state)
 120 {
 121         const struct drm_framebuffer *fb = plane_state->base.fb;
 122         unsigned int cpp;
 123 
 124         if (!plane_state->base.visible)
 125                 return 0;
 126 
 127         cpp = fb->format->cpp[0];
 128 
 129         /*
 130          * Based on HSD#:1408715493
 131          * NV12 cpp == 4, P010 cpp == 8
 132          *
 133          * FIXME what is the logic behind this?
 134          */
 135         if (fb->format->is_yuv && fb->format->num_planes > 1)
 136                 cpp *= 4;
 137 
 138         return cpp * crtc_state->pixel_rate;
 139 }
 140 
 141 int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
 142                                         struct intel_crtc_state *new_crtc_state,
 143                                         const struct intel_plane_state *old_plane_state,
 144                                         struct intel_plane_state *new_plane_state)
 145 {
 146         struct intel_plane *plane = to_intel_plane(new_plane_state->base.plane);
 147         int ret;
 148 
 149         new_crtc_state->active_planes &= ~BIT(plane->id);
 150         new_crtc_state->nv12_planes &= ~BIT(plane->id);
 151         new_crtc_state->c8_planes &= ~BIT(plane->id);
 152         new_crtc_state->data_rate[plane->id] = 0;
 153         new_plane_state->base.visible = false;
 154 
 155         if (!new_plane_state->base.crtc && !old_plane_state->base.crtc)
 156                 return 0;
 157 
 158         ret = plane->check_plane(new_crtc_state, new_plane_state);
 159         if (ret)
 160                 return ret;
 161 
 162         /* FIXME pre-g4x don't work like this */
 163         if (new_plane_state->base.visible)
 164                 new_crtc_state->active_planes |= BIT(plane->id);
 165 
 166         if (new_plane_state->base.visible &&
 167             is_planar_yuv_format(new_plane_state->base.fb->format->format))
 168                 new_crtc_state->nv12_planes |= BIT(plane->id);
 169 
 170         if (new_plane_state->base.visible &&
 171             new_plane_state->base.fb->format->format == DRM_FORMAT_C8)
 172                 new_crtc_state->c8_planes |= BIT(plane->id);
 173 
 174         if (new_plane_state->base.visible || old_plane_state->base.visible)
 175                 new_crtc_state->update_planes |= BIT(plane->id);
 176 
 177         new_crtc_state->data_rate[plane->id] =
 178                 intel_plane_data_rate(new_crtc_state, new_plane_state);
 179 
 180         return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
 181                                                old_plane_state, new_plane_state);
 182 }
 183 
 184 static struct intel_crtc *
 185 get_crtc_from_states(const struct intel_plane_state *old_plane_state,
 186                      const struct intel_plane_state *new_plane_state)
 187 {
 188         if (new_plane_state->base.crtc)
 189                 return to_intel_crtc(new_plane_state->base.crtc);
 190 
 191         if (old_plane_state->base.crtc)
 192                 return to_intel_crtc(old_plane_state->base.crtc);
 193 
 194         return NULL;
 195 }
 196 
 197 static int intel_plane_atomic_check(struct drm_plane *_plane,
 198                                     struct drm_plane_state *_new_plane_state)
 199 {
 200         struct intel_plane *plane = to_intel_plane(_plane);
 201         struct intel_atomic_state *state =
 202                 to_intel_atomic_state(_new_plane_state->state);
 203         struct intel_plane_state *new_plane_state =
 204                 to_intel_plane_state(_new_plane_state);
 205         const struct intel_plane_state *old_plane_state =
 206                 intel_atomic_get_old_plane_state(state, plane);
 207         struct intel_crtc *crtc =
 208                 get_crtc_from_states(old_plane_state, new_plane_state);
 209         const struct intel_crtc_state *old_crtc_state;
 210         struct intel_crtc_state *new_crtc_state;
 211 
 212         new_plane_state->base.visible = false;
 213         if (!crtc)
 214                 return 0;
 215 
 216         old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
 217         new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
 218 
 219         return intel_plane_atomic_check_with_state(old_crtc_state,
 220                                                    new_crtc_state,
 221                                                    old_plane_state,
 222                                                    new_plane_state);
 223 }
 224 
 225 static struct intel_plane *
 226 skl_next_plane_to_commit(struct intel_atomic_state *state,
 227                          struct intel_crtc *crtc,
 228                          struct skl_ddb_entry entries_y[I915_MAX_PLANES],
 229                          struct skl_ddb_entry entries_uv[I915_MAX_PLANES],
 230                          unsigned int *update_mask)
 231 {
 232         struct intel_crtc_state *crtc_state =
 233                 intel_atomic_get_new_crtc_state(state, crtc);
 234         struct intel_plane_state *plane_state;
 235         struct intel_plane *plane;
 236         int i;
 237 
 238         if (*update_mask == 0)
 239                 return NULL;
 240 
 241         for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
 242                 enum plane_id plane_id = plane->id;
 243 
 244                 if (crtc->pipe != plane->pipe ||
 245                     !(*update_mask & BIT(plane_id)))
 246                         continue;
 247 
 248                 if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
 249                                                 entries_y,
 250                                                 I915_MAX_PLANES, plane_id) ||
 251                     skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id],
 252                                                 entries_uv,
 253                                                 I915_MAX_PLANES, plane_id))
 254                         continue;
 255 
 256                 *update_mask &= ~BIT(plane_id);
 257                 entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
 258                 entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id];
 259 
 260                 return plane;
 261         }
 262 
 263         /* should never happen */
 264         WARN_ON(1);
 265 
 266         return NULL;
 267 }
 268 
 269 void intel_update_plane(struct intel_plane *plane,
 270                         const struct intel_crtc_state *crtc_state,
 271                         const struct intel_plane_state *plane_state)
 272 {
 273         struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
 274 
 275         trace_intel_update_plane(&plane->base, crtc);
 276         plane->update_plane(plane, crtc_state, plane_state);
 277 }
 278 
 279 void intel_update_slave(struct intel_plane *plane,
 280                         const struct intel_crtc_state *crtc_state,
 281                         const struct intel_plane_state *plane_state)
 282 {
 283         struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
 284 
 285         trace_intel_update_plane(&plane->base, crtc);
 286         plane->update_slave(plane, crtc_state, plane_state);
 287 }
 288 
 289 void intel_disable_plane(struct intel_plane *plane,
 290                          const struct intel_crtc_state *crtc_state)
 291 {
 292         struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
 293 
 294         trace_intel_disable_plane(&plane->base, crtc);
 295         plane->disable_plane(plane, crtc_state);
 296 }
 297 
 298 void skl_update_planes_on_crtc(struct intel_atomic_state *state,
 299                                struct intel_crtc *crtc)
 300 {
 301         struct intel_crtc_state *old_crtc_state =
 302                 intel_atomic_get_old_crtc_state(state, crtc);
 303         struct intel_crtc_state *new_crtc_state =
 304                 intel_atomic_get_new_crtc_state(state, crtc);
 305         struct skl_ddb_entry entries_y[I915_MAX_PLANES];
 306         struct skl_ddb_entry entries_uv[I915_MAX_PLANES];
 307         u32 update_mask = new_crtc_state->update_planes;
 308         struct intel_plane *plane;
 309 
 310         memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y,
 311                sizeof(old_crtc_state->wm.skl.plane_ddb_y));
 312         memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv,
 313                sizeof(old_crtc_state->wm.skl.plane_ddb_uv));
 314 
 315         while ((plane = skl_next_plane_to_commit(state, crtc,
 316                                                  entries_y, entries_uv,
 317                                                  &update_mask))) {
 318                 struct intel_plane_state *new_plane_state =
 319                         intel_atomic_get_new_plane_state(state, plane);
 320 
 321                 if (new_plane_state->base.visible) {
 322                         intel_update_plane(plane, new_crtc_state, new_plane_state);
 323                 } else if (new_plane_state->slave) {
 324                         struct intel_plane *master =
 325                                 new_plane_state->linked_plane;
 326 
 327                         /*
 328                          * We update the slave plane from this function because
 329                          * programming it from the master plane's update_plane
 330                          * callback runs into issues when the Y plane is
 331                          * reassigned, disabled or used by a different plane.
 332                          *
 333                          * The slave plane is updated with the master plane's
 334                          * plane_state.
 335                          */
 336                         new_plane_state =
 337                                 intel_atomic_get_new_plane_state(state, master);
 338 
 339                         intel_update_slave(plane, new_crtc_state, new_plane_state);
 340                 } else {
 341                         intel_disable_plane(plane, new_crtc_state);
 342                 }
 343         }
 344 }
 345 
 346 void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
 347                                 struct intel_crtc *crtc)
 348 {
 349         struct intel_crtc_state *new_crtc_state =
 350                 intel_atomic_get_new_crtc_state(state, crtc);
 351         u32 update_mask = new_crtc_state->update_planes;
 352         struct intel_plane_state *new_plane_state;
 353         struct intel_plane *plane;
 354         int i;
 355 
 356         for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
 357                 if (crtc->pipe != plane->pipe ||
 358                     !(update_mask & BIT(plane->id)))
 359                         continue;
 360 
 361                 if (new_plane_state->base.visible)
 362                         intel_update_plane(plane, new_crtc_state, new_plane_state);
 363                 else
 364                         intel_disable_plane(plane, new_crtc_state);
 365         }
 366 }
 367 
 368 const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
 369         .prepare_fb = intel_prepare_plane_fb,
 370         .cleanup_fb = intel_cleanup_plane_fb,
 371         .atomic_check = intel_plane_atomic_check,
 372 };

/* [<][>][^][v][top][bottom][index][help] */