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