xref: /linux/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c (revision 02e6c5b76f0eb6d85cebb7603c342809c3c6b14a)
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_fb_dma_helper.h>
12 #include <drm/drm_fourcc.h>
13 #include <drm/drm_framebuffer.h>
14 #include <drm/drm_gem_dma_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 
21 struct 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 static inline struct shmob_drm_plane *to_shmob_plane(struct drm_plane *plane)
38 {
39 	return container_of(plane, struct shmob_drm_plane, plane);
40 }
41 
42 static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane,
43 					 struct drm_framebuffer *fb,
44 					 int x, int y)
45 {
46 	struct drm_gem_dma_object *gem;
47 	unsigned int bpp;
48 
49 	bpp = shmob_drm_format_is_yuv(splane->format) ? 8 : splane->format->bpp;
50 	gem = drm_fb_dma_get_gem_obj(fb, 0);
51 	splane->dma[0] = gem->dma_addr + fb->offsets[0]
52 		       + y * fb->pitches[0] + x * bpp / 8;
53 
54 	if (shmob_drm_format_is_yuv(splane->format)) {
55 		bpp = splane->format->bpp - 8;
56 		gem = drm_fb_dma_get_gem_obj(fb, 1);
57 		splane->dma[1] = gem->dma_addr + fb->offsets[1]
58 			       + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
59 			       + x * (bpp == 16 ? 2 : 1);
60 	}
61 }
62 
63 static void __shmob_drm_plane_setup(struct shmob_drm_plane *splane,
64 				    struct drm_framebuffer *fb)
65 {
66 	struct shmob_drm_device *sdev = splane->plane.dev->dev_private;
67 	u32 format;
68 
69 	/* TODO: Support ROP3 mode */
70 	format = LDBBSIFR_EN | (splane->alpha << LDBBSIFR_LAY_SHIFT) |
71 		 splane->format->ldbbsifr;
72 
73 #define plane_reg_dump(sdev, splane, reg) \
74 	dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
75 		splane->index, #reg, \
76 		lcdc_read(sdev, reg(splane->index)), \
77 		lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
78 
79 	plane_reg_dump(sdev, splane, LDBnBSIFR);
80 	plane_reg_dump(sdev, splane, LDBnBSSZR);
81 	plane_reg_dump(sdev, splane, LDBnBLOCR);
82 	plane_reg_dump(sdev, splane, LDBnBSMWR);
83 	plane_reg_dump(sdev, splane, LDBnBSAYR);
84 	plane_reg_dump(sdev, splane, LDBnBSACR);
85 
86 	lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
87 	dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
88 		"LDBCR", lcdc_read(sdev, LDBCR));
89 
90 	lcdc_write(sdev, LDBnBSIFR(splane->index), format);
91 
92 	lcdc_write(sdev, LDBnBSSZR(splane->index),
93 		   (splane->crtc_h << LDBBSSZR_BVSS_SHIFT) |
94 		   (splane->crtc_w << LDBBSSZR_BHSS_SHIFT));
95 	lcdc_write(sdev, LDBnBLOCR(splane->index),
96 		   (splane->crtc_y << LDBBLOCR_CVLC_SHIFT) |
97 		   (splane->crtc_x << LDBBLOCR_CHLC_SHIFT));
98 	lcdc_write(sdev, LDBnBSMWR(splane->index),
99 		   fb->pitches[0] << LDBBSMWR_BSMW_SHIFT);
100 
101 	shmob_drm_plane_compute_base(splane, fb, splane->src_x, splane->src_y);
102 
103 	lcdc_write(sdev, LDBnBSAYR(splane->index), splane->dma[0]);
104 	if (shmob_drm_format_is_yuv(splane->format))
105 		lcdc_write(sdev, LDBnBSACR(splane->index), splane->dma[1]);
106 
107 	lcdc_write(sdev, LDBCR,
108 		   LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
109 	dev_dbg(sdev->ddev.dev, "%s(%u): %s 0x%08x\n", __func__, splane->index,
110 		"LDBCR", lcdc_read(sdev, LDBCR));
111 
112 	plane_reg_dump(sdev, splane, LDBnBSIFR);
113 	plane_reg_dump(sdev, splane, LDBnBSSZR);
114 	plane_reg_dump(sdev, splane, LDBnBLOCR);
115 	plane_reg_dump(sdev, splane, LDBnBSMWR);
116 	plane_reg_dump(sdev, splane, LDBnBSAYR);
117 	plane_reg_dump(sdev, splane, LDBnBSACR);
118 }
119 
120 void shmob_drm_plane_setup(struct drm_plane *plane)
121 {
122 	struct shmob_drm_plane *splane = to_shmob_plane(plane);
123 
124 	if (plane->fb == NULL)
125 		return;
126 
127 	__shmob_drm_plane_setup(splane, plane->fb);
128 }
129 
130 static int
131 shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
132 		       struct drm_framebuffer *fb, int crtc_x, int crtc_y,
133 		       unsigned int crtc_w, unsigned int crtc_h,
134 		       uint32_t src_x, uint32_t src_y,
135 		       uint32_t src_w, uint32_t src_h,
136 		       struct drm_modeset_acquire_ctx *ctx)
137 {
138 	struct shmob_drm_plane *splane = to_shmob_plane(plane);
139 	struct shmob_drm_device *sdev = plane->dev->dev_private;
140 	const struct shmob_drm_format_info *format;
141 
142 	format = shmob_drm_format_info(fb->format->format);
143 	if (format == NULL) {
144 		dev_dbg(sdev->dev, "update_plane: unsupported format %p4cc\n",
145 			&fb->format->format);
146 		return -EINVAL;
147 	}
148 
149 	if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
150 		dev_dbg(sdev->dev, "%s: scaling not supported\n", __func__);
151 		return -EINVAL;
152 	}
153 
154 	splane->format = format;
155 
156 	splane->src_x = src_x >> 16;
157 	splane->src_y = src_y >> 16;
158 	splane->crtc_x = crtc_x;
159 	splane->crtc_y = crtc_y;
160 	splane->crtc_w = crtc_w;
161 	splane->crtc_h = crtc_h;
162 
163 	__shmob_drm_plane_setup(splane, fb);
164 	return 0;
165 }
166 
167 static int shmob_drm_plane_disable(struct drm_plane *plane,
168 				   struct drm_modeset_acquire_ctx *ctx)
169 {
170 	struct shmob_drm_plane *splane = to_shmob_plane(plane);
171 	struct shmob_drm_device *sdev = plane->dev->dev_private;
172 
173 	splane->format = NULL;
174 
175 	lcdc_write(sdev, LDBCR, LDBCR_UPC(splane->index));
176 	lcdc_write(sdev, LDBnBSIFR(splane->index), 0);
177 	lcdc_write(sdev, LDBCR,
178 		   LDBCR_UPF(splane->index) | LDBCR_UPD(splane->index));
179 	return 0;
180 }
181 
182 static const struct drm_plane_funcs shmob_drm_plane_funcs = {
183 	.update_plane = shmob_drm_plane_update,
184 	.disable_plane = shmob_drm_plane_disable,
185 };
186 
187 static const uint32_t formats[] = {
188 	DRM_FORMAT_RGB565,
189 	DRM_FORMAT_RGB888,
190 	DRM_FORMAT_ARGB8888,
191 	DRM_FORMAT_XRGB8888,
192 	DRM_FORMAT_NV12,
193 	DRM_FORMAT_NV21,
194 	DRM_FORMAT_NV16,
195 	DRM_FORMAT_NV61,
196 	DRM_FORMAT_NV24,
197 	DRM_FORMAT_NV42,
198 };
199 
200 int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
201 {
202 	struct shmob_drm_plane *splane;
203 
204 	splane = drmm_universal_plane_alloc(&sdev->ddev, struct shmob_drm_plane,
205 					    plane, 1, &shmob_drm_plane_funcs,
206 					    formats, ARRAY_SIZE(formats), NULL,
207 					    DRM_PLANE_TYPE_OVERLAY, NULL);
208 	if (IS_ERR(splane))
209 		return PTR_ERR(splane);
210 
211 	splane->index = index;
212 	splane->alpha = 255;
213 
214 	return 0;
215 }
216