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