Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * shmob_drm_plane.c  --  SH Mobile DRM Planes
0004  *
0005  * Copyright (C) 2012 Renesas Electronics Corporation
0006  *
0007  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
0008  */
0009 
0010 #include <drm/drm_crtc.h>
0011 #include <drm/drm_crtc_helper.h>
0012 #include <drm/drm_fb_cma_helper.h>
0013 #include <drm/drm_fourcc.h>
0014 #include <drm/drm_framebuffer.h>
0015 #include <drm/drm_gem_cma_helper.h>
0016 
0017 #include "shmob_drm_drv.h"
0018 #include "shmob_drm_kms.h"
0019 #include "shmob_drm_plane.h"
0020 #include "shmob_drm_regs.h"
0021 
0022 struct shmob_drm_plane {
0023     struct drm_plane plane;
0024     unsigned int index;
0025     unsigned int alpha;
0026 
0027     const struct shmob_drm_format_info *format;
0028     unsigned long dma[2];
0029 
0030     unsigned int src_x;
0031     unsigned int src_y;
0032     unsigned int crtc_x;
0033     unsigned int crtc_y;
0034     unsigned int crtc_w;
0035     unsigned int crtc_h;
0036 };
0037 
0038 #define to_shmob_plane(p)   container_of(p, struct shmob_drm_plane, plane)
0039 
0040 static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane,
0041                      struct drm_framebuffer *fb,
0042                      int x, int y)
0043 {
0044     struct drm_gem_cma_object *gem;
0045     unsigned int bpp;
0046 
0047     bpp = splane->format->yuv ? 8 : splane->format->bpp;
0048     gem = drm_fb_cma_get_gem_obj(fb, 0);
0049     splane->dma[0] = gem->paddr + fb->offsets[0]
0050                + y * fb->pitches[0] + x * bpp / 8;
0051 
0052     if (splane->format->yuv) {
0053         bpp = splane->format->bpp - 8;
0054         gem = drm_fb_cma_get_gem_obj(fb, 1);
0055         splane->dma[1] = gem->paddr + fb->offsets[1]
0056                    + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
0057                    + x * (bpp == 16 ? 2 : 1);
0058     }
0059 }
0060 
0061 static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane,
0062                     struct drm_framebuffer *fb)
0063 {
0064     struct shmob_drm_device *sdev = splane->plane.dev->dev_private;
0065     u32 format;
0066 
0067     /* TODO: Support ROP3 mode */
0068     format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT);
0069 
0070     switch (splane->format->fourcc) {
0071     case DRM_FORMAT_RGB565:
0072     case DRM_FORMAT_NV21:
0073     case DRM_FORMAT_NV61:
0074     case DRM_FORMAT_NV42:
0075         format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW;
0076         break;
0077     case DRM_FORMAT_RGB888:
0078     case DRM_FORMAT_NV12:
0079     case DRM_FORMAT_NV16:
0080     case DRM_FORMAT_NV24:
0081         format |= LDBBSIFR_SWPL | LDBBSIFR_SWPW | LDBBSIFR_SWPB;
0082         break;
0083     case DRM_FORMAT_ARGB8888:
0084     default:
0085         format |= LDBBSIFR_SWPL;
0086         break;
0087     }
0088 
0089     switch (splane->format->fourcc) {
0090     case DRM_FORMAT_RGB565:
0091         format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB16;
0092         break;
0093     case DRM_FORMAT_RGB888:
0094         format |= LDBBSIFR_AL_1 | LDBBSIFR_RY | LDBBSIFR_RPKF_RGB24;
0095         break;
0096     case DRM_FORMAT_ARGB8888:
0097         format |= LDBBSIFR_AL_PK | LDBBSIFR_RY | LDDFR_PKF_ARGB32;
0098         break;
0099     case DRM_FORMAT_NV12:
0100     case DRM_FORMAT_NV21:
0101         format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_420;
0102         break;
0103     case DRM_FORMAT_NV16:
0104     case DRM_FORMAT_NV61:
0105         format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_422;
0106         break;
0107     case DRM_FORMAT_NV24:
0108     case DRM_FORMAT_NV42:
0109         format |= LDBBSIFR_AL_1 | LDBBSIFR_CHRR_444;
0110         break;
0111     }
0112 
0113 #define plane_reg_dump(sdev, splane, reg) \
0114     dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
0115         splane->index, #reg, \
0116         lcdc_read(sdev, reg(splane->index)), \
0117         lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
0118 
0119     plane_reg_dump(sdev, splane, LDBnBSIFR);
0120     plane_reg_dump(sdev, splane, LDBnBSSZR);
0121     plane_reg_dump(sdev, splane, LDBnBLOCR);
0122     plane_reg_dump(sdev, splane, LDBnBSMWR);
0123     plane_reg_dump(sdev, splane, LDBnBSAYR);
0124     plane_reg_dump(sdev, splane, LDBnBSACR);
0125 
0126     lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
0127     dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
0128         "LDBCR", lcdc_read(sdev, LDBCR));
0129 
0130     lcdc_write(sdev, LDBnBSIFR(splane->index), format);
0131 
0132     lcdc_write(sdev, LDBnBSSZR(splane->index),
0133            (splane->crtc_h << LDBBSSZR_BVSS_SHIFT) |
0134            (splane->crtc_w << LDBBSSZR_BHSS_SHIFT));
0135     lcdc_write(sdev, LDBnBLOCR(splane->index),
0136            (splane->crtc_y << LDBBLOCR_CVLC_SHIFT) |
0137            (splane->crtc_x << LDBBLOCR_CHLC_SHIFT));
0138     lcdc_write(sdev, LDBnBSMWR(splane->index),
0139            fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
0140 
0141     shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y);
0142 
0143     lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]);
0144     if (splane->format->yuv)
0145         lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]);
0146 
0147     lcdc_write(sdev, LDBCR,
0148            LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
0149     dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
0150         "LDBCR", lcdc_read(sdev, LDBCR));
0151 
0152     plane_reg_dump(sdev, splane, LDBnBSIFR);
0153     plane_reg_dump(sdev, splane, LDBnBSSZR);
0154     plane_reg_dump(sdev, splane, LDBnBLOCR);
0155     plane_reg_dump(sdev, splane, LDBnBSMWR);
0156     plane_reg_dump(sdev, splane, LDBnBSAYR);
0157     plane_reg_dump(sdev, splane, LDBnBSACR);
0158 }
0159 
0160 void shmob_drm_plane_setup(struct drm_plane *plane)
0161 {
0162     struct shmob_drm_plane *splane = to_shmob_plane(plane);
0163 
0164     if (plane->fb == NULL)
0165         return;
0166 
0167     __shmob_drm_plane_setup(splane, plane->fb);
0168 }
0169 
0170 static int
0171 shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
0172                struct drm_framebuffer *fb, int crtc_x, int crtc_y,
0173                unsigned int crtc_w, unsigned int crtc_h,
0174                uint32_t src_x, uint32_t src_y,
0175                uint32_t src_w, uint32_t src_h,
0176                struct drm_modeset_acquire_ctx *ctx)
0177 {
0178     struct shmob_drm_plane *splane = to_shmob_plane(plane);
0179     struct shmob_drm_device *sdev = plane->dev->dev_private;
0180     const struct shmob_drm_format_info *format;
0181 
0182     format = shmob_drm_format_info(fb->format->format);
0183     if (format == NULL) {
0184         dev_dbg(sdev->dev, "update_plane: unsupported format %08x\n",
0185             fb->format->format);
0186         return -EINVAL;
0187     }
0188 
0189     if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
0190         dev_dbg(sdev->dev, "%s: scaling not supported\n", __func__);
0191         return -EINVAL;
0192     }
0193 
0194     splane->format = format;
0195 
0196     splane->src_x = src_x >> 16;
0197     splane->src_y = src_y >> 16;
0198     splane->crtc_x = crtc_x;
0199     splane->crtc_y = crtc_y;
0200     splane->crtc_w = crtc_w;
0201     splane->crtc_h = crtc_h;
0202 
0203     __shmob_drm_plane_setup(splane, fb);
0204     return 0;
0205 }
0206 
0207 static int shmob_drm_plane_disable(struct drm_plane *plane,
0208                    struct drm_modeset_acquire_ctx *ctx)
0209 {
0210     struct shmob_drm_plane *splane = to_shmob_plane(plane);
0211     struct shmob_drm_device *sdev = plane->dev->dev_private;
0212 
0213     splane->format = NULL;
0214 
0215     lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
0216     return 0;
0217 }
0218 
0219 static void shmob_drm_plane_destroy(struct drm_plane *plane)
0220 {
0221     drm_plane_force_disable(plane);
0222     drm_plane_cleanup(plane);
0223 }
0224 
0225 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
0226     .update_plane = shmob_drm_plane_update,
0227     .disable_plane = shmob_drm_plane_disable,
0228     .destroy = shmob_drm_plane_destroy,
0229 };
0230 
0231 static const uint32_t formats[] = {
0232     DRM_FORMAT_RGB565,
0233     DRM_FORMAT_RGB888,
0234     DRM_FORMAT_ARGB8888,
0235     DRM_FORMAT_NV12,
0236     DRM_FORMAT_NV21,
0237     DRM_FORMAT_NV16,
0238     DRM_FORMAT_NV61,
0239     DRM_FORMAT_NV24,
0240     DRM_FORMAT_NV42,
0241 };
0242 
0243 int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
0244 {
0245     struct shmob_drm_plane *splane;
0246     int ret;
0247 
0248     splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL);
0249     if (splane == NULL)
0250         return -ENOMEM;
0251 
0252     splane->index = index;
0253     splane->alpha = 255;
0254 
0255     ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
0256                  &shmob_drm_plane_funcs, formats,
0257                  ARRAY_SIZE(formats), false);
0258 
0259     return ret;
0260 }