xref: /openbmc/linux/drivers/gpu/drm/tegra/plane.c (revision e2c75e76)
1 /*
2  * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8 
9 #include <drm/drm_atomic.h>
10 #include <drm/drm_atomic_helper.h>
11 #include <drm/drm_plane_helper.h>
12 
13 #include "dc.h"
14 #include "plane.h"
15 
16 static void tegra_plane_destroy(struct drm_plane *plane)
17 {
18 	struct tegra_plane *p = to_tegra_plane(plane);
19 
20 	drm_plane_cleanup(plane);
21 	kfree(p);
22 }
23 
24 static void tegra_plane_reset(struct drm_plane *plane)
25 {
26 	struct tegra_plane_state *state;
27 
28 	if (plane->state)
29 		__drm_atomic_helper_plane_destroy_state(plane->state);
30 
31 	kfree(plane->state);
32 	plane->state = NULL;
33 
34 	state = kzalloc(sizeof(*state), GFP_KERNEL);
35 	if (state) {
36 		plane->state = &state->base;
37 		plane->state->plane = plane;
38 	}
39 }
40 
41 static struct drm_plane_state *
42 tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
43 {
44 	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
45 	struct tegra_plane_state *copy;
46 	unsigned int i;
47 
48 	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
49 	if (!copy)
50 		return NULL;
51 
52 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
53 	copy->tiling = state->tiling;
54 	copy->format = state->format;
55 	copy->swap = state->swap;
56 	copy->opaque = state->opaque;
57 
58 	for (i = 0; i < 3; i++)
59 		copy->dependent[i] = state->dependent[i];
60 
61 	return &copy->base;
62 }
63 
64 static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
65 					     struct drm_plane_state *state)
66 {
67 	__drm_atomic_helper_plane_destroy_state(state);
68 	kfree(state);
69 }
70 
71 const struct drm_plane_funcs tegra_plane_funcs = {
72 	.update_plane = drm_atomic_helper_update_plane,
73 	.disable_plane = drm_atomic_helper_disable_plane,
74 	.destroy = tegra_plane_destroy,
75 	.reset = tegra_plane_reset,
76 	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
77 	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
78 };
79 
80 int tegra_plane_state_add(struct tegra_plane *plane,
81 			  struct drm_plane_state *state)
82 {
83 	struct drm_crtc_state *crtc_state;
84 	struct tegra_dc_state *tegra;
85 	struct drm_rect clip;
86 	int err;
87 
88 	/* Propagate errors from allocation or locking failures. */
89 	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
90 	if (IS_ERR(crtc_state))
91 		return PTR_ERR(crtc_state);
92 
93 	clip.x1 = 0;
94 	clip.y1 = 0;
95 	clip.x2 = crtc_state->mode.hdisplay;
96 	clip.y2 = crtc_state->mode.vdisplay;
97 
98 	/* Check plane state for visibility and calculate clipping bounds */
99 	err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
100 						  0, INT_MAX, true, true);
101 	if (err < 0)
102 		return err;
103 
104 	tegra = to_dc_state(crtc_state);
105 
106 	tegra->planes |= WIN_A_ACT_REQ << plane->index;
107 
108 	return 0;
109 }
110 
111 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
112 {
113 	/* assume no swapping of fetched data */
114 	if (swap)
115 		*swap = BYTE_SWAP_NOSWAP;
116 
117 	switch (fourcc) {
118 	case DRM_FORMAT_ARGB4444:
119 		*format = WIN_COLOR_DEPTH_B4G4R4A4;
120 		break;
121 
122 	case DRM_FORMAT_ARGB1555:
123 		*format = WIN_COLOR_DEPTH_B5G5R5A1;
124 		break;
125 
126 	case DRM_FORMAT_RGB565:
127 		*format = WIN_COLOR_DEPTH_B5G6R5;
128 		break;
129 
130 	case DRM_FORMAT_RGBA5551:
131 		*format = WIN_COLOR_DEPTH_A1B5G5R5;
132 		break;
133 
134 	case DRM_FORMAT_ARGB8888:
135 		*format = WIN_COLOR_DEPTH_B8G8R8A8;
136 		break;
137 
138 	case DRM_FORMAT_ABGR8888:
139 		*format = WIN_COLOR_DEPTH_R8G8B8A8;
140 		break;
141 
142 	case DRM_FORMAT_ABGR4444:
143 		*format = WIN_COLOR_DEPTH_R4G4B4A4;
144 		break;
145 
146 	case DRM_FORMAT_ABGR1555:
147 		*format = WIN_COLOR_DEPTH_R5G5B5A;
148 		break;
149 
150 	case DRM_FORMAT_BGRA5551:
151 		*format = WIN_COLOR_DEPTH_AR5G5B5;
152 		break;
153 
154 	case DRM_FORMAT_XRGB1555:
155 		*format = WIN_COLOR_DEPTH_B5G5R5X1;
156 		break;
157 
158 	case DRM_FORMAT_RGBX5551:
159 		*format = WIN_COLOR_DEPTH_X1B5G5R5;
160 		break;
161 
162 	case DRM_FORMAT_XBGR1555:
163 		*format = WIN_COLOR_DEPTH_R5G5B5X1;
164 		break;
165 
166 	case DRM_FORMAT_BGRX5551:
167 		*format = WIN_COLOR_DEPTH_X1R5G5B5;
168 		break;
169 
170 	case DRM_FORMAT_BGR565:
171 		*format = WIN_COLOR_DEPTH_R5G6B5;
172 		break;
173 
174 	case DRM_FORMAT_BGRA8888:
175 		*format = WIN_COLOR_DEPTH_A8R8G8B8;
176 		break;
177 
178 	case DRM_FORMAT_RGBA8888:
179 		*format = WIN_COLOR_DEPTH_A8B8G8R8;
180 		break;
181 
182 	case DRM_FORMAT_XRGB8888:
183 		*format = WIN_COLOR_DEPTH_B8G8R8X8;
184 		break;
185 
186 	case DRM_FORMAT_XBGR8888:
187 		*format = WIN_COLOR_DEPTH_R8G8B8X8;
188 		break;
189 
190 	case DRM_FORMAT_UYVY:
191 		*format = WIN_COLOR_DEPTH_YCbCr422;
192 		break;
193 
194 	case DRM_FORMAT_YUYV:
195 		if (!swap)
196 			return -EINVAL;
197 
198 		*format = WIN_COLOR_DEPTH_YCbCr422;
199 		*swap = BYTE_SWAP_SWAP2;
200 		break;
201 
202 	case DRM_FORMAT_YUV420:
203 		*format = WIN_COLOR_DEPTH_YCbCr420P;
204 		break;
205 
206 	case DRM_FORMAT_YUV422:
207 		*format = WIN_COLOR_DEPTH_YCbCr422P;
208 		break;
209 
210 	default:
211 		return -EINVAL;
212 	}
213 
214 	return 0;
215 }
216 
217 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
218 {
219 	switch (format) {
220 	case WIN_COLOR_DEPTH_YCbCr422:
221 	case WIN_COLOR_DEPTH_YUV422:
222 		if (planar)
223 			*planar = false;
224 
225 		return true;
226 
227 	case WIN_COLOR_DEPTH_YCbCr420P:
228 	case WIN_COLOR_DEPTH_YUV420P:
229 	case WIN_COLOR_DEPTH_YCbCr422P:
230 	case WIN_COLOR_DEPTH_YUV422P:
231 	case WIN_COLOR_DEPTH_YCbCr422R:
232 	case WIN_COLOR_DEPTH_YUV422R:
233 	case WIN_COLOR_DEPTH_YCbCr422RA:
234 	case WIN_COLOR_DEPTH_YUV422RA:
235 		if (planar)
236 			*planar = true;
237 
238 		return true;
239 	}
240 
241 	if (planar)
242 		*planar = false;
243 
244 	return false;
245 }
246 
247 static bool __drm_format_has_alpha(u32 format)
248 {
249 	switch (format) {
250 	case DRM_FORMAT_ARGB1555:
251 	case DRM_FORMAT_RGBA5551:
252 	case DRM_FORMAT_ABGR8888:
253 	case DRM_FORMAT_ARGB8888:
254 		return true;
255 	}
256 
257 	return false;
258 }
259 
260 /*
261  * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
262  * be emulated using the alpha formats and alpha blending disabled.
263  */
264 bool tegra_plane_format_has_alpha(unsigned int format)
265 {
266 	switch (format) {
267 	case WIN_COLOR_DEPTH_B5G5R5A1:
268 	case WIN_COLOR_DEPTH_A1B5G5R5:
269 	case WIN_COLOR_DEPTH_R8G8B8A8:
270 	case WIN_COLOR_DEPTH_B8G8R8A8:
271 		return true;
272 	}
273 
274 	return false;
275 }
276 
277 int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
278 {
279 	if (tegra_plane_format_is_yuv(opaque, NULL)) {
280 		*alpha = opaque;
281 		return 0;
282 	}
283 
284 	switch (opaque) {
285 	case WIN_COLOR_DEPTH_B5G5R5X1:
286 		*alpha = WIN_COLOR_DEPTH_B5G5R5A1;
287 		return 0;
288 
289 	case WIN_COLOR_DEPTH_X1B5G5R5:
290 		*alpha = WIN_COLOR_DEPTH_A1B5G5R5;
291 		return 0;
292 
293 	case WIN_COLOR_DEPTH_R8G8B8X8:
294 		*alpha = WIN_COLOR_DEPTH_R8G8B8A8;
295 		return 0;
296 
297 	case WIN_COLOR_DEPTH_B8G8R8X8:
298 		*alpha = WIN_COLOR_DEPTH_B8G8R8A8;
299 		return 0;
300 	}
301 
302 	return -EINVAL;
303 }
304 
305 unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
306 					   struct tegra_plane *other)
307 {
308 	unsigned int index = 0, i;
309 
310 	WARN_ON(plane == other);
311 
312 	for (i = 0; i < 3; i++) {
313 		if (i == plane->index)
314 			continue;
315 
316 		if (i == other->index)
317 			break;
318 
319 		index++;
320 	}
321 
322 	return index;
323 }
324 
325 void tegra_plane_check_dependent(struct tegra_plane *tegra,
326 				 struct tegra_plane_state *state)
327 {
328 	struct drm_plane_state *old, *new;
329 	struct drm_plane *plane;
330 	unsigned int zpos[2];
331 	unsigned int i;
332 
333 	for (i = 0; i < 3; i++)
334 		state->dependent[i] = false;
335 
336 	for (i = 0; i < 2; i++)
337 		zpos[i] = 0;
338 
339 	for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {
340 		struct tegra_plane *p = to_tegra_plane(plane);
341 		unsigned index;
342 
343 		/* skip this plane and planes on different CRTCs */
344 		if (p == tegra || new->crtc != state->base.crtc)
345 			continue;
346 
347 		index = tegra_plane_get_overlap_index(tegra, p);
348 
349 		/*
350 		 * If any of the other planes is on top of this plane and uses
351 		 * a format with an alpha component, mark this plane as being
352 		 * dependent, meaning it's alpha value will be 1 minus the sum
353 		 * of alpha components of the overlapping planes.
354 		 */
355 		if (p->index > tegra->index) {
356 			if (__drm_format_has_alpha(new->fb->format->format))
357 				state->dependent[index] = true;
358 
359 			/* keep track of the Z position */
360 			zpos[index] = p->index;
361 		}
362 	}
363 
364 	/*
365 	 * The region where three windows overlap is the intersection of the
366 	 * two regions where two windows overlap. It contributes to the area
367 	 * if any of the windows on top of it have an alpha component.
368 	 */
369 	for (i = 0; i < 2; i++)
370 		state->dependent[2] = state->dependent[2] ||
371 				      state->dependent[i];
372 
373 	/*
374 	 * However, if any of the windows on top of this window is opaque, it
375 	 * will completely conceal this window within that area, so avoid the
376 	 * window from contributing to the area.
377 	 */
378 	for (i = 0; i < 2; i++) {
379 		if (zpos[i] > tegra->index)
380 			state->dependent[2] = state->dependent[2] &&
381 					      state->dependent[i];
382 	}
383 }
384