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 /= fb->format->hsub;
 119        y /= fb->format->vsub;
 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 /= fb->format->hsub;
 138        y /= fb->format->vsub;
 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        unsigned int zpos = (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
 277        struct ipu_plane_state *ipu_state;
 278
 279        if (plane->state) {
 280                ipu_state = to_ipu_plane_state(plane->state);
 281                __drm_atomic_helper_plane_destroy_state(plane->state);
 282                kfree(ipu_state);
 283                plane->state = NULL;
 284        }
 285
 286        ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
 287
 288        if (ipu_state) {
 289                __drm_atomic_helper_plane_reset(plane, &ipu_state->base);
 290                ipu_state->base.zpos = zpos;
 291                ipu_state->base.normalized_zpos = zpos;
 292        }
 293}
 294
 295static struct drm_plane_state *
 296ipu_plane_duplicate_state(struct drm_plane *plane)
 297{
 298        struct ipu_plane_state *state;
 299
 300        if (WARN_ON(!plane->state))
 301                return NULL;
 302
 303        state = kmalloc(sizeof(*state), GFP_KERNEL);
 304        if (state)
 305                __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
 306
 307        return &state->base;
 308}
 309
 310static void ipu_plane_destroy_state(struct drm_plane *plane,
 311                                    struct drm_plane_state *state)
 312{
 313        struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
 314
 315        __drm_atomic_helper_plane_destroy_state(state);
 316        kfree(ipu_state);
 317}
 318
 319static bool ipu_plane_format_mod_supported(struct drm_plane *plane,
 320                                           uint32_t format, uint64_t modifier)
 321{
 322        struct ipu_soc *ipu = to_ipu_plane(plane)->ipu;
 323
 324        /* linear is supported for all planes and formats */
 325        if (modifier == DRM_FORMAT_MOD_LINEAR)
 326                return true;
 327
 328        /* without a PRG there are no supported modifiers */
 329        if (!ipu_prg_present(ipu))
 330                return false;
 331
 332        return ipu_prg_format_supported(ipu, format, modifier);
 333}
 334
 335static const struct drm_plane_funcs ipu_plane_funcs = {
 336        .update_plane   = drm_atomic_helper_update_plane,
 337        .disable_plane  = drm_atomic_helper_disable_plane,
 338        .destroy        = ipu_plane_destroy,
 339        .reset          = ipu_plane_state_reset,
 340        .atomic_duplicate_state = ipu_plane_duplicate_state,
 341        .atomic_destroy_state   = ipu_plane_destroy_state,
 342        .format_mod_supported = ipu_plane_format_mod_supported,
 343};
 344
 345static int ipu_plane_atomic_check(struct drm_plane *plane,
 346                                  struct drm_plane_state *state)
 347{
 348        struct drm_plane_state *old_state = plane->state;
 349        struct drm_crtc_state *crtc_state;
 350        struct device *dev = plane->dev->dev;
 351        struct drm_framebuffer *fb = state->fb;
 352        struct drm_framebuffer *old_fb = old_state->fb;
 353        unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
 354        bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
 355        int ret;
 356
 357        /* Ok to disable */
 358        if (!fb)
 359                return 0;
 360
 361        if (!state->crtc)
 362                return -EINVAL;
 363
 364        crtc_state =
 365                drm_atomic_get_existing_crtc_state(state->state, state->crtc);
 366        if (WARN_ON(!crtc_state))
 367                return -EINVAL;
 368
 369        ret = drm_atomic_helper_check_plane_state(state, crtc_state,
 370                                                  DRM_PLANE_HELPER_NO_SCALING,
 371                                                  DRM_PLANE_HELPER_NO_SCALING,
 372                                                  can_position, true);
 373        if (ret)
 374                return ret;
 375
 376        /* nothing to check when disabling or disabled */
 377        if (!crtc_state->enable)
 378                return 0;
 379
 380        switch (plane->type) {
 381        case DRM_PLANE_TYPE_PRIMARY:
 382                /* full plane minimum width is 13 pixels */
 383                if (drm_rect_width(&state->dst) < 13)
 384                        return -EINVAL;
 385                break;
 386        case DRM_PLANE_TYPE_OVERLAY:
 387                break;
 388        default:
 389                dev_warn(dev, "Unsupported plane type %d\n", plane->type);
 390                return -EINVAL;
 391        }
 392
 393        if (drm_rect_height(&state->dst) < 2)
 394                return -EINVAL;
 395
 396        /*
 397         * We support resizing active plane or changing its format by
 398         * forcing CRTC mode change in plane's ->atomic_check callback
 399         * and disabling all affected active planes in CRTC's ->atomic_disable
 400         * callback.  The planes will be reenabled in plane's ->atomic_update
 401         * callback.
 402         */
 403        if (old_fb &&
 404            (drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) ||
 405             drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) ||
 406             fb->format != old_fb->format))
 407                crtc_state->mode_changed = true;
 408
 409        eba = drm_plane_state_to_eba(state, 0);
 410
 411        if (eba & 0x7)
 412                return -EINVAL;
 413
 414        if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
 415                return -EINVAL;
 416
 417        if (old_fb && fb->pitches[0] != old_fb->pitches[0])
 418                crtc_state->mode_changed = true;
 419
 420        switch (fb->format->format) {
 421        case DRM_FORMAT_YUV420:
 422        case DRM_FORMAT_YVU420:
 423        case DRM_FORMAT_YUV422:
 424        case DRM_FORMAT_YVU422:
 425        case DRM_FORMAT_YUV444:
 426        case DRM_FORMAT_YVU444:
 427                /*
 428                 * Multiplanar formats have to meet the following restrictions:
 429                 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
 430                 * - EBA, UBO and VBO are a multiple of 8
 431                 * - UBO and VBO are unsigned and not larger than 0xfffff8
 432                 * - Only EBA may be changed while scanout is active
 433                 * - The strides of U and V planes must be identical.
 434                 */
 435                vbo = drm_plane_state_to_vbo(state);
 436
 437                if (vbo & 0x7 || vbo > 0xfffff8)
 438                        return -EINVAL;
 439
 440                if (old_fb && (fb->format == old_fb->format)) {
 441                        old_vbo = drm_plane_state_to_vbo(old_state);
 442                        if (vbo != old_vbo)
 443                                crtc_state->mode_changed = true;
 444                }
 445
 446                if (fb->pitches[1] != fb->pitches[2])
 447                        return -EINVAL;
 448
 449                /* fall-through */
 450        case DRM_FORMAT_NV12:
 451        case DRM_FORMAT_NV16:
 452                ubo = drm_plane_state_to_ubo(state);
 453
 454                if (ubo & 0x7 || ubo > 0xfffff8)
 455                        return -EINVAL;
 456
 457                if (old_fb && (fb->format == old_fb->format)) {
 458                        old_ubo = drm_plane_state_to_ubo(old_state);
 459                        if (ubo != old_ubo)
 460                                crtc_state->mode_changed = true;
 461                }
 462
 463                if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
 464                        return -EINVAL;
 465
 466                if (old_fb && old_fb->pitches[1] != fb->pitches[1])
 467                        crtc_state->mode_changed = true;
 468
 469                /*
 470                 * The x/y offsets must be even in case of horizontal/vertical
 471                 * chroma subsampling.
 472                 */
 473                if (((state->src.x1 >> 16) & (fb->format->hsub - 1)) ||
 474                    ((state->src.y1 >> 16) & (fb->format->vsub - 1)))
 475                        return -EINVAL;
 476                break;
 477        case DRM_FORMAT_RGB565_A8:
 478        case DRM_FORMAT_BGR565_A8:
 479        case DRM_FORMAT_RGB888_A8:
 480        case DRM_FORMAT_BGR888_A8:
 481        case DRM_FORMAT_RGBX8888_A8:
 482        case DRM_FORMAT_BGRX8888_A8:
 483                alpha_eba = drm_plane_state_to_eba(state, 1);
 484                if (alpha_eba & 0x7)
 485                        return -EINVAL;
 486
 487                if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
 488                        return -EINVAL;
 489
 490                if (old_fb && old_fb->pitches[1] != fb->pitches[1])
 491                        crtc_state->mode_changed = true;
 492                break;
 493        }
 494
 495        return 0;
 496}
 497
 498static void ipu_plane_atomic_disable(struct drm_plane *plane,
 499                                     struct drm_plane_state *old_state)
 500{
 501        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 502
 503        if (ipu_plane->dp)
 504                ipu_dp_disable_channel(ipu_plane->dp, true);
 505        ipu_plane->disabling = true;
 506}
 507
 508static int ipu_chan_assign_axi_id(int ipu_chan)
 509{
 510        switch (ipu_chan) {
 511        case IPUV3_CHANNEL_MEM_BG_SYNC:
 512                return 1;
 513        case IPUV3_CHANNEL_MEM_FG_SYNC:
 514                return 2;
 515        case IPUV3_CHANNEL_MEM_DC_SYNC:
 516                return 3;
 517        default:
 518                return 0;
 519        }
 520}
 521
 522static void ipu_calculate_bursts(u32 width, u32 cpp, u32 stride,
 523                                 u8 *burstsize, u8 *num_bursts)
 524{
 525        const unsigned int width_bytes = width * cpp;
 526        unsigned int npb, bursts;
 527
 528        /* Maximum number of pixels per burst without overshooting stride */
 529        for (npb = 64 / cpp; npb > 0; --npb) {
 530                if (round_up(width_bytes, npb * cpp) <= stride)
 531                        break;
 532        }
 533        *burstsize = npb;
 534
 535        /* Maximum number of consecutive bursts without overshooting stride */
 536        for (bursts = 8; bursts > 1; bursts /= 2) {
 537                if (round_up(width_bytes, npb * cpp * bursts) <= stride)
 538                        break;
 539        }
 540        *num_bursts = bursts;
 541}
 542
 543static void ipu_plane_atomic_update(struct drm_plane *plane,
 544                                    struct drm_plane_state *old_state)
 545{
 546        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 547        struct drm_plane_state *state = plane->state;
 548        struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
 549        struct drm_crtc_state *crtc_state = state->crtc->state;
 550        struct drm_framebuffer *fb = state->fb;
 551        struct drm_rect *dst = &state->dst;
 552        unsigned long eba, ubo, vbo;
 553        unsigned long alpha_eba = 0;
 554        enum ipu_color_space ics;
 555        unsigned int axi_id = 0;
 556        const struct drm_format_info *info;
 557        u8 burstsize, num_bursts;
 558        u32 width, height;
 559        int active;
 560
 561        if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
 562                ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);
 563
 564        switch (ipu_plane->dp_flow) {
 565        case IPU_DP_FLOW_SYNC_BG:
 566                if (state->normalized_zpos == 1) {
 567                        ipu_dp_set_global_alpha(ipu_plane->dp,
 568                                                !fb->format->has_alpha, 0xff,
 569                                                true);
 570                } else {
 571                        ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
 572                }
 573                break;
 574        case IPU_DP_FLOW_SYNC_FG:
 575                if (state->normalized_zpos == 1) {
 576                        ipu_dp_set_global_alpha(ipu_plane->dp,
 577                                                !fb->format->has_alpha, 0xff,
 578                                                false);
 579                }
 580                break;
 581        }
 582
 583        eba = drm_plane_state_to_eba(state, 0);
 584
 585        /*
 586         * Configure PRG channel and attached PRE, this changes the EBA to an
 587         * internal SRAM location.
 588         */
 589        if (ipu_state->use_pre) {
 590                axi_id = ipu_chan_assign_axi_id(ipu_plane->dma);
 591                ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
 592                                          drm_rect_width(&state->src) >> 16,
 593                                          drm_rect_height(&state->src) >> 16,
 594                                          fb->pitches[0], fb->format->format,
 595                                          fb->modifier, &eba);
 596        }
 597
 598        if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
 599                /* nothing to do if PRE is used */
 600                if (ipu_state->use_pre)
 601                        return;
 602                active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
 603                ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
 604                ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
 605                if (ipu_plane_separate_alpha(ipu_plane)) {
 606                        active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
 607                        ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
 608                                             alpha_eba);
 609                        ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
 610                }
 611                return;
 612        }
 613
 614        ics = ipu_drm_fourcc_to_colorspace(fb->format->format);
 615        switch (ipu_plane->dp_flow) {
 616        case IPU_DP_FLOW_SYNC_BG:
 617                ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB);
 618                break;
 619        case IPU_DP_FLOW_SYNC_FG:
 620                ipu_dp_setup_channel(ipu_plane->dp, ics,
 621                                        IPUV3_COLORSPACE_UNKNOWN);
 622                break;
 623        }
 624
 625        ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
 626
 627        width = drm_rect_width(&state->src) >> 16;
 628        height = drm_rect_height(&state->src) >> 16;
 629        info = drm_format_info(fb->format->format);
 630        ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0],
 631                             &burstsize, &num_bursts);
 632
 633        ipu_cpmem_zero(ipu_plane->ipu_ch);
 634        ipu_cpmem_set_resolution(ipu_plane->ipu_ch, width, height);
 635        ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->format->format);
 636        ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, burstsize);
 637        ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
 638        ipu_idmac_enable_watermark(ipu_plane->ipu_ch, true);
 639        ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
 640        ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
 641        ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id);
 642
 643        switch (fb->format->format) {
 644        case DRM_FORMAT_YUV420:
 645        case DRM_FORMAT_YVU420:
 646        case DRM_FORMAT_YUV422:
 647        case DRM_FORMAT_YVU422:
 648        case DRM_FORMAT_YUV444:
 649        case DRM_FORMAT_YVU444:
 650                ubo = drm_plane_state_to_ubo(state);
 651                vbo = drm_plane_state_to_vbo(state);
 652                if (fb->format->format == DRM_FORMAT_YVU420 ||
 653                    fb->format->format == DRM_FORMAT_YVU422 ||
 654                    fb->format->format == DRM_FORMAT_YVU444)
 655                        swap(ubo, vbo);
 656
 657                ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
 658                                              fb->pitches[1], ubo, vbo);
 659
 660                dev_dbg(ipu_plane->base.dev->dev,
 661                        "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
 662                        state->src.x1 >> 16, state->src.y1 >> 16);
 663                break;
 664        case DRM_FORMAT_NV12:
 665        case DRM_FORMAT_NV16:
 666                ubo = drm_plane_state_to_ubo(state);
 667
 668                ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
 669                                              fb->pitches[1], ubo, ubo);
 670
 671                dev_dbg(ipu_plane->base.dev->dev,
 672                        "phy = %lu %lu, x = %d, y = %d", eba, ubo,
 673                        state->src.x1 >> 16, state->src.y1 >> 16);
 674                break;
 675        case DRM_FORMAT_RGB565_A8:
 676        case DRM_FORMAT_BGR565_A8:
 677        case DRM_FORMAT_RGB888_A8:
 678        case DRM_FORMAT_BGR888_A8:
 679        case DRM_FORMAT_RGBX8888_A8:
 680        case DRM_FORMAT_BGRX8888_A8:
 681                alpha_eba = drm_plane_state_to_eba(state, 1);
 682                num_bursts = 0;
 683
 684                dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d",
 685                        eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16);
 686
 687                ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
 688
 689                ipu_cpmem_zero(ipu_plane->alpha_ch);
 690                ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
 691                                         drm_rect_width(&state->src) >> 16,
 692                                         drm_rect_height(&state->src) >> 16);
 693                ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
 694                ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
 695                ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
 696                ipu_cpmem_set_stride(ipu_plane->alpha_ch, fb->pitches[1]);
 697                ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
 698                ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
 699                ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
 700                break;
 701        default:
 702                dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
 703                        eba, state->src.x1 >> 16, state->src.y1 >> 16);
 704                break;
 705        }
 706        ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
 707        ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
 708        ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts);
 709        ipu_plane_enable(ipu_plane);
 710}
 711
 712static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
 713        .prepare_fb = drm_gem_fb_prepare_fb,
 714        .atomic_check = ipu_plane_atomic_check,
 715        .atomic_disable = ipu_plane_atomic_disable,
 716        .atomic_update = ipu_plane_atomic_update,
 717};
 718
 719bool ipu_plane_atomic_update_pending(struct drm_plane *plane)
 720{
 721        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 722        struct drm_plane_state *state = plane->state;
 723        struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
 724
 725        /* disabled crtcs must not block the update */
 726        if (!state->crtc)
 727                return false;
 728
 729        if (ipu_state->use_pre)
 730                return ipu_prg_channel_configure_pending(ipu_plane->ipu_ch);
 731
 732        /*
 733         * Pretend no update is pending in the non-PRE/PRG case. For this to
 734         * happen, an atomic update would have to be deferred until after the
 735         * start of the next frame and simultaneously interrupt latency would
 736         * have to be high enough to let the atomic update finish and issue an
 737         * event before the previous end of frame interrupt handler can be
 738         * executed.
 739         */
 740        return false;
 741}
 742int ipu_planes_assign_pre(struct drm_device *dev,
 743                          struct drm_atomic_state *state)
 744{
 745        struct drm_crtc_state *old_crtc_state, *crtc_state;
 746        struct drm_plane_state *plane_state;
 747        struct ipu_plane_state *ipu_state;
 748        struct ipu_plane *ipu_plane;
 749        struct drm_plane *plane;
 750        struct drm_crtc *crtc;
 751        int available_pres = ipu_prg_max_active_channels();
 752        int ret, i;
 753
 754        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) {
 755                ret = drm_atomic_add_affected_planes(state, crtc);
 756                if (ret)
 757                        return ret;
 758        }
 759
 760        /*
 761         * We are going over the planes in 2 passes: first we assign PREs to
 762         * planes with a tiling modifier, which need the PREs to resolve into
 763         * linear. Any failure to assign a PRE there is fatal. In the second
 764         * pass we try to assign PREs to linear FBs, to improve memory access
 765         * patterns for them. Failure at this point is non-fatal, as we can
 766         * scan out linear FBs without a PRE.
 767         */
 768        for_each_new_plane_in_state(state, plane, plane_state, i) {
 769                ipu_state = to_ipu_plane_state(plane_state);
 770                ipu_plane = to_ipu_plane(plane);
 771
 772                if (!plane_state->fb) {
 773                        ipu_state->use_pre = false;
 774                        continue;
 775                }
 776
 777                if (!(plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) ||
 778                    plane_state->fb->modifier == DRM_FORMAT_MOD_LINEAR)
 779                        continue;
 780
 781                if (!ipu_prg_present(ipu_plane->ipu) || !available_pres)
 782                        return -EINVAL;
 783
 784                if (!ipu_prg_format_supported(ipu_plane->ipu,
 785                                              plane_state->fb->format->format,
 786                                              plane_state->fb->modifier))
 787                        return -EINVAL;
 788
 789                ipu_state->use_pre = true;
 790                available_pres--;
 791        }
 792
 793        for_each_new_plane_in_state(state, plane, plane_state, i) {
 794                ipu_state = to_ipu_plane_state(plane_state);
 795                ipu_plane = to_ipu_plane(plane);
 796
 797                if (!plane_state->fb) {
 798                        ipu_state->use_pre = false;
 799                        continue;
 800                }
 801
 802                if ((plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) &&
 803                    plane_state->fb->modifier != DRM_FORMAT_MOD_LINEAR)
 804                        continue;
 805
 806                /* make sure that modifier is initialized */
 807                plane_state->fb->modifier = DRM_FORMAT_MOD_LINEAR;
 808
 809                if (ipu_prg_present(ipu_plane->ipu) && available_pres &&
 810                    ipu_prg_format_supported(ipu_plane->ipu,
 811                                             plane_state->fb->format->format,
 812                                             plane_state->fb->modifier)) {
 813                        ipu_state->use_pre = true;
 814                        available_pres--;
 815                } else {
 816                        ipu_state->use_pre = false;
 817                }
 818        }
 819
 820        return 0;
 821}
 822EXPORT_SYMBOL_GPL(ipu_planes_assign_pre);
 823
 824struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
 825                                 int dma, int dp, unsigned int possible_crtcs,
 826                                 enum drm_plane_type type)
 827{
 828        struct ipu_plane *ipu_plane;
 829        const uint64_t *modifiers = ipu_format_modifiers;
 830        unsigned int zpos = (type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
 831        int ret;
 832
 833        DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
 834                      dma, dp, possible_crtcs);
 835
 836        ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
 837        if (!ipu_plane) {
 838                DRM_ERROR("failed to allocate plane\n");
 839                return ERR_PTR(-ENOMEM);
 840        }
 841
 842        ipu_plane->ipu = ipu;
 843        ipu_plane->dma = dma;
 844        ipu_plane->dp_flow = dp;
 845
 846        if (ipu_prg_present(ipu))
 847                modifiers = pre_format_modifiers;
 848
 849        ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
 850                                       &ipu_plane_funcs, ipu_plane_formats,
 851                                       ARRAY_SIZE(ipu_plane_formats),
 852                                       modifiers, type, NULL);
 853        if (ret) {
 854                DRM_ERROR("failed to initialize plane\n");
 855                kfree(ipu_plane);
 856                return ERR_PTR(ret);
 857        }
 858
 859        drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
 860
 861        if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG)
 862                drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, 1);
 863        else
 864                drm_plane_create_zpos_immutable_property(&ipu_plane->base, 0);
 865
 866        return ipu_plane;
 867}
 868