linux/drivers/gpu/drm/mediatek/mtk_drm_plane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015 MediaTek Inc.
   4 * Author: CK Hu <ck.hu@mediatek.com>
   5 */
   6
   7#include <drm/drm_atomic.h>
   8#include <drm/drm_atomic_helper.h>
   9#include <drm/drm_atomic_uapi.h>
  10#include <drm/drm_fourcc.h>
  11#include <drm/drm_gem_atomic_helper.h>
  12#include <drm/drm_plane_helper.h>
  13
  14#include "mtk_drm_crtc.h"
  15#include "mtk_drm_ddp_comp.h"
  16#include "mtk_drm_drv.h"
  17#include "mtk_drm_gem.h"
  18#include "mtk_drm_plane.h"
  19
  20static const u32 formats[] = {
  21        DRM_FORMAT_XRGB8888,
  22        DRM_FORMAT_ARGB8888,
  23        DRM_FORMAT_BGRX8888,
  24        DRM_FORMAT_BGRA8888,
  25        DRM_FORMAT_ABGR8888,
  26        DRM_FORMAT_XBGR8888,
  27        DRM_FORMAT_RGB888,
  28        DRM_FORMAT_BGR888,
  29        DRM_FORMAT_RGB565,
  30        DRM_FORMAT_UYVY,
  31        DRM_FORMAT_YUYV,
  32};
  33
  34static void mtk_plane_reset(struct drm_plane *plane)
  35{
  36        struct mtk_plane_state *state;
  37
  38        if (plane->state) {
  39                __drm_atomic_helper_plane_destroy_state(plane->state);
  40
  41                state = to_mtk_plane_state(plane->state);
  42                memset(state, 0, sizeof(*state));
  43        } else {
  44                state = kzalloc(sizeof(*state), GFP_KERNEL);
  45                if (!state)
  46                        return;
  47                plane->state = &state->base;
  48        }
  49
  50        state->base.plane = plane;
  51        state->pending.format = DRM_FORMAT_RGB565;
  52}
  53
  54static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
  55{
  56        struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
  57        struct mtk_plane_state *state;
  58
  59        state = kzalloc(sizeof(*state), GFP_KERNEL);
  60        if (!state)
  61                return NULL;
  62
  63        __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
  64
  65        WARN_ON(state->base.plane != plane);
  66
  67        state->pending = old_state->pending;
  68
  69        return &state->base;
  70}
  71
  72static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
  73                                        struct drm_plane_state *state)
  74{
  75        __drm_atomic_helper_plane_destroy_state(state);
  76        kfree(to_mtk_plane_state(state));
  77}
  78
  79static int mtk_plane_atomic_async_check(struct drm_plane *plane,
  80                                        struct drm_atomic_state *state)
  81{
  82        struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
  83                                                                                 plane);
  84        struct drm_crtc_state *crtc_state;
  85        int ret;
  86
  87        if (plane != new_plane_state->crtc->cursor)
  88                return -EINVAL;
  89
  90        if (!plane->state)
  91                return -EINVAL;
  92
  93        if (!plane->state->fb)
  94                return -EINVAL;
  95
  96        ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane,
  97                                       to_mtk_plane_state(new_plane_state));
  98        if (ret)
  99                return ret;
 100
 101        if (state)
 102                crtc_state = drm_atomic_get_existing_crtc_state(state,
 103                                                                new_plane_state->crtc);
 104        else /* Special case for asynchronous cursor updates. */
 105                crtc_state = new_plane_state->crtc->state;
 106
 107        return drm_atomic_helper_check_plane_state(plane->state, crtc_state,
 108                                                   DRM_PLANE_HELPER_NO_SCALING,
 109                                                   DRM_PLANE_HELPER_NO_SCALING,
 110                                                   true, true);
 111}
 112
 113static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
 114                                       struct mtk_plane_state *mtk_plane_state)
 115{
 116        struct drm_framebuffer *fb = new_state->fb;
 117        struct drm_gem_object *gem;
 118        struct mtk_drm_gem_obj *mtk_gem;
 119        unsigned int pitch, format;
 120        dma_addr_t addr;
 121
 122        gem = fb->obj[0];
 123        mtk_gem = to_mtk_gem_obj(gem);
 124        addr = mtk_gem->dma_addr;
 125        pitch = fb->pitches[0];
 126        format = fb->format->format;
 127
 128        addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
 129        addr += (new_state->src.y1 >> 16) * pitch;
 130
 131        mtk_plane_state->pending.enable = true;
 132        mtk_plane_state->pending.pitch = pitch;
 133        mtk_plane_state->pending.format = format;
 134        mtk_plane_state->pending.addr = addr;
 135        mtk_plane_state->pending.x = new_state->dst.x1;
 136        mtk_plane_state->pending.y = new_state->dst.y1;
 137        mtk_plane_state->pending.width = drm_rect_width(&new_state->dst);
 138        mtk_plane_state->pending.height = drm_rect_height(&new_state->dst);
 139        mtk_plane_state->pending.rotation = new_state->rotation;
 140}
 141
 142static void mtk_plane_atomic_async_update(struct drm_plane *plane,
 143                                          struct drm_atomic_state *state)
 144{
 145        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
 146                                                                           plane);
 147        struct mtk_plane_state *new_plane_state = to_mtk_plane_state(plane->state);
 148
 149        plane->state->crtc_x = new_state->crtc_x;
 150        plane->state->crtc_y = new_state->crtc_y;
 151        plane->state->crtc_h = new_state->crtc_h;
 152        plane->state->crtc_w = new_state->crtc_w;
 153        plane->state->src_x = new_state->src_x;
 154        plane->state->src_y = new_state->src_y;
 155        plane->state->src_h = new_state->src_h;
 156        plane->state->src_w = new_state->src_w;
 157        swap(plane->state->fb, new_state->fb);
 158
 159        mtk_plane_update_new_state(new_state, new_plane_state);
 160        wmb(); /* Make sure the above parameters are set before update */
 161        new_plane_state->pending.async_dirty = true;
 162        mtk_drm_crtc_async_update(new_state->crtc, plane, state);
 163}
 164
 165static const struct drm_plane_funcs mtk_plane_funcs = {
 166        .update_plane = drm_atomic_helper_update_plane,
 167        .disable_plane = drm_atomic_helper_disable_plane,
 168        .destroy = drm_plane_cleanup,
 169        .reset = mtk_plane_reset,
 170        .atomic_duplicate_state = mtk_plane_duplicate_state,
 171        .atomic_destroy_state = mtk_drm_plane_destroy_state,
 172};
 173
 174static int mtk_plane_atomic_check(struct drm_plane *plane,
 175                                  struct drm_atomic_state *state)
 176{
 177        struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
 178                                                                                 plane);
 179        struct drm_framebuffer *fb = new_plane_state->fb;
 180        struct drm_crtc_state *crtc_state;
 181        int ret;
 182
 183        if (!fb)
 184                return 0;
 185
 186        if (WARN_ON(!new_plane_state->crtc))
 187                return 0;
 188
 189        ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane,
 190                                       to_mtk_plane_state(new_plane_state));
 191        if (ret)
 192                return ret;
 193
 194        crtc_state = drm_atomic_get_crtc_state(state,
 195                                               new_plane_state->crtc);
 196        if (IS_ERR(crtc_state))
 197                return PTR_ERR(crtc_state);
 198
 199        return drm_atomic_helper_check_plane_state(new_plane_state,
 200                                                   crtc_state,
 201                                                   DRM_PLANE_HELPER_NO_SCALING,
 202                                                   DRM_PLANE_HELPER_NO_SCALING,
 203                                                   true, true);
 204}
 205
 206static void mtk_plane_atomic_disable(struct drm_plane *plane,
 207                                     struct drm_atomic_state *state)
 208{
 209        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
 210                                                                           plane);
 211        struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
 212        mtk_plane_state->pending.enable = false;
 213        wmb(); /* Make sure the above parameter is set before update */
 214        mtk_plane_state->pending.dirty = true;
 215}
 216
 217static void mtk_plane_atomic_update(struct drm_plane *plane,
 218                                    struct drm_atomic_state *state)
 219{
 220        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
 221                                                                           plane);
 222        struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
 223
 224        if (!new_state->crtc || WARN_ON(!new_state->fb))
 225                return;
 226
 227        if (!new_state->visible) {
 228                mtk_plane_atomic_disable(plane, state);
 229                return;
 230        }
 231
 232        mtk_plane_update_new_state(new_state, mtk_plane_state);
 233        wmb(); /* Make sure the above parameters are set before update */
 234        mtk_plane_state->pending.dirty = true;
 235}
 236
 237static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
 238        .atomic_check = mtk_plane_atomic_check,
 239        .atomic_update = mtk_plane_atomic_update,
 240        .atomic_disable = mtk_plane_atomic_disable,
 241        .atomic_async_update = mtk_plane_atomic_async_update,
 242        .atomic_async_check = mtk_plane_atomic_async_check,
 243};
 244
 245int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
 246                   unsigned long possible_crtcs, enum drm_plane_type type,
 247                   unsigned int supported_rotations)
 248{
 249        int err;
 250
 251        err = drm_universal_plane_init(dev, plane, possible_crtcs,
 252                                       &mtk_plane_funcs, formats,
 253                                       ARRAY_SIZE(formats), NULL, type, NULL);
 254        if (err) {
 255                DRM_ERROR("failed to initialize plane\n");
 256                return err;
 257        }
 258
 259        if (supported_rotations & ~DRM_MODE_ROTATE_0) {
 260                err = drm_plane_create_rotation_property(plane,
 261                                                         DRM_MODE_ROTATE_0,
 262                                                         supported_rotations);
 263                if (err)
 264                        DRM_INFO("Create rotation property failed\n");
 265        }
 266
 267        drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
 268
 269        return 0;
 270}
 271