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
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.
12 This patch includes work by Eric Anholt, James Hughes, Phil Elwell,
13 Dave Stevenson, Dom Cobley, and Jonathon Bell.
15 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
17 drm/vc4: Fixup firmware-kms after "drm/atomic: Pass the full state to CRTC atomic enable/disable"
19 Prototype for those calls changed, so amend fkms (which isn't
22 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
24 drm/vc4: Fixup fkms for API change
26 Atomic flush and check changed API, so fix up the downstream-only
29 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
31 drm/vc4: Make normalize_zpos conditional on using fkms
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.
36 Can be later squashed into (and fixes):
37 drm/vc4: Add firmware-kms mode
39 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
41 drm/vc4: FKMS: Change of Broadcast RGB mode needs a mode change
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
47 https://github.com/raspberrypi/firmware/issues/1580
49 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
51 vc4/drv: Only notify firmware of display done with kms
53 fkms driver still wants firmware display to be active
55 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
57 ydrm/vc4: fkms: Fix margin calculations for the right/bottom edges
59 The calculations clipped the right/bottom edge of the clipped
60 range based on the left/top margins.
62 https://github.com/raspberrypi/linux/issues/4447
64 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
66 drm/vc4: fkms: Use new devm_rpi_firmware_get api
68 drm/kms: Add allow_fb_modifiers
70 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
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
84 --- a/drivers/gpu/drm/vc4/Makefile
85 +++ b/drivers/gpu/drm/vc4/Makefile
86 @@ -9,6 +9,7 @@ vc4-y := \
90 + vc4_firmware_kms.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;
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,
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 @@ -227,6 +227,18 @@ static const struct of_device_id vc4_dma
112 + * we need this helper function for determining presence of fkms
113 + * before it's been bound
115 +static bool firmware_kms(void)
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"));
123 static int vc4_drm_bind(struct device *dev)
125 struct platform_device *pdev = to_platform_device(dev);
126 @@ -290,7 +302,7 @@ static int vc4_drm_bind(struct device *d
131 + if (firmware && !firmware_kms()) {
132 ret = rpi_firmware_property(firmware,
133 RPI_FIRMWARE_NOTIFY_DISPLAY_DONE,
135 @@ -304,16 +316,20 @@ static int vc4_drm_bind(struct device *d
139 - ret = vc4_plane_create_additional_planes(drm);
142 + if (!vc4->firmware_kms) {
143 + ret = vc4_plane_create_additional_planes(drm);
148 ret = vc4_kms_load(drm);
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);
159 ret = drm_dev_register(drm, 0);
161 @@ -360,6 +376,7 @@ static struct platform_driver *const com
165 + &vc4_firmware_kms_driver,
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 {
176 + struct rpi_firmware *firmware;
183 + struct vc4_fkms *fkms;
185 struct vc4_hang_state *hang_state;
187 @@ -896,6 +900,9 @@ extern struct platform_driver vc4_dsi_dr
189 extern const struct dma_fence_ops vc4_fence_ops;
191 +/* vc4_firmware_kms.c */
192 +extern struct platform_driver vc4_firmware_kms_driver;
195 int vc4_gem_init(struct drm_device *dev);
196 int vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
198 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
200 +// SPDX-License-Identifier: GPL-2.0-only
202 + * Copyright (C) 2016 Broadcom
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.
210 + * DOC: VC4 firmware KMS module.
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.
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>
227 +#include <linux/component.h>
228 +#include <linux/clk.h>
229 +#include <linux/debugfs.h>
230 +#include <linux/module.h>
232 +#include <soc/bcm2835/raspberrypi-firmware.h>
234 +#include "vc4_drv.h"
235 +#include "vc4_regs.h"
236 +#include "vc_image_types.h"
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");
242 +struct get_display_cfg {
243 + u32 max_pixel_clock[2]; //Max pixel clock for each display
247 + struct get_display_cfg cfg;
251 +#define PLANES_PER_CRTC 8
265 + u32 src_x; /* 16p16 */
266 + u32 src_y; /* 16p16 */
268 + u32 src_w; /* 16p16 */
269 + u32 src_h; /* 16p16 */
282 + u32 planes[4]; /* DMA address of each plane */
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)
293 +struct mailbox_set_plane {
294 + struct rpi_firmware_property_tag_header tag;
295 + struct set_plane plane;
298 +struct mailbox_blank_display {
299 + struct rpi_firmware_property_tag_header tag1;
301 + struct rpi_firmware_property_tag_header tag2;
305 +struct mailbox_display_pwr {
306 + struct rpi_firmware_property_tag_header tag1;
311 +struct mailbox_get_edid {
312 + struct rpi_firmware_property_tag_header tag1;
314 + u32 display_number;
318 +struct set_timings {
323 + u32 clock; /* in kHz */
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)
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)
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)
362 +#define TIMINGS_FLAGS_DBL_CLK BIT(10)
365 +struct mailbox_set_mode {
366 + struct rpi_firmware_property_tag_header tag1;
367 + struct set_timings timings;
370 +static const struct vc_image_format {
371 + u32 drm; /* DRM_FORMAT_* */
372 + u32 vc_image; /* VC_IMAGE_* */
374 +} vc_image_formats[] = {
376 + .drm = DRM_FORMAT_XRGB8888,
377 + .vc_image = VC_IMAGE_XRGB8888,
380 + .drm = DRM_FORMAT_ARGB8888,
381 + .vc_image = VC_IMAGE_ARGB8888,
384 + * FIXME: Need to resolve which DRM format goes to which vc_image format
385 + * for the remaining RGBA and RGBX formats.
387 + * .drm = DRM_FORMAT_ABGR8888,
388 + * .vc_image = VC_IMAGE_RGBA8888,
391 + * .drm = DRM_FORMAT_XBGR8888,
392 + * .vc_image = VC_IMAGE_RGBA8888,
396 + .drm = DRM_FORMAT_RGB565,
397 + .vc_image = VC_IMAGE_RGB565,
400 + .drm = DRM_FORMAT_RGB888,
401 + .vc_image = VC_IMAGE_BGR888,
404 + .drm = DRM_FORMAT_BGR888,
405 + .vc_image = VC_IMAGE_RGB888,
408 + .drm = DRM_FORMAT_YUV422,
409 + .vc_image = VC_IMAGE_YUV422PLANAR,
412 + .drm = DRM_FORMAT_YUV420,
413 + .vc_image = VC_IMAGE_YUV420,
416 + .drm = DRM_FORMAT_YVU420,
417 + .vc_image = VC_IMAGE_YUV420,
421 + .drm = DRM_FORMAT_NV12,
422 + .vc_image = VC_IMAGE_YUV420SP,
425 + .drm = DRM_FORMAT_NV21,
426 + .vc_image = VC_IMAGE_YUV420SP,
430 + .drm = DRM_FORMAT_P030,
431 + .vc_image = VC_IMAGE_YUV10COL,
435 +static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
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];
447 +/* The firmware delivers a vblank interrupt to us through the SMI
448 + * hardware, which has only this one register.
451 +#define SMIDSW0 0x14
452 +#define SMIDSW1 0x1C
453 +#define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
455 +/* Flag to denote that the firmware is giving multiple display callbacks */
456 +#define SMI_NEW 0xabcd0000
458 +#define vc4_crtc vc4_kms_crtc
459 +#define to_vc4_crtc to_vc4_kms_crtc
461 + struct drm_crtc base;
462 + struct drm_encoder *encoder;
463 + struct drm_connector *connector;
464 + void __iomem *regs;
466 + struct drm_pending_vblank_event *event;
467 + bool vblank_enabled;
468 + u32 display_number;
472 +static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
474 + return container_of(crtc, struct vc4_crtc, base);
477 +struct vc4_fkms_encoder {
478 + struct drm_encoder base;
480 + bool rgb_range_selectable;
484 +static inline struct vc4_fkms_encoder *
485 +to_vc4_fkms_encoder(struct drm_encoder *encoder)
487 + return container_of(encoder, struct vc4_fkms_encoder, base);
490 +/* "Broadcast RGB" property.
491 + * Allows overriding of HDMI full or limited range RGB
493 +#define VC4_BROADCAST_RGB_AUTO 0
494 +#define VC4_BROADCAST_RGB_FULL 1
495 +#define VC4_BROADCAST_RGB_LIMITED 2
497 +/* VC4 FKMS connector KMS struct */
498 +struct vc4_fkms_connector {
499 + struct drm_connector base;
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()
505 + struct drm_encoder *encoder;
506 + struct vc4_dev *vc4_dev;
507 + u32 display_number;
510 + struct drm_property *broadcast_rgb_property;
513 +static inline struct vc4_fkms_connector *
514 +to_vc4_fkms_connector(struct drm_connector *connector)
516 + return container_of(connector, struct vc4_fkms_connector, base);
519 +/* VC4 FKMS connector state */
520 +struct vc4_fkms_connector_state {
521 + struct drm_connector_state base;
526 +#define to_vc4_fkms_connector_state(x) \
527 + container_of(x, struct vc4_fkms_connector_state, base)
529 +static u32 vc4_get_display_type(u32 display_number)
531 + const u32 display_types[] = {
532 + /* The firmware display (DispmanX) IDs map to specific types in
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 */
545 + return display_number > ARRAY_SIZE(display_types) - 1 ?
546 + DRM_MODE_ENCODER_NONE : display_types[display_number];
549 +/* Firmware's structure for making an FB mbox call. */
551 + u32 xres, yres, xres_virtual, yres_virtual;
553 + u32 xoffset, yoffset;
559 +struct vc4_fkms_plane {
560 + struct drm_plane base;
561 + struct fbinfo_s *fbinfo;
562 + dma_addr_t fbinfo_bus_addr;
564 + struct mailbox_set_plane mb;
567 +static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
569 + return (struct vc4_fkms_plane *)plane;
572 +static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
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 },
579 + .display = vc4_plane->mb.plane.display,
580 + .plane_id = vc4_plane->mb.plane.plane_id,
583 + static const char * const plane_types[] = {
590 + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
591 + plane->base.id, plane->name, plane_types[plane->type],
592 + blank ? "blank" : "unblank");
595 + ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
598 + ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
599 + sizeof(vc4_plane->mb));
601 + WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
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)
610 + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
611 + struct drm_connector_state *conn_state;
612 + struct drm_connector *conn;
615 + *left = vc4_state->margins.left;
616 + *right = vc4_state->margins.right;
617 + *top = vc4_state->margins.top;
618 + *bottom = vc4_state->margins.bottom;
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.
625 + for_each_new_connector_in_state(state->state, conn, conn_state, i) {
626 + if (conn_state->crtc != state->crtc)
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;
637 +static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
638 + struct set_plane *plane)
640 + unsigned int left, right, top, bottom;
641 + int adjhdisplay, adjvdisplay;
642 + struct drm_crtc_state *crtc_state;
644 + crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
647 + vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
649 + if (!left && !right && !top && !bottom)
652 + if (left + right >= crtc_state->mode.hdisplay ||
653 + top + bottom >= crtc_state->mode.vdisplay)
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;
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;
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);
675 + if (!plane->dst_w || !plane->dst_h)
681 +static void vc4_plane_atomic_update(struct drm_plane *plane,
682 + struct drm_atomic_state *old_state)
684 + struct drm_plane_state *state = plane->state;
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.
690 + * If the CRTC is on (or going to be on) and we're enabled,
691 + * then unblank. Otherwise, stay blank until CRTC enable.
693 + if (state->crtc->state->active)
694 + vc4_plane_set_blank(plane, false);
697 +static void vc4_plane_atomic_disable(struct drm_plane *plane,
698 + struct drm_atomic_state *old_state)
700 + struct drm_plane_state *state = plane->state;
701 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
703 + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
704 + plane->base.id, plane->name,
707 + vc4_plane->mb.plane.vc_image_type,
710 + vc4_plane_set_blank(plane, true);
713 +static bool plane_enabled(struct drm_plane_state *state)
715 + return state->fb && state->crtc;
718 +static int vc4_plane_to_mb(struct drm_plane *plane,
719 + struct mailbox_set_plane *mb,
720 + struct drm_plane_state *state)
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;
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];
749 + rotation = drm_rotation_simplify(state->rotation,
750 + DRM_MODE_ROTATE_0 |
751 + DRM_MODE_REFLECT_X |
752 + DRM_MODE_REFLECT_Y);
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;
760 + vc4_fkms_margins_adj(state, &mb->plane);
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.
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];
771 + mb->plane.planes[2] = 0;
773 + /* Special case the YUV420 with U and V as line interleaved
774 + * planes as we have special handling for that case.
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;
780 + switch (state->color_encoding) {
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;
787 + mb->plane.color_encoding =
788 + VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
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;
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;
802 + mb->plane.planes[1] = 0;
803 + mb->plane.planes[2] = 0;
805 + mb->plane.planes[3] = 0;
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;
813 + case VC_IMAGE_ARGB8888:
814 + mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
816 + case VC_IMAGE_RGB565:
817 + mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
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;
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.
831 + /* Note that the column pitch is passed across in lines, not
834 + mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
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,
842 + mb->plane.vc_image_type,
851 + mb->plane.planes[0],
852 + mb->plane.planes[1],
853 + mb->plane.planes[2],
856 + state->normalized_zpos);
861 +static int vc4_plane_atomic_check(struct drm_plane *plane,
862 + struct drm_atomic_state *state)
864 + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
866 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
868 + if (!plane_enabled(new_plane_state))
871 + return vc4_plane_to_mb(plane, &vc4_plane->mb, new_plane_state);
874 +/* Called during init to allocate the plane's atomic state. */
875 +static void vc4_plane_reset(struct drm_plane *plane)
877 + struct vc4_plane_state *vc4_state;
879 + WARN_ON(plane->state);
881 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
885 + __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
888 +static void vc4_plane_destroy(struct drm_plane *plane)
890 + drm_plane_cleanup(plane);
893 +static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
897 + /* Support T_TILING for RGB formats only. */
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:
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:
917 + case DRM_FORMAT_P030:
918 + switch (fourcc_mod_broadcom_mod(modifier)) {
919 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
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:
931 + return (modifier == DRM_FORMAT_MOD_LINEAR);
935 +static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
937 + struct vc4_plane_state *vc4_state;
939 + if (WARN_ON(!plane->state))
942 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
946 + __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
948 + return &vc4_state->base;
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,
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,
970 +static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
971 + enum drm_plane_type type,
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;
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).
986 + DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
987 + DRM_FORMAT_MOD_BROADCOM_SAND128,
988 + DRM_FORMAT_MOD_INVALID,
992 + vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
999 + for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
1000 + formats[num_formats++] = vc_image_formats[i].drm;
1002 + plane = &vc4_plane->base;
1003 + ret = drm_universal_plane_init(dev, plane, 0,
1005 + formats, num_formats, modifiers,
1008 + /* FIXME: Do we need to be checking return values from all these calls?
1010 + drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
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);
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.
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.
1037 + case DRM_PLANE_TYPE_PRIMARY:
1040 + case DRM_PLANE_TYPE_OVERLAY:
1043 + case DRM_PLANE_TYPE_CURSOR:
1047 + drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
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;
1060 + vc4_plane_destroy(plane);
1062 + return ERR_PTR(ret);
1065 +static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
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},
1077 + union hdmi_infoframe frame;
1080 + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode);
1082 + DRM_ERROR("couldn't fill AVI infoframe\n");
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;
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;
1113 + switch (frame.avi.picture_aspect) {
1115 + case HDMI_PICTURE_ASPECT_NONE:
1116 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
1118 + case HDMI_PICTURE_ASPECT_4_3:
1119 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
1121 + case HDMI_PICTURE_ASPECT_16_9:
1122 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
1124 + case HDMI_PICTURE_ASPECT_64_27:
1125 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
1127 + case HDMI_PICTURE_ASPECT_256_135:
1128 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
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;
1137 + mb.timings.video_id_code = frame.avi.video_code;
1139 + if (!vc4_encoder->hdmi_monitor) {
1140 + mb.timings.flags |= TIMINGS_FLAGS_DVI;
1142 + struct vc4_fkms_connector_state *conn_state =
1143 + to_vc4_fkms_connector_state(vc4_crtc->connector->state);
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;
1151 + if (conn_state->broadcast_rgb ==
1152 + VC4_BROADCAST_RGB_LIMITED)
1153 + mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
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
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;
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:
1182 + ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
1185 +static void vc4_crtc_disable(struct drm_crtc *crtc,
1186 + struct drm_atomic_state *state)
1188 + struct drm_device *dev = crtc->dev;
1189 + struct drm_plane *plane;
1191 + DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
1193 + drm_crtc_vblank_off(crtc);
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.
1202 + drm_atomic_crtc_for_each_plane(plane, crtc)
1203 + vc4_plane_atomic_disable(plane, state);
1206 + * Make sure we issue a vblank event after disabling the CRTC if
1207 + * someone was waiting it.
1209 + if (crtc->state->event) {
1210 + unsigned long flags;
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);
1219 +static void vc4_crtc_consume_event(struct drm_crtc *crtc)
1221 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1222 + struct drm_device *dev = crtc->dev;
1223 + unsigned long flags;
1225 + if (!crtc->state->event)
1228 + crtc->state->event->pipe = drm_crtc_index(crtc);
1230 + WARN_ON(drm_crtc_vblank_get(crtc) != 0);
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);
1238 +static void vc4_crtc_enable(struct drm_crtc *crtc,
1239 + struct drm_atomic_state *state)
1241 + struct drm_plane *plane;
1243 + DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
1245 + drm_crtc_vblank_on(crtc);
1246 + vc4_crtc_consume_event(crtc);
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);
1254 +static enum drm_mode_status
1255 +vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
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;
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",
1266 + return MODE_NO_DBLESCAN;
1269 + /* Disable refresh rates > defined threshold (default 85Hz) as limited
1272 + if (drm_mode_vrefresh(mode) > fkms_max_refresh_rate)
1273 + return MODE_BAD_VVALUE;
1275 + /* Limit the pixel clock based on the HDMI clock limits from the
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;
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;
1291 + /* Pi4 can't generate odd horizontal timings on HDMI, so reject modes
1292 + * that would set them.
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;
1310 +static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
1311 + struct drm_atomic_state *state)
1313 + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
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;
1320 + DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
1322 + for_each_new_connector_in_state(crtc_state->state, conn, conn_state, i) {
1323 + if (conn_state->crtc != crtc)
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;
1335 +static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
1336 + struct drm_atomic_state *state)
1338 + struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
1341 + DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
1343 + if (crtc->state->active && old_state->active && crtc->state->event)
1344 + vc4_crtc_consume_event(crtc);
1347 +static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
1349 + struct drm_crtc *crtc = &vc4_crtc->base;
1350 + struct drm_device *dev = crtc->dev;
1351 + unsigned long flags;
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);
1359 + spin_unlock_irqrestore(&dev->event_lock, flags);
1362 +static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
1364 + struct vc4_crtc **crtc_list = data;
1366 + u32 stat = readl(crtc_list[0]->regs + SMICS);
1367 + irqreturn_t ret = IRQ_NONE;
1370 + if (stat & SMICS_INTERRUPTS) {
1371 + writel(0, crtc_list[0]->regs + SMICS);
1373 + chan = readl(crtc_list[0]->regs + SMIDSW0);
1375 + if ((chan & 0xFFFF0000) != SMI_NEW) {
1376 + /* Older firmware. Treat the one interrupt as vblank/
1377 + * complete for all crtcs.
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]);
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]);
1392 + if (crtc_list[1]) {
1393 + /* Check for the secondary display too */
1394 + chan = readl(crtc_list[0]->regs + SMIDSW1);
1397 + writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
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]);
1406 + ret = IRQ_HANDLED;
1412 +static int vc4_fkms_page_flip(struct drm_crtc *crtc,
1413 + struct drm_framebuffer *fb,
1414 + struct drm_pending_vblank_event *event,
1416 + struct drm_modeset_acquire_ctx *ctx)
1418 + if (flags & DRM_MODE_PAGE_FLIP_ASYNC) {
1419 + DRM_ERROR("Async flips aren't allowed\n");
1423 + return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
1426 +static struct drm_crtc_state *
1427 +vc4_fkms_crtc_duplicate_state(struct drm_crtc *crtc)
1429 + struct vc4_crtc_state *vc4_state, *old_vc4_state;
1431 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
1435 + old_vc4_state = to_vc4_crtc_state(crtc->state);
1436 + vc4_state->margins = old_vc4_state->margins;
1438 + __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
1439 + return &vc4_state->base;
1443 +vc4_fkms_crtc_reset(struct drm_crtc *crtc)
1446 + __drm_atomic_helper_crtc_destroy_state(crtc->state);
1448 + crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
1450 + crtc->state->crtc = crtc;
1453 +static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
1455 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1457 + DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
1459 + vc4_crtc->vblank_enabled = true;
1464 +static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
1466 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1468 + DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
1470 + vc4_crtc->vblank_enabled = false;
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,
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,
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 },
1503 +static enum drm_connector_status
1504 +vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
1506 + DRM_DEBUG_KMS("connector detect.\n");
1507 + return connector_status_connected;
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)
1514 + struct vc4_dev *vc4 = fkms_connector->vc4_dev;
1515 + struct set_timings timings = { 0 };
1518 + timings.display = fkms_connector->display_number;
1520 + ret = rpi_firmware_property(vc4->firmware,
1521 + RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
1523 + if (ret || !timings.clock)
1524 + /* No mode returned - abort */
1527 + /* Equivalent to DRM_MODE macro. */
1528 + memset(mode, 0, sizeof(*mode));
1529 + strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
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;
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;
1544 + if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
1545 + mode->flags |= DRM_MODE_FLAG_PHSYNC;
1547 + mode->flags |= DRM_MODE_FLAG_NHSYNC;
1549 + if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
1550 + mode->flags |= DRM_MODE_FLAG_PVSYNC;
1552 + mode->flags |= DRM_MODE_FLAG_NVSYNC;
1554 + if (timings.flags & TIMINGS_FLAGS_INTERLACE)
1555 + mode->flags |= DRM_MODE_FLAG_INTERLACE;
1560 +static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
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,
1570 + .display_number = fkms_connector->display_number,
1574 + ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
1577 + memcpy(buf, mb.edid, len);
1582 +static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
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;
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,
1597 + drm_mode_probed_add(connector, mode);
1598 + num_modes = 1; /* 1 mode */
1600 + edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
1603 + /* FIXME: Can we do CEC?
1604 + * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
1609 + vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
1611 + drm_connector_update_edid_property(connector, edid);
1612 + num_modes = drm_add_edid_modes(connector, edid);
1619 +/* This is the DSI panel resolution. Use this as a default should the firmware
1620 + * not respond to our request for the timings.
1622 +static const struct drm_display_mode lcd_mode = {
1623 + DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
1625 + 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
1626 + 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
1630 +static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
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;
1637 + if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
1638 + mode = drm_mode_duplicate(connector->dev,
1641 + mode = drm_mode_duplicate(connector->dev,
1645 + DRM_ERROR("Failed to create a new display mode\n");
1649 + drm_mode_probed_add(connector, mode);
1651 + /* We have one mode */
1655 +static struct drm_encoder *
1656 +vc4_fkms_connector_best_encoder(struct drm_connector *connector)
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;
1664 +static void vc4_fkms_connector_destroy(struct drm_connector *connector)
1666 + DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
1667 + connector->base.id);
1668 + drm_connector_unregister(connector);
1669 + drm_connector_cleanup(connector);
1673 + * vc4_connector_duplicate_state - duplicate connector state
1674 + * @connector: digital connector
1676 + * Allocates and returns a copy of the connector state (both common and
1677 + * digital connector specific) for the specified connector.
1679 + * Returns: The newly allocated connector state, or NULL on failure.
1681 +struct drm_connector_state *
1682 +vc4_connector_duplicate_state(struct drm_connector *connector)
1684 + struct vc4_fkms_connector_state *state;
1686 + state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
1690 + __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
1691 + return &state->base;
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.
1701 + * Returns the atomic property value for a digital connector.
1703 +int vc4_connector_atomic_get_property(struct drm_connector *connector,
1704 + const struct drm_connector_state *state,
1705 + struct drm_property *property,
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);
1713 + if (property == fkms_connector->broadcast_rgb_property) {
1714 + *val = vc4_conn_state->broadcast_rgb;
1716 + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
1717 + property->base.id, property->name);
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.
1731 + * Sets the atomic property value for a digital connector.
1733 +int vc4_connector_atomic_set_property(struct drm_connector *connector,
1734 + struct drm_connector_state *state,
1735 + struct drm_property *property,
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);
1743 + if (property == fkms_connector->broadcast_rgb_property) {
1744 + vc4_conn_state->broadcast_rgb = val;
1748 + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
1749 + property->base.id, property->name);
1753 +int vc4_connector_atomic_check(struct drm_connector *connector,
1754 + struct drm_atomic_state *state)
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;
1769 + if (vc4_old_state->broadcast_rgb != vc4_new_state->broadcast_rgb) {
1770 + struct drm_crtc_state *crtc_state;
1772 + crtc_state = drm_atomic_get_crtc_state(state, crtc);
1773 + if (IS_ERR(crtc_state))
1774 + return PTR_ERR(crtc_state);
1776 + crtc_state->mode_changed = true;
1781 +static void vc4_hdmi_connector_reset(struct drm_connector *connector)
1783 + drm_atomic_helper_connector_reset(connector);
1784 + drm_atomic_helper_connector_tv_reset(connector);
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,
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,
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,
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" },
1816 +vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
1818 + struct drm_device *dev = fkms_connector->base.dev;
1819 + struct drm_property *prop;
1821 + prop = fkms_connector->broadcast_rgb_property;
1823 + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
1825 + broadcast_rgb_names,
1826 + ARRAY_SIZE(broadcast_rgb_names));
1830 + fkms_connector->broadcast_rgb_property = prop;
1833 + drm_object_attach_property(&fkms_connector->base.base, prop, 0);
1836 +static struct drm_connector *
1837 +vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
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);
1846 + DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
1848 + fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
1850 + if (!fkms_connector)
1851 + return ERR_PTR(-ENOMEM);
1854 + * Allocate enough memory to hold vc4_fkms_connector_state,
1856 + conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
1857 + if (!conn_state) {
1858 + kfree(fkms_connector);
1859 + return ERR_PTR(-ENOMEM);
1862 + connector = &fkms_connector->base;
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;
1869 + __drm_atomic_helper_connector_reset(connector,
1870 + &conn_state->base);
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;
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;
1892 + ret = drm_mode_create_tv_margin_properties(dev);
1896 + drm_connector_attach_tv_margin_properties(connector);
1898 + connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
1899 + DRM_CONNECTOR_POLL_DISCONNECT);
1901 + connector->doublescan_allowed = 0;
1903 + vc4_attach_broadcast_rgb_property(fkms_connector);
1905 + drm_connector_attach_encoder(connector, encoder);
1911 + vc4_fkms_connector_destroy(connector);
1913 + return ERR_PTR(ret);
1916 +static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
1918 + DRM_DEBUG_KMS("Encoder_destroy\n");
1919 + drm_encoder_cleanup(encoder);
1922 +static const struct drm_encoder_funcs vc4_fkms_encoder_funcs = {
1923 + .destroy = vc4_fkms_encoder_destroy,
1926 +static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
1928 + struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
1929 + struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
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,
1937 + rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
1940 +static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
1942 + vc4_fkms_display_power(encoder, true);
1943 + DRM_DEBUG_KMS("Encoder_enable\n");
1946 +static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
1948 + vc4_fkms_display_power(encoder, false);
1949 + DRM_DEBUG_KMS("Encoder_disable\n");
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,
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)
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, },
1972 + struct drm_plane *planes[PLANES_PER_CRTC];
1975 + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
1978 + crtc = &vc4_crtc->base;
1980 + vc4_crtc->display_number = display_ref;
1981 + vc4_crtc->display_type = vc4_get_display_type(display_ref);
1983 + /* Blank the firmware provided framebuffer */
1984 + rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
1986 + for (i = 0; i < PLANES_PER_CRTC; i++) {
1987 + planes[i] = vc4_fkms_plane_init(drm,
1989 + DRM_PLANE_TYPE_PRIMARY :
1990 + (i == PLANES_PER_CRTC - 1) ?
1991 + DRM_PLANE_TYPE_CURSOR :
1992 + DRM_PLANE_TYPE_OVERLAY,
1994 + i + (display_idx * PLANES_PER_CRTC)
1996 + if (IS_ERR(planes[i])) {
1997 + dev_err(dev, "failed to construct plane %u\n", i);
1998 + ret = PTR_ERR(planes[i]);
2003 + drm_crtc_init_with_planes(drm, crtc, planes[0],
2004 + planes[PLANES_PER_CRTC - 1], &vc4_crtc_funcs,
2006 + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
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);
2012 + vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
2015 + vc4_crtc->encoder = &vc4_encoder->base;
2017 + vc4_encoder->display_num = display_ref;
2018 + vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc);
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);
2025 + vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
2027 + if (IS_ERR(vc4_crtc->connector)) {
2028 + ret = PTR_ERR(vc4_crtc->connector);
2029 + goto err_destroy_encoder;
2032 + *ret_crtc = vc4_crtc;
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);
2047 +static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
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;
2060 + vc4->firmware_kms = true;
2062 + fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
2066 + match = of_match_device(vc4_firmware_kms_dt_match, dev);
2070 + fkms->bcm2711 = true;
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;
2078 + of_node_put(firmware_node);
2080 + ret = rpi_firmware_property(vc4->firmware,
2081 + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
2082 + &num_displays, sizeof(u32));
2084 + /* If we fail to get the number of displays, then
2085 + * assume old firmware that doesn't have the mailbox call, so just
2090 + DRM_WARN("Unable to determine number of displays - assuming 1\n");
2094 + ret = rpi_firmware_property(vc4->firmware,
2095 + RPI_FIRMWARE_GET_DISPLAY_CFG,
2096 + &fkms->cfg, sizeof(fkms->cfg));
2100 + /* The firmware works in Hz. This will be compared against kHz, so div
2101 + * 1000 now rather than multiple times later.
2103 + fkms->cfg.max_pixel_clock[0] /= 1000;
2104 + fkms->cfg.max_pixel_clock[1] /= 1000;
2106 + /* Allocate a list, with space for a NULL on the end */
2107 + crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
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?
2122 + DRM_ERROR("Failed to get display id %u\n", display_num);
2124 + ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
2125 + &crtc_list[display_num]);
2127 + DRM_ERROR("Oh dear, failed to create display %u\n",
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");
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);
2142 + DRM_ERROR("Oh dear, failed to register IRQ\n");
2144 + DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
2149 + platform_set_drvdata(pdev, crtc_list);
2154 +static void vc4_fkms_unbind(struct device *dev, struct device *master,
2157 + struct platform_device *pdev = to_platform_device(dev);
2158 + struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
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);
2167 + platform_set_drvdata(pdev, NULL);
2170 +static const struct component_ops vc4_fkms_ops = {
2171 + .bind = vc4_fkms_bind,
2172 + .unbind = vc4_fkms_unbind,
2175 +static int vc4_fkms_probe(struct platform_device *pdev)
2177 + return component_add(&pdev->dev, &vc4_fkms_ops);
2180 +static int vc4_fkms_remove(struct platform_device *pdev)
2182 + component_del(&pdev->dev, &vc4_fkms_ops);
2186 +struct platform_driver vc4_firmware_kms_driver = {
2187 + .probe = vc4_fkms_probe,
2188 + .remove = vc4_fkms_remove,
2190 + .name = "vc4_firmware_kms",
2191 + .of_match_table = vc4_firmware_kms_dt_match,
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;
2200 + if (vc4->firmware_kms)
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;
2210 - if (!new_crtc_state->commit)
2211 + if (!new_crtc_state->commit || vc4->firmware_kms)
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;
2219 - if (vc4->hvs->hvs5) {
2220 + if (vc4->hvs && vc4->hvs->hvs5) {
2221 unsigned long core_rate = max_t(unsigned long,
2223 new_hvs_state->core_clock_rate);
2224 @@ -402,10 +405,12 @@ static void vc4_atomic_commit_tail(struc
2226 vc4_ctm_commit(vc4, state);
2228 - if (vc4->hvs->hvs5)
2229 - vc5_hvs_pv_muxing_commit(vc4, state);
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);
2236 + vc4_hvs_pv_muxing_commit(vc4, state);
2239 drm_atomic_helper_commit_planes(dev, state, 0);
2241 @@ -419,7 +424,7 @@ static void vc4_atomic_commit_tail(struc
2243 drm_atomic_helper_cleanup_planes(dev, state);
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);
2250 @@ -437,11 +442,21 @@ static void vc4_atomic_commit_tail(struc
2252 static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
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;
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.
2266 + if (!vc4->firmware_kms)
2267 + state->legacy_cursor_update = false;
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)
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;
2284 + if (vc4->firmware_kms)
2287 /* Nothing to do here, let's skip it */
2288 if (old_crtc_state->enable == new_crtc_state->enable)
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;
2297 ret = vc4_ctm_obj_init(vc4);
2300 +++ b/drivers/gpu/drm/vc4/vc_image_types.h
2304 + * Copyright (c) 2012, Broadcom Europe Ltd
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
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.
2317 + VC_IMAGE_MIN = 0, //bounds for error checking
2319 + VC_IMAGE_RGB565 = 1,
2325 + /* 4bpp palettised image */
2327 + /* A separated format of 16 colour/light shorts followed by 16 z
2331 + /* 16 colours followed by 16 z values */
2333 + /* A separated format of 16 material/colour/light shorts followed by
2337 + /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
2339 + /* 32-bit format holding 18 bits of 6.6.6 RGB */
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 */
2347 + /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
2348 + * line of V (16-byte padded)
2351 + /* RGB565 with a transparent patch */
2353 + /* Compressed (4444) version of RGBA32 */
2355 + /* VCIII codec format */
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 */
2371 + /* VCIII T-format 8 bit generic sample */
2373 + /* VCIII T-format 8-bit palette */
2375 + /* VCIII T-format 4-bit palette */
2377 + /* VCIII T-format Ericsson Texture Compressed */
2379 + /* RGB888 with R & B swapped */
2381 + /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
2382 + * each row of pixels
2384 + VC_IMAGE_BGR888_NP,
2385 + /* Bayer image, extra defines which variant is being used */
2387 + /* General wrapper for codec images e.g. JPEG from camera */
2389 + /* VCIII codec format */
2390 + VC_IMAGE_YUV_UV32,
2391 + /* VCIII T-format 8-bit luma */
2393 + /* VCIII T-format 8-bit alpha */
2395 + /* VCIII T-format 16-bit generic sample */
2396 + VC_IMAGE_TF_SHORT,
2397 + /* VCIII T-format 1bpp black/white */
2400 + /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
2402 + /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
2403 + * a per line basis)
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,
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,
2417 + /* 32bpp like RGBA32 but with unused alpha */
2419 + /* 32bpp, corresponding to RGBA with unused alpha */
2420 + VC_IMAGE_RGBX8888,
2421 + /* 32bpp, corresponding to BGRA with unused alpha */
2422 + VC_IMAGE_BGRX8888,
2424 + /* Y as a plane, then UV byte interleaved in plane with same pitch,
2427 + VC_IMAGE_YUV420SP,
2429 + /* Y, U, & V planes separately 4:4:4 */
2430 + VC_IMAGE_YUV444PLANAR,
2432 + /* T-format 8-bit U - same as TF_Y8 buf from U plane */
2434 + /* T-format 8-bit U - same as TF_Y8 buf from V plane */
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,
2448 + VC_IMAGE_MAX, /* bounds for error checking */
2449 + VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
2453 + /* Unknown or unset - defaults to BT601 interstitial */
2454 + VC_IMAGE_YUVINFO_UNSPECIFIED = 0,
2456 + /* colour-space conversions data [4 bits] */
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,
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,
2475 + VC_IMAGE_YUVINFO_CSC_REC_2020 = 9,
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 {
2489 RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
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,