linux/drivers/gpu/drm/tegra/plane.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <drm/drm_atomic.h>
  10#include <drm/drm_atomic_helper.h>
  11#include <drm/drm_plane_helper.h>
  12
  13#include "dc.h"
  14#include "plane.h"
  15
  16static void tegra_plane_destroy(struct drm_plane *plane)
  17{
  18        struct tegra_plane *p = to_tegra_plane(plane);
  19
  20        drm_plane_cleanup(plane);
  21        kfree(p);
  22}
  23
  24static void tegra_plane_reset(struct drm_plane *plane)
  25{
  26        struct tegra_plane_state *state;
  27
  28        if (plane->state)
  29                __drm_atomic_helper_plane_destroy_state(plane->state);
  30
  31        kfree(plane->state);
  32        plane->state = NULL;
  33
  34        state = kzalloc(sizeof(*state), GFP_KERNEL);
  35        if (state) {
  36                plane->state = &state->base;
  37                plane->state->plane = plane;
  38        }
  39}
  40
  41static struct drm_plane_state *
  42tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
  43{
  44        struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
  45        struct tegra_plane_state *copy;
  46        unsigned int i;
  47
  48        copy = kmalloc(sizeof(*copy), GFP_KERNEL);
  49        if (!copy)
  50                return NULL;
  51
  52        __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
  53        copy->tiling = state->tiling;
  54        copy->format = state->format;
  55        copy->swap = state->swap;
  56        copy->opaque = state->opaque;
  57
  58        for (i = 0; i < 3; i++)
  59                copy->dependent[i] = state->dependent[i];
  60
  61        return &copy->base;
  62}
  63
  64static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
  65                                             struct drm_plane_state *state)
  66{
  67        __drm_atomic_helper_plane_destroy_state(state);
  68        kfree(state);
  69}
  70
  71static bool tegra_plane_format_mod_supported(struct drm_plane *plane,
  72                                             uint32_t format,
  73                                             uint64_t modifier)
  74{
  75        const struct drm_format_info *info = drm_format_info(format);
  76
  77        if (modifier == DRM_FORMAT_MOD_LINEAR)
  78                return true;
  79
  80        if (info->num_planes == 1)
  81                return true;
  82
  83        return false;
  84}
  85
  86const struct drm_plane_funcs tegra_plane_funcs = {
  87        .update_plane = drm_atomic_helper_update_plane,
  88        .disable_plane = drm_atomic_helper_disable_plane,
  89        .destroy = tegra_plane_destroy,
  90        .reset = tegra_plane_reset,
  91        .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
  92        .atomic_destroy_state = tegra_plane_atomic_destroy_state,
  93        .format_mod_supported = tegra_plane_format_mod_supported,
  94};
  95
  96int tegra_plane_state_add(struct tegra_plane *plane,
  97                          struct drm_plane_state *state)
  98{
  99        struct drm_crtc_state *crtc_state;
 100        struct tegra_dc_state *tegra;
 101        int err;
 102
 103        /* Propagate errors from allocation or locking failures. */
 104        crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
 105        if (IS_ERR(crtc_state))
 106                return PTR_ERR(crtc_state);
 107
 108        /* Check plane state for visibility and calculate clipping bounds */
 109        err = drm_atomic_helper_check_plane_state(state, crtc_state,
 110                                                  0, INT_MAX, true, true);
 111        if (err < 0)
 112                return err;
 113
 114        tegra = to_dc_state(crtc_state);
 115
 116        tegra->planes |= WIN_A_ACT_REQ << plane->index;
 117
 118        return 0;
 119}
 120
 121int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
 122{
 123        /* assume no swapping of fetched data */
 124        if (swap)
 125                *swap = BYTE_SWAP_NOSWAP;
 126
 127        switch (fourcc) {
 128        case DRM_FORMAT_ARGB4444:
 129                *format = WIN_COLOR_DEPTH_B4G4R4A4;
 130                break;
 131
 132        case DRM_FORMAT_ARGB1555:
 133                *format = WIN_COLOR_DEPTH_B5G5R5A1;
 134                break;
 135
 136        case DRM_FORMAT_RGB565:
 137                *format = WIN_COLOR_DEPTH_B5G6R5;
 138                break;
 139
 140        case DRM_FORMAT_RGBA5551:
 141                *format = WIN_COLOR_DEPTH_A1B5G5R5;
 142                break;
 143
 144        case DRM_FORMAT_ARGB8888:
 145                *format = WIN_COLOR_DEPTH_B8G8R8A8;
 146                break;
 147
 148        case DRM_FORMAT_ABGR8888:
 149                *format = WIN_COLOR_DEPTH_R8G8B8A8;
 150                break;
 151
 152        case DRM_FORMAT_ABGR4444:
 153                *format = WIN_COLOR_DEPTH_R4G4B4A4;
 154                break;
 155
 156        case DRM_FORMAT_ABGR1555:
 157                *format = WIN_COLOR_DEPTH_R5G5B5A;
 158                break;
 159
 160        case DRM_FORMAT_BGRA5551:
 161                *format = WIN_COLOR_DEPTH_AR5G5B5;
 162                break;
 163
 164        case DRM_FORMAT_XRGB1555:
 165                *format = WIN_COLOR_DEPTH_B5G5R5X1;
 166                break;
 167
 168        case DRM_FORMAT_RGBX5551:
 169                *format = WIN_COLOR_DEPTH_X1B5G5R5;
 170                break;
 171
 172        case DRM_FORMAT_XBGR1555:
 173                *format = WIN_COLOR_DEPTH_R5G5B5X1;
 174                break;
 175
 176        case DRM_FORMAT_BGRX5551:
 177                *format = WIN_COLOR_DEPTH_X1R5G5B5;
 178                break;
 179
 180        case DRM_FORMAT_BGR565:
 181                *format = WIN_COLOR_DEPTH_R5G6B5;
 182                break;
 183
 184        case DRM_FORMAT_BGRA8888:
 185                *format = WIN_COLOR_DEPTH_A8R8G8B8;
 186                break;
 187
 188        case DRM_FORMAT_RGBA8888:
 189                *format = WIN_COLOR_DEPTH_A8B8G8R8;
 190                break;
 191
 192        case DRM_FORMAT_XRGB8888:
 193                *format = WIN_COLOR_DEPTH_B8G8R8X8;
 194                break;
 195
 196        case DRM_FORMAT_XBGR8888:
 197                *format = WIN_COLOR_DEPTH_R8G8B8X8;
 198                break;
 199
 200        case DRM_FORMAT_UYVY:
 201                *format = WIN_COLOR_DEPTH_YCbCr422;
 202                break;
 203
 204        case DRM_FORMAT_YUYV:
 205                if (!swap)
 206                        return -EINVAL;
 207
 208                *format = WIN_COLOR_DEPTH_YCbCr422;
 209                *swap = BYTE_SWAP_SWAP2;
 210                break;
 211
 212        case DRM_FORMAT_YUV420:
 213                *format = WIN_COLOR_DEPTH_YCbCr420P;
 214                break;
 215
 216        case DRM_FORMAT_YUV422:
 217                *format = WIN_COLOR_DEPTH_YCbCr422P;
 218                break;
 219
 220        default:
 221                return -EINVAL;
 222        }
 223
 224        return 0;
 225}
 226
 227bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
 228{
 229        switch (format) {
 230        case WIN_COLOR_DEPTH_YCbCr422:
 231        case WIN_COLOR_DEPTH_YUV422:
 232                if (planar)
 233                        *planar = false;
 234
 235                return true;
 236
 237        case WIN_COLOR_DEPTH_YCbCr420P:
 238        case WIN_COLOR_DEPTH_YUV420P:
 239        case WIN_COLOR_DEPTH_YCbCr422P:
 240        case WIN_COLOR_DEPTH_YUV422P:
 241        case WIN_COLOR_DEPTH_YCbCr422R:
 242        case WIN_COLOR_DEPTH_YUV422R:
 243        case WIN_COLOR_DEPTH_YCbCr422RA:
 244        case WIN_COLOR_DEPTH_YUV422RA:
 245                if (planar)
 246                        *planar = true;
 247
 248                return true;
 249        }
 250
 251        if (planar)
 252                *planar = false;
 253
 254        return false;
 255}
 256
 257static bool __drm_format_has_alpha(u32 format)
 258{
 259        switch (format) {
 260        case DRM_FORMAT_ARGB1555:
 261        case DRM_FORMAT_RGBA5551:
 262        case DRM_FORMAT_ABGR8888:
 263        case DRM_FORMAT_ARGB8888:
 264                return true;
 265        }
 266
 267        return false;
 268}
 269
 270/*
 271 * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
 272 * be emulated using the alpha formats and alpha blending disabled.
 273 */
 274bool tegra_plane_format_has_alpha(unsigned int format)
 275{
 276        switch (format) {
 277        case WIN_COLOR_DEPTH_B5G5R5A1:
 278        case WIN_COLOR_DEPTH_A1B5G5R5:
 279        case WIN_COLOR_DEPTH_R8G8B8A8:
 280        case WIN_COLOR_DEPTH_B8G8R8A8:
 281                return true;
 282        }
 283
 284        return false;
 285}
 286
 287int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
 288{
 289        if (tegra_plane_format_is_yuv(opaque, NULL)) {
 290                *alpha = opaque;
 291                return 0;
 292        }
 293
 294        switch (opaque) {
 295        case WIN_COLOR_DEPTH_B5G5R5X1:
 296                *alpha = WIN_COLOR_DEPTH_B5G5R5A1;
 297                return 0;
 298
 299        case WIN_COLOR_DEPTH_X1B5G5R5:
 300                *alpha = WIN_COLOR_DEPTH_A1B5G5R5;
 301                return 0;
 302
 303        case WIN_COLOR_DEPTH_R8G8B8X8:
 304                *alpha = WIN_COLOR_DEPTH_R8G8B8A8;
 305                return 0;
 306
 307        case WIN_COLOR_DEPTH_B8G8R8X8:
 308                *alpha = WIN_COLOR_DEPTH_B8G8R8A8;
 309                return 0;
 310
 311        case WIN_COLOR_DEPTH_B5G6R5:
 312                *alpha = opaque;
 313                return 0;
 314        }
 315
 316        return -EINVAL;
 317}
 318
 319static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
 320                                                  struct tegra_plane *other)
 321{
 322        unsigned int index = 0, i;
 323
 324        WARN_ON(plane == other);
 325
 326        for (i = 0; i < 3; i++) {
 327                if (i == plane->index)
 328                        continue;
 329
 330                if (i == other->index)
 331                        break;
 332
 333                index++;
 334        }
 335
 336        return index;
 337}
 338
 339void tegra_plane_check_dependent(struct tegra_plane *tegra,
 340                                 struct tegra_plane_state *state)
 341{
 342        struct drm_plane_state *old, *new;
 343        struct drm_plane *plane;
 344        unsigned int zpos[2];
 345        unsigned int i;
 346
 347        for (i = 0; i < 2; i++)
 348                zpos[i] = 0;
 349
 350        for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {
 351                struct tegra_plane *p = to_tegra_plane(plane);
 352                unsigned index;
 353
 354                /* skip this plane and planes on different CRTCs */
 355                if (p == tegra || new->crtc != state->base.crtc)
 356                        continue;
 357
 358                index = tegra_plane_get_overlap_index(tegra, p);
 359
 360                state->dependent[index] = false;
 361
 362                /*
 363                 * If any of the other planes is on top of this plane and uses
 364                 * a format with an alpha component, mark this plane as being
 365                 * dependent, meaning it's alpha value will be 1 minus the sum
 366                 * of alpha components of the overlapping planes.
 367                 */
 368                if (p->index > tegra->index) {
 369                        if (__drm_format_has_alpha(new->fb->format->format))
 370                                state->dependent[index] = true;
 371
 372                        /* keep track of the Z position */
 373                        zpos[index] = p->index;
 374                }
 375        }
 376
 377        /*
 378         * The region where three windows overlap is the intersection of the
 379         * two regions where two windows overlap. It contributes to the area
 380         * if any of the windows on top of it have an alpha component.
 381         */
 382        for (i = 0; i < 2; i++)
 383                state->dependent[2] = state->dependent[2] ||
 384                                      state->dependent[i];
 385
 386        /*
 387         * However, if any of the windows on top of this window is opaque, it
 388         * will completely conceal this window within that area, so avoid the
 389         * window from contributing to the area.
 390         */
 391        for (i = 0; i < 2; i++) {
 392                if (zpos[i] > tegra->index)
 393                        state->dependent[2] = state->dependent[2] &&
 394                                              state->dependent[i];
 395        }
 396}
 397