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