Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 16static 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
 24static 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
 41static struct drm_plane_state *
 42tegra_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
 64static 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
 71static bool tegra_plane_format_mod_supported(struct drm_plane *plane,
 72					     uint32_t format,
 73					     uint64_t modifier)
 74{
 75	const struct drm_format_info *info = drm_format_info(format);
 76
 77	if (modifier == DRM_FORMAT_MOD_LINEAR)
 78		return true;
 79
 80	if (info->num_planes == 1)
 81		return true;
 82
 83	return false;
 84}
 85
 86const struct drm_plane_funcs tegra_plane_funcs = {
 87	.update_plane = drm_atomic_helper_update_plane,
 88	.disable_plane = drm_atomic_helper_disable_plane,
 89	.destroy = tegra_plane_destroy,
 90	.reset = tegra_plane_reset,
 91	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
 92	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
 93	.format_mod_supported = tegra_plane_format_mod_supported,
 94};
 95
 96int tegra_plane_state_add(struct tegra_plane *plane,
 97			  struct drm_plane_state *state)
 98{
 99	struct drm_crtc_state *crtc_state;
100	struct tegra_dc_state *tegra;
101	int err;
102
103	/* Propagate errors from allocation or locking failures. */
104	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
105	if (IS_ERR(crtc_state))
106		return PTR_ERR(crtc_state);
107
108	/* Check plane state for visibility and calculate clipping bounds */
109	err = drm_atomic_helper_check_plane_state(state, crtc_state,
110						  0, INT_MAX, true, true);
111	if (err < 0)
112		return err;
113
114	tegra = to_dc_state(crtc_state);
115
116	tegra->planes |= WIN_A_ACT_REQ << plane->index;
117
118	return 0;
119}
120
121int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
122{
123	/* assume no swapping of fetched data */
124	if (swap)
125		*swap = BYTE_SWAP_NOSWAP;
126
127	switch (fourcc) {
128	case DRM_FORMAT_ARGB4444:
129		*format = WIN_COLOR_DEPTH_B4G4R4A4;
130		break;
131
132	case DRM_FORMAT_ARGB1555:
133		*format = WIN_COLOR_DEPTH_B5G5R5A1;
134		break;
135
136	case DRM_FORMAT_RGB565:
137		*format = WIN_COLOR_DEPTH_B5G6R5;
138		break;
139
140	case DRM_FORMAT_RGBA5551:
141		*format = WIN_COLOR_DEPTH_A1B5G5R5;
142		break;
143
144	case DRM_FORMAT_ARGB8888:
145		*format = WIN_COLOR_DEPTH_B8G8R8A8;
146		break;
147
148	case DRM_FORMAT_ABGR8888:
149		*format = WIN_COLOR_DEPTH_R8G8B8A8;
150		break;
151
152	case DRM_FORMAT_ABGR4444:
153		*format = WIN_COLOR_DEPTH_R4G4B4A4;
154		break;
155
156	case DRM_FORMAT_ABGR1555:
157		*format = WIN_COLOR_DEPTH_R5G5B5A;
158		break;
159
160	case DRM_FORMAT_BGRA5551:
161		*format = WIN_COLOR_DEPTH_AR5G5B5;
162		break;
163
164	case DRM_FORMAT_XRGB1555:
165		*format = WIN_COLOR_DEPTH_B5G5R5X1;
166		break;
167
168	case DRM_FORMAT_RGBX5551:
169		*format = WIN_COLOR_DEPTH_X1B5G5R5;
170		break;
171
172	case DRM_FORMAT_XBGR1555:
173		*format = WIN_COLOR_DEPTH_R5G5B5X1;
174		break;
175
176	case DRM_FORMAT_BGRX5551:
177		*format = WIN_COLOR_DEPTH_X1R5G5B5;
178		break;
179
180	case DRM_FORMAT_BGR565:
181		*format = WIN_COLOR_DEPTH_R5G6B5;
182		break;
183
184	case DRM_FORMAT_BGRA8888:
185		*format = WIN_COLOR_DEPTH_A8R8G8B8;
186		break;
187
188	case DRM_FORMAT_RGBA8888:
189		*format = WIN_COLOR_DEPTH_A8B8G8R8;
190		break;
191
192	case DRM_FORMAT_XRGB8888:
193		*format = WIN_COLOR_DEPTH_B8G8R8X8;
194		break;
195
196	case DRM_FORMAT_XBGR8888:
197		*format = WIN_COLOR_DEPTH_R8G8B8X8;
198		break;
199
200	case DRM_FORMAT_UYVY:
201		*format = WIN_COLOR_DEPTH_YCbCr422;
202		break;
203
204	case DRM_FORMAT_YUYV:
205		if (!swap)
206			return -EINVAL;
207
208		*format = WIN_COLOR_DEPTH_YCbCr422;
209		*swap = BYTE_SWAP_SWAP2;
210		break;
211
212	case DRM_FORMAT_YUV420:
213		*format = WIN_COLOR_DEPTH_YCbCr420P;
214		break;
215
216	case DRM_FORMAT_YUV422:
217		*format = WIN_COLOR_DEPTH_YCbCr422P;
218		break;
219
220	default:
221		return -EINVAL;
222	}
223
224	return 0;
225}
226
227bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
228{
229	switch (format) {
230	case WIN_COLOR_DEPTH_YCbCr422:
231	case WIN_COLOR_DEPTH_YUV422:
232		if (planar)
233			*planar = false;
234
235		return true;
236
237	case WIN_COLOR_DEPTH_YCbCr420P:
238	case WIN_COLOR_DEPTH_YUV420P:
239	case WIN_COLOR_DEPTH_YCbCr422P:
240	case WIN_COLOR_DEPTH_YUV422P:
241	case WIN_COLOR_DEPTH_YCbCr422R:
242	case WIN_COLOR_DEPTH_YUV422R:
243	case WIN_COLOR_DEPTH_YCbCr422RA:
244	case WIN_COLOR_DEPTH_YUV422RA:
245		if (planar)
246			*planar = true;
247
248		return true;
249	}
250
251	if (planar)
252		*planar = false;
253
254	return false;
255}
256
257static bool __drm_format_has_alpha(u32 format)
258{
259	switch (format) {
260	case DRM_FORMAT_ARGB1555:
261	case DRM_FORMAT_RGBA5551:
262	case DRM_FORMAT_ABGR8888:
263	case DRM_FORMAT_ARGB8888:
264		return true;
265	}
266
267	return false;
268}
269
270/*
271 * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
272 * be emulated using the alpha formats and alpha blending disabled.
273 */
274bool tegra_plane_format_has_alpha(unsigned int format)
275{
276	switch (format) {
277	case WIN_COLOR_DEPTH_B5G5R5A1:
278	case WIN_COLOR_DEPTH_A1B5G5R5:
279	case WIN_COLOR_DEPTH_R8G8B8A8:
280	case WIN_COLOR_DEPTH_B8G8R8A8:
281		return true;
282	}
283
284	return false;
285}
286
287int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
288{
289	if (tegra_plane_format_is_yuv(opaque, NULL)) {
290		*alpha = opaque;
291		return 0;
292	}
293
294	switch (opaque) {
295	case WIN_COLOR_DEPTH_B5G5R5X1:
296		*alpha = WIN_COLOR_DEPTH_B5G5R5A1;
297		return 0;
298
299	case WIN_COLOR_DEPTH_X1B5G5R5:
300		*alpha = WIN_COLOR_DEPTH_A1B5G5R5;
301		return 0;
302
303	case WIN_COLOR_DEPTH_R8G8B8X8:
304		*alpha = WIN_COLOR_DEPTH_R8G8B8A8;
305		return 0;
306
307	case WIN_COLOR_DEPTH_B8G8R8X8:
308		*alpha = WIN_COLOR_DEPTH_B8G8R8A8;
309		return 0;
310
311	case WIN_COLOR_DEPTH_B5G6R5:
312		*alpha = opaque;
313		return 0;
314	}
315
316	return -EINVAL;
317}
318
319static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
320						  struct tegra_plane *other)
321{
322	unsigned int index = 0, i;
323
324	WARN_ON(plane == other);
325
326	for (i = 0; i < 3; i++) {
327		if (i == plane->index)
328			continue;
329
330		if (i == other->index)
331			break;
332
333		index++;
334	}
335
336	return index;
337}
338
339void tegra_plane_check_dependent(struct tegra_plane *tegra,
340				 struct tegra_plane_state *state)
341{
342	struct drm_plane_state *old, *new;
343	struct drm_plane *plane;
344	unsigned int zpos[2];
345	unsigned int i;
346
347	for (i = 0; i < 2; i++)
348		zpos[i] = 0;
349
350	for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {
351		struct tegra_plane *p = to_tegra_plane(plane);
352		unsigned index;
353
354		/* skip this plane and planes on different CRTCs */
355		if (p == tegra || new->crtc != state->base.crtc)
356			continue;
357
358		index = tegra_plane_get_overlap_index(tegra, p);
359
360		state->dependent[index] = false;
361
362		/*
363		 * If any of the other planes is on top of this plane and uses
364		 * a format with an alpha component, mark this plane as being
365		 * dependent, meaning it's alpha value will be 1 minus the sum
366		 * of alpha components of the overlapping planes.
367		 */
368		if (p->index > tegra->index) {
369			if (__drm_format_has_alpha(new->fb->format->format))
370				state->dependent[index] = true;
371
372			/* keep track of the Z position */
373			zpos[index] = p->index;
374		}
375	}
376
377	/*
378	 * The region where three windows overlap is the intersection of the
379	 * two regions where two windows overlap. It contributes to the area
380	 * if any of the windows on top of it have an alpha component.
381	 */
382	for (i = 0; i < 2; i++)
383		state->dependent[2] = state->dependent[2] ||
384				      state->dependent[i];
385
386	/*
387	 * However, if any of the windows on top of this window is opaque, it
388	 * will completely conceal this window within that area, so avoid the
389	 * window from contributing to the area.
390	 */
391	for (i = 0; i < 2; i++) {
392		if (zpos[i] > tegra->index)
393			state->dependent[2] = state->dependent[2] &&
394					      state->dependent[i];
395	}
396}