root/drivers/gpu/drm/tegra/plane.c

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

DEFINITIONS

This source file includes following definitions.
  1. tegra_plane_destroy
  2. tegra_plane_reset
  3. tegra_plane_atomic_duplicate_state
  4. tegra_plane_atomic_destroy_state
  5. tegra_plane_format_mod_supported
  6. tegra_plane_state_add
  7. tegra_plane_format
  8. tegra_plane_format_is_yuv
  9. __drm_format_has_alpha
  10. tegra_plane_format_get_alpha
  11. tegra_plane_setup_opacity
  12. tegra_plane_check_transparency
  13. tegra_plane_get_overlap_index
  14. tegra_plane_update_transparency
  15. tegra_plane_setup_transparency
  16. tegra_plane_setup_legacy_state

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
   4  */
   5 
   6 #include <drm/drm_atomic.h>
   7 #include <drm/drm_atomic_helper.h>
   8 #include <drm/drm_fourcc.h>
   9 #include <drm/drm_plane_helper.h>
  10 
  11 #include "dc.h"
  12 #include "plane.h"
  13 
  14 static void tegra_plane_destroy(struct drm_plane *plane)
  15 {
  16         struct tegra_plane *p = to_tegra_plane(plane);
  17 
  18         drm_plane_cleanup(plane);
  19         kfree(p);
  20 }
  21 
  22 static void tegra_plane_reset(struct drm_plane *plane)
  23 {
  24         struct tegra_plane *p = to_tegra_plane(plane);
  25         struct tegra_plane_state *state;
  26 
  27         if (plane->state)
  28                 __drm_atomic_helper_plane_destroy_state(plane->state);
  29 
  30         kfree(plane->state);
  31         plane->state = NULL;
  32 
  33         state = kzalloc(sizeof(*state), GFP_KERNEL);
  34         if (state) {
  35                 plane->state = &state->base;
  36                 plane->state->plane = plane;
  37                 plane->state->zpos = p->index;
  38                 plane->state->normalized_zpos = p->index;
  39         }
  40 }
  41 
  42 static struct drm_plane_state *
  43 tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
  44 {
  45         struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
  46         struct tegra_plane_state *copy;
  47         unsigned int i;
  48 
  49         copy = kmalloc(sizeof(*copy), GFP_KERNEL);
  50         if (!copy)
  51                 return NULL;
  52 
  53         __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
  54         copy->tiling = state->tiling;
  55         copy->format = state->format;
  56         copy->swap = state->swap;
  57         copy->bottom_up = state->bottom_up;
  58         copy->opaque = state->opaque;
  59 
  60         for (i = 0; i < 2; i++)
  61                 copy->blending[i] = state->blending[i];
  62 
  63         return &copy->base;
  64 }
  65 
  66 static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
  67                                              struct drm_plane_state *state)
  68 {
  69         __drm_atomic_helper_plane_destroy_state(state);
  70         kfree(state);
  71 }
  72 
  73 static bool tegra_plane_format_mod_supported(struct drm_plane *plane,
  74                                              uint32_t format,
  75                                              uint64_t modifier)
  76 {
  77         const struct drm_format_info *info = drm_format_info(format);
  78 
  79         if (modifier == DRM_FORMAT_MOD_LINEAR)
  80                 return true;
  81 
  82         if (info->num_planes == 1)
  83                 return true;
  84 
  85         return false;
  86 }
  87 
  88 const struct drm_plane_funcs tegra_plane_funcs = {
  89         .update_plane = drm_atomic_helper_update_plane,
  90         .disable_plane = drm_atomic_helper_disable_plane,
  91         .destroy = tegra_plane_destroy,
  92         .reset = tegra_plane_reset,
  93         .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
  94         .atomic_destroy_state = tegra_plane_atomic_destroy_state,
  95         .format_mod_supported = tegra_plane_format_mod_supported,
  96 };
  97 
  98 int tegra_plane_state_add(struct tegra_plane *plane,
  99                           struct drm_plane_state *state)
 100 {
 101         struct drm_crtc_state *crtc_state;
 102         struct tegra_dc_state *tegra;
 103         int err;
 104 
 105         /* Propagate errors from allocation or locking failures. */
 106         crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
 107         if (IS_ERR(crtc_state))
 108                 return PTR_ERR(crtc_state);
 109 
 110         /* Check plane state for visibility and calculate clipping bounds */
 111         err = drm_atomic_helper_check_plane_state(state, crtc_state,
 112                                                   0, INT_MAX, true, true);
 113         if (err < 0)
 114                 return err;
 115 
 116         tegra = to_dc_state(crtc_state);
 117 
 118         tegra->planes |= WIN_A_ACT_REQ << plane->index;
 119 
 120         return 0;
 121 }
 122 
 123 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
 124 {
 125         /* assume no swapping of fetched data */
 126         if (swap)
 127                 *swap = BYTE_SWAP_NOSWAP;
 128 
 129         switch (fourcc) {
 130         case DRM_FORMAT_ARGB4444:
 131                 *format = WIN_COLOR_DEPTH_B4G4R4A4;
 132                 break;
 133 
 134         case DRM_FORMAT_ARGB1555:
 135                 *format = WIN_COLOR_DEPTH_B5G5R5A1;
 136                 break;
 137 
 138         case DRM_FORMAT_RGB565:
 139                 *format = WIN_COLOR_DEPTH_B5G6R5;
 140                 break;
 141 
 142         case DRM_FORMAT_RGBA5551:
 143                 *format = WIN_COLOR_DEPTH_A1B5G5R5;
 144                 break;
 145 
 146         case DRM_FORMAT_ARGB8888:
 147                 *format = WIN_COLOR_DEPTH_B8G8R8A8;
 148                 break;
 149 
 150         case DRM_FORMAT_ABGR8888:
 151                 *format = WIN_COLOR_DEPTH_R8G8B8A8;
 152                 break;
 153 
 154         case DRM_FORMAT_ABGR4444:
 155                 *format = WIN_COLOR_DEPTH_R4G4B4A4;
 156                 break;
 157 
 158         case DRM_FORMAT_ABGR1555:
 159                 *format = WIN_COLOR_DEPTH_R5G5B5A;
 160                 break;
 161 
 162         case DRM_FORMAT_BGRA5551:
 163                 *format = WIN_COLOR_DEPTH_AR5G5B5;
 164                 break;
 165 
 166         case DRM_FORMAT_XRGB1555:
 167                 *format = WIN_COLOR_DEPTH_B5G5R5X1;
 168                 break;
 169 
 170         case DRM_FORMAT_RGBX5551:
 171                 *format = WIN_COLOR_DEPTH_X1B5G5R5;
 172                 break;
 173 
 174         case DRM_FORMAT_XBGR1555:
 175                 *format = WIN_COLOR_DEPTH_R5G5B5X1;
 176                 break;
 177 
 178         case DRM_FORMAT_BGRX5551:
 179                 *format = WIN_COLOR_DEPTH_X1R5G5B5;
 180                 break;
 181 
 182         case DRM_FORMAT_BGR565:
 183                 *format = WIN_COLOR_DEPTH_R5G6B5;
 184                 break;
 185 
 186         case DRM_FORMAT_BGRA8888:
 187                 *format = WIN_COLOR_DEPTH_A8R8G8B8;
 188                 break;
 189 
 190         case DRM_FORMAT_RGBA8888:
 191                 *format = WIN_COLOR_DEPTH_A8B8G8R8;
 192                 break;
 193 
 194         case DRM_FORMAT_XRGB8888:
 195                 *format = WIN_COLOR_DEPTH_B8G8R8X8;
 196                 break;
 197 
 198         case DRM_FORMAT_XBGR8888:
 199                 *format = WIN_COLOR_DEPTH_R8G8B8X8;
 200                 break;
 201 
 202         case DRM_FORMAT_UYVY:
 203                 *format = WIN_COLOR_DEPTH_YCbCr422;
 204                 break;
 205 
 206         case DRM_FORMAT_YUYV:
 207                 if (!swap)
 208                         return -EINVAL;
 209 
 210                 *format = WIN_COLOR_DEPTH_YCbCr422;
 211                 *swap = BYTE_SWAP_SWAP2;
 212                 break;
 213 
 214         case DRM_FORMAT_YUV420:
 215                 *format = WIN_COLOR_DEPTH_YCbCr420P;
 216                 break;
 217 
 218         case DRM_FORMAT_YUV422:
 219                 *format = WIN_COLOR_DEPTH_YCbCr422P;
 220                 break;
 221 
 222         default:
 223                 return -EINVAL;
 224         }
 225 
 226         return 0;
 227 }
 228 
 229 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
 230 {
 231         switch (format) {
 232         case WIN_COLOR_DEPTH_YCbCr422:
 233         case WIN_COLOR_DEPTH_YUV422:
 234                 if (planar)
 235                         *planar = false;
 236 
 237                 return true;
 238 
 239         case WIN_COLOR_DEPTH_YCbCr420P:
 240         case WIN_COLOR_DEPTH_YUV420P:
 241         case WIN_COLOR_DEPTH_YCbCr422P:
 242         case WIN_COLOR_DEPTH_YUV422P:
 243         case WIN_COLOR_DEPTH_YCbCr422R:
 244         case WIN_COLOR_DEPTH_YUV422R:
 245         case WIN_COLOR_DEPTH_YCbCr422RA:
 246         case WIN_COLOR_DEPTH_YUV422RA:
 247                 if (planar)
 248                         *planar = true;
 249 
 250                 return true;
 251         }
 252 
 253         if (planar)
 254                 *planar = false;
 255 
 256         return false;
 257 }
 258 
 259 static bool __drm_format_has_alpha(u32 format)
 260 {
 261         switch (format) {
 262         case DRM_FORMAT_ARGB1555:
 263         case DRM_FORMAT_RGBA5551:
 264         case DRM_FORMAT_ABGR8888:
 265         case DRM_FORMAT_ARGB8888:
 266                 return true;
 267         }
 268 
 269         return false;
 270 }
 271 
 272 static int tegra_plane_format_get_alpha(unsigned int opaque,
 273                                         unsigned int *alpha)
 274 {
 275         if (tegra_plane_format_is_yuv(opaque, NULL)) {
 276                 *alpha = opaque;
 277                 return 0;
 278         }
 279 
 280         switch (opaque) {
 281         case WIN_COLOR_DEPTH_B5G5R5X1:
 282                 *alpha = WIN_COLOR_DEPTH_B5G5R5A1;
 283                 return 0;
 284 
 285         case WIN_COLOR_DEPTH_X1B5G5R5:
 286                 *alpha = WIN_COLOR_DEPTH_A1B5G5R5;
 287                 return 0;
 288 
 289         case WIN_COLOR_DEPTH_R8G8B8X8:
 290                 *alpha = WIN_COLOR_DEPTH_R8G8B8A8;
 291                 return 0;
 292 
 293         case WIN_COLOR_DEPTH_B8G8R8X8:
 294                 *alpha = WIN_COLOR_DEPTH_B8G8R8A8;
 295                 return 0;
 296 
 297         case WIN_COLOR_DEPTH_B5G6R5:
 298                 *alpha = opaque;
 299                 return 0;
 300         }
 301 
 302         return -EINVAL;
 303 }
 304 
 305 /*
 306  * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
 307  * be emulated using the alpha formats and alpha blending disabled.
 308  */
 309 static int tegra_plane_setup_opacity(struct tegra_plane *tegra,
 310                                      struct tegra_plane_state *state)
 311 {
 312         unsigned int format;
 313         int err;
 314 
 315         switch (state->format) {
 316         case WIN_COLOR_DEPTH_B5G5R5A1:
 317         case WIN_COLOR_DEPTH_A1B5G5R5:
 318         case WIN_COLOR_DEPTH_R8G8B8A8:
 319         case WIN_COLOR_DEPTH_B8G8R8A8:
 320                 state->opaque = false;
 321                 break;
 322 
 323         default:
 324                 err = tegra_plane_format_get_alpha(state->format, &format);
 325                 if (err < 0)
 326                         return err;
 327 
 328                 state->format = format;
 329                 state->opaque = true;
 330                 break;
 331         }
 332 
 333         return 0;
 334 }
 335 
 336 static int tegra_plane_check_transparency(struct tegra_plane *tegra,
 337                                           struct tegra_plane_state *state)
 338 {
 339         struct drm_plane_state *old, *plane_state;
 340         struct drm_plane *plane;
 341 
 342         old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base);
 343 
 344         /* check if zpos / transparency changed */
 345         if (old->normalized_zpos == state->base.normalized_zpos &&
 346             to_tegra_plane_state(old)->opaque == state->opaque)
 347                 return 0;
 348 
 349         /* include all sibling planes into this commit */
 350         drm_for_each_plane(plane, tegra->base.dev) {
 351                 struct tegra_plane *p = to_tegra_plane(plane);
 352 
 353                 /* skip this plane and planes on different CRTCs */
 354                 if (p == tegra || p->dc != tegra->dc)
 355                         continue;
 356 
 357                 plane_state = drm_atomic_get_plane_state(state->base.state,
 358                                                          plane);
 359                 if (IS_ERR(plane_state))
 360                         return PTR_ERR(plane_state);
 361         }
 362 
 363         return 1;
 364 }
 365 
 366 static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
 367                                                   struct tegra_plane *other)
 368 {
 369         unsigned int index = 0, i;
 370 
 371         WARN_ON(plane == other);
 372 
 373         for (i = 0; i < 3; i++) {
 374                 if (i == plane->index)
 375                         continue;
 376 
 377                 if (i == other->index)
 378                         break;
 379 
 380                 index++;
 381         }
 382 
 383         return index;
 384 }
 385 
 386 static void tegra_plane_update_transparency(struct tegra_plane *tegra,
 387                                             struct tegra_plane_state *state)
 388 {
 389         struct drm_plane_state *new;
 390         struct drm_plane *plane;
 391         unsigned int i;
 392 
 393         for_each_new_plane_in_state(state->base.state, plane, new, i) {
 394                 struct tegra_plane *p = to_tegra_plane(plane);
 395                 unsigned index;
 396 
 397                 /* skip this plane and planes on different CRTCs */
 398                 if (p == tegra || p->dc != tegra->dc)
 399                         continue;
 400 
 401                 index = tegra_plane_get_overlap_index(tegra, p);
 402 
 403                 if (new->fb && __drm_format_has_alpha(new->fb->format->format))
 404                         state->blending[index].alpha = true;
 405                 else
 406                         state->blending[index].alpha = false;
 407 
 408                 if (new->normalized_zpos > state->base.normalized_zpos)
 409                         state->blending[index].top = true;
 410                 else
 411                         state->blending[index].top = false;
 412 
 413                 /*
 414                  * Missing framebuffer means that plane is disabled, in this
 415                  * case mark B / C window as top to be able to differentiate
 416                  * windows indices order in regards to zPos for the middle
 417                  * window X / Y registers programming.
 418                  */
 419                 if (!new->fb)
 420                         state->blending[index].top = (index == 1);
 421         }
 422 }
 423 
 424 static int tegra_plane_setup_transparency(struct tegra_plane *tegra,
 425                                           struct tegra_plane_state *state)
 426 {
 427         struct tegra_plane_state *tegra_state;
 428         struct drm_plane_state *new;
 429         struct drm_plane *plane;
 430         int err;
 431 
 432         /*
 433          * If planes zpos / transparency changed, sibling planes blending
 434          * state may require adjustment and in this case they will be included
 435          * into this atom commit, otherwise blending state is unchanged.
 436          */
 437         err = tegra_plane_check_transparency(tegra, state);
 438         if (err <= 0)
 439                 return err;
 440 
 441         /*
 442          * All planes are now in the atomic state, walk them up and update
 443          * transparency state for each plane.
 444          */
 445         drm_for_each_plane(plane, tegra->base.dev) {
 446                 struct tegra_plane *p = to_tegra_plane(plane);
 447 
 448                 /* skip planes on different CRTCs */
 449                 if (p->dc != tegra->dc)
 450                         continue;
 451 
 452                 new = drm_atomic_get_new_plane_state(state->base.state, plane);
 453                 tegra_state = to_tegra_plane_state(new);
 454 
 455                 /*
 456                  * There is no need to update blending state for the disabled
 457                  * plane.
 458                  */
 459                 if (new->fb)
 460                         tegra_plane_update_transparency(p, tegra_state);
 461         }
 462 
 463         return 0;
 464 }
 465 
 466 int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
 467                                    struct tegra_plane_state *state)
 468 {
 469         int err;
 470 
 471         err = tegra_plane_setup_opacity(tegra, state);
 472         if (err < 0)
 473                 return err;
 474 
 475         err = tegra_plane_setup_transparency(tegra, state);
 476         if (err < 0)
 477                 return err;
 478 
 479         return 0;
 480 }

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