Commit | Line | Data |
---|---|---|
5acd3514 TR |
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; | |
ebae8d07 | 46 | unsigned int i; |
5acd3514 TR |
47 | |
48 | copy = kmalloc(sizeof(*copy), GFP_KERNEL); | |
49 | if (!copy) | |
50 | return NULL; | |
51 | ||
52 | __drm_atomic_helper_plane_duplicate_state(plane, ©->base); | |
53 | copy->tiling = state->tiling; | |
54 | copy->format = state->format; | |
55 | copy->swap = state->swap; | |
ebae8d07 TR |
56 | copy->opaque = state->opaque; |
57 | ||
58 | for (i = 0; i < 3; i++) | |
59 | copy->dependent[i] = state->dependent[i]; | |
5acd3514 TR |
60 | |
61 | return ©->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) { | |
511c7023 TR |
118 | case DRM_FORMAT_ARGB4444: |
119 | *format = WIN_COLOR_DEPTH_B4G4R4A4; | |
7772fdae TR |
120 | break; |
121 | ||
511c7023 TR |
122 | case DRM_FORMAT_ARGB1555: |
123 | *format = WIN_COLOR_DEPTH_B5G5R5A1; | |
5acd3514 TR |
124 | break; |
125 | ||
511c7023 TR |
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; | |
7772fdae TR |
132 | break; |
133 | ||
134 | case DRM_FORMAT_ARGB8888: | |
5acd3514 TR |
135 | *format = WIN_COLOR_DEPTH_B8G8R8A8; |
136 | break; | |
137 | ||
511c7023 TR |
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; | |
5acd3514 TR |
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 | } | |
ebae8d07 TR |
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 | { | |
5467a8b8 TR |
279 | if (tegra_plane_format_is_yuv(opaque, NULL)) { |
280 | *alpha = opaque; | |
281 | return 0; | |
282 | } | |
283 | ||
ebae8d07 TR |
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; | |
8a927d64 TR |
300 | |
301 | case WIN_COLOR_DEPTH_B5G6R5: | |
302 | *alpha = opaque; | |
303 | return 0; | |
ebae8d07 TR |
304 | } |
305 | ||
306 | return -EINVAL; | |
307 | } | |
308 | ||
309 | unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, | |
310 | struct tegra_plane *other) | |
311 | { | |
312 | unsigned int index = 0, i; | |
313 | ||
314 | WARN_ON(plane == other); | |
315 | ||
316 | for (i = 0; i < 3; i++) { | |
317 | if (i == plane->index) | |
318 | continue; | |
319 | ||
320 | if (i == other->index) | |
321 | break; | |
322 | ||
323 | index++; | |
324 | } | |
325 | ||
326 | return index; | |
327 | } | |
328 | ||
329 | void tegra_plane_check_dependent(struct tegra_plane *tegra, | |
330 | struct tegra_plane_state *state) | |
331 | { | |
332 | struct drm_plane_state *old, *new; | |
333 | struct drm_plane *plane; | |
334 | unsigned int zpos[2]; | |
335 | unsigned int i; | |
336 | ||
ebae8d07 TR |
337 | for (i = 0; i < 2; i++) |
338 | zpos[i] = 0; | |
339 | ||
340 | for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) { | |
341 | struct tegra_plane *p = to_tegra_plane(plane); | |
342 | unsigned index; | |
343 | ||
344 | /* skip this plane and planes on different CRTCs */ | |
345 | if (p == tegra || new->crtc != state->base.crtc) | |
346 | continue; | |
347 | ||
348 | index = tegra_plane_get_overlap_index(tegra, p); | |
349 | ||
48519232 DO |
350 | state->dependent[index] = false; |
351 | ||
ebae8d07 TR |
352 | /* |
353 | * If any of the other planes is on top of this plane and uses | |
354 | * a format with an alpha component, mark this plane as being | |
355 | * dependent, meaning it's alpha value will be 1 minus the sum | |
356 | * of alpha components of the overlapping planes. | |
357 | */ | |
358 | if (p->index > tegra->index) { | |
359 | if (__drm_format_has_alpha(new->fb->format->format)) | |
360 | state->dependent[index] = true; | |
361 | ||
362 | /* keep track of the Z position */ | |
363 | zpos[index] = p->index; | |
364 | } | |
365 | } | |
366 | ||
367 | /* | |
368 | * The region where three windows overlap is the intersection of the | |
369 | * two regions where two windows overlap. It contributes to the area | |
370 | * if any of the windows on top of it have an alpha component. | |
371 | */ | |
372 | for (i = 0; i < 2; i++) | |
373 | state->dependent[2] = state->dependent[2] || | |
374 | state->dependent[i]; | |
375 | ||
376 | /* | |
377 | * However, if any of the windows on top of this window is opaque, it | |
378 | * will completely conceal this window within that area, so avoid the | |
379 | * window from contributing to the area. | |
380 | */ | |
381 | for (i = 0; i < 2; i++) { | |
382 | if (zpos[i] > tegra->index) | |
383 | state->dependent[2] = state->dependent[2] && | |
384 | state->dependent[i]; | |
385 | } | |
386 | } |