linux/drivers/gpu/drm/imx/ipuv3-plane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * i.MX IPUv3 DP Overlay Planes
   4 *
   5 * Copyright (C) 2013 Philipp Zabel, Pengutronix
   6 */
   7
   8#include <drm/drmP.h>
   9#include <drm/drm_atomic.h>
  10#include <drm/drm_atomic_helper.h>
  11#include <drm/drm_fb_cma_helper.h>
  12#include <drm/drm_gem_cma_helper.h>
  13#include <drm/drm_gem_framebuffer_helper.h>
  14#include <drm/drm_plane_helper.h>
  15
  16#include "video/imx-ipu-v3.h"
  17#include "imx-drm.h"
  18#include "ipuv3-plane.h"
  19
  20struct ipu_plane_state {
  21        struct drm_plane_state base;
  22        bool use_pre;
  23};
  24
  25static inline struct ipu_plane_state *
  26to_ipu_plane_state(struct drm_plane_state *p)
  27{
  28        return container_of(p, struct ipu_plane_state, base);
  29}
  30
  31static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
  32{
  33        return container_of(p, struct ipu_plane, base);
  34}
  35
  36static const uint32_t ipu_plane_formats[] = {
  37        DRM_FORMAT_ARGB1555,
  38        DRM_FORMAT_XRGB1555,
  39        DRM_FORMAT_ABGR1555,
  40        DRM_FORMAT_XBGR1555,
  41        DRM_FORMAT_RGBA5551,
  42        DRM_FORMAT_BGRA5551,
  43        DRM_FORMAT_ARGB4444,
  44        DRM_FORMAT_ARGB8888,
  45        DRM_FORMAT_XRGB8888,
  46        DRM_FORMAT_ABGR8888,
  47        DRM_FORMAT_XBGR8888,
  48        DRM_FORMAT_RGBA8888,
  49        DRM_FORMAT_RGBX8888,
  50        DRM_FORMAT_BGRA8888,
  51        DRM_FORMAT_BGRX8888,
  52        DRM_FORMAT_UYVY,
  53        DRM_FORMAT_VYUY,
  54        DRM_FORMAT_YUYV,
  55        DRM_FORMAT_YVYU,
  56        DRM_FORMAT_YUV420,
  57        DRM_FORMAT_YVU420,
  58        DRM_FORMAT_YUV422,
  59        DRM_FORMAT_YVU422,
  60        DRM_FORMAT_YUV444,
  61        DRM_FORMAT_YVU444,
  62        DRM_FORMAT_NV12,
  63        DRM_FORMAT_NV16,
  64        DRM_FORMAT_RGB565,
  65        DRM_FORMAT_RGB565_A8,
  66        DRM_FORMAT_BGR565_A8,
  67        DRM_FORMAT_RGB888_A8,
  68        DRM_FORMAT_BGR888_A8,
  69        DRM_FORMAT_RGBX8888_A8,
  70        DRM_FORMAT_BGRX8888_A8,
  71};
  72
  73static const uint64_t ipu_format_modifiers[] = {
  74        DRM_FORMAT_MOD_LINEAR,
  75        DRM_FORMAT_MOD_INVALID
  76};
  77
  78static const uint64_t pre_format_modifiers[] = {
  79        DRM_FORMAT_MOD_LINEAR,
  80        DRM_FORMAT_MOD_VIVANTE_TILED,
  81        DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
  82        DRM_FORMAT_MOD_INVALID
  83};
  84
  85int ipu_plane_irq(struct ipu_plane *ipu_plane)
  86{
  87        return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
  88                                     IPU_IRQ_EOF);
  89}
  90
  91static inline unsigned long
  92drm_plane_state_to_eba(struct drm_plane_state *state, int plane)
  93{
  94        struct drm_framebuffer *fb = state->fb;
  95        struct drm_gem_cma_object *cma_obj;
  96        int x = state->src.x1 >> 16;
  97        int y = state->src.y1 >> 16;
  98
  99        cma_obj = drm_fb_cma_get_gem_obj(fb, plane);
 100        BUG_ON(!cma_obj);
 101
 102        return cma_obj->paddr + fb->offsets[plane] + fb->pitches[plane] * y +
 103               fb->format->cpp[plane] * x;
 104}
 105
 106static inline unsigned long
 107drm_plane_state_to_ubo(struct drm_plane_state *state)
 108{
 109        struct drm_framebuffer *fb = state->fb;
 110        struct drm_gem_cma_object *cma_obj;
 111        unsigned long eba = drm_plane_state_to_eba(state, 0);
 112        int x = state->src.x1 >> 16;
 113        int y = state->src.y1 >> 16;
 114
 115        cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
 116        BUG_ON(!cma_obj);
 117
 118        x /= drm_format_horz_chroma_subsampling(fb->format->format);
 119        y /= drm_format_vert_chroma_subsampling(fb->format->format);
 120
 121        return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
 122               fb->format->cpp[1] * x - eba;
 123}
 124
 125static inline unsigned long
 126drm_plane_state_to_vbo(struct drm_plane_state *state)
 127{
 128        struct drm_framebuffer *fb = state->fb;
 129        struct drm_gem_cma_object *cma_obj;
 130        unsigned long eba = drm_plane_state_to_eba(state, 0);
 131        int x = state->src.x1 >> 16;
 132        int y = state->src.y1 >> 16;
 133
 134        cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
 135        BUG_ON(!cma_obj);
 136
 137        x /= drm_format_horz_chroma_subsampling(fb->format->format);
 138        y /= drm_format_vert_chroma_subsampling(fb->format->format);
 139
 140        return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y +
 141               fb->format->cpp[2] * x - eba;
 142}
 143
 144void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
 145{
 146        if (!IS_ERR_OR_NULL(ipu_plane->dp))
 147                ipu_dp_put(ipu_plane->dp);
 148        if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
 149                ipu_dmfc_put(ipu_plane->dmfc);
 150        if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
 151                ipu_idmac_put(ipu_plane->ipu_ch);
 152        if (!IS_ERR_OR_NULL(ipu_plane->alpha_ch))
 153                ipu_idmac_put(ipu_plane->alpha_ch);
 154}
 155
 156int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
 157{
 158        int ret;
 159        int alpha_ch;
 160
 161        ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
 162        if (IS_ERR(ipu_plane->ipu_ch)) {
 163                ret = PTR_ERR(ipu_plane->ipu_ch);
 164                DRM_ERROR("failed to get idmac channel: %d\n", ret);
 165                return ret;
 166        }
 167
 168        alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
 169        if (alpha_ch >= 0) {
 170                ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
 171                if (IS_ERR(ipu_plane->alpha_ch)) {
 172                        ret = PTR_ERR(ipu_plane->alpha_ch);
 173                        DRM_ERROR("failed to get alpha idmac channel %d: %d\n",
 174                                  alpha_ch, ret);
 175                        return ret;
 176                }
 177        }
 178
 179        ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
 180        if (IS_ERR(ipu_plane->dmfc)) {
 181                ret = PTR_ERR(ipu_plane->dmfc);
 182                DRM_ERROR("failed to get dmfc: ret %d\n", ret);
 183                goto err_out;
 184        }
 185
 186        if (ipu_plane->dp_flow >= 0) {
 187                ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
 188                if (IS_ERR(ipu_plane->dp)) {
 189                        ret = PTR_ERR(ipu_plane->dp);
 190                        DRM_ERROR("failed to get dp flow: %d\n", ret);
 191                        goto err_out;
 192                }
 193        }
 194
 195        return 0;
 196err_out:
 197        ipu_plane_put_resources(ipu_plane);
 198
 199        return ret;
 200}
 201
 202static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
 203{
 204        switch (ipu_plane->base.state->fb->format->format) {
 205        case DRM_FORMAT_RGB565_A8:
 206        case DRM_FORMAT_BGR565_A8:
 207        case DRM_FORMAT_RGB888_A8:
 208        case DRM_FORMAT_BGR888_A8:
 209        case DRM_FORMAT_RGBX8888_A8:
 210        case DRM_FORMAT_BGRX8888_A8:
 211                return true;
 212        default:
 213                return false;
 214        }
 215}
 216
 217static void ipu_plane_enable(struct ipu_plane *ipu_plane)
 218{
 219        if (ipu_plane->dp)
 220                ipu_dp_enable(ipu_plane->ipu);
 221        ipu_dmfc_enable_channel(ipu_plane->dmfc);
 222        ipu_idmac_enable_channel(ipu_plane->ipu_ch);
 223        if (ipu_plane_separate_alpha(ipu_plane))
 224                ipu_idmac_enable_channel(ipu_plane->alpha_ch);
 225        if (ipu_plane->dp)
 226                ipu_dp_enable_channel(ipu_plane->dp);
 227}
 228
 229void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
 230{
 231        int ret;
 232
 233        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 234
 235        ret = ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
 236        if (ret == -ETIMEDOUT) {
 237                DRM_ERROR("[PLANE:%d] IDMAC timeout\n",
 238                          ipu_plane->base.base.id);
 239        }
 240
 241        if (ipu_plane->dp && disable_dp_channel)
 242                ipu_dp_disable_channel(ipu_plane->dp, false);
 243        ipu_idmac_disable_channel(ipu_plane->ipu_ch);
 244        if (ipu_plane->alpha_ch)
 245                ipu_idmac_disable_channel(ipu_plane->alpha_ch);
 246        ipu_dmfc_disable_channel(ipu_plane->dmfc);
 247        if (ipu_plane->dp)
 248                ipu_dp_disable(ipu_plane->ipu);
 249        if (ipu_prg_present(ipu_plane->ipu))
 250                ipu_prg_channel_disable(ipu_plane->ipu_ch);
 251}
 252
 253void ipu_plane_disable_deferred(struct drm_plane *plane)
 254{
 255        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 256
 257        if (ipu_plane->disabling) {
 258                ipu_plane->disabling = false;
 259                ipu_plane_disable(ipu_plane, false);
 260        }
 261}
 262EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
 263
 264static void ipu_plane_destroy(struct drm_plane *plane)
 265{
 266        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 267
 268        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 269
 270        drm_plane_cleanup(plane);
 271        kfree(ipu_plane);
 272}
 273
 274static void ipu_plane_state_reset(struct drm_plane *plane)
 275{
 276        struct ipu_plane_state *ipu_state;
 277
 278        if (plane->state) {
 279                ipu_state = to_ipu_plane_state(plane->state);
 280                __drm_atomic_helper_plane_destroy_state(plane->state);
 281                kfree(ipu_state);
 282                plane->state = NULL;
 283        }
 284
 285        ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
 286
 287        if (ipu_state)
 288                __drm_atomic_helper_plane_reset(plane, &ipu_state->base);
 289}
 290
 291static struct drm_plane_state *
 292ipu_plane_duplicate_state(struct drm_plane *plane)
 293{
 294        struct ipu_plane_state *state;
 295
 296        if (WARN_ON(!plane->state))
 297                return NULL;
 298
 299        state = kmalloc(sizeof(*state), GFP_KERNEL);
 300        if (state)
 301                __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
 302
 303        return &state->base;
 304}
 305
 306static void ipu_plane_destroy_state(struct drm_plane *plane,
 307                                    struct drm_plane_state *state)
 308{
 309        struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
 310
 311        __drm_atomic_helper_plane_destroy_state(state);
 312        kfree(ipu_state);
 313}
 314
 315static bool ipu_plane_format_mod_supported(struct drm_plane *plane,
 316                                           uint32_t format, uint64_t modifier)
 317{
 318        struct ipu_soc *ipu = to_ipu_plane(plane)->ipu;
 319
 320        /* linear is supported for all planes and formats */
 321        if (modifier == DRM_FORMAT_MOD_LINEAR)
 322                return true;
 323
 324        /* without a PRG there are no supported modifiers */
 325        if (!ipu_prg_present(ipu))
 326                return false;
 327
 328        return ipu_prg_format_supported(ipu, format, modifier);
 329}
 330
 331static const struct drm_plane_funcs ipu_plane_funcs = {
 332        .update_plane   = drm_atomic_helper_update_plane,
 333        .disable_plane  = drm_atomic_helper_disable_plane,
 334        .destroy        = ipu_plane_destroy,
 335        .reset          = ipu_plane_state_reset,
 336        .atomic_duplicate_state = ipu_plane_duplicate_state,
 337        .atomic_destroy_state   = ipu_plane_destroy_state,
 338        .format_mod_supported = ipu_plane_format_mod_supported,
 339};
 340
 341static int ipu_plane_atomic_check(struct drm_plane *plane,
 342                                  struct drm_plane_state *state)
 343{
 344        struct drm_plane_state *old_state = plane->state;
 345        struct drm_crtc_state *crtc_state;
 346        struct device *dev = plane->dev->dev;
 347        struct drm_framebuffer *fb = state->fb;
 348        struct drm_framebuffer *old_fb = old_state->fb;
 349        unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
 350        bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
 351        int hsub, vsub;
 352        int ret;
 353
 354        /* Ok to disable */
 355        if (!fb)
 356                return 0;
 357
 358        if (!state->crtc)
 359                return -EINVAL;
 360
 361        crtc_state =
 362                drm_atomic_get_existing_crtc_state(state->state, state->crtc);
 363        if (WARN_ON(!crtc_state))
 364                return -EINVAL;
 365
 366        ret = drm_atomic_helper_check_plane_state(state, crtc_state,
 367                                                  DRM_PLANE_HELPER_NO_SCALING,
 368                                                  DRM_PLANE_HELPER_NO_SCALING,
 369                                                  can_position, true);
 370        if (ret)
 371                return ret;
 372
 373        /* nothing to check when disabling or disabled */
 374        if (!crtc_state->enable)
 375                return 0;
 376
 377        switch (plane->type) {
 378        case DRM_PLANE_TYPE_PRIMARY:
 379                /* full plane minimum width is 13 pixels */
 380                if (drm_rect_width(&state->dst) < 13)
 381                        return -EINVAL;
 382                break;
 383        case DRM_PLANE_TYPE_OVERLAY:
 384                break;
 385        default:
 386                dev_warn(dev, "Unsupported plane type %d\n", plane->type);
 387                return -EINVAL;
 388        }
 389
 390        if (drm_rect_height(&state->dst) < 2)
 391                return -EINVAL;
 392
 393        /*
 394         * We support resizing active plane or changing its format by
 395         * forcing CRTC mode change in plane's ->atomic_check callback
 396         * and disabling all affected active planes in CRTC's ->atomic_disable
 397         * callback.  The planes will be reenabled in plane's ->atomic_update
 398         * callback.
 399         */
 400        if (old_fb &&
 401            (drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) ||
 402             drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) ||
 403             fb->format != old_fb->format))
 404                crtc_state->mode_changed = true;
 405
 406        eba = drm_plane_state_to_eba(state, 0);
 407
 408        if (eba & 0x7)
 409                return -EINVAL;
 410
 411        if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
 412                return -EINVAL;
 413
 414        if (old_fb && fb->pitches[0] != old_fb->pitches[0])
 415                crtc_state->mode_changed = true;
 416
 417        switch (fb->format->format) {
 418        case DRM_FORMAT_YUV420:
 419        case DRM_FORMAT_YVU420:
 420        case DRM_FORMAT_YUV422:
 421        case DRM_FORMAT_YVU422:
 422        case DRM_FORMAT_YUV444:
 423        case DRM_FORMAT_YVU444:
 424                /*
 425                 * Multiplanar formats have to meet the following restrictions:
 426                 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
 427                 * - EBA, UBO and VBO are a multiple of 8
 428                 * - UBO and VBO are unsigned and not larger than 0xfffff8
 429                 * - Only EBA may be changed while scanout is active
 430                 * - The strides of U and V planes must be identical.
 431                 */
 432                vbo = drm_plane_state_to_vbo(state);
 433
 434                if (vbo & 0x7 || vbo > 0xfffff8)
 435                        return -EINVAL;
 436
 437                if (old_fb && (fb->format == old_fb->format)) {
 438                        old_vbo = drm_plane_state_to_vbo(old_state);
 439                        if (vbo != old_vbo)
 440                                crtc_state->mode_changed = true;
 441                }
 442
 443                if (fb->pitches[1] != fb->pitches[2])
 444                        return -EINVAL;
 445
 446                /* fall-through */
 447        case DRM_FORMAT_NV12:
 448        case DRM_FORMAT_NV16:
 449                ubo = drm_plane_state_to_ubo(state);
 450
 451                if (ubo & 0x7 || ubo > 0xfffff8)
 452                        return -EINVAL;
 453
 454                if (old_fb && (fb->format == old_fb->format)) {
 455                        old_ubo = drm_plane_state_to_ubo(old_state);
 456                        if (ubo != old_ubo)
 457                                crtc_state->mode_changed = true;
 458                }
 459
 460                if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
 461                        return -EINVAL;
 462
 463                if (old_fb && old_fb->pitches[1] != fb->pitches[1])
 464                        crtc_state->mode_changed = true;
 465
 466                /*
 467                 * The x/y offsets must be even in case of horizontal/vertical
 468                 * chroma subsampling.
 469                 */
 470                hsub = drm_format_horz_chroma_subsampling(fb->format->format);
 471                vsub = drm_format_vert_chroma_subsampling(fb->format->format);
 472                if (((state->src.x1 >> 16) & (hsub - 1)) ||
 473                    ((state->src.y1 >> 16) & (vsub - 1)))
 474                        return -EINVAL;
 475                break;
 476        case DRM_FORMAT_RGB565_A8:
 477        case DRM_FORMAT_BGR565_A8:
 478        case DRM_FORMAT_RGB888_A8:
 479        case DRM_FORMAT_BGR888_A8:
 480        case DRM_FORMAT_RGBX8888_A8:
 481        case DRM_FORMAT_BGRX8888_A8:
 482                alpha_eba = drm_plane_state_to_eba(state, 1);
 483                if (alpha_eba & 0x7)
 484                        return -EINVAL;
 485
 486                if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
 487                        return -EINVAL;
 488
 489                if (old_fb && old_fb->pitches[1] != fb->pitches[1])
 490                        crtc_state->mode_changed = true;
 491                break;
 492        }
 493
 494        return 0;
 495}
 496
 497static void ipu_plane_atomic_disable(struct drm_plane *plane,
 498                                     struct drm_plane_state *old_state)
 499{
 500        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 501
 502        if (ipu_plane->dp)
 503                ipu_dp_disable_channel(ipu_plane->dp, true);
 504        ipu_plane->disabling = true;
 505}
 506
 507static int ipu_chan_assign_axi_id(int ipu_chan)
 508{
 509        switch (ipu_chan) {
 510        case IPUV3_CHANNEL_MEM_BG_SYNC:
 511                return 1;
 512        case IPUV3_CHANNEL_MEM_FG_SYNC:
 513                return 2;
 514        case IPUV3_CHANNEL_MEM_DC_SYNC:
 515                return 3;
 516        default:
 517                return 0;
 518        }
 519}
 520
 521static void ipu_calculate_bursts(u32 width, u32 cpp, u32 stride,
 522                                 u8 *burstsize, u8 *num_bursts)
 523{
 524        const unsigned int width_bytes = width * cpp;
 525        unsigned int npb, bursts;
 526
 527        /* Maximum number of pixels per burst without overshooting stride */
 528        for (npb = 64 / cpp; npb > 0; --npb) {
 529                if (round_up(width_bytes, npb * cpp) <= stride)
 530                        break;
 531        }
 532        *burstsize = npb;
 533
 534        /* Maximum number of consecutive bursts without overshooting stride */
 535        for (bursts = 8; bursts > 1; bursts /= 2) {
 536                if (round_up(width_bytes, npb * cpp * bursts) <= stride)
 537                        break;
 538        }
 539        *num_bursts = bursts;
 540}
 541
 542static void ipu_plane_atomic_update(struct drm_plane *plane,
 543                                    struct drm_plane_state *old_state)
 544{
 545        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 546        struct drm_plane_state *state = plane->state;
 547        struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
 548        struct drm_crtc_state *crtc_state = state->crtc->state;
 549        struct drm_framebuffer *fb = state->fb;
 550        struct drm_rect *dst = &state->dst;
 551        unsigned long eba, ubo, vbo;
 552        unsigned long alpha_eba = 0;
 553        enum ipu_color_space ics;
 554        unsigned int axi_id = 0;
 555        const struct drm_format_info *info;
 556        u8 burstsize, num_bursts;
 557        u32 width, height;
 558        int active;
 559
 560        if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
 561                ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);
 562
 563        eba = drm_plane_state_to_eba(state, 0);
 564
 565        /*
 566         * Configure PRG channel and attached PRE, this changes the EBA to an
 567         * internal SRAM location.
 568         */
 569        if (ipu_state->use_pre) {
 570                axi_id = ipu_chan_assign_axi_id(ipu_plane->dma);
 571                ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
 572                                          drm_rect_width(&state->src) >> 16,
 573                                          drm_rect_height(&state->src) >> 16,
 574                                          fb->pitches[0], fb->format->format,
 575                                          fb->modifier, &eba);
 576        }
 577
 578        if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
 579                /* nothing to do if PRE is used */
 580                if (ipu_state->use_pre)
 581                        return;
 582                active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
 583                ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
 584                ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
 585                if (ipu_plane_separate_alpha(ipu_plane)) {
 586                        active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
 587                        ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
 588                                             alpha_eba);
 589                        ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
 590                }
 591                return;
 592        }
 593
 594        ics = ipu_drm_fourcc_to_colorspace(fb->format->format);
 595        switch (ipu_plane->dp_flow) {
 596        case IPU_DP_FLOW_SYNC_BG:
 597                ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB);
 598                ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
 599                break;
 600        case IPU_DP_FLOW_SYNC_FG:
 601                ipu_dp_setup_channel(ipu_plane->dp, ics,
 602                                        IPUV3_COLORSPACE_UNKNOWN);
 603                /* Enable local alpha on partial plane */
 604                switch (fb->format->format) {
 605                case DRM_FORMAT_ARGB1555:
 606                case DRM_FORMAT_ABGR1555:
 607                case DRM_FORMAT_RGBA5551:
 608                case DRM_FORMAT_BGRA5551:
 609                case DRM_FORMAT_ARGB4444:
 610                case DRM_FORMAT_ARGB8888:
 611                case DRM_FORMAT_ABGR8888:
 612                case DRM_FORMAT_RGBA8888:
 613                case DRM_FORMAT_BGRA8888:
 614                case DRM_FORMAT_RGB565_A8:
 615                case DRM_FORMAT_BGR565_A8:
 616                case DRM_FORMAT_RGB888_A8:
 617                case DRM_FORMAT_BGR888_A8:
 618                case DRM_FORMAT_RGBX8888_A8:
 619                case DRM_FORMAT_BGRX8888_A8:
 620                        ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
 621                        break;
 622                default:
 623                        ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
 624                        break;
 625                }
 626        }
 627
 628        ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
 629
 630        width = drm_rect_width(&state->src) >> 16;
 631        height = drm_rect_height(&state->src) >> 16;
 632        info = drm_format_info(fb->format->format);
 633        ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0],
 634                             &burstsize, &num_bursts);
 635
 636        ipu_cpmem_zero(ipu_plane->ipu_ch);
 637        ipu_cpmem_set_resolution(ipu_plane->ipu_ch, width, height);
 638        ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->format->format);
 639        ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, burstsize);
 640        ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
 641        ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
 642        ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
 643        ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id);
 644
 645        switch (fb->format->format) {
 646        case DRM_FORMAT_YUV420:
 647        case DRM_FORMAT_YVU420:
 648        case DRM_FORMAT_YUV422:
 649        case DRM_FORMAT_YVU422:
 650        case DRM_FORMAT_YUV444:
 651        case DRM_FORMAT_YVU444:
 652                ubo = drm_plane_state_to_ubo(state);
 653                vbo = drm_plane_state_to_vbo(state);
 654                if (fb->format->format == DRM_FORMAT_YVU420 ||
 655                    fb->format->format == DRM_FORMAT_YVU422 ||
 656                    fb->format->format == DRM_FORMAT_YVU444)
 657                        swap(ubo, vbo);
 658
 659                ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
 660                                              fb->pitches[1], ubo, vbo);
 661
 662                dev_dbg(ipu_plane->base.dev->dev,
 663                        "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
 664                        state->src.x1 >> 16, state->src.y1 >> 16);
 665                break;
 666        case DRM_FORMAT_NV12:
 667        case DRM_FORMAT_NV16:
 668                ubo = drm_plane_state_to_ubo(state);
 669
 670                ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
 671                                              fb->pitches[1], ubo, ubo);
 672
 673                dev_dbg(ipu_plane->base.dev->dev,
 674                        "phy = %lu %lu, x = %d, y = %d", eba, ubo,
 675                        state->src.x1 >> 16, state->src.y1 >> 16);
 676                break;
 677        case DRM_FORMAT_RGB565_A8:
 678        case DRM_FORMAT_BGR565_A8:
 679        case DRM_FORMAT_RGB888_A8:
 680        case DRM_FORMAT_BGR888_A8:
 681        case DRM_FORMAT_RGBX8888_A8:
 682        case DRM_FORMAT_BGRX8888_A8:
 683                alpha_eba = drm_plane_state_to_eba(state, 1);
 684                num_bursts = 0;
 685
 686                dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d",
 687                        eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16);
 688
 689                ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
 690
 691                ipu_cpmem_zero(ipu_plane->alpha_ch);
 692                ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
 693                                         drm_rect_width(&state->src) >> 16,
 694                                         drm_rect_height(&state->src) >> 16);
 695                ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
 696                ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
 697                ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
 698                ipu_cpmem_set_stride(ipu_plane->alpha_ch, fb->pitches[1]);
 699                ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
 700                ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
 701                ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
 702                break;
 703        default:
 704                dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
 705                        eba, state->src.x1 >> 16, state->src.y1 >> 16);
 706                break;
 707        }
 708        ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
 709        ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
 710        ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts);
 711        ipu_plane_enable(ipu_plane);
 712}
 713
 714static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
 715        .prepare_fb = drm_gem_fb_prepare_fb,
 716        .atomic_check = ipu_plane_atomic_check,
 717        .atomic_disable = ipu_plane_atomic_disable,
 718        .atomic_update = ipu_plane_atomic_update,
 719};
 720
 721int ipu_planes_assign_pre(struct drm_device *dev,
 722                          struct drm_atomic_state *state)
 723{
 724        struct drm_crtc_state *old_crtc_state, *crtc_state;
 725        struct drm_plane_state *plane_state;
 726        struct ipu_plane_state *ipu_state;
 727        struct ipu_plane *ipu_plane;
 728        struct drm_plane *plane;
 729        struct drm_crtc *crtc;
 730        int available_pres = ipu_prg_max_active_channels();
 731        int ret, i;
 732
 733        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) {
 734                ret = drm_atomic_add_affected_planes(state, crtc);
 735                if (ret)
 736                        return ret;
 737        }
 738
 739        /*
 740         * We are going over the planes in 2 passes: first we assign PREs to
 741         * planes with a tiling modifier, which need the PREs to resolve into
 742         * linear. Any failure to assign a PRE there is fatal. In the second
 743         * pass we try to assign PREs to linear FBs, to improve memory access
 744         * patterns for them. Failure at this point is non-fatal, as we can
 745         * scan out linear FBs without a PRE.
 746         */
 747        for_each_new_plane_in_state(state, plane, plane_state, i) {
 748                ipu_state = to_ipu_plane_state(plane_state);
 749                ipu_plane = to_ipu_plane(plane);
 750
 751                if (!plane_state->fb) {
 752                        ipu_state->use_pre = false;
 753                        continue;
 754                }
 755
 756                if (!(plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) ||
 757                    plane_state->fb->modifier == DRM_FORMAT_MOD_LINEAR)
 758                        continue;
 759
 760                if (!ipu_prg_present(ipu_plane->ipu) || !available_pres)
 761                        return -EINVAL;
 762
 763                if (!ipu_prg_format_supported(ipu_plane->ipu,
 764                                              plane_state->fb->format->format,
 765                                              plane_state->fb->modifier))
 766                        return -EINVAL;
 767
 768                ipu_state->use_pre = true;
 769                available_pres--;
 770        }
 771
 772        for_each_new_plane_in_state(state, plane, plane_state, i) {
 773                ipu_state = to_ipu_plane_state(plane_state);
 774                ipu_plane = to_ipu_plane(plane);
 775
 776                if (!plane_state->fb) {
 777                        ipu_state->use_pre = false;
 778                        continue;
 779                }
 780
 781                if ((plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) &&
 782                    plane_state->fb->modifier != DRM_FORMAT_MOD_LINEAR)
 783                        continue;
 784
 785                /* make sure that modifier is initialized */
 786                plane_state->fb->modifier = DRM_FORMAT_MOD_LINEAR;
 787
 788                if (ipu_prg_present(ipu_plane->ipu) && available_pres &&
 789                    ipu_prg_format_supported(ipu_plane->ipu,
 790                                             plane_state->fb->format->format,
 791                                             plane_state->fb->modifier)) {
 792                        ipu_state->use_pre = true;
 793                        available_pres--;
 794                } else {
 795                        ipu_state->use_pre = false;
 796                }
 797        }
 798
 799        return 0;
 800}
 801EXPORT_SYMBOL_GPL(ipu_planes_assign_pre);
 802
 803struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
 804                                 int dma, int dp, unsigned int possible_crtcs,
 805                                 enum drm_plane_type type)
 806{
 807        struct ipu_plane *ipu_plane;
 808        const uint64_t *modifiers = ipu_format_modifiers;
 809        int ret;
 810
 811        DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
 812                      dma, dp, possible_crtcs);
 813
 814        ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
 815        if (!ipu_plane) {
 816                DRM_ERROR("failed to allocate plane\n");
 817                return ERR_PTR(-ENOMEM);
 818        }
 819
 820        ipu_plane->ipu = ipu;
 821        ipu_plane->dma = dma;
 822        ipu_plane->dp_flow = dp;
 823
 824        if (ipu_prg_present(ipu))
 825                modifiers = pre_format_modifiers;
 826
 827        ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
 828                                       &ipu_plane_funcs, ipu_plane_formats,
 829                                       ARRAY_SIZE(ipu_plane_formats),
 830                                       modifiers, type, NULL);
 831        if (ret) {
 832                DRM_ERROR("failed to initialize plane\n");
 833                kfree(ipu_plane);
 834                return ERR_PTR(ret);
 835        }
 836
 837        drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
 838
 839        return ipu_plane;
 840}
 841