linux/drivers/gpu/drm/shmobile/shmob_drm_plane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * shmob_drm_plane.c  --  SH Mobile DRM Planes
   4 *
   5 * Copyright (C) 2012 Renesas Electronics Corporation
   6 *
   7 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   8 */
   9
  10#include <drm/drm_crtc.h>
  11#include <drm/drm_crtc_helper.h>
  12#include <drm/drm_fb_cma_helper.h>
  13#include <drm/drm_fourcc.h>
  14#include <drm/drm_gem_cma_helper.h>
  15
  16#include "shmob_drm_drv.h"
  17#include "shmob_drm_kms.h"
  18#include "shmob_drm_plane.h"
  19#include "shmob_drm_regs.h"
  20
  21struct shmob_drm_plane {
  22        struct drm_plane plane;
  23        unsigned int index;
  24        unsigned int alpha;
  25
  26        const struct shmob_drm_format_info *format;
  27        unsigned long dma[2];
  28
  29        unsigned int src_x;
  30        unsigned int src_y;
  31        unsigned int crtc_x;
  32        unsigned int crtc_y;
  33        unsigned int crtc_w;
  34        unsigned int crtc_h;
  35};
  36
  37#define to_shmob_plane(p)       container_of(p, struct shmob_drm_plane, plane)
  38
  39static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane,
  40                                         struct drm_framebuffer *fb,
  41                                         int x, int y)
  42{
  43        struct drm_gem_cma_object *gem;
  44        unsigned int bpp;
  45
  46        bpp = splane->format->yuv ? 8 : splane->format->bpp;
  47        gem = drm_fb_cma_get_gem_obj(fb, 0);
  48        splane->dma[0] = gem->paddr + fb->offsets[0]
  49                       + y * fb->pitches[0] + x * bpp / 8;
  50
  51        if (splane->format->yuv) {
  52                bpp = splane->format->bpp - 8;
  53                gem = drm_fb_cma_get_gem_obj(fb, 1);
  54                splane->dma[1] = gem->paddr + fb->offsets[1]
  55                               + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
  56                               + x * (bpp == 16 ? 2 : 1);
  57        }
  58}
  59
  60static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane,
  61                                    struct drm_framebuffer *fb)
  62{
  63        struct shmob_drm_device *sdev = splane->plane.dev->dev_private;
  64        u32 format;
  65
  66        /* TODO: Support ROP3 mode */
  67        format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT);
  68
  69        switch (splane->format->fourcc) {
  70        case DRM_FORMAT_RGB565:
  71        case DRM_FORMAT_NV21:
  72        case DRM_FORMAT_NV61:
  73        case DRM_FORMAT_NV42:
  74                format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
  75                break;
  76        case DRM_FORMAT_RGB888:
  77        case DRM_FORMAT_NV12:
  78        case DRM_FORMAT_NV16:
  79        case DRM_FORMAT_NV24:
  80                format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
  81                break;
  82        case DRM_FORMAT_ARGB8888:
  83        default:
  84                format |= LDBBSIFR_SWPL;
  85                break;
  86        }
  87
  88        switch (splane->format->fourcc) {
  89        case DRM_FORMAT_RGB565:
  90                format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
  91                break;
  92        case DRM_FORMAT_RGB888:
  93                format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
  94                break;
  95        case DRM_FORMAT_ARGB8888:
  96                format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
  97                break;
  98        case DRM_FORMAT_NV12:
  99        case DRM_FORMAT_NV21:
 100                format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
 101                break;
 102        case DRM_FORMAT_NV16:
 103        case DRM_FORMAT_NV61:
 104                format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
 105                break;
 106        case DRM_FORMAT_NV24:
 107        case DRM_FORMAT_NV42:
 108                format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
 109                break;
 110        }
 111
 112#define plane_reg_dump(sdev, splane, reg) \
 113        dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
 114                splane->index, #reg, \
 115                lcdc_read(sdev, reg(splane->index)), \
 116                lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
 117
 118        plane_reg_dump(sdev, splane, LDBnBSIFR);
 119        plane_reg_dump(sdev, splane, LDBnBSSZR);
 120        plane_reg_dump(sdev, splane, LDBnBLOCR);
 121        plane_reg_dump(sdev, splane, LDBnBSMWR);
 122        plane_reg_dump(sdev, splane, LDBnBSAYR);
 123        plane_reg_dump(sdev, splane, LDBnBSACR);
 124
 125        lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
 126        dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
 127                "LDBCR", lcdc_read(sdev, LDBCR));
 128
 129        lcdc_write(sdev, LDBnBSIFR(splane->index), format);
 130
 131        lcdc_write(sdev, LDBnBSSZR(splane->index),
 132                   (splane->crtc_h << LDBBSSZR_BVSS_SHIFT) |
 133                   (splane->crtc_w << LDBBSSZR_BHSS_SHIFT));
 134        lcdc_write(sdev, LDBnBLOCR(splane->index),
 135                   (splane->crtc_y << LDBBLOCR_CVLC_SHIFT) |
 136                   (splane->crtc_x << LDBBLOCR_CHLC_SHIFT));
 137        lcdc_write(sdev, LDBnBSMWR(splane->index),
 138                   fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
 139
 140        shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y);
 141
 142        lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]);
 143        if (splane->format->yuv)
 144                lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]);
 145
 146        lcdc_write(sdev, LDBCR,
 147                   LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
 148        dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
 149                "LDBCR", lcdc_read(sdev, LDBCR));
 150
 151        plane_reg_dump(sdev, splane, LDBnBSIFR);
 152        plane_reg_dump(sdev, splane, LDBnBSSZR);
 153        plane_reg_dump(sdev, splane, LDBnBLOCR);
 154        plane_reg_dump(sdev, splane, LDBnBSMWR);
 155        plane_reg_dump(sdev, splane, LDBnBSAYR);
 156        plane_reg_dump(sdev, splane, LDBnBSACR);
 157}
 158
 159void shmob_drm_plane_setup(struct drm_plane *plane)
 160{
 161        struct shmob_drm_plane *splane = to_shmob_plane(plane);
 162
 163        if (plane->fb == NULL)
 164                return;
 165
 166        __shmob_drm_plane_setup(splane, plane->fb);
 167}
 168
 169static int
 170shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 171                       struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 172                       unsigned int crtc_w, unsigned int crtc_h,
 173                       uint32_t src_x, uint32_t src_y,
 174                       uint32_t src_w, uint32_t src_h,
 175                       struct drm_modeset_acquire_ctx *ctx)
 176{
 177        struct shmob_drm_plane *splane = to_shmob_plane(plane);
 178        struct shmob_drm_device *sdev = plane->dev->dev_private;
 179        const struct shmob_drm_format_info *format;
 180
 181        format = shmob_drm_format_info(fb->format->format);
 182        if (format == NULL) {
 183                dev_dbg(sdev->dev, "update_plane: unsupported format %08x\n",
 184                        fb->format->format);
 185                return -EINVAL;
 186        }
 187
 188        if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
 189                dev_dbg(sdev->dev, "%s: scaling not supported\n", __func__);
 190                return -EINVAL;
 191        }
 192
 193        splane->format = format;
 194
 195        splane->src_x = src_x >> 16;
 196        splane->src_y = src_y >> 16;
 197        splane->crtc_x = crtc_x;
 198        splane->crtc_y = crtc_y;
 199        splane->crtc_w = crtc_w;
 200        splane->crtc_h = crtc_h;
 201
 202        __shmob_drm_plane_setup(splane, fb);
 203        return 0;
 204}
 205
 206static int shmob_drm_plane_disable(struct drm_plane *plane,
 207                                   struct drm_modeset_acquire_ctx *ctx)
 208{
 209        struct shmob_drm_plane *splane = to_shmob_plane(plane);
 210        struct shmob_drm_device *sdev = plane->dev->dev_private;
 211
 212        splane->format = NULL;
 213
 214        lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
 215        return 0;
 216}
 217
 218static void shmob_drm_plane_destroy(struct drm_plane *plane)
 219{
 220        drm_plane_force_disable(plane);
 221        drm_plane_cleanup(plane);
 222}
 223
 224static const struct drm_plane_funcs shmob_drm_plane_funcs = {
 225        .update_plane = shmob_drm_plane_update,
 226        .disable_plane = shmob_drm_plane_disable,
 227        .destroy = shmob_drm_plane_destroy,
 228};
 229
 230static const uint32_t formats[] = {
 231        DRM_FORMAT_RGB565,
 232        DRM_FORMAT_RGB888,
 233        DRM_FORMAT_ARGB8888,
 234        DRM_FORMAT_NV12,
 235        DRM_FORMAT_NV21,
 236        DRM_FORMAT_NV16,
 237        DRM_FORMAT_NV61,
 238        DRM_FORMAT_NV24,
 239        DRM_FORMAT_NV42,
 240};
 241
 242int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
 243{
 244        struct shmob_drm_plane *splane;
 245        int ret;
 246
 247        splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL);
 248        if (splane == NULL)
 249                return -ENOMEM;
 250
 251        splane->index = index;
 252        splane->alpha = 255;
 253
 254        ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
 255                             &shmob_drm_plane_funcs, formats,
 256                             ARRAY_SIZE(formats), false);
 257
 258        return ret;
 259}
 260