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