Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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