bcm27xx: update patches from RPi foundation
[oweals/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0234-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch
1 From 75e1dce99c260cb1365edd9af68cb5c07487831c Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Wed, 27 Mar 2019 17:45:01 +0000
4 Subject: [PATCH] drm: vc4: Add an overlay plane to vc4-firmware-kms
5
6 This uses a new API that is exposed via the mailbox service
7 to stick an element straight on the screen using DispmanX.
8
9 The primary and cursor planes have also been switched to using
10 the new plane API, and it supports layering based on the DRM
11 zpos parameter.
12
13 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
14 ---
15  drivers/gpu/drm/vc4/vc4_firmware_kms.c     | 518 ++++++++++++++-------
16  drivers/gpu/drm/vc4/vc4_kms.c              |   1 +
17  drivers/gpu/drm/vc4/vc_image_types.h       | 143 ++++++
18  include/soc/bcm2835/raspberrypi-firmware.h |   2 +
19  4 files changed, 495 insertions(+), 169 deletions(-)
20  create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h
21
22 --- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
23 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
24 @@ -28,8 +28,46 @@
25  #include "linux/of_device.h"
26  #include "vc4_drv.h"
27  #include "vc4_regs.h"
28 +#include "vc_image_types.h"
29  #include <soc/bcm2835/raspberrypi-firmware.h>
30  
31 +struct set_plane {
32 +       u8 display;
33 +       u8 plane_id;
34 +       u8 vc_image_type;
35 +       s8 layer;
36 +
37 +       u16 width;
38 +       u16 height;
39 +
40 +       u16 pitch;
41 +       u16 vpitch;
42 +
43 +       u32 src_x;      /* 16p16 */
44 +       u32 src_y;      /* 16p16 */
45 +
46 +       u32 src_w;      /* 16p16 */
47 +       u32 src_h;      /* 16p16 */
48 +
49 +       s16 dst_x;
50 +       s16 dst_y;
51 +
52 +       u16 dst_w;
53 +       u16 dst_h;
54 +
55 +       u8 alpha;
56 +       u8 num_planes;
57 +       u8 is_vu;
58 +       u8 padding;
59 +
60 +       u32 planes[4];  /* DMA address of each plane */
61 +};
62 +
63 +struct mailbox_set_plane {
64 +       struct rpi_firmware_property_tag_header tag;
65 +       struct set_plane plane;
66 +};
67 +
68  struct fb_alloc_tags {
69         struct rpi_firmware_property_tag_header tag1;
70         u32 xres, yres;
71 @@ -49,6 +87,79 @@ struct fb_alloc_tags {
72         u32 layer;
73  };
74  
75 +static const struct vc_image_format {
76 +       u32 drm;        /* DRM_FORMAT_* */
77 +       u32 vc_image;   /* VC_IMAGE_* */
78 +       u32 is_vu;
79 +} vc_image_formats[] = {
80 +       {
81 +               .drm = DRM_FORMAT_XRGB8888,
82 +               .vc_image = VC_IMAGE_XRGB8888,
83 +       },
84 +       {
85 +               .drm = DRM_FORMAT_ARGB8888,
86 +               .vc_image = VC_IMAGE_ARGB8888,
87 +       },
88 +/*
89 + *     FIXME: Need to resolve which DRM format goes to which vc_image format
90 + *     for the remaining RGBA and RGBX formats.
91 + *     {
92 + *             .drm = DRM_FORMAT_ABGR8888,
93 + *             .vc_image = VC_IMAGE_RGBA8888,
94 + *     },
95 + *     {
96 + *             .drm = DRM_FORMAT_XBGR8888,
97 + *             .vc_image = VC_IMAGE_RGBA8888,
98 + *     },
99 + */
100 +       {
101 +               .drm = DRM_FORMAT_RGB565,
102 +               .vc_image = VC_IMAGE_RGB565,
103 +       },
104 +       {
105 +               .drm = DRM_FORMAT_RGB888,
106 +               .vc_image = VC_IMAGE_BGR888,
107 +       },
108 +       {
109 +               .drm = DRM_FORMAT_BGR888,
110 +               .vc_image = VC_IMAGE_RGB888,
111 +       },
112 +       {
113 +               .drm = DRM_FORMAT_YUV422,
114 +               .vc_image = VC_IMAGE_YUV422PLANAR,
115 +       },
116 +       {
117 +               .drm = DRM_FORMAT_YUV420,
118 +               .vc_image = VC_IMAGE_YUV420,
119 +       },
120 +       {
121 +               .drm = DRM_FORMAT_YVU420,
122 +               .vc_image = VC_IMAGE_YUV420,
123 +               .is_vu = 1,
124 +       },
125 +       {
126 +               .drm = DRM_FORMAT_NV12,
127 +               .vc_image = VC_IMAGE_YUV420SP,
128 +       },
129 +       {
130 +               .drm = DRM_FORMAT_NV21,
131 +               .vc_image = VC_IMAGE_YUV420SP,
132 +               .is_vu = 1,
133 +       },
134 +};
135 +
136 +static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
137 +{
138 +       unsigned int i;
139 +
140 +       for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
141 +               if (vc_image_formats[i].drm == drm_format)
142 +                       return &vc_image_formats[i];
143 +       }
144 +
145 +       return NULL;
146 +}
147 +
148  /* The firmware delivers a vblank interrupt to us through the SMI
149   * hardware, which has only this one register.
150   */
151 @@ -115,6 +226,7 @@ struct vc4_fkms_plane {
152         struct fbinfo_s *fbinfo;
153         dma_addr_t fbinfo_bus_addr;
154         u32 pitch;
155 +       struct mailbox_set_plane mb;
156  };
157  
158  static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
159 @@ -122,165 +234,183 @@ static inline struct vc4_fkms_plane *to_
160         return (struct vc4_fkms_plane *)plane;
161  }
162  
163 -/* Turns the display on/off. */
164 -static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank)
165 +static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
166  {
167         struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
168 +       struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
169 +       struct mailbox_set_plane blank_mb = {
170 +               .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
171 +               .plane = {
172 +                       .display = vc4_plane->mb.plane.display,
173 +                       .plane_id = vc4_plane->mb.plane.plane_id,
174 +               }
175 +       };
176 +       int ret;
177  
178 -       u32 packet = blank;
179 -
180 -       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s",
181 +       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s",
182                          plane->base.id, plane->name,
183                          blank ? "blank" : "unblank");
184  
185 -       return rpi_firmware_property(vc4->firmware,
186 -                                    RPI_FIRMWARE_FRAMEBUFFER_BLANK,
187 -                                    &packet, sizeof(packet));
188 +       if (blank)
189 +               ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
190 +                                                sizeof(blank_mb));
191 +       else
192 +               ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
193 +                                                sizeof(vc4_plane->mb));
194 +
195 +       WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
196 +                 __func__);
197 +       return ret;
198  }
199  
200 -static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
201 -                                           struct drm_plane_state *old_state)
202 +static void vc4_plane_atomic_update(struct drm_plane *plane,
203 +                                   struct drm_plane_state *old_state)
204  {
205 -       struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
206         struct drm_plane_state *state = plane->state;
207         struct drm_framebuffer *fb = state->fb;
208         struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
209 -       u32 format = fb->format->format;
210 -       struct fb_alloc_tags fbinfo = {
211 -               .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT,
212 -                         8, 0, },
213 -                       .xres = state->crtc_w,
214 -                       .yres = state->crtc_h,
215 -               .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT,
216 -                         8, 0, },
217 -                       .xres_virtual = state->crtc_w,
218 -                       .yres_virtual = state->crtc_h,
219 -               .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 },
220 -                       .bpp = 32,
221 -               .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 },
222 -                       .xoffset = 0,
223 -                       .yoffset = 0,
224 -               .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 },
225 -                       .base = bo->paddr + fb->offsets[0],
226 -                       .screen_size = state->crtc_w * state->crtc_h * 4,
227 -               .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 },
228 -                       .pitch = fb->pitches[0],
229 -               .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 },
230 -                       .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2,
231 -               .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 },
232 -                       .layer = -127,
233 -       };
234 -       u32 bpp = 32;
235 -       int ret;
236 +       const struct drm_format_info *drm_fmt = fb->format;
237 +       const struct vc_image_format *vc_fmt =
238 +                                       vc4_get_vc_image_fmt(drm_fmt->format);
239 +       struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
240 +       struct mailbox_set_plane *mb = &vc4_plane->mb;
241 +       struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
242 +       int num_planes = fb->format->num_planes;
243 +       struct drm_display_mode *mode = &state->crtc->mode;
244  
245 -       if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
246 -               fbinfo.bpp |= BIT(31);
247 +       mb->plane.vc_image_type = vc_fmt->vc_image;
248 +       mb->plane.width = fb->width;
249 +       mb->plane.height = fb->height;
250 +       mb->plane.pitch = fb->pitches[0];
251 +       mb->plane.src_w = state->src_w;
252 +       mb->plane.src_h = state->src_h;
253 +       mb->plane.src_x = state->src_x;
254 +       mb->plane.src_y = state->src_y;
255 +       mb->plane.dst_w = state->crtc_w;
256 +       mb->plane.dst_h = state->crtc_h;
257 +       mb->plane.dst_x = state->crtc_x;
258 +       mb->plane.dst_y = state->crtc_y;
259 +       mb->plane.alpha = state->alpha >> 8;
260 +       mb->plane.layer = state->normalized_zpos ?
261 +                                       state->normalized_zpos : -127;
262 +       mb->plane.num_planes = num_planes;
263 +       mb->plane.is_vu = vc_fmt->is_vu;
264 +       mb->plane.planes[0] = bo->paddr + fb->offsets[0];
265  
266 -       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
267 +       /* FIXME: If the dest rect goes off screen then clip the src rect so we
268 +        * don't have off-screen pixels.
269 +        */
270 +       if (plane->type == DRM_PLANE_TYPE_CURSOR) {
271 +               /* There is no scaling on the cursor plane, therefore the calcs
272 +                * to alter the source crop as the cursor goes off the screen
273 +                * are simple.
274 +                */
275 +               if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
276 +                       mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
277 +                       mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
278 +                                                                       << 16;
279 +               }
280 +               if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
281 +                       mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
282 +                       mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
283 +                                                                       << 16;
284 +               }
285 +       }
286 +
287 +       if (num_planes > 1) {
288 +               /* Assume this must be YUV */
289 +               /* Makes assumptions on the stride for the chroma planes as we
290 +                * can't easily plumb in non-standard pitches.
291 +                */
292 +               mb->plane.planes[1] = bo->paddr + fb->offsets[1];
293 +               if (num_planes > 2)
294 +                       mb->plane.planes[2] = bo->paddr + fb->offsets[2];
295 +               else
296 +                       mb->plane.planes[2] = 0;
297 +
298 +               /* Special case the YUV420 with U and V as line interleaved
299 +                * planes as we have special handling for that case.
300 +                */
301 +               if (num_planes == 3 &&
302 +                   (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
303 +                       mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
304 +       } else {
305 +               mb->plane.planes[1] = 0;
306 +               mb->plane.planes[2] = 0;
307 +       }
308 +       mb->plane.planes[3] = 0;
309 +
310 +       switch (fb->modifier) {
311 +       case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
312 +               switch (mb->plane.vc_image_type) {
313 +               case VC_IMAGE_RGBX32:
314 +                       mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
315 +                       break;
316 +               case VC_IMAGE_RGBA32:
317 +                       mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
318 +                       break;
319 +               case VC_IMAGE_RGB565:
320 +                       mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
321 +                       break;
322 +               }
323 +               break;
324 +       case DRM_FORMAT_MOD_BROADCOM_SAND128:
325 +               mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
326 +               mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
327 +               break;
328 +       }
329 +
330 +       if (vc4_crtc) {
331 +               mb->plane.dst_x += vc4_crtc->overscan[0];
332 +               mb->plane.dst_y += vc4_crtc->overscan[1];
333 +       }
334 +
335 +       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n",
336                          plane->base.id, plane->name,
337 -                        state->crtc_w,
338 -                        state->crtc_h,
339 -                        bpp,
340 +                        mb->plane.width,
341 +                        mb->plane.height,
342 +                        mb->plane.vc_image_type,
343                          state->crtc_x,
344                          state->crtc_y,
345 -                        &fbinfo.base,
346 -                        fb->pitches[0]);
347 -
348 -       ret = rpi_firmware_property_list(vc4->firmware, &fbinfo,
349 -                                        sizeof(fbinfo));
350 -       WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]);
351 -       WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]);
352 -
353 -       /* If the CRTC is on (or going to be on) and we're enabled,
354 +                        state->crtc_w,
355 +                        state->crtc_h,
356 +                        mb->plane.src_x,
357 +                        mb->plane.src_y,
358 +                        mb->plane.src_w,
359 +                        mb->plane.src_h,
360 +                        mb->plane.planes[0],
361 +                        mb->plane.planes[1],
362 +                        mb->plane.planes[2],
363 +                        fb->pitches[0],
364 +                        state->alpha,
365 +                        state->normalized_zpos);
366 +
367 +       /*
368 +        * Do NOT set now, as we haven't checked if the crtc is active or not.
369 +        * Set from vc4_plane_set_blank instead.
370 +        *
371 +        * If the CRTC is on (or going to be on) and we're enabled,
372          * then unblank.  Otherwise, stay blank until CRTC enable.
373 -       */
374 +        */
375         if (state->crtc->state->active)
376 -               vc4_plane_set_primary_blank(plane, false);
377 +               vc4_plane_set_blank(plane, false);
378  }
379  
380 -static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
381 -                                            struct drm_plane_state *old_state)
382 +static void vc4_plane_atomic_disable(struct drm_plane *plane,
383 +                                    struct drm_plane_state *old_state)
384  {
385 -       vc4_plane_set_primary_blank(plane, true);
386 -}
387 -
388 -static void vc4_cursor_plane_atomic_update(struct drm_plane *plane,
389 -                                          struct drm_plane_state *old_state)
390 -{
391 -       struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
392 +       //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
393         struct drm_plane_state *state = plane->state;
394 -       struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc);
395 -       struct drm_framebuffer *fb = state->fb;
396 -       struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
397 -       dma_addr_t addr = bo->paddr + fb->offsets[0];
398 -       int ret;
399 -       u32 packet_state[] = {
400 -               state->crtc->state->active,
401 -               state->crtc_x,
402 -               state->crtc_y,
403 -               0
404 -       };
405 -       WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
406 +       struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
407  
408 -       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)",
409 +       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
410                          plane->base.id, plane->name,
411                          state->crtc_w,
412                          state->crtc_h,
413 +                        vc4_plane->mb.plane.vc_image_type,
414                          state->crtc_x,
415 -                        state->crtc_y,
416 -                        &addr,
417 -                        fb->pitches[0]);
418 -
419 -       /* add on the top/left offsets when overscan is active */
420 -       if (vc4_crtc) {
421 -               packet_state[1] += vc4_crtc->overscan[0];
422 -               packet_state[2] += vc4_crtc->overscan[1];
423 -       }
424 -
425 -       ret = rpi_firmware_property(vc4->firmware,
426 -                                   RPI_FIRMWARE_SET_CURSOR_STATE,
427 -                                   &packet_state,
428 -                                   sizeof(packet_state));
429 -       if (ret || packet_state[0] != 0)
430 -               DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
431 -
432 -       /* Note: When the cursor contents change, the modesetting
433 -        * driver calls drm_mode_cursor_univeral() with
434 -        * DRM_MODE_CURSOR_BO, which means a new fb will be allocated.
435 -        */
436 -       if (!old_state ||
437 -           state->crtc_w != old_state->crtc_w ||
438 -           state->crtc_h != old_state->crtc_h ||
439 -           fb != old_state->fb) {
440 -               u32 packet_info[] = { state->crtc_w, state->crtc_h,
441 -                                     0, /* unused */
442 -                                     addr,
443 -                                     0, 0, /* hotx, hoty */};
444 -
445 -               ret = rpi_firmware_property(vc4->firmware,
446 -                                           RPI_FIRMWARE_SET_CURSOR_INFO,
447 -                                           &packet_info,
448 -                                           sizeof(packet_info));
449 -               if (ret || packet_info[0] != 0)
450 -                       DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]);
451 -       }
452 -}
453 -
454 -static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane,
455 -                                           struct drm_plane_state *old_state)
456 -{
457 -       struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
458 -       u32 packet_state[] = { false, 0, 0, 0 };
459 -       int ret;
460 -
461 -       DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name);
462 -
463 -       ret = rpi_firmware_property(vc4->firmware,
464 -                                   RPI_FIRMWARE_SET_CURSOR_STATE,
465 -                                   &packet_state,
466 -                                   sizeof(packet_state));
467 -       if (ret || packet_state[0] != 0)
468 -               DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
469 +                        state->crtc_y);
470 +       vc4_plane_set_blank(plane, true);
471  }
472  
473  static int vc4_plane_atomic_check(struct drm_plane *plane,
474 @@ -302,6 +432,7 @@ static bool vc4_fkms_format_mod_supporte
475         switch (format) {
476         case DRM_FORMAT_XRGB8888:
477         case DRM_FORMAT_ARGB8888:
478 +       case DRM_FORMAT_RGB565:
479                 switch (modifier) {
480                 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
481                 case DRM_FORMAT_MOD_LINEAR:
482 @@ -310,8 +441,22 @@ static bool vc4_fkms_format_mod_supporte
483                 default:
484                         return false;
485                 }
486 +       case DRM_FORMAT_NV12:
487 +       case DRM_FORMAT_NV21:
488 +               switch (fourcc_mod_broadcom_mod(modifier)) {
489 +               case DRM_FORMAT_MOD_LINEAR:
490 +               case DRM_FORMAT_MOD_BROADCOM_SAND128:
491 +                       return true;
492 +               default:
493 +                       return false;
494 +               }
495 +       case DRM_FORMAT_RGB888:
496 +       case DRM_FORMAT_BGR888:
497 +       case DRM_FORMAT_YUV422:
498 +       case DRM_FORMAT_YUV420:
499 +       case DRM_FORMAT_YVU420:
500         default:
501 -               return false;
502 +               return (modifier == DRM_FORMAT_MOD_LINEAR);
503         }
504  }
505  
506 @@ -326,31 +471,24 @@ static const struct drm_plane_funcs vc4_
507         .format_mod_supported = vc4_fkms_format_mod_supported,
508  };
509  
510 -static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
511 -       .prepare_fb = drm_gem_fb_prepare_fb,
512 -       .cleanup_fb = NULL,
513 -       .atomic_check = vc4_plane_atomic_check,
514 -       .atomic_update = vc4_primary_plane_atomic_update,
515 -       .atomic_disable = vc4_primary_plane_atomic_disable,
516 -};
517 -
518 -static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
519 +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
520         .prepare_fb = drm_gem_fb_prepare_fb,
521         .cleanup_fb = NULL,
522         .atomic_check = vc4_plane_atomic_check,
523 -       .atomic_update = vc4_cursor_plane_atomic_update,
524 -       .atomic_disable = vc4_cursor_plane_atomic_disable,
525 +       .atomic_update = vc4_plane_atomic_update,
526 +       .atomic_disable = vc4_plane_atomic_disable,
527  };
528  
529  static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
530 -                                            enum drm_plane_type type)
531 +                                            enum drm_plane_type type,
532 +                                            u8 plane_id)
533  {
534 -       /* Primary and cursor planes only */
535         struct drm_plane *plane = NULL;
536         struct vc4_fkms_plane *vc4_plane;
537 -       u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
538 +       u32 formats[ARRAY_SIZE(vc_image_formats)];
539 +       unsigned int default_zpos = 0;
540 +       u32 num_formats = 0;
541         int ret = 0;
542 -       bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
543         static const uint64_t modifiers[] = {
544                 DRM_FORMAT_MOD_LINEAR,
545                 /* VC4_T_TILED should come after linear, because we
546 @@ -359,6 +497,7 @@ static struct drm_plane *vc4_fkms_plane_
547                 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
548                 DRM_FORMAT_MOD_INVALID,
549         };
550 +       int i;
551  
552         vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
553                                  GFP_KERNEL);
554 @@ -367,19 +506,48 @@ static struct drm_plane *vc4_fkms_plane_
555                 goto fail;
556         }
557  
558 +       for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
559 +               formats[num_formats++] = vc_image_formats[i].drm;
560 +
561         plane = &vc4_plane->base;
562         ret = drm_universal_plane_init(dev, plane, 0xff,
563                                        &vc4_plane_funcs,
564 -                                      formats, primary ? 2 : 1, modifiers,
565 -                                      type, primary ? "primary" : "cursor");
566 +                                      formats, num_formats, modifiers,
567 +                                      type, NULL);
568  
569 -       if (type == DRM_PLANE_TYPE_PRIMARY)
570 -               drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
571 -       else
572 -               drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
573 +       drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
574  
575         drm_plane_create_alpha_property(plane);
576  
577 +       /*
578 +        * Default frame buffer setup is with FB on -127, and raspistill etc
579 +        * tend to drop overlays on layer 2. Cursor plane was on layer +127.
580 +        *
581 +        * For F-KMS the mailbox call allows for a s8.
582 +        * Remap zpos 0 to -127 for the background layer, but leave all the
583 +        * other layers as requested by KMS.
584 +        */
585 +       switch (type) {
586 +       case DRM_PLANE_TYPE_PRIMARY:
587 +               default_zpos = 0;
588 +               break;
589 +       case DRM_PLANE_TYPE_OVERLAY:
590 +               default_zpos = 1;
591 +               break;
592 +       case DRM_PLANE_TYPE_CURSOR:
593 +               default_zpos = 2;
594 +               break;
595 +       }
596 +       drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
597 +
598 +       /* Prepare the static elements of the mailbox structure */
599 +       vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
600 +       vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
601 +       vc4_plane->mb.tag.req_resp_size = 0;
602 +       vc4_plane->mb.plane.display = 0;
603 +       vc4_plane->mb.plane.plane_id = plane_id;
604 +       vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
605 +
606         return plane;
607  fail:
608         if (plane)
609 @@ -401,19 +569,23 @@ static void vc4_crtc_disable(struct drm_
610          * whether anything scans out at all, but the firmware doesn't
611          * give us a CRTC-level control for that.
612          */
613 -       vc4_cursor_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
614 -       vc4_plane_set_primary_blank(crtc->primary, true);
615 +
616 +       vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state);
617 +       vc4_plane_atomic_disable(crtc->primary, crtc->primary->state);
618 +
619 +       /* FIXME: Disable overlay planes */
620  }
621  
622  static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
623  {
624         /* Unblank the planes (if they're supposed to be displayed). */
625 +
626         if (crtc->primary->state->fb)
627 -               vc4_plane_set_primary_blank(crtc->primary, false);
628 -       if (crtc->cursor->state->fb) {
629 -               vc4_cursor_plane_atomic_update(crtc->cursor,
630 -                                              crtc->cursor->state);
631 -       }
632 +               vc4_plane_set_blank(crtc->primary, false);
633 +       if (crtc->cursor->state->fb)
634 +               vc4_plane_set_blank(crtc->cursor, crtc->cursor->state);
635 +
636 +       /* FIXME: Enable overlay planes */
637  }
638  
639  static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
640 @@ -673,8 +845,10 @@ static int vc4_fkms_bind(struct device *
641         struct vc4_crtc *vc4_crtc;
642         struct vc4_fkms_encoder *vc4_encoder;
643         struct drm_crtc *crtc;
644 -       struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
645 +       struct drm_plane *primary_plane, *overlay_plane, *cursor_plane;
646 +       struct drm_plane *destroy_plane, *temp;
647         struct device_node *firmware_node;
648 +       u32 blank = 1;
649         int ret;
650  
651         vc4->firmware_kms = true;
652 @@ -703,20 +877,26 @@ static int vc4_fkms_bind(struct device *
653         if (IS_ERR(vc4_crtc->regs))
654                 return PTR_ERR(vc4_crtc->regs);
655  
656 -       /* For now, we create just the primary and the legacy cursor
657 -        * planes.  We should be able to stack more planes on easily,
658 -        * but to do that we would need to compute the bandwidth
659 -        * requirement of the plane configuration, and reject ones
660 -        * that will take too much.
661 -        */
662 -       primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
663 +       /* Blank the firmware provided framebuffer */
664 +       rpi_firmware_property(vc4->firmware,
665 +                             RPI_FIRMWARE_FRAMEBUFFER_BLANK,
666 +                             &blank, sizeof(blank));
667 +
668 +       primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
669         if (IS_ERR(primary_plane)) {
670                 dev_err(dev, "failed to construct primary plane\n");
671                 ret = PTR_ERR(primary_plane);
672                 goto err;
673         }
674  
675 -       cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
676 +       overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1);
677 +       if (IS_ERR(overlay_plane)) {
678 +               dev_err(dev, "failed to construct overlay plane\n");
679 +               ret = PTR_ERR(overlay_plane);
680 +               goto err;
681 +       }
682 +
683 +       cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2);
684         if (IS_ERR(cursor_plane)) {
685                 dev_err(dev, "failed to construct cursor plane\n");
686                 ret = PTR_ERR(cursor_plane);
687 --- a/drivers/gpu/drm/vc4/vc4_kms.c
688 +++ b/drivers/gpu/drm/vc4/vc4_kms.c
689 @@ -542,6 +542,7 @@ int vc4_kms_load(struct drm_device *dev)
690         dev->mode_config.preferred_depth = 24;
691         dev->mode_config.async_page_flip = true;
692         dev->mode_config.allow_fb_modifiers = true;
693 +       dev->mode_config.normalize_zpos = true;
694  
695         drm_modeset_lock_init(&vc4->ctm_state_lock);
696  
697 --- /dev/null
698 +++ b/drivers/gpu/drm/vc4/vc_image_types.h
699 @@ -0,0 +1,143 @@
700 +
701 +/*
702 + * Copyright (c) 2012, Broadcom Europe Ltd
703 + *
704 + * Values taken from vc_image_types.h released by Broadcom at
705 + * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
706 + *
707 + * This program is free software; you can redistribute it and/or modify
708 + * it under the terms of the GNU General Public License version 2 as
709 + * published by the Free Software Foundation.
710 + */
711 +
712 +enum {
713 +       VC_IMAGE_MIN = 0, //bounds for error checking
714 +
715 +       VC_IMAGE_RGB565 = 1,
716 +       VC_IMAGE_1BPP,
717 +       VC_IMAGE_YUV420,
718 +       VC_IMAGE_48BPP,
719 +       VC_IMAGE_RGB888,
720 +       VC_IMAGE_8BPP,
721 +       /* 4bpp palettised image */
722 +       VC_IMAGE_4BPP,
723 +       /* A separated format of 16 colour/light shorts followed by 16 z
724 +        * values
725 +        */
726 +       VC_IMAGE_3D32,
727 +       /* 16 colours followed by 16 z values */
728 +       VC_IMAGE_3D32B,
729 +       /* A separated format of 16 material/colour/light shorts followed by
730 +        * 16 z values
731 +        */
732 +       VC_IMAGE_3D32MAT,
733 +       /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
734 +       VC_IMAGE_RGB2X9,
735 +       /* 32-bit format holding 18 bits of 6.6.6 RGB */
736 +       VC_IMAGE_RGB666,
737 +       /* 4bpp palettised image with embedded palette */
738 +       VC_IMAGE_PAL4_OBSOLETE,
739 +       /* 8bpp palettised image with embedded palette */
740 +       VC_IMAGE_PAL8_OBSOLETE,
741 +       /* RGB888 with an alpha byte after each pixel */
742 +       VC_IMAGE_RGBA32,
743 +       /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
744 +        * line of V (16-byte padded)
745 +        */
746 +       VC_IMAGE_YUV422,
747 +       /* RGB565 with a transparent patch */
748 +       VC_IMAGE_RGBA565,
749 +       /* Compressed (4444) version of RGBA32 */
750 +       VC_IMAGE_RGBA16,
751 +       /* VCIII codec format */
752 +       VC_IMAGE_YUV_UV,
753 +       /* VCIII T-format RGBA8888 */
754 +       VC_IMAGE_TF_RGBA32,
755 +       /* VCIII T-format RGBx8888 */
756 +       VC_IMAGE_TF_RGBX32,
757 +       /* VCIII T-format float */
758 +       VC_IMAGE_TF_FLOAT,
759 +       /* VCIII T-format RGBA4444 */
760 +       VC_IMAGE_TF_RGBA16,
761 +       /* VCIII T-format RGB5551 */
762 +       VC_IMAGE_TF_RGBA5551,
763 +       /* VCIII T-format RGB565 */
764 +       VC_IMAGE_TF_RGB565,
765 +       /* VCIII T-format 8-bit luma and 8-bit alpha */
766 +       VC_IMAGE_TF_YA88,
767 +       /* VCIII T-format 8 bit generic sample */
768 +       VC_IMAGE_TF_BYTE,
769 +       /* VCIII T-format 8-bit palette */
770 +       VC_IMAGE_TF_PAL8,
771 +       /* VCIII T-format 4-bit palette */
772 +       VC_IMAGE_TF_PAL4,
773 +       /* VCIII T-format Ericsson Texture Compressed */
774 +       VC_IMAGE_TF_ETC1,
775 +       /* RGB888 with R & B swapped */
776 +       VC_IMAGE_BGR888,
777 +       /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
778 +        * each row of pixels
779 +        */
780 +       VC_IMAGE_BGR888_NP,
781 +       /* Bayer image, extra defines which variant is being used */
782 +       VC_IMAGE_BAYER,
783 +       /* General wrapper for codec images e.g. JPEG from camera */
784 +       VC_IMAGE_CODEC,
785 +       /* VCIII codec format */
786 +       VC_IMAGE_YUV_UV32,
787 +       /* VCIII T-format 8-bit luma */
788 +       VC_IMAGE_TF_Y8,
789 +       /* VCIII T-format 8-bit alpha */
790 +       VC_IMAGE_TF_A8,
791 +       /* VCIII T-format 16-bit generic sample */
792 +       VC_IMAGE_TF_SHORT,
793 +       /* VCIII T-format 1bpp black/white */
794 +       VC_IMAGE_TF_1BPP,
795 +       VC_IMAGE_OPENGL,
796 +       /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
797 +       VC_IMAGE_YUV444I,
798 +       /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
799 +        * a per line basis)
800 +        */
801 +       VC_IMAGE_YUV422PLANAR,
802 +       /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
803 +       VC_IMAGE_ARGB8888,
804 +       /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
805 +       VC_IMAGE_XRGB8888,
806 +
807 +       /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
808 +       VC_IMAGE_YUV422YUYV,
809 +       VC_IMAGE_YUV422YVYU,
810 +       VC_IMAGE_YUV422UYVY,
811 +       VC_IMAGE_YUV422VYUY,
812 +
813 +       /* 32bpp like RGBA32 but with unused alpha */
814 +       VC_IMAGE_RGBX32,
815 +       /* 32bpp, corresponding to RGBA with unused alpha */
816 +       VC_IMAGE_RGBX8888,
817 +       /* 32bpp, corresponding to BGRA with unused alpha */
818 +       VC_IMAGE_BGRX8888,
819 +
820 +       /* Y as a plane, then UV byte interleaved in plane with with same pitch,
821 +        * half height
822 +        */
823 +       VC_IMAGE_YUV420SP,
824 +
825 +       /* Y, U, & V planes separately 4:4:4 */
826 +       VC_IMAGE_YUV444PLANAR,
827 +
828 +       /* T-format 8-bit U - same as TF_Y8 buf from U plane */
829 +       VC_IMAGE_TF_U8,
830 +       /* T-format 8-bit U - same as TF_Y8 buf from V plane */
831 +       VC_IMAGE_TF_V8,
832 +
833 +       /* YUV4:2:0 planar, 16bit values */
834 +       VC_IMAGE_YUV420_16,
835 +       /* YUV4:2:0 codec format, 16bit values */
836 +       VC_IMAGE_YUV_UV_16,
837 +       /* YUV4:2:0 with U,V in side-by-side format */
838 +       VC_IMAGE_YUV420_S,
839 +
840 +       VC_IMAGE_MAX,     /* bounds for error checking */
841 +       VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
842 +};
843 --- a/include/soc/bcm2835/raspberrypi-firmware.h
844 +++ b/include/soc/bcm2835/raspberrypi-firmware.h
845 @@ -147,6 +147,8 @@ enum rpi_firmware_property_tag {
846  
847         RPI_FIRMWARE_VCHIQ_INIT =                             0x00048010,
848  
849 +       RPI_FIRMWARE_SET_PLANE =                              0x00048015,
850 +
851         RPI_FIRMWARE_GET_COMMAND_LINE =                       0x00050001,
852         RPI_FIRMWARE_GET_DMA_CHANNELS =                       0x00060001,
853  };