bcm27xx: add support for linux v5.15
[openwrt/staging/chunkeey.git] / target / linux / bcm27xx / patches-5.15 / 950-0452-drm-vc4-Add-firmware-kms-mode.patch
1 From 0396d0bd56a5c2941c02f858599de3b0cbc93c75 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Mon, 7 Sep 2020 17:32:27 +0100
4 Subject: [PATCH] drm/vc4: Add firmware-kms mode
5
6 This is a squash of all firmware-kms related patches from previous
7 branches, up to and including
8 "drm/vc4: Set the possible crtcs mask correctly for planes with FKMS"
9 plus a couple of minor fixups for the 5.9 branch.
10 Please refer to earlier branches for full history.
11
12 This patch includes work by Eric Anholt, James Hughes, Phil Elwell,
13 Dave Stevenson, Dom Cobley, and Jonathon Bell.
14
15 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
16
17 drm/vc4: Fixup firmware-kms after "drm/atomic: Pass the full state to CRTC atomic enable/disable"
18
19 Prototype for those calls changed, so amend fkms (which isn't
20 upstream) to match.
21
22 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
23
24 drm/vc4: Fixup fkms for API change
25
26 Atomic flush and check changed API, so fix up the downstream-only
27 FKMS driver.
28
29 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
30
31 drm/vc4: Make normalize_zpos conditional on using fkms
32
33 Eric's view was that there was no point in having zpos
34 support on vc4 as all the planes had the same functionality.
35
36 Can be later squashed into (and fixes):
37 drm/vc4: Add firmware-kms mode
38
39 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
40
41 drm/vc4: FKMS: Change of Broadcast RGB mode needs a mode change
42
43 The Broadcast RGB (aka HDMI limited/full range) property is only
44 notified to the firmware on mode change, so this needs to be
45 signalled when set.
46
47 https://github.com/raspberrypi/firmware/issues/1580
48
49 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
50
51 vc4/drv: Only notify firmware of display done with kms
52
53 fkms driver still wants firmware display to be active
54
55 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
56
57 ydrm/vc4: fkms: Fix margin calculations for the right/bottom edges
58
59 The calculations clipped the right/bottom edge of the clipped
60 range based on the left/top margins.
61
62 https://github.com/raspberrypi/linux/issues/4447
63
64 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
65
66 drm/vc4: fkms: Use new devm_rpi_firmware_get api
67
68 drm/kms: Add allow_fb_modifiers
69
70 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
71 ---
72 drivers/gpu/drm/vc4/Makefile | 1 +
73 drivers/gpu/drm/vc4/vc4_debugfs.c | 2 +-
74 drivers/gpu/drm/vc4/vc4_drv.c | 29 +-
75 drivers/gpu/drm/vc4/vc4_drv.h | 7 +
76 drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1994 ++++++++++++++++++++
77 drivers/gpu/drm/vc4/vc4_kms.c | 35 +-
78 drivers/gpu/drm/vc4/vc_image_types.h | 175 ++
79 include/soc/bcm2835/raspberrypi-firmware.h | 6 +
80 8 files changed, 2235 insertions(+), 14 deletions(-)
81 create mode 100644 drivers/gpu/drm/vc4/vc4_firmware_kms.c
82 create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h
83
84 --- a/drivers/gpu/drm/vc4/Makefile
85 +++ b/drivers/gpu/drm/vc4/Makefile
86 @@ -9,6 +9,7 @@ vc4-y := \
87 vc4_dpi.o \
88 vc4_dsi.o \
89 vc4_fence.o \
90 + vc4_firmware_kms.o \
91 vc4_kms.o \
92 vc4_gem.o \
93 vc4_hdmi.o \
94 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c
95 +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
96 @@ -27,7 +27,7 @@ vc4_debugfs_init(struct drm_minor *minor
97 struct vc4_dev *vc4 = to_vc4_dev(minor->dev);
98 struct vc4_debugfs_info_entry *entry;
99
100 - if (!of_device_is_compatible(vc4->hvs->pdev->dev.of_node,
101 + if (vc4->hvs && !of_device_is_compatible(vc4->hvs->pdev->dev.of_node,
102 "brcm,bcm2711-vc5"))
103 debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
104 minor->debugfs_root, &vc4->load_tracker_enabled);
105 --- a/drivers/gpu/drm/vc4/vc4_drv.c
106 +++ b/drivers/gpu/drm/vc4/vc4_drv.c
107 @@ -226,6 +226,18 @@ const struct of_device_id vc4_dma_range_
108 {}
109 };
110
111 +/*
112 + * we need this helper function for determining presence of fkms
113 + * before it's been bound
114 + */
115 +static bool firmware_kms(void)
116 +{
117 + return of_device_is_available(of_find_compatible_node(NULL, NULL,
118 + "raspberrypi,rpi-firmware-kms")) ||
119 + of_device_is_available(of_find_compatible_node(NULL, NULL,
120 + "raspberrypi,rpi-firmware-kms-2711"));
121 +}
122 +
123 static int vc4_drm_bind(struct device *dev)
124 {
125 struct platform_device *pdev = to_platform_device(dev);
126 @@ -289,7 +301,7 @@ static int vc4_drm_bind(struct device *d
127 if (ret)
128 return ret;
129
130 - if (firmware) {
131 + if (firmware && !firmware_kms()) {
132 ret = rpi_firmware_property(firmware,
133 RPI_FIRMWARE_NOTIFY_DISPLAY_DONE,
134 NULL, 0);
135 @@ -303,16 +315,20 @@ static int vc4_drm_bind(struct device *d
136 if (ret)
137 return ret;
138
139 - ret = vc4_plane_create_additional_planes(drm);
140 - if (ret)
141 - goto unbind_all;
142 + if (!vc4->firmware_kms) {
143 + ret = vc4_plane_create_additional_planes(drm);
144 + if (ret)
145 + goto unbind_all;
146 + }
147
148 ret = vc4_kms_load(drm);
149 if (ret < 0)
150 goto unbind_all;
151
152 - drm_for_each_crtc(crtc, drm)
153 - vc4_crtc_disable_at_boot(crtc);
154 + if (!vc4->firmware_kms) {
155 + drm_for_each_crtc(crtc, drm)
156 + vc4_crtc_disable_at_boot(crtc);
157 + }
158
159 ret = drm_dev_register(drm, 0);
160 if (ret < 0)
161 @@ -359,6 +375,7 @@ static struct platform_driver *const com
162 &vc4_dsi_driver,
163 &vc4_txp_driver,
164 &vc4_crtc_driver,
165 + &vc4_firmware_kms_driver,
166 &vc4_v3d_driver,
167 };
168
169 --- a/drivers/gpu/drm/vc4/vc4_drv.h
170 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
171 @@ -76,11 +76,15 @@ struct vc4_dev {
172
173 unsigned int irq;
174
175 + bool firmware_kms;
176 + struct rpi_firmware *firmware;
177 +
178 struct vc4_hvs *hvs;
179 struct vc4_v3d *v3d;
180 struct vc4_dpi *dpi;
181 struct vc4_vec *vec;
182 struct vc4_txp *txp;
183 + struct vc4_fkms *fkms;
184
185 struct vc4_hang_state *hang_state;
186
187 @@ -896,6 +900,9 @@ extern struct platform_driver vc4_dsi_dr
188 /* vc4_fence.c */
189 extern const struct dma_fence_ops vc4_fence_ops;
190
191 +/* vc4_firmware_kms.c */
192 +extern struct platform_driver vc4_firmware_kms_driver;
193 +
194 /* vc4_gem.c */
195 int vc4_gem_init(struct drm_device *dev);
196 int vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
197 --- /dev/null
198 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
199 @@ -0,0 +1,1994 @@
200 +// SPDX-License-Identifier: GPL-2.0-only
201 +/*
202 + * Copyright (C) 2016 Broadcom
203 + *
204 + * This program is free software; you can redistribute it and/or modify
205 + * it under the terms of the GNU General Public License version 2 as
206 + * published by the Free Software Foundation.
207 + */
208 +
209 +/**
210 + * DOC: VC4 firmware KMS module.
211 + *
212 + * As a hack to get us from the current closed source driver world
213 + * toward a totally open stack, implement KMS on top of the Raspberry
214 + * Pi's firmware display stack.
215 + */
216 +
217 +#include <drm/drm_atomic_helper.h>
218 +#include <drm/drm_crtc_helper.h>
219 +#include <drm/drm_drv.h>
220 +#include <drm/drm_fb_cma_helper.h>
221 +#include <drm/drm_fourcc.h>
222 +#include <drm/drm_gem_atomic_helper.h>
223 +#include <drm/drm_plane_helper.h>
224 +#include <drm/drm_probe_helper.h>
225 +#include <drm/drm_vblank.h>
226 +
227 +#include <linux/component.h>
228 +#include <linux/clk.h>
229 +#include <linux/debugfs.h>
230 +#include <linux/module.h>
231 +
232 +#include <soc/bcm2835/raspberrypi-firmware.h>
233 +
234 +#include "vc4_drv.h"
235 +#include "vc4_regs.h"
236 +#include "vc_image_types.h"
237 +
238 +int fkms_max_refresh_rate = 85;
239 +module_param(fkms_max_refresh_rate, int, 0644);
240 +MODULE_PARM_DESC(fkms_max_refresh_rate, "Max supported refresh rate");
241 +
242 +struct get_display_cfg {
243 + u32 max_pixel_clock[2]; //Max pixel clock for each display
244 +};
245 +
246 +struct vc4_fkms {
247 + struct get_display_cfg cfg;
248 + bool bcm2711;
249 +};
250 +
251 +#define PLANES_PER_CRTC 8
252 +
253 +struct set_plane {
254 + u8 display;
255 + u8 plane_id;
256 + u8 vc_image_type;
257 + s8 layer;
258 +
259 + u16 width;
260 + u16 height;
261 +
262 + u16 pitch;
263 + u16 vpitch;
264 +
265 + u32 src_x; /* 16p16 */
266 + u32 src_y; /* 16p16 */
267 +
268 + u32 src_w; /* 16p16 */
269 + u32 src_h; /* 16p16 */
270 +
271 + s16 dst_x;
272 + s16 dst_y;
273 +
274 + u16 dst_w;
275 + u16 dst_h;
276 +
277 + u8 alpha;
278 + u8 num_planes;
279 + u8 is_vu;
280 + u8 color_encoding;
281 +
282 + u32 planes[4]; /* DMA address of each plane */
283 +
284 + u32 transform;
285 +};
286 +
287 +/* Values for the transform field */
288 +#define TRANSFORM_NO_ROTATE 0
289 +#define TRANSFORM_ROTATE_180 BIT(1)
290 +#define TRANSFORM_FLIP_HRIZ BIT(16)
291 +#define TRANSFORM_FLIP_VERT BIT(17)
292 +
293 +struct mailbox_set_plane {
294 + struct rpi_firmware_property_tag_header tag;
295 + struct set_plane plane;
296 +};
297 +
298 +struct mailbox_blank_display {
299 + struct rpi_firmware_property_tag_header tag1;
300 + u32 display;
301 + struct rpi_firmware_property_tag_header tag2;
302 + u32 blank;
303 +};
304 +
305 +struct mailbox_display_pwr {
306 + struct rpi_firmware_property_tag_header tag1;
307 + u32 display;
308 + u32 state;
309 +};
310 +
311 +struct mailbox_get_edid {
312 + struct rpi_firmware_property_tag_header tag1;
313 + u32 block;
314 + u32 display_number;
315 + u8 edid[128];
316 +};
317 +
318 +struct set_timings {
319 + u8 display;
320 + u8 padding;
321 + u16 video_id_code;
322 +
323 + u32 clock; /* in kHz */
324 +
325 + u16 hdisplay;
326 + u16 hsync_start;
327 +
328 + u16 hsync_end;
329 + u16 htotal;
330 +
331 + u16 hskew;
332 + u16 vdisplay;
333 +
334 + u16 vsync_start;
335 + u16 vsync_end;
336 +
337 + u16 vtotal;
338 + u16 vscan;
339 +
340 + u16 vrefresh;
341 + u16 padding2;
342 +
343 + u32 flags;
344 +#define TIMINGS_FLAGS_H_SYNC_POS BIT(0)
345 +#define TIMINGS_FLAGS_H_SYNC_NEG 0
346 +#define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
347 +#define TIMINGS_FLAGS_V_SYNC_NEG 0
348 +#define TIMINGS_FLAGS_INTERLACE BIT(2)
349 +
350 +#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
351 +#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
352 +#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4)
353 +#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4)
354 +#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4)
355 +#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4)
356 +
357 +/* Limited range RGB flag. Not set corresponds to full range. */
358 +#define TIMINGS_FLAGS_RGB_LIMITED BIT(8)
359 +/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */
360 +#define TIMINGS_FLAGS_DVI BIT(9)
361 +/* Double clock */
362 +#define TIMINGS_FLAGS_DBL_CLK BIT(10)
363 +};
364 +
365 +struct mailbox_set_mode {
366 + struct rpi_firmware_property_tag_header tag1;
367 + struct set_timings timings;
368 +};
369 +
370 +static const struct vc_image_format {
371 + u32 drm; /* DRM_FORMAT_* */
372 + u32 vc_image; /* VC_IMAGE_* */
373 + u32 is_vu;
374 +} vc_image_formats[] = {
375 + {
376 + .drm = DRM_FORMAT_XRGB8888,
377 + .vc_image = VC_IMAGE_XRGB8888,
378 + },
379 + {
380 + .drm = DRM_FORMAT_ARGB8888,
381 + .vc_image = VC_IMAGE_ARGB8888,
382 + },
383 +/*
384 + * FIXME: Need to resolve which DRM format goes to which vc_image format
385 + * for the remaining RGBA and RGBX formats.
386 + * {
387 + * .drm = DRM_FORMAT_ABGR8888,
388 + * .vc_image = VC_IMAGE_RGBA8888,
389 + * },
390 + * {
391 + * .drm = DRM_FORMAT_XBGR8888,
392 + * .vc_image = VC_IMAGE_RGBA8888,
393 + * },
394 + */
395 + {
396 + .drm = DRM_FORMAT_RGB565,
397 + .vc_image = VC_IMAGE_RGB565,
398 + },
399 + {
400 + .drm = DRM_FORMAT_RGB888,
401 + .vc_image = VC_IMAGE_BGR888,
402 + },
403 + {
404 + .drm = DRM_FORMAT_BGR888,
405 + .vc_image = VC_IMAGE_RGB888,
406 + },
407 + {
408 + .drm = DRM_FORMAT_YUV422,
409 + .vc_image = VC_IMAGE_YUV422PLANAR,
410 + },
411 + {
412 + .drm = DRM_FORMAT_YUV420,
413 + .vc_image = VC_IMAGE_YUV420,
414 + },
415 + {
416 + .drm = DRM_FORMAT_YVU420,
417 + .vc_image = VC_IMAGE_YUV420,
418 + .is_vu = 1,
419 + },
420 + {
421 + .drm = DRM_FORMAT_NV12,
422 + .vc_image = VC_IMAGE_YUV420SP,
423 + },
424 + {
425 + .drm = DRM_FORMAT_NV21,
426 + .vc_image = VC_IMAGE_YUV420SP,
427 + .is_vu = 1,
428 + },
429 + {
430 + .drm = DRM_FORMAT_P030,
431 + .vc_image = VC_IMAGE_YUV10COL,
432 + },
433 +};
434 +
435 +static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
436 +{
437 + unsigned int i;
438 +
439 + for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
440 + if (vc_image_formats[i].drm == drm_format)
441 + return &vc_image_formats[i];
442 + }
443 +
444 + return NULL;
445 +}
446 +
447 +/* The firmware delivers a vblank interrupt to us through the SMI
448 + * hardware, which has only this one register.
449 + */
450 +#define SMICS 0x0
451 +#define SMIDSW0 0x14
452 +#define SMIDSW1 0x1C
453 +#define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
454 +
455 +/* Flag to denote that the firmware is giving multiple display callbacks */
456 +#define SMI_NEW 0xabcd0000
457 +
458 +#define vc4_crtc vc4_kms_crtc
459 +#define to_vc4_crtc to_vc4_kms_crtc
460 +struct vc4_crtc {
461 + struct drm_crtc base;
462 + struct drm_encoder *encoder;
463 + struct drm_connector *connector;
464 + void __iomem *regs;
465 +
466 + struct drm_pending_vblank_event *event;
467 + bool vblank_enabled;
468 + u32 display_number;
469 + u32 display_type;
470 +};
471 +
472 +static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
473 +{
474 + return container_of(crtc, struct vc4_crtc, base);
475 +}
476 +
477 +struct vc4_fkms_encoder {
478 + struct drm_encoder base;
479 + bool hdmi_monitor;
480 + bool rgb_range_selectable;
481 + int display_num;
482 +};
483 +
484 +static inline struct vc4_fkms_encoder *
485 +to_vc4_fkms_encoder(struct drm_encoder *encoder)
486 +{
487 + return container_of(encoder, struct vc4_fkms_encoder, base);
488 +}
489 +
490 +/* "Broadcast RGB" property.
491 + * Allows overriding of HDMI full or limited range RGB
492 + */
493 +#define VC4_BROADCAST_RGB_AUTO 0
494 +#define VC4_BROADCAST_RGB_FULL 1
495 +#define VC4_BROADCAST_RGB_LIMITED 2
496 +
497 +/* VC4 FKMS connector KMS struct */
498 +struct vc4_fkms_connector {
499 + struct drm_connector base;
500 +
501 + /* Since the connector is attached to just the one encoder,
502 + * this is the reference to it so we can do the best_encoder()
503 + * hook.
504 + */
505 + struct drm_encoder *encoder;
506 + struct vc4_dev *vc4_dev;
507 + u32 display_number;
508 + u32 display_type;
509 +
510 + struct drm_property *broadcast_rgb_property;
511 +};
512 +
513 +static inline struct vc4_fkms_connector *
514 +to_vc4_fkms_connector(struct drm_connector *connector)
515 +{
516 + return container_of(connector, struct vc4_fkms_connector, base);
517 +}
518 +
519 +/* VC4 FKMS connector state */
520 +struct vc4_fkms_connector_state {
521 + struct drm_connector_state base;
522 +
523 + int broadcast_rgb;
524 +};
525 +
526 +#define to_vc4_fkms_connector_state(x) \
527 + container_of(x, struct vc4_fkms_connector_state, base)
528 +
529 +static u32 vc4_get_display_type(u32 display_number)
530 +{
531 + const u32 display_types[] = {
532 + /* The firmware display (DispmanX) IDs map to specific types in
533 + * a fixed manner.
534 + */
535 + DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */
536 + DRM_MODE_ENCODER_DSI, /* AUX_LCD */
537 + DRM_MODE_ENCODER_TMDS, /* HDMI0 */
538 + DRM_MODE_ENCODER_TVDAC, /* VEC */
539 + DRM_MODE_ENCODER_NONE, /* FORCE_LCD */
540 + DRM_MODE_ENCODER_NONE, /* FORCE_TV */
541 + DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */
542 + DRM_MODE_ENCODER_TMDS, /* HDMI1 */
543 + DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */
544 + };
545 + return display_number > ARRAY_SIZE(display_types) - 1 ?
546 + DRM_MODE_ENCODER_NONE : display_types[display_number];
547 +}
548 +
549 +/* Firmware's structure for making an FB mbox call. */
550 +struct fbinfo_s {
551 + u32 xres, yres, xres_virtual, yres_virtual;
552 + u32 pitch, bpp;
553 + u32 xoffset, yoffset;
554 + u32 base;
555 + u32 screen_size;
556 + u16 cmap[256];
557 +};
558 +
559 +struct vc4_fkms_plane {
560 + struct drm_plane base;
561 + struct fbinfo_s *fbinfo;
562 + dma_addr_t fbinfo_bus_addr;
563 + u32 pitch;
564 + struct mailbox_set_plane mb;
565 +};
566 +
567 +static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
568 +{
569 + return (struct vc4_fkms_plane *)plane;
570 +}
571 +
572 +static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
573 +{
574 + struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
575 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
576 + struct mailbox_set_plane blank_mb = {
577 + .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
578 + .plane = {
579 + .display = vc4_plane->mb.plane.display,
580 + .plane_id = vc4_plane->mb.plane.plane_id,
581 + }
582 + };
583 + static const char * const plane_types[] = {
584 + "overlay",
585 + "primary",
586 + "cursor"
587 + };
588 + int ret;
589 +
590 + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
591 + plane->base.id, plane->name, plane_types[plane->type],
592 + blank ? "blank" : "unblank");
593 +
594 + if (blank)
595 + ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
596 + sizeof(blank_mb));
597 + else
598 + ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
599 + sizeof(vc4_plane->mb));
600 +
601 + WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
602 + __func__);
603 + return ret;
604 +}
605 +
606 +static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
607 + unsigned int *left, unsigned int *right,
608 + unsigned int *top, unsigned int *bottom)
609 +{
610 + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
611 + struct drm_connector_state *conn_state;
612 + struct drm_connector *conn;
613 + int i;
614 +
615 + *left = vc4_state->margins.left;
616 + *right = vc4_state->margins.right;
617 + *top = vc4_state->margins.top;
618 + *bottom = vc4_state->margins.bottom;
619 +
620 + /* We have to interate over all new connector states because
621 + * vc4_fkms_crtc_get_margins() might be called before
622 + * vc4_fkms_crtc_atomic_check() which means margins info in
623 + * vc4_crtc_state might be outdated.
624 + */
625 + for_each_new_connector_in_state(state->state, conn, conn_state, i) {
626 + if (conn_state->crtc != state->crtc)
627 + continue;
628 +
629 + *left = conn_state->tv.margins.left;
630 + *right = conn_state->tv.margins.right;
631 + *top = conn_state->tv.margins.top;
632 + *bottom = conn_state->tv.margins.bottom;
633 + break;
634 + }
635 +}
636 +
637 +static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
638 + struct set_plane *plane)
639 +{
640 + unsigned int left, right, top, bottom;
641 + int adjhdisplay, adjvdisplay;
642 + struct drm_crtc_state *crtc_state;
643 +
644 + crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
645 + pstate->crtc);
646 +
647 + vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
648 +
649 + if (!left && !right && !top && !bottom)
650 + return 0;
651 +
652 + if (left + right >= crtc_state->mode.hdisplay ||
653 + top + bottom >= crtc_state->mode.vdisplay)
654 + return -EINVAL;
655 +
656 + adjhdisplay = crtc_state->mode.hdisplay - (left + right);
657 + plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
658 + (int)crtc_state->mode.hdisplay);
659 + plane->dst_x += left;
660 + if (plane->dst_x > (int)(crtc_state->mode.hdisplay - right))
661 + plane->dst_x = crtc_state->mode.hdisplay - right;
662 +
663 + adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
664 + plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
665 + (int)crtc_state->mode.vdisplay);
666 + plane->dst_y += top;
667 + if (plane->dst_y > (int)(crtc_state->mode.vdisplay - bottom))
668 + plane->dst_y = crtc_state->mode.vdisplay - bottom;
669 +
670 + plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
671 + crtc_state->mode.hdisplay);
672 + plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
673 + crtc_state->mode.vdisplay);
674 +
675 + if (!plane->dst_w || !plane->dst_h)
676 + return -EINVAL;
677 +
678 + return 0;
679 +}
680 +
681 +static void vc4_plane_atomic_update(struct drm_plane *plane,
682 + struct drm_atomic_state *old_state)
683 +{
684 + struct drm_plane_state *state = plane->state;
685 +
686 + /*
687 + * Do NOT set now, as we haven't checked if the crtc is active or not.
688 + * Set from vc4_plane_set_blank instead.
689 + *
690 + * If the CRTC is on (or going to be on) and we're enabled,
691 + * then unblank. Otherwise, stay blank until CRTC enable.
692 + */
693 + if (state->crtc->state->active)
694 + vc4_plane_set_blank(plane, false);
695 +}
696 +
697 +static void vc4_plane_atomic_disable(struct drm_plane *plane,
698 + struct drm_atomic_state *old_state)
699 +{
700 + struct drm_plane_state *state = plane->state;
701 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
702 +
703 + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
704 + plane->base.id, plane->name,
705 + state->crtc_w,
706 + state->crtc_h,
707 + vc4_plane->mb.plane.vc_image_type,
708 + state->crtc_x,
709 + state->crtc_y);
710 + vc4_plane_set_blank(plane, true);
711 +}
712 +
713 +static bool plane_enabled(struct drm_plane_state *state)
714 +{
715 + return state->fb && state->crtc;
716 +}
717 +
718 +static int vc4_plane_to_mb(struct drm_plane *plane,
719 + struct mailbox_set_plane *mb,
720 + struct drm_plane_state *state)
721 +{
722 + struct drm_framebuffer *fb = state->fb;
723 + struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
724 + const struct drm_format_info *drm_fmt = fb->format;
725 + const struct vc_image_format *vc_fmt =
726 + vc4_get_vc_image_fmt(drm_fmt->format);
727 + int num_planes = fb->format->num_planes;
728 + unsigned int rotation;
729 +
730 + mb->plane.vc_image_type = vc_fmt->vc_image;
731 + mb->plane.width = fb->width;
732 + mb->plane.height = fb->height;
733 + mb->plane.pitch = fb->pitches[0];
734 + mb->plane.src_w = state->src_w;
735 + mb->plane.src_h = state->src_h;
736 + mb->plane.src_x = state->src_x;
737 + mb->plane.src_y = state->src_y;
738 + mb->plane.dst_w = state->crtc_w;
739 + mb->plane.dst_h = state->crtc_h;
740 + mb->plane.dst_x = state->crtc_x;
741 + mb->plane.dst_y = state->crtc_y;
742 + mb->plane.alpha = state->alpha >> 8;
743 + mb->plane.layer = state->normalized_zpos ?
744 + state->normalized_zpos : -127;
745 + mb->plane.num_planes = num_planes;
746 + mb->plane.is_vu = vc_fmt->is_vu;
747 + mb->plane.planes[0] = bo->paddr + fb->offsets[0];
748 +
749 + rotation = drm_rotation_simplify(state->rotation,
750 + DRM_MODE_ROTATE_0 |
751 + DRM_MODE_REFLECT_X |
752 + DRM_MODE_REFLECT_Y);
753 +
754 + mb->plane.transform = TRANSFORM_NO_ROTATE;
755 + if (rotation & DRM_MODE_REFLECT_X)
756 + mb->plane.transform |= TRANSFORM_FLIP_HRIZ;
757 + if (rotation & DRM_MODE_REFLECT_Y)
758 + mb->plane.transform |= TRANSFORM_FLIP_VERT;
759 +
760 + vc4_fkms_margins_adj(state, &mb->plane);
761 +
762 + if (num_planes > 1) {
763 + /* Assume this must be YUV */
764 + /* Makes assumptions on the stride for the chroma planes as we
765 + * can't easily plumb in non-standard pitches.
766 + */
767 + mb->plane.planes[1] = bo->paddr + fb->offsets[1];
768 + if (num_planes > 2)
769 + mb->plane.planes[2] = bo->paddr + fb->offsets[2];
770 + else
771 + mb->plane.planes[2] = 0;
772 +
773 + /* Special case the YUV420 with U and V as line interleaved
774 + * planes as we have special handling for that case.
775 + */
776 + if (num_planes == 3 &&
777 + (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
778 + mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
779 +
780 + switch (state->color_encoding) {
781 + default:
782 + case DRM_COLOR_YCBCR_BT601:
783 + if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE)
784 + mb->plane.color_encoding =
785 + VC_IMAGE_YUVINFO_CSC_ITUR_BT601;
786 + else
787 + mb->plane.color_encoding =
788 + VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
789 + break;
790 + case DRM_COLOR_YCBCR_BT709:
791 + /* Currently no support for a full range BT709 */
792 + mb->plane.color_encoding =
793 + VC_IMAGE_YUVINFO_CSC_ITUR_BT709;
794 + break;
795 + case DRM_COLOR_YCBCR_BT2020:
796 + /* Currently no support for a full range BT2020 */
797 + mb->plane.color_encoding =
798 + VC_IMAGE_YUVINFO_CSC_REC_2020;
799 + break;
800 + }
801 + } else {
802 + mb->plane.planes[1] = 0;
803 + mb->plane.planes[2] = 0;
804 + }
805 + mb->plane.planes[3] = 0;
806 +
807 + switch (fourcc_mod_broadcom_mod(fb->modifier)) {
808 + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
809 + switch (mb->plane.vc_image_type) {
810 + case VC_IMAGE_XRGB8888:
811 + mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
812 + break;
813 + case VC_IMAGE_ARGB8888:
814 + mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
815 + break;
816 + case VC_IMAGE_RGB565:
817 + mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
818 + break;
819 + }
820 + break;
821 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
822 + switch (mb->plane.vc_image_type) {
823 + case VC_IMAGE_YUV420SP:
824 + mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
825 + break;
826 + /* VC_IMAGE_YUV10COL could be included in here, but it is only
827 + * valid as a SAND128 format, so the table at the top will have
828 + * already set the correct format.
829 + */
830 + }
831 + /* Note that the column pitch is passed across in lines, not
832 + * bytes.
833 + */
834 + mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
835 + break;
836 + }
837 +
838 + 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",
839 + plane->base.id, plane->name,
840 + mb->plane.width,
841 + mb->plane.height,
842 + mb->plane.vc_image_type,
843 + state->crtc_x,
844 + state->crtc_y,
845 + state->crtc_w,
846 + state->crtc_h,
847 + mb->plane.src_x,
848 + mb->plane.src_y,
849 + mb->plane.src_w,
850 + mb->plane.src_h,
851 + mb->plane.planes[0],
852 + mb->plane.planes[1],
853 + mb->plane.planes[2],
854 + fb->pitches[0],
855 + state->alpha,
856 + state->normalized_zpos);
857 +
858 + return 0;
859 +}
860 +
861 +static int vc4_plane_atomic_check(struct drm_plane *plane,
862 + struct drm_atomic_state *state)
863 +{
864 + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
865 + plane);
866 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
867 +
868 + if (!plane_enabled(new_plane_state))
869 + return 0;
870 +
871 + return vc4_plane_to_mb(plane, &vc4_plane->mb, new_plane_state);
872 +}
873 +
874 +/* Called during init to allocate the plane's atomic state. */
875 +static void vc4_plane_reset(struct drm_plane *plane)
876 +{
877 + struct vc4_plane_state *vc4_state;
878 +
879 + WARN_ON(plane->state);
880 +
881 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
882 + if (!vc4_state)
883 + return;
884 +
885 + __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
886 +}
887 +
888 +static void vc4_plane_destroy(struct drm_plane *plane)
889 +{
890 + drm_plane_cleanup(plane);
891 +}
892 +
893 +static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
894 + uint32_t format,
895 + uint64_t modifier)
896 +{
897 + /* Support T_TILING for RGB formats only. */
898 + switch (format) {
899 + case DRM_FORMAT_XRGB8888:
900 + case DRM_FORMAT_ARGB8888:
901 + case DRM_FORMAT_RGB565:
902 + switch (modifier) {
903 + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
904 + case DRM_FORMAT_MOD_LINEAR:
905 + return true;
906 + default:
907 + return false;
908 + }
909 + case DRM_FORMAT_NV12:
910 + switch (fourcc_mod_broadcom_mod(modifier)) {
911 + case DRM_FORMAT_MOD_LINEAR:
912 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
913 + return true;
914 + default:
915 + return false;
916 + }
917 + case DRM_FORMAT_P030:
918 + switch (fourcc_mod_broadcom_mod(modifier)) {
919 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
920 + return true;
921 + default:
922 + return false;
923 + }
924 + case DRM_FORMAT_NV21:
925 + case DRM_FORMAT_RGB888:
926 + case DRM_FORMAT_BGR888:
927 + case DRM_FORMAT_YUV422:
928 + case DRM_FORMAT_YUV420:
929 + case DRM_FORMAT_YVU420:
930 + default:
931 + return (modifier == DRM_FORMAT_MOD_LINEAR);
932 + }
933 +}
934 +
935 +static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
936 +{
937 + struct vc4_plane_state *vc4_state;
938 +
939 + if (WARN_ON(!plane->state))
940 + return NULL;
941 +
942 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
943 + if (!vc4_state)
944 + return NULL;
945 +
946 + __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
947 +
948 + return &vc4_state->base;
949 +}
950 +
951 +static const struct drm_plane_funcs vc4_plane_funcs = {
952 + .update_plane = drm_atomic_helper_update_plane,
953 + .disable_plane = drm_atomic_helper_disable_plane,
954 + .destroy = vc4_plane_destroy,
955 + .set_property = NULL,
956 + .reset = vc4_plane_reset,
957 + .atomic_duplicate_state = vc4_plane_duplicate_state,
958 + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
959 + .format_mod_supported = vc4_fkms_format_mod_supported,
960 +};
961 +
962 +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
963 + .prepare_fb = drm_gem_plane_helper_prepare_fb,
964 + .cleanup_fb = NULL,
965 + .atomic_check = vc4_plane_atomic_check,
966 + .atomic_update = vc4_plane_atomic_update,
967 + .atomic_disable = vc4_plane_atomic_disable,
968 +};
969 +
970 +static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
971 + enum drm_plane_type type,
972 + u8 display_num,
973 + u8 plane_id)
974 +{
975 + struct drm_plane *plane = NULL;
976 + struct vc4_fkms_plane *vc4_plane;
977 + u32 formats[ARRAY_SIZE(vc_image_formats)];
978 + unsigned int default_zpos = 0;
979 + u32 num_formats = 0;
980 + int ret = 0;
981 + static const uint64_t modifiers[] = {
982 + DRM_FORMAT_MOD_LINEAR,
983 + /* VC4_T_TILED should come after linear, because we
984 + * would prefer to scan out linear (less bus traffic).
985 + */
986 + DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
987 + DRM_FORMAT_MOD_BROADCOM_SAND128,
988 + DRM_FORMAT_MOD_INVALID,
989 + };
990 + int i;
991 +
992 + vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
993 + GFP_KERNEL);
994 + if (!vc4_plane) {
995 + ret = -ENOMEM;
996 + goto fail;
997 + }
998 +
999 + for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
1000 + formats[num_formats++] = vc_image_formats[i].drm;
1001 +
1002 + plane = &vc4_plane->base;
1003 + ret = drm_universal_plane_init(dev, plane, 0,
1004 + &vc4_plane_funcs,
1005 + formats, num_formats, modifiers,
1006 + type, NULL);
1007 +
1008 + /* FIXME: Do we need to be checking return values from all these calls?
1009 + */
1010 + drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
1011 +
1012 + drm_plane_create_alpha_property(plane);
1013 + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
1014 + DRM_MODE_ROTATE_0 |
1015 + DRM_MODE_ROTATE_180 |
1016 + DRM_MODE_REFLECT_X |
1017 + DRM_MODE_REFLECT_Y);
1018 + drm_plane_create_color_properties(plane,
1019 + BIT(DRM_COLOR_YCBCR_BT601) |
1020 + BIT(DRM_COLOR_YCBCR_BT709) |
1021 + BIT(DRM_COLOR_YCBCR_BT2020),
1022 + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
1023 + BIT(DRM_COLOR_YCBCR_FULL_RANGE),
1024 + DRM_COLOR_YCBCR_BT709,
1025 + DRM_COLOR_YCBCR_LIMITED_RANGE);
1026 +
1027 + /*
1028 + * Default frame buffer setup is with FB on -127, and raspistill etc
1029 + * tend to drop overlays on layer 2. Cursor plane was on layer +127.
1030 + *
1031 + * For F-KMS the mailbox call allows for a s8.
1032 + * Remap zpos 0 to -127 for the background layer, but leave all the
1033 + * other layers as requested by KMS.
1034 + */
1035 + switch (type) {
1036 + default:
1037 + case DRM_PLANE_TYPE_PRIMARY:
1038 + default_zpos = 0;
1039 + break;
1040 + case DRM_PLANE_TYPE_OVERLAY:
1041 + default_zpos = 1;
1042 + break;
1043 + case DRM_PLANE_TYPE_CURSOR:
1044 + default_zpos = 2;
1045 + break;
1046 + }
1047 + drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
1048 +
1049 + /* Prepare the static elements of the mailbox structure */
1050 + vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
1051 + vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
1052 + vc4_plane->mb.tag.req_resp_size = 0;
1053 + vc4_plane->mb.plane.display = display_num;
1054 + vc4_plane->mb.plane.plane_id = plane_id;
1055 + vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
1056 +
1057 + return plane;
1058 +fail:
1059 + if (plane)
1060 + vc4_plane_destroy(plane);
1061 +
1062 + return ERR_PTR(ret);
1063 +}
1064 +
1065 +static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
1066 +{
1067 + struct drm_device *dev = crtc->dev;
1068 + struct vc4_dev *vc4 = to_vc4_dev(dev);
1069 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1070 + struct drm_display_mode *mode = &crtc->state->adjusted_mode;
1071 + struct vc4_fkms_encoder *vc4_encoder =
1072 + to_vc4_fkms_encoder(vc4_crtc->encoder);
1073 + struct mailbox_set_mode mb = {
1074 + .tag1 = { RPI_FIRMWARE_SET_TIMING,
1075 + sizeof(struct set_timings), 0},
1076 + };
1077 + union hdmi_infoframe frame;
1078 + int ret;
1079 +
1080 + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode);
1081 + if (ret < 0) {
1082 + DRM_ERROR("couldn't fill AVI infoframe\n");
1083 + return;
1084 + }
1085 +
1086 + DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n",
1087 + vc4_crtc->display_number, mode->name, mode->clock,
1088 + mode->hdisplay, mode->hsync_start, mode->hsync_end,
1089 + mode->htotal, mode->hskew, mode->vdisplay,
1090 + mode->vsync_start, mode->vsync_end, mode->vtotal,
1091 + mode->vscan, drm_mode_vrefresh(mode),
1092 + mode->picture_aspect_ratio, mode->flags);
1093 + mb.timings.display = vc4_crtc->display_number;
1094 +
1095 + mb.timings.clock = mode->clock;
1096 + mb.timings.hdisplay = mode->hdisplay;
1097 + mb.timings.hsync_start = mode->hsync_start;
1098 + mb.timings.hsync_end = mode->hsync_end;
1099 + mb.timings.htotal = mode->htotal;
1100 + mb.timings.hskew = mode->hskew;
1101 + mb.timings.vdisplay = mode->vdisplay;
1102 + mb.timings.vsync_start = mode->vsync_start;
1103 + mb.timings.vsync_end = mode->vsync_end;
1104 + mb.timings.vtotal = mode->vtotal;
1105 + mb.timings.vscan = mode->vscan;
1106 + mb.timings.vrefresh = drm_mode_vrefresh(mode);
1107 + mb.timings.flags = 0;
1108 + if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1109 + mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
1110 + if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1111 + mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS;
1112 +
1113 + switch (frame.avi.picture_aspect) {
1114 + default:
1115 + case HDMI_PICTURE_ASPECT_NONE:
1116 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
1117 + break;
1118 + case HDMI_PICTURE_ASPECT_4_3:
1119 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
1120 + break;
1121 + case HDMI_PICTURE_ASPECT_16_9:
1122 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
1123 + break;
1124 + case HDMI_PICTURE_ASPECT_64_27:
1125 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
1126 + break;
1127 + case HDMI_PICTURE_ASPECT_256_135:
1128 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
1129 + break;
1130 + }
1131 +
1132 + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1133 + mb.timings.flags |= TIMINGS_FLAGS_INTERLACE;
1134 + if (mode->flags & DRM_MODE_FLAG_DBLCLK)
1135 + mb.timings.flags |= TIMINGS_FLAGS_DBL_CLK;
1136 +
1137 + mb.timings.video_id_code = frame.avi.video_code;
1138 +
1139 + if (!vc4_encoder->hdmi_monitor) {
1140 + mb.timings.flags |= TIMINGS_FLAGS_DVI;
1141 + } else {
1142 + struct vc4_fkms_connector_state *conn_state =
1143 + to_vc4_fkms_connector_state(vc4_crtc->connector->state);
1144 +
1145 + if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
1146 + /* See CEA-861-E - 5.1 Default Encoding Parameters */
1147 + if (drm_default_rgb_quant_range(mode) ==
1148 + HDMI_QUANTIZATION_RANGE_LIMITED)
1149 + mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
1150 + } else {
1151 + if (conn_state->broadcast_rgb ==
1152 + VC4_BROADCAST_RGB_LIMITED)
1153 + mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
1154 +
1155 + /* If not using the default range, then do not provide
1156 + * a VIC as the HDMI spec requires that we do not
1157 + * signal the opposite of the defined range in the AVI
1158 + * infoframe.
1159 + */
1160 + if (!!(mb.timings.flags & TIMINGS_FLAGS_RGB_LIMITED) !=
1161 + (drm_default_rgb_quant_range(mode) ==
1162 + HDMI_QUANTIZATION_RANGE_LIMITED))
1163 + mb.timings.video_id_code = 0;
1164 + }
1165 + }
1166 +
1167 + /*
1168 + * FIXME: To implement
1169 + * switch(mode->flag & DRM_MODE_FLAG_3D_MASK) {
1170 + * case DRM_MODE_FLAG_3D_NONE:
1171 + * case DRM_MODE_FLAG_3D_FRAME_PACKING:
1172 + * case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
1173 + * case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
1174 + * case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
1175 + * case DRM_MODE_FLAG_3D_L_DEPTH:
1176 + * case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
1177 + * case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1178 + * case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1179 + * }
1180 + */
1181 +
1182 + ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
1183 +}
1184 +
1185 +static void vc4_crtc_disable(struct drm_crtc *crtc,
1186 + struct drm_atomic_state *state)
1187 +{
1188 + struct drm_device *dev = crtc->dev;
1189 + struct drm_plane *plane;
1190 +
1191 + DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
1192 + crtc->base.id);
1193 + drm_crtc_vblank_off(crtc);
1194 +
1195 + /* Always turn the planes off on CRTC disable. In DRM, planes
1196 + * are enabled/disabled through the update/disable hooks
1197 + * above, and the CRTC enable/disable independently controls
1198 + * whether anything scans out at all, but the firmware doesn't
1199 + * give us a CRTC-level control for that.
1200 + */
1201 +
1202 + drm_atomic_crtc_for_each_plane(plane, crtc)
1203 + vc4_plane_atomic_disable(plane, state);
1204 +
1205 + /*
1206 + * Make sure we issue a vblank event after disabling the CRTC if
1207 + * someone was waiting it.
1208 + */
1209 + if (crtc->state->event) {
1210 + unsigned long flags;
1211 +
1212 + spin_lock_irqsave(&dev->event_lock, flags);
1213 + drm_crtc_send_vblank_event(crtc, crtc->state->event);
1214 + crtc->state->event = NULL;
1215 + spin_unlock_irqrestore(&dev->event_lock, flags);
1216 + }
1217 +}
1218 +
1219 +static void vc4_crtc_consume_event(struct drm_crtc *crtc)
1220 +{
1221 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1222 + struct drm_device *dev = crtc->dev;
1223 + unsigned long flags;
1224 +
1225 + if (!crtc->state->event)
1226 + return;
1227 +
1228 + crtc->state->event->pipe = drm_crtc_index(crtc);
1229 +
1230 + WARN_ON(drm_crtc_vblank_get(crtc) != 0);
1231 +
1232 + spin_lock_irqsave(&dev->event_lock, flags);
1233 + vc4_crtc->event = crtc->state->event;
1234 + crtc->state->event = NULL;
1235 + spin_unlock_irqrestore(&dev->event_lock, flags);
1236 +}
1237 +
1238 +static void vc4_crtc_enable(struct drm_crtc *crtc,
1239 + struct drm_atomic_state *state)
1240 +{
1241 + struct drm_plane *plane;
1242 +
1243 + DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
1244 + crtc->base.id);
1245 + drm_crtc_vblank_on(crtc);
1246 + vc4_crtc_consume_event(crtc);
1247 +
1248 + /* Unblank the planes (if they're supposed to be displayed). */
1249 + drm_atomic_crtc_for_each_plane(plane, crtc)
1250 + if (plane->state->fb)
1251 + vc4_plane_set_blank(plane, plane->state->visible);
1252 +}
1253 +
1254 +static enum drm_mode_status
1255 +vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
1256 +{
1257 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1258 + struct drm_device *dev = crtc->dev;
1259 + struct vc4_dev *vc4 = to_vc4_dev(dev);
1260 + struct vc4_fkms *fkms = vc4->fkms;
1261 +
1262 + /* Do not allow doublescan modes from user space */
1263 + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
1264 + DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
1265 + crtc->base.id);
1266 + return MODE_NO_DBLESCAN;
1267 + }
1268 +
1269 + /* Disable refresh rates > defined threshold (default 85Hz) as limited
1270 + * gain from them
1271 + */
1272 + if (drm_mode_vrefresh(mode) > fkms_max_refresh_rate)
1273 + return MODE_BAD_VVALUE;
1274 +
1275 + /* Limit the pixel clock based on the HDMI clock limits from the
1276 + * firmware
1277 + */
1278 + switch (vc4_crtc->display_number) {
1279 + case 2: /* HDMI0 */
1280 + if (fkms->cfg.max_pixel_clock[0] &&
1281 + mode->clock > fkms->cfg.max_pixel_clock[0])
1282 + return MODE_CLOCK_HIGH;
1283 + break;
1284 + case 7: /* HDMI1 */
1285 + if (fkms->cfg.max_pixel_clock[1] &&
1286 + mode->clock > fkms->cfg.max_pixel_clock[1])
1287 + return MODE_CLOCK_HIGH;
1288 + break;
1289 + }
1290 +
1291 + /* Pi4 can't generate odd horizontal timings on HDMI, so reject modes
1292 + * that would set them.
1293 + */
1294 + if (fkms->bcm2711 &&
1295 + (vc4_crtc->display_number == 2 || vc4_crtc->display_number == 7) &&
1296 + !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
1297 + ((mode->hdisplay | /* active */
1298 + (mode->hsync_start - mode->hdisplay) | /* front porch */
1299 + (mode->hsync_end - mode->hsync_start) | /* sync pulse */
1300 + (mode->htotal - mode->hsync_end)) & 1)) /* back porch */ {
1301 + DRM_DEBUG_KMS("[CRTC:%d] Odd timing rejected %u %u %u %u.\n",
1302 + crtc->base.id, mode->hdisplay, mode->hsync_start,
1303 + mode->hsync_end, mode->htotal);
1304 + return MODE_H_ILLEGAL;
1305 + }
1306 +
1307 + return MODE_OK;
1308 +}
1309 +
1310 +static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
1311 + struct drm_atomic_state *state)
1312 +{
1313 + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
1314 + crtc);
1315 + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
1316 + struct drm_connector *conn;
1317 + struct drm_connector_state *conn_state;
1318 + int i;
1319 +
1320 + DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
1321 +
1322 + for_each_new_connector_in_state(crtc_state->state, conn, conn_state, i) {
1323 + if (conn_state->crtc != crtc)
1324 + continue;
1325 +
1326 + vc4_state->margins.left = conn_state->tv.margins.left;
1327 + vc4_state->margins.right = conn_state->tv.margins.right;
1328 + vc4_state->margins.top = conn_state->tv.margins.top;
1329 + vc4_state->margins.bottom = conn_state->tv.margins.bottom;
1330 + break;
1331 + }
1332 + return 0;
1333 +}
1334 +
1335 +static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
1336 + struct drm_atomic_state *state)
1337 +{
1338 + struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
1339 + crtc);
1340 +
1341 + DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
1342 + crtc->base.id);
1343 + if (crtc->state->active && old_state->active && crtc->state->event)
1344 + vc4_crtc_consume_event(crtc);
1345 +}
1346 +
1347 +static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
1348 +{
1349 + struct drm_crtc *crtc = &vc4_crtc->base;
1350 + struct drm_device *dev = crtc->dev;
1351 + unsigned long flags;
1352 +
1353 + spin_lock_irqsave(&dev->event_lock, flags);
1354 + if (vc4_crtc->event) {
1355 + drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
1356 + vc4_crtc->event = NULL;
1357 + drm_crtc_vblank_put(crtc);
1358 + }
1359 + spin_unlock_irqrestore(&dev->event_lock, flags);
1360 +}
1361 +
1362 +static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
1363 +{
1364 + struct vc4_crtc **crtc_list = data;
1365 + int i;
1366 + u32 stat = readl(crtc_list[0]->regs + SMICS);
1367 + irqreturn_t ret = IRQ_NONE;
1368 + u32 chan;
1369 +
1370 + if (stat & SMICS_INTERRUPTS) {
1371 + writel(0, crtc_list[0]->regs + SMICS);
1372 +
1373 + chan = readl(crtc_list[0]->regs + SMIDSW0);
1374 +
1375 + if ((chan & 0xFFFF0000) != SMI_NEW) {
1376 + /* Older firmware. Treat the one interrupt as vblank/
1377 + * complete for all crtcs.
1378 + */
1379 + for (i = 0; crtc_list[i]; i++) {
1380 + if (crtc_list[i]->vblank_enabled)
1381 + drm_crtc_handle_vblank(&crtc_list[i]->base);
1382 + vc4_crtc_handle_page_flip(crtc_list[i]);
1383 + }
1384 + } else {
1385 + if (chan & 1) {
1386 + writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
1387 + if (crtc_list[0]->vblank_enabled)
1388 + drm_crtc_handle_vblank(&crtc_list[0]->base);
1389 + vc4_crtc_handle_page_flip(crtc_list[0]);
1390 + }
1391 +
1392 + if (crtc_list[1]) {
1393 + /* Check for the secondary display too */
1394 + chan = readl(crtc_list[0]->regs + SMIDSW1);
1395 +
1396 + if (chan & 1) {
1397 + writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
1398 +
1399 + if (crtc_list[1]->vblank_enabled)
1400 + drm_crtc_handle_vblank(&crtc_list[1]->base);
1401 + vc4_crtc_handle_page_flip(crtc_list[1]);
1402 + }
1403 + }
1404 + }
1405 +
1406 + ret = IRQ_HANDLED;
1407 + }
1408 +
1409 + return ret;
1410 +}
1411 +
1412 +static int vc4_fkms_page_flip(struct drm_crtc *crtc,
1413 + struct drm_framebuffer *fb,
1414 + struct drm_pending_vblank_event *event,
1415 + uint32_t flags,
1416 + struct drm_modeset_acquire_ctx *ctx)
1417 +{
1418 + if (flags & DRM_MODE_PAGE_FLIP_ASYNC) {
1419 + DRM_ERROR("Async flips aren't allowed\n");
1420 + return -EINVAL;
1421 + }
1422 +
1423 + return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
1424 +}
1425 +
1426 +static struct drm_crtc_state *
1427 +vc4_fkms_crtc_duplicate_state(struct drm_crtc *crtc)
1428 +{
1429 + struct vc4_crtc_state *vc4_state, *old_vc4_state;
1430 +
1431 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
1432 + if (!vc4_state)
1433 + return NULL;
1434 +
1435 + old_vc4_state = to_vc4_crtc_state(crtc->state);
1436 + vc4_state->margins = old_vc4_state->margins;
1437 +
1438 + __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
1439 + return &vc4_state->base;
1440 +}
1441 +
1442 +static void
1443 +vc4_fkms_crtc_reset(struct drm_crtc *crtc)
1444 +{
1445 + if (crtc->state)
1446 + __drm_atomic_helper_crtc_destroy_state(crtc->state);
1447 +
1448 + crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
1449 + if (crtc->state)
1450 + crtc->state->crtc = crtc;
1451 +}
1452 +
1453 +static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
1454 +{
1455 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1456 +
1457 + DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
1458 + crtc->base.id);
1459 + vc4_crtc->vblank_enabled = true;
1460 +
1461 + return 0;
1462 +}
1463 +
1464 +static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
1465 +{
1466 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1467 +
1468 + DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
1469 + crtc->base.id);
1470 + vc4_crtc->vblank_enabled = false;
1471 +}
1472 +
1473 +static const struct drm_crtc_funcs vc4_crtc_funcs = {
1474 + .set_config = drm_atomic_helper_set_config,
1475 + .destroy = drm_crtc_cleanup,
1476 + .page_flip = vc4_fkms_page_flip,
1477 + .set_property = NULL,
1478 + .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
1479 + .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
1480 + .reset = vc4_fkms_crtc_reset,
1481 + .atomic_duplicate_state = vc4_fkms_crtc_duplicate_state,
1482 + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
1483 + .enable_vblank = vc4_fkms_enable_vblank,
1484 + .disable_vblank = vc4_fkms_disable_vblank,
1485 +};
1486 +
1487 +static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
1488 + .mode_set_nofb = vc4_crtc_mode_set_nofb,
1489 + .mode_valid = vc4_crtc_mode_valid,
1490 + .atomic_check = vc4_crtc_atomic_check,
1491 + .atomic_flush = vc4_crtc_atomic_flush,
1492 + .atomic_enable = vc4_crtc_enable,
1493 + .atomic_disable = vc4_crtc_disable,
1494 +};
1495 +
1496 +static const struct of_device_id vc4_firmware_kms_dt_match[] = {
1497 + { .compatible = "raspberrypi,rpi-firmware-kms" },
1498 + { .compatible = "raspberrypi,rpi-firmware-kms-2711",
1499 + .data = (void *)1 },
1500 + {}
1501 +};
1502 +
1503 +static enum drm_connector_status
1504 +vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
1505 +{
1506 + DRM_DEBUG_KMS("connector detect.\n");
1507 + return connector_status_connected;
1508 +}
1509 +
1510 +/* Queries the firmware to populate a drm_mode structure for this display */
1511 +static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
1512 + struct drm_display_mode *mode)
1513 +{
1514 + struct vc4_dev *vc4 = fkms_connector->vc4_dev;
1515 + struct set_timings timings = { 0 };
1516 + int ret;
1517 +
1518 + timings.display = fkms_connector->display_number;
1519 +
1520 + ret = rpi_firmware_property(vc4->firmware,
1521 + RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
1522 + sizeof(timings));
1523 + if (ret || !timings.clock)
1524 + /* No mode returned - abort */
1525 + return -1;
1526 +
1527 + /* Equivalent to DRM_MODE macro. */
1528 + memset(mode, 0, sizeof(*mode));
1529 + strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
1530 + mode->status = 0;
1531 + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
1532 + mode->clock = timings.clock;
1533 + mode->hdisplay = timings.hdisplay;
1534 + mode->hsync_start = timings.hsync_start;
1535 + mode->hsync_end = timings.hsync_end;
1536 + mode->htotal = timings.htotal;
1537 + mode->hskew = 0;
1538 + mode->vdisplay = timings.vdisplay;
1539 + mode->vsync_start = timings.vsync_start;
1540 + mode->vsync_end = timings.vsync_end;
1541 + mode->vtotal = timings.vtotal;
1542 + mode->vscan = timings.vscan;
1543 +
1544 + if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
1545 + mode->flags |= DRM_MODE_FLAG_PHSYNC;
1546 + else
1547 + mode->flags |= DRM_MODE_FLAG_NHSYNC;
1548 +
1549 + if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
1550 + mode->flags |= DRM_MODE_FLAG_PVSYNC;
1551 + else
1552 + mode->flags |= DRM_MODE_FLAG_NVSYNC;
1553 +
1554 + if (timings.flags & TIMINGS_FLAGS_INTERLACE)
1555 + mode->flags |= DRM_MODE_FLAG_INTERLACE;
1556 +
1557 + return 0;
1558 +}
1559 +
1560 +static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
1561 + size_t len)
1562 +{
1563 + struct vc4_fkms_connector *fkms_connector =
1564 + (struct vc4_fkms_connector *)data;
1565 + struct vc4_dev *vc4 = fkms_connector->vc4_dev;
1566 + struct mailbox_get_edid mb = {
1567 + .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY,
1568 + 128 + 8, 0 },
1569 + .block = block,
1570 + .display_number = fkms_connector->display_number,
1571 + };
1572 + int ret = 0;
1573 +
1574 + ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
1575 +
1576 + if (!ret)
1577 + memcpy(buf, mb.edid, len);
1578 +
1579 + return ret;
1580 +}
1581 +
1582 +static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
1583 +{
1584 + struct vc4_fkms_connector *fkms_connector =
1585 + to_vc4_fkms_connector(connector);
1586 + struct drm_encoder *encoder = fkms_connector->encoder;
1587 + struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
1588 + struct drm_display_mode fw_mode;
1589 + struct drm_display_mode *mode;
1590 + struct edid *edid;
1591 + int num_modes;
1592 +
1593 + if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
1594 + drm_mode_debug_printmodeline(&fw_mode);
1595 + mode = drm_mode_duplicate(connector->dev,
1596 + &fw_mode);
1597 + drm_mode_probed_add(connector, mode);
1598 + num_modes = 1; /* 1 mode */
1599 + } else {
1600 + edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
1601 + fkms_connector);
1602 +
1603 + /* FIXME: Can we do CEC?
1604 + * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
1605 + * if (!edid)
1606 + * return -ENODEV;
1607 + */
1608 +
1609 + vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
1610 +
1611 + drm_connector_update_edid_property(connector, edid);
1612 + num_modes = drm_add_edid_modes(connector, edid);
1613 + kfree(edid);
1614 + }
1615 +
1616 + return num_modes;
1617 +}
1618 +
1619 +/* This is the DSI panel resolution. Use this as a default should the firmware
1620 + * not respond to our request for the timings.
1621 + */
1622 +static const struct drm_display_mode lcd_mode = {
1623 + DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
1624 + 25979400 / 1000,
1625 + 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
1626 + 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
1627 + 0)
1628 +};
1629 +
1630 +static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
1631 +{
1632 + struct vc4_fkms_connector *fkms_connector =
1633 + to_vc4_fkms_connector(connector);
1634 + struct drm_display_mode *mode;
1635 + struct drm_display_mode fw_mode;
1636 +
1637 + if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
1638 + mode = drm_mode_duplicate(connector->dev,
1639 + &fw_mode);
1640 + else
1641 + mode = drm_mode_duplicate(connector->dev,
1642 + &lcd_mode);
1643 +
1644 + if (!mode) {
1645 + DRM_ERROR("Failed to create a new display mode\n");
1646 + return -ENOMEM;
1647 + }
1648 +
1649 + drm_mode_probed_add(connector, mode);
1650 +
1651 + /* We have one mode */
1652 + return 1;
1653 +}
1654 +
1655 +static struct drm_encoder *
1656 +vc4_fkms_connector_best_encoder(struct drm_connector *connector)
1657 +{
1658 + struct vc4_fkms_connector *fkms_connector =
1659 + to_vc4_fkms_connector(connector);
1660 + DRM_DEBUG_KMS("best_connector.\n");
1661 + return fkms_connector->encoder;
1662 +}
1663 +
1664 +static void vc4_fkms_connector_destroy(struct drm_connector *connector)
1665 +{
1666 + DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
1667 + connector->base.id);
1668 + drm_connector_unregister(connector);
1669 + drm_connector_cleanup(connector);
1670 +}
1671 +
1672 +/**
1673 + * vc4_connector_duplicate_state - duplicate connector state
1674 + * @connector: digital connector
1675 + *
1676 + * Allocates and returns a copy of the connector state (both common and
1677 + * digital connector specific) for the specified connector.
1678 + *
1679 + * Returns: The newly allocated connector state, or NULL on failure.
1680 + */
1681 +struct drm_connector_state *
1682 +vc4_connector_duplicate_state(struct drm_connector *connector)
1683 +{
1684 + struct vc4_fkms_connector_state *state;
1685 +
1686 + state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
1687 + if (!state)
1688 + return NULL;
1689 +
1690 + __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
1691 + return &state->base;
1692 +}
1693 +
1694 +/**
1695 + * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
1696 + * @connector: Connector to get the property for.
1697 + * @state: Connector state to retrieve the property from.
1698 + * @property: Property to retrieve.
1699 + * @val: Return value for the property.
1700 + *
1701 + * Returns the atomic property value for a digital connector.
1702 + */
1703 +int vc4_connector_atomic_get_property(struct drm_connector *connector,
1704 + const struct drm_connector_state *state,
1705 + struct drm_property *property,
1706 + uint64_t *val)
1707 +{
1708 + struct vc4_fkms_connector *fkms_connector =
1709 + to_vc4_fkms_connector(connector);
1710 + struct vc4_fkms_connector_state *vc4_conn_state =
1711 + to_vc4_fkms_connector_state(state);
1712 +
1713 + if (property == fkms_connector->broadcast_rgb_property) {
1714 + *val = vc4_conn_state->broadcast_rgb;
1715 + } else {
1716 + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
1717 + property->base.id, property->name);
1718 + return -EINVAL;
1719 + }
1720 +
1721 + return 0;
1722 +}
1723 +
1724 +/**
1725 + * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
1726 + * @connector: Connector to set the property for.
1727 + * @state: Connector state to set the property on.
1728 + * @property: Property to set.
1729 + * @val: New value for the property.
1730 + *
1731 + * Sets the atomic property value for a digital connector.
1732 + */
1733 +int vc4_connector_atomic_set_property(struct drm_connector *connector,
1734 + struct drm_connector_state *state,
1735 + struct drm_property *property,
1736 + uint64_t val)
1737 +{
1738 + struct vc4_fkms_connector *fkms_connector =
1739 + to_vc4_fkms_connector(connector);
1740 + struct vc4_fkms_connector_state *vc4_conn_state =
1741 + to_vc4_fkms_connector_state(state);
1742 +
1743 + if (property == fkms_connector->broadcast_rgb_property) {
1744 + vc4_conn_state->broadcast_rgb = val;
1745 + return 0;
1746 + }
1747 +
1748 + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
1749 + property->base.id, property->name);
1750 + return -EINVAL;
1751 +}
1752 +
1753 +int vc4_connector_atomic_check(struct drm_connector *connector,
1754 + struct drm_atomic_state *state)
1755 +{
1756 + struct drm_connector_state *old_state =
1757 + drm_atomic_get_old_connector_state(state, connector);
1758 + struct vc4_fkms_connector_state *vc4_old_state =
1759 + to_vc4_fkms_connector_state(old_state);
1760 + struct drm_connector_state *new_state =
1761 + drm_atomic_get_new_connector_state(state, connector);
1762 + struct vc4_fkms_connector_state *vc4_new_state =
1763 + to_vc4_fkms_connector_state(new_state);
1764 + struct drm_crtc *crtc = new_state->crtc;
1765 +
1766 + if (!crtc)
1767 + return 0;
1768 +
1769 + if (vc4_old_state->broadcast_rgb != vc4_new_state->broadcast_rgb) {
1770 + struct drm_crtc_state *crtc_state;
1771 +
1772 + crtc_state = drm_atomic_get_crtc_state(state, crtc);
1773 + if (IS_ERR(crtc_state))
1774 + return PTR_ERR(crtc_state);
1775 +
1776 + crtc_state->mode_changed = true;
1777 + }
1778 + return 0;
1779 +}
1780 +
1781 +static void vc4_hdmi_connector_reset(struct drm_connector *connector)
1782 +{
1783 + drm_atomic_helper_connector_reset(connector);
1784 + drm_atomic_helper_connector_tv_reset(connector);
1785 +}
1786 +
1787 +static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
1788 + .detect = vc4_fkms_connector_detect,
1789 + .fill_modes = drm_helper_probe_single_connector_modes,
1790 + .destroy = vc4_fkms_connector_destroy,
1791 + .reset = vc4_hdmi_connector_reset,
1792 + .atomic_duplicate_state = vc4_connector_duplicate_state,
1793 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1794 + .atomic_get_property = vc4_connector_atomic_get_property,
1795 + .atomic_set_property = vc4_connector_atomic_set_property,
1796 +};
1797 +
1798 +static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
1799 + .get_modes = vc4_fkms_connector_get_modes,
1800 + .best_encoder = vc4_fkms_connector_best_encoder,
1801 + .atomic_check = vc4_connector_atomic_check,
1802 +};
1803 +
1804 +static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = {
1805 + .get_modes = vc4_fkms_lcd_connector_get_modes,
1806 + .best_encoder = vc4_fkms_connector_best_encoder,
1807 +};
1808 +
1809 +static const struct drm_prop_enum_list broadcast_rgb_names[] = {
1810 + { VC4_BROADCAST_RGB_AUTO, "Automatic" },
1811 + { VC4_BROADCAST_RGB_FULL, "Full" },
1812 + { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
1813 +};
1814 +
1815 +static void
1816 +vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
1817 +{
1818 + struct drm_device *dev = fkms_connector->base.dev;
1819 + struct drm_property *prop;
1820 +
1821 + prop = fkms_connector->broadcast_rgb_property;
1822 + if (!prop) {
1823 + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
1824 + "Broadcast RGB",
1825 + broadcast_rgb_names,
1826 + ARRAY_SIZE(broadcast_rgb_names));
1827 + if (!prop)
1828 + return;
1829 +
1830 + fkms_connector->broadcast_rgb_property = prop;
1831 + }
1832 +
1833 + drm_object_attach_property(&fkms_connector->base.base, prop, 0);
1834 +}
1835 +
1836 +static struct drm_connector *
1837 +vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
1838 + u32 display_num)
1839 +{
1840 + struct drm_connector *connector = NULL;
1841 + struct vc4_fkms_connector *fkms_connector;
1842 + struct vc4_fkms_connector_state *conn_state = NULL;
1843 + struct vc4_dev *vc4_dev = to_vc4_dev(dev);
1844 + int ret = 0;
1845 +
1846 + DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
1847 +
1848 + fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
1849 + GFP_KERNEL);
1850 + if (!fkms_connector)
1851 + return ERR_PTR(-ENOMEM);
1852 +
1853 + /*
1854 + * Allocate enough memory to hold vc4_fkms_connector_state,
1855 + */
1856 + conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
1857 + if (!conn_state) {
1858 + kfree(fkms_connector);
1859 + return ERR_PTR(-ENOMEM);
1860 + }
1861 +
1862 + connector = &fkms_connector->base;
1863 +
1864 + fkms_connector->encoder = encoder;
1865 + fkms_connector->display_number = display_num;
1866 + fkms_connector->display_type = vc4_get_display_type(display_num);
1867 + fkms_connector->vc4_dev = vc4_dev;
1868 +
1869 + __drm_atomic_helper_connector_reset(connector,
1870 + &conn_state->base);
1871 +
1872 + if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
1873 + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
1874 + DRM_MODE_CONNECTOR_DSI);
1875 + drm_connector_helper_add(connector,
1876 + &vc4_fkms_lcd_conn_helper_funcs);
1877 + connector->interlace_allowed = 0;
1878 + } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) {
1879 + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
1880 + DRM_MODE_CONNECTOR_Composite);
1881 + drm_connector_helper_add(connector,
1882 + &vc4_fkms_lcd_conn_helper_funcs);
1883 + connector->interlace_allowed = 1;
1884 + } else {
1885 + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
1886 + DRM_MODE_CONNECTOR_HDMIA);
1887 + drm_connector_helper_add(connector,
1888 + &vc4_fkms_connector_helper_funcs);
1889 + connector->interlace_allowed = 1;
1890 + }
1891 +
1892 + ret = drm_mode_create_tv_margin_properties(dev);
1893 + if (ret)
1894 + goto fail;
1895 +
1896 + drm_connector_attach_tv_margin_properties(connector);
1897 +
1898 + connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
1899 + DRM_CONNECTOR_POLL_DISCONNECT);
1900 +
1901 + connector->doublescan_allowed = 0;
1902 +
1903 + vc4_attach_broadcast_rgb_property(fkms_connector);
1904 +
1905 + drm_connector_attach_encoder(connector, encoder);
1906 +
1907 + return connector;
1908 +
1909 + fail:
1910 + if (connector)
1911 + vc4_fkms_connector_destroy(connector);
1912 +
1913 + return ERR_PTR(ret);
1914 +}
1915 +
1916 +static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
1917 +{
1918 + DRM_DEBUG_KMS("Encoder_destroy\n");
1919 + drm_encoder_cleanup(encoder);
1920 +}
1921 +
1922 +static const struct drm_encoder_funcs vc4_fkms_encoder_funcs = {
1923 + .destroy = vc4_fkms_encoder_destroy,
1924 +};
1925 +
1926 +static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
1927 +{
1928 + struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
1929 + struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
1930 +
1931 + struct mailbox_display_pwr pwr = {
1932 + .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, },
1933 + .display = vc4_encoder->display_num,
1934 + .state = power ? 1 : 0,
1935 + };
1936 +
1937 + rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
1938 +}
1939 +
1940 +static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
1941 +{
1942 + vc4_fkms_display_power(encoder, true);
1943 + DRM_DEBUG_KMS("Encoder_enable\n");
1944 +}
1945 +
1946 +static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
1947 +{
1948 + vc4_fkms_display_power(encoder, false);
1949 + DRM_DEBUG_KMS("Encoder_disable\n");
1950 +}
1951 +
1952 +static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
1953 + .enable = vc4_fkms_encoder_enable,
1954 + .disable = vc4_fkms_encoder_disable,
1955 +};
1956 +
1957 +static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
1958 + int display_idx, int display_ref,
1959 + struct vc4_crtc **ret_crtc)
1960 +{
1961 + struct vc4_dev *vc4 = to_vc4_dev(drm);
1962 + struct vc4_crtc *vc4_crtc;
1963 + struct vc4_fkms_encoder *vc4_encoder;
1964 + struct drm_crtc *crtc;
1965 + struct drm_plane *destroy_plane, *temp;
1966 + struct mailbox_blank_display blank = {
1967 + .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
1968 + .display = display_idx,
1969 + .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, },
1970 + .blank = 1,
1971 + };
1972 + struct drm_plane *planes[PLANES_PER_CRTC];
1973 + int ret, i;
1974 +
1975 + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
1976 + if (!vc4_crtc)
1977 + return -ENOMEM;
1978 + crtc = &vc4_crtc->base;
1979 +
1980 + vc4_crtc->display_number = display_ref;
1981 + vc4_crtc->display_type = vc4_get_display_type(display_ref);
1982 +
1983 + /* Blank the firmware provided framebuffer */
1984 + rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
1985 +
1986 + for (i = 0; i < PLANES_PER_CRTC; i++) {
1987 + planes[i] = vc4_fkms_plane_init(drm,
1988 + (i == 0) ?
1989 + DRM_PLANE_TYPE_PRIMARY :
1990 + (i == PLANES_PER_CRTC - 1) ?
1991 + DRM_PLANE_TYPE_CURSOR :
1992 + DRM_PLANE_TYPE_OVERLAY,
1993 + display_ref,
1994 + i + (display_idx * PLANES_PER_CRTC)
1995 + );
1996 + if (IS_ERR(planes[i])) {
1997 + dev_err(dev, "failed to construct plane %u\n", i);
1998 + ret = PTR_ERR(planes[i]);
1999 + goto err;
2000 + }
2001 + }
2002 +
2003 + drm_crtc_init_with_planes(drm, crtc, planes[0],
2004 + planes[PLANES_PER_CRTC - 1], &vc4_crtc_funcs,
2005 + NULL);
2006 + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
2007 +
2008 + /* Update the possible_crtcs mask for the overlay plane(s) */
2009 + for (i = 1; i < (PLANES_PER_CRTC - 1); i++)
2010 + planes[i]->possible_crtcs = drm_crtc_mask(crtc);
2011 +
2012 + vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
2013 + if (!vc4_encoder)
2014 + return -ENOMEM;
2015 + vc4_crtc->encoder = &vc4_encoder->base;
2016 +
2017 + vc4_encoder->display_num = display_ref;
2018 + vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc);
2019 +
2020 + drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
2021 + vc4_crtc->display_type, NULL);
2022 + drm_encoder_helper_add(&vc4_encoder->base,
2023 + &vc4_fkms_encoder_helper_funcs);
2024 +
2025 + vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
2026 + display_ref);
2027 + if (IS_ERR(vc4_crtc->connector)) {
2028 + ret = PTR_ERR(vc4_crtc->connector);
2029 + goto err_destroy_encoder;
2030 + }
2031 +
2032 + *ret_crtc = vc4_crtc;
2033 +
2034 + return 0;
2035 +
2036 +err_destroy_encoder:
2037 + vc4_fkms_encoder_destroy(vc4_crtc->encoder);
2038 + list_for_each_entry_safe(destroy_plane, temp,
2039 + &drm->mode_config.plane_list, head) {
2040 + if (destroy_plane->possible_crtcs == 1 << drm_crtc_index(crtc))
2041 + destroy_plane->funcs->destroy(destroy_plane);
2042 + }
2043 +err:
2044 + return ret;
2045 +}
2046 +
2047 +static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
2048 +{
2049 + struct platform_device *pdev = to_platform_device(dev);
2050 + struct drm_device *drm = dev_get_drvdata(master);
2051 + struct vc4_dev *vc4 = to_vc4_dev(drm);
2052 + struct device_node *firmware_node;
2053 + const struct of_device_id *match;
2054 + struct vc4_crtc **crtc_list;
2055 + u32 num_displays, display_num;
2056 + struct vc4_fkms *fkms;
2057 + int ret;
2058 + u32 display_id;
2059 +
2060 + vc4->firmware_kms = true;
2061 +
2062 + fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
2063 + if (!fkms)
2064 + return -ENOMEM;
2065 +
2066 + match = of_match_device(vc4_firmware_kms_dt_match, dev);
2067 + if (!match)
2068 + return -ENODEV;
2069 + if (match->data)
2070 + fkms->bcm2711 = true;
2071 +
2072 + firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
2073 + vc4->firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node);
2074 + if (!vc4->firmware) {
2075 + DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
2076 + return -EPROBE_DEFER;
2077 + }
2078 + of_node_put(firmware_node);
2079 +
2080 + ret = rpi_firmware_property(vc4->firmware,
2081 + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
2082 + &num_displays, sizeof(u32));
2083 +
2084 + /* If we fail to get the number of displays, then
2085 + * assume old firmware that doesn't have the mailbox call, so just
2086 + * set one display
2087 + */
2088 + if (ret) {
2089 + num_displays = 1;
2090 + DRM_WARN("Unable to determine number of displays - assuming 1\n");
2091 + ret = 0;
2092 + }
2093 +
2094 + ret = rpi_firmware_property(vc4->firmware,
2095 + RPI_FIRMWARE_GET_DISPLAY_CFG,
2096 + &fkms->cfg, sizeof(fkms->cfg));
2097 +
2098 + if (ret)
2099 + return -EINVAL;
2100 + /* The firmware works in Hz. This will be compared against kHz, so div
2101 + * 1000 now rather than multiple times later.
2102 + */
2103 + fkms->cfg.max_pixel_clock[0] /= 1000;
2104 + fkms->cfg.max_pixel_clock[1] /= 1000;
2105 +
2106 + /* Allocate a list, with space for a NULL on the end */
2107 + crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
2108 + GFP_KERNEL);
2109 + if (!crtc_list)
2110 + return -ENOMEM;
2111 +
2112 + for (display_num = 0; display_num < num_displays; display_num++) {
2113 + display_id = display_num;
2114 + ret = rpi_firmware_property(vc4->firmware,
2115 + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
2116 + &display_id, sizeof(display_id));
2117 + /* FIXME: Determine the correct error handling here.
2118 + * Should we fail to create the one "screen" but keep the
2119 + * others, or fail the whole thing?
2120 + */
2121 + if (ret)
2122 + DRM_ERROR("Failed to get display id %u\n", display_num);
2123 +
2124 + ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
2125 + &crtc_list[display_num]);
2126 + if (ret)
2127 + DRM_ERROR("Oh dear, failed to create display %u\n",
2128 + display_num);
2129 + }
2130 +
2131 + if (num_displays > 0) {
2132 + /* Map the SMI interrupt reg */
2133 + crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
2134 + if (IS_ERR(crtc_list[0]->regs))
2135 + DRM_ERROR("Oh dear, failed to map registers\n");
2136 +
2137 + writel(0, crtc_list[0]->regs + SMICS);
2138 + ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
2139 + vc4_crtc_irq_handler, 0,
2140 + "vc4 firmware kms", crtc_list);
2141 + if (ret)
2142 + DRM_ERROR("Oh dear, failed to register IRQ\n");
2143 + } else {
2144 + DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
2145 + }
2146 +
2147 + vc4->fkms = fkms;
2148 +
2149 + platform_set_drvdata(pdev, crtc_list);
2150 +
2151 + return 0;
2152 +}
2153 +
2154 +static void vc4_fkms_unbind(struct device *dev, struct device *master,
2155 + void *data)
2156 +{
2157 + struct platform_device *pdev = to_platform_device(dev);
2158 + struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
2159 + int i;
2160 +
2161 + for (i = 0; crtc_list[i]; i++) {
2162 + vc4_fkms_connector_destroy(crtc_list[i]->connector);
2163 + vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
2164 + drm_crtc_cleanup(&crtc_list[i]->base);
2165 + }
2166 +
2167 + platform_set_drvdata(pdev, NULL);
2168 +}
2169 +
2170 +static const struct component_ops vc4_fkms_ops = {
2171 + .bind = vc4_fkms_bind,
2172 + .unbind = vc4_fkms_unbind,
2173 +};
2174 +
2175 +static int vc4_fkms_probe(struct platform_device *pdev)
2176 +{
2177 + return component_add(&pdev->dev, &vc4_fkms_ops);
2178 +}
2179 +
2180 +static int vc4_fkms_remove(struct platform_device *pdev)
2181 +{
2182 + component_del(&pdev->dev, &vc4_fkms_ops);
2183 + return 0;
2184 +}
2185 +
2186 +struct platform_driver vc4_firmware_kms_driver = {
2187 + .probe = vc4_fkms_probe,
2188 + .remove = vc4_fkms_remove,
2189 + .driver = {
2190 + .name = "vc4_firmware_kms",
2191 + .of_match_table = vc4_firmware_kms_dt_match,
2192 + },
2193 +};
2194 --- a/drivers/gpu/drm/vc4/vc4_kms.c
2195 +++ b/drivers/gpu/drm/vc4/vc4_kms.c
2196 @@ -160,6 +160,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru
2197 struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
2198 struct drm_color_ctm *ctm = ctm_state->ctm;
2199
2200 + if (vc4->firmware_kms)
2201 + return;
2202 +
2203 if (ctm_state->fifo) {
2204 HVS_WRITE(SCALER_OLEDCOEF2,
2205 VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]),
2206 @@ -359,7 +362,7 @@ static void vc4_atomic_commit_tail(struc
2207 for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
2208 struct vc4_crtc_state *vc4_crtc_state;
2209
2210 - if (!new_crtc_state->commit)
2211 + if (!new_crtc_state->commit || vc4->firmware_kms)
2212 continue;
2213
2214 vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
2215 @@ -385,7 +388,7 @@ static void vc4_atomic_commit_tail(struc
2216 old_hvs_state->fifo_state[channel].pending_commit = NULL;
2217 }
2218
2219 - if (vc4->hvs->hvs5) {
2220 + if (vc4->hvs && vc4->hvs->hvs5) {
2221 unsigned long core_rate = max_t(unsigned long,
2222 500000000,
2223 new_hvs_state->core_clock_rate);
2224 @@ -402,10 +405,12 @@ static void vc4_atomic_commit_tail(struc
2225
2226 vc4_ctm_commit(vc4, state);
2227
2228 - if (vc4->hvs->hvs5)
2229 - vc5_hvs_pv_muxing_commit(vc4, state);
2230 - else
2231 - vc4_hvs_pv_muxing_commit(vc4, state);
2232 + if (!vc4->firmware_kms) {
2233 + if (vc4->hvs && vc4->hvs->hvs5)
2234 + vc5_hvs_pv_muxing_commit(vc4, state);
2235 + else
2236 + vc4_hvs_pv_muxing_commit(vc4, state);
2237 + }
2238
2239 drm_atomic_helper_commit_planes(dev, state, 0);
2240
2241 @@ -419,7 +424,7 @@ static void vc4_atomic_commit_tail(struc
2242
2243 drm_atomic_helper_cleanup_planes(dev, state);
2244
2245 - if (vc4->hvs->hvs5) {
2246 + if (vc4->hvs && vc4->hvs->hvs5) {
2247 drm_dbg(dev, "Running the core clock at %lu Hz\n",
2248 new_hvs_state->core_clock_rate);
2249
2250 @@ -437,11 +442,21 @@ static void vc4_atomic_commit_tail(struc
2251
2252 static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
2253 {
2254 + struct drm_device *dev = state->dev;
2255 + struct vc4_dev *vc4 = to_vc4_dev(dev);
2256 struct drm_crtc_state *crtc_state;
2257 struct vc4_hvs_state *hvs_state;
2258 struct drm_crtc *crtc;
2259 unsigned int i;
2260
2261 + /* We know for sure we don't want an async update here. Set
2262 + * state->legacy_cursor_update to false to prevent
2263 + * drm_atomic_helper_setup_commit() from auto-completing
2264 + * commit->flip_done.
2265 + */
2266 + if (!vc4->firmware_kms)
2267 + state->legacy_cursor_update = false;
2268 +
2269 hvs_state = vc4_hvs_get_new_global_state(state);
2270 if (WARN_ON(IS_ERR(hvs_state)))
2271 return PTR_ERR(hvs_state);
2272 @@ -775,6 +790,7 @@ static int vc4_hvs_channels_obj_init(str
2273 static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
2274 struct drm_atomic_state *state)
2275 {
2276 + struct vc4_dev *vc4 = to_vc4_dev(state->dev);
2277 struct vc4_hvs_state *hvs_new_state;
2278 struct drm_crtc_state *old_crtc_state, *new_crtc_state;
2279 struct drm_crtc *crtc;
2280 @@ -798,6 +814,9 @@ static int vc4_pv_muxing_atomic_check(st
2281 unsigned int matching_channels;
2282 unsigned int channel;
2283
2284 + if (vc4->firmware_kms)
2285 + continue;
2286 +
2287 /* Nothing to do here, let's skip it */
2288 if (old_crtc_state->enable == new_crtc_state->enable)
2289 continue;
2290 @@ -995,6 +1014,8 @@ int vc4_kms_load(struct drm_device *dev)
2291 dev->mode_config.helper_private = &vc4_mode_config_helpers;
2292 dev->mode_config.preferred_depth = 24;
2293 dev->mode_config.async_page_flip = true;
2294 + if (vc4->firmware_kms)
2295 + dev->mode_config.normalize_zpos = true;
2296
2297 ret = vc4_ctm_obj_init(vc4);
2298 if (ret)
2299 --- /dev/null
2300 +++ b/drivers/gpu/drm/vc4/vc_image_types.h
2301 @@ -0,0 +1,175 @@
2302 +
2303 +/*
2304 + * Copyright (c) 2012, Broadcom Europe Ltd
2305 + *
2306 + * Values taken from vc_image_types.h released by Broadcom at
2307 + * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
2308 + * and vc_image_structs.h at
2309 + * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h
2310 + *
2311 + * This program is free software; you can redistribute it and/or modify
2312 + * it under the terms of the GNU General Public License version 2 as
2313 + * published by the Free Software Foundation.
2314 + */
2315 +
2316 +enum {
2317 + VC_IMAGE_MIN = 0, //bounds for error checking
2318 +
2319 + VC_IMAGE_RGB565 = 1,
2320 + VC_IMAGE_1BPP,
2321 + VC_IMAGE_YUV420,
2322 + VC_IMAGE_48BPP,
2323 + VC_IMAGE_RGB888,
2324 + VC_IMAGE_8BPP,
2325 + /* 4bpp palettised image */
2326 + VC_IMAGE_4BPP,
2327 + /* A separated format of 16 colour/light shorts followed by 16 z
2328 + * values
2329 + */
2330 + VC_IMAGE_3D32,
2331 + /* 16 colours followed by 16 z values */
2332 + VC_IMAGE_3D32B,
2333 + /* A separated format of 16 material/colour/light shorts followed by
2334 + * 16 z values
2335 + */
2336 + VC_IMAGE_3D32MAT,
2337 + /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
2338 + VC_IMAGE_RGB2X9,
2339 + /* 32-bit format holding 18 bits of 6.6.6 RGB */
2340 + VC_IMAGE_RGB666,
2341 + /* 4bpp palettised image with embedded palette */
2342 + VC_IMAGE_PAL4_OBSOLETE,
2343 + /* 8bpp palettised image with embedded palette */
2344 + VC_IMAGE_PAL8_OBSOLETE,
2345 + /* RGB888 with an alpha byte after each pixel */
2346 + VC_IMAGE_RGBA32,
2347 + /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
2348 + * line of V (16-byte padded)
2349 + */
2350 + VC_IMAGE_YUV422,
2351 + /* RGB565 with a transparent patch */
2352 + VC_IMAGE_RGBA565,
2353 + /* Compressed (4444) version of RGBA32 */
2354 + VC_IMAGE_RGBA16,
2355 + /* VCIII codec format */
2356 + VC_IMAGE_YUV_UV,
2357 + /* VCIII T-format RGBA8888 */
2358 + VC_IMAGE_TF_RGBA32,
2359 + /* VCIII T-format RGBx8888 */
2360 + VC_IMAGE_TF_RGBX32,
2361 + /* VCIII T-format float */
2362 + VC_IMAGE_TF_FLOAT,
2363 + /* VCIII T-format RGBA4444 */
2364 + VC_IMAGE_TF_RGBA16,
2365 + /* VCIII T-format RGB5551 */
2366 + VC_IMAGE_TF_RGBA5551,
2367 + /* VCIII T-format RGB565 */
2368 + VC_IMAGE_TF_RGB565,
2369 + /* VCIII T-format 8-bit luma and 8-bit alpha */
2370 + VC_IMAGE_TF_YA88,
2371 + /* VCIII T-format 8 bit generic sample */
2372 + VC_IMAGE_TF_BYTE,
2373 + /* VCIII T-format 8-bit palette */
2374 + VC_IMAGE_TF_PAL8,
2375 + /* VCIII T-format 4-bit palette */
2376 + VC_IMAGE_TF_PAL4,
2377 + /* VCIII T-format Ericsson Texture Compressed */
2378 + VC_IMAGE_TF_ETC1,
2379 + /* RGB888 with R & B swapped */
2380 + VC_IMAGE_BGR888,
2381 + /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
2382 + * each row of pixels
2383 + */
2384 + VC_IMAGE_BGR888_NP,
2385 + /* Bayer image, extra defines which variant is being used */
2386 + VC_IMAGE_BAYER,
2387 + /* General wrapper for codec images e.g. JPEG from camera */
2388 + VC_IMAGE_CODEC,
2389 + /* VCIII codec format */
2390 + VC_IMAGE_YUV_UV32,
2391 + /* VCIII T-format 8-bit luma */
2392 + VC_IMAGE_TF_Y8,
2393 + /* VCIII T-format 8-bit alpha */
2394 + VC_IMAGE_TF_A8,
2395 + /* VCIII T-format 16-bit generic sample */
2396 + VC_IMAGE_TF_SHORT,
2397 + /* VCIII T-format 1bpp black/white */
2398 + VC_IMAGE_TF_1BPP,
2399 + VC_IMAGE_OPENGL,
2400 + /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
2401 + VC_IMAGE_YUV444I,
2402 + /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
2403 + * a per line basis)
2404 + */
2405 + VC_IMAGE_YUV422PLANAR,
2406 + /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
2407 + VC_IMAGE_ARGB8888,
2408 + /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
2409 + VC_IMAGE_XRGB8888,
2410 +
2411 + /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
2412 + VC_IMAGE_YUV422YUYV,
2413 + VC_IMAGE_YUV422YVYU,
2414 + VC_IMAGE_YUV422UYVY,
2415 + VC_IMAGE_YUV422VYUY,
2416 +
2417 + /* 32bpp like RGBA32 but with unused alpha */
2418 + VC_IMAGE_RGBX32,
2419 + /* 32bpp, corresponding to RGBA with unused alpha */
2420 + VC_IMAGE_RGBX8888,
2421 + /* 32bpp, corresponding to BGRA with unused alpha */
2422 + VC_IMAGE_BGRX8888,
2423 +
2424 + /* Y as a plane, then UV byte interleaved in plane with same pitch,
2425 + * half height
2426 + */
2427 + VC_IMAGE_YUV420SP,
2428 +
2429 + /* Y, U, & V planes separately 4:4:4 */
2430 + VC_IMAGE_YUV444PLANAR,
2431 +
2432 + /* T-format 8-bit U - same as TF_Y8 buf from U plane */
2433 + VC_IMAGE_TF_U8,
2434 + /* T-format 8-bit U - same as TF_Y8 buf from V plane */
2435 + VC_IMAGE_TF_V8,
2436 +
2437 + /* YUV4:2:0 planar, 16bit values */
2438 + VC_IMAGE_YUV420_16,
2439 + /* YUV4:2:0 codec format, 16bit values */
2440 + VC_IMAGE_YUV_UV_16,
2441 + /* YUV4:2:0 with U,V in side-by-side format */
2442 + VC_IMAGE_YUV420_S,
2443 + /* 10-bit YUV 420 column image format */
2444 + VC_IMAGE_YUV10COL,
2445 + /* 32-bpp, 10-bit R/G/B, 2-bit Alpha */
2446 + VC_IMAGE_RGBA1010102,
2447 +
2448 + VC_IMAGE_MAX, /* bounds for error checking */
2449 + VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
2450 +};
2451 +
2452 +enum {
2453 + /* Unknown or unset - defaults to BT601 interstitial */
2454 + VC_IMAGE_YUVINFO_UNSPECIFIED = 0,
2455 +
2456 + /* colour-space conversions data [4 bits] */
2457 +
2458 + /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
2459 + VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1,
2460 + /* ITU-R BT.709-3 [HDTV] */
2461 + VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2,
2462 + /* JPEG JFIF */
2463 + VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3,
2464 + /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
2465 + VC_IMAGE_YUVINFO_CSC_FCC = 4,
2466 + /* Society of Motion Picture and Television Engineers 240M (1999) */
2467 + VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5,
2468 + /* ITU-R BT.470-2 System M */
2469 + VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6,
2470 + /* ITU-R BT.470-2 System B,G */
2471 + VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,
2472 + /* JPEG JFIF, but with 16..255 luma */
2473 + VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8,
2474 + /* Rec 2020 */
2475 + VC_IMAGE_YUVINFO_CSC_REC_2020 = 9,
2476 +};
2477 --- a/include/soc/bcm2835/raspberrypi-firmware.h
2478 +++ b/include/soc/bcm2835/raspberrypi-firmware.h
2479 @@ -73,6 +73,7 @@ enum rpi_firmware_property_tag {
2480 RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
2481 RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
2482 RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
2483 + RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023,
2484 RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
2485 RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
2486 RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
2487 @@ -149,6 +150,11 @@ enum rpi_firmware_property_tag {
2488
2489 RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
2490
2491 + RPI_FIRMWARE_SET_PLANE = 0x00048015,
2492 + RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
2493 + RPI_FIRMWARE_SET_TIMING = 0x00048017,
2494 + RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
2495 + RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019,
2496 RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
2497 RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
2498 };