1 From 0f304a905699ed05a418ac1cd98bcec6f2220a89 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 drivers/gpu/drm/vc4/Makefile | 1 +
25 drivers/gpu/drm/vc4/vc4_drv.c | 15 +-
26 drivers/gpu/drm/vc4/vc4_drv.h | 8 +
27 drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1958 ++++++++++++++++++++
28 drivers/gpu/drm/vc4/vc4_kms.c | 27 +-
29 drivers/gpu/drm/vc4/vc_image_types.h | 175 ++
30 include/soc/bcm2835/raspberrypi-firmware.h | 6 +
31 7 files changed, 2177 insertions(+), 13 deletions(-)
32 create mode 100644 drivers/gpu/drm/vc4/vc4_firmware_kms.c
33 create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h
35 --- a/drivers/gpu/drm/vc4/Makefile
36 +++ b/drivers/gpu/drm/vc4/Makefile
37 @@ -9,6 +9,7 @@ vc4-y := \
41 + vc4_firmware_kms.o \
45 --- a/drivers/gpu/drm/vc4/vc4_drv.c
46 +++ b/drivers/gpu/drm/vc4/vc4_drv.c
47 @@ -307,9 +307,11 @@ static int vc4_drm_bind(struct device *d
51 - ret = vc4_plane_create_additional_planes(drm);
54 + if (!vc4->firmware_kms) {
55 + ret = vc4_plane_create_additional_planes(drm);
60 drm_fb_helper_remove_conflicting_framebuffers(NULL, "vc4drmfb", false);
62 @@ -317,8 +319,10 @@ static int vc4_drm_bind(struct device *d
66 - drm_for_each_crtc(crtc, drm)
67 - vc4_crtc_disable_at_boot(crtc);
68 + if (!vc4->firmware_kms) {
69 + drm_for_each_crtc(crtc, drm)
70 + vc4_crtc_disable_at_boot(crtc);
73 ret = drm_dev_register(drm, 0);
75 @@ -356,6 +360,7 @@ static struct platform_driver *const com
79 + &vc4_firmware_kms_driver,
83 --- a/drivers/gpu/drm/vc4/vc4_drv.h
84 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
85 @@ -74,12 +74,17 @@ struct vc4_perfmon {
87 struct drm_device base;
90 + struct rpi_firmware *firmware;
92 + struct vc4_hdmi *hdmi;
99 + struct vc4_fkms *fkms;
101 struct vc4_hang_state *hang_state;
103 @@ -877,6 +882,9 @@ extern struct platform_driver vc4_dsi_dr
105 extern const struct dma_fence_ops vc4_fence_ops;
107 +/* vc4_firmware_kms.c */
108 +extern struct platform_driver vc4_firmware_kms_driver;
111 int vc4_gem_init(struct drm_device *dev);
112 int vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
114 +++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
116 +// SPDX-License-Identifier: GPL-2.0-only
118 + * Copyright (C) 2016 Broadcom
120 + * This program is free software; you can redistribute it and/or modify
121 + * it under the terms of the GNU General Public License version 2 as
122 + * published by the Free Software Foundation.
126 + * DOC: VC4 firmware KMS module.
128 + * As a hack to get us from the current closed source driver world
129 + * toward a totally open stack, implement KMS on top of the Raspberry
130 + * Pi's firmware display stack.
133 +#include <drm/drm_atomic_helper.h>
134 +#include <drm/drm_crtc_helper.h>
135 +#include <drm/drm_drv.h>
136 +#include <drm/drm_fb_cma_helper.h>
137 +#include <drm/drm_fourcc.h>
138 +#include <drm/drm_gem_framebuffer_helper.h>
139 +#include <drm/drm_plane_helper.h>
140 +#include <drm/drm_probe_helper.h>
141 +#include <drm/drm_vblank.h>
143 +#include <linux/component.h>
144 +#include <linux/clk.h>
145 +#include <linux/debugfs.h>
146 +#include <linux/module.h>
148 +#include <soc/bcm2835/raspberrypi-firmware.h>
150 +#include "vc4_drv.h"
151 +#include "vc4_regs.h"
152 +#include "vc_image_types.h"
154 +int fkms_max_refresh_rate = 85;
155 +module_param(fkms_max_refresh_rate, int, 0644);
156 +MODULE_PARM_DESC(fkms_max_refresh_rate, "Max supported refresh rate");
158 +struct get_display_cfg {
159 + u32 max_pixel_clock[2]; //Max pixel clock for each display
163 + struct get_display_cfg cfg;
167 +#define PLANES_PER_CRTC 8
181 + u32 src_x; /* 16p16 */
182 + u32 src_y; /* 16p16 */
184 + u32 src_w; /* 16p16 */
185 + u32 src_h; /* 16p16 */
198 + u32 planes[4]; /* DMA address of each plane */
203 +/* Values for the transform field */
204 +#define TRANSFORM_NO_ROTATE 0
205 +#define TRANSFORM_ROTATE_180 BIT(1)
206 +#define TRANSFORM_FLIP_HRIZ BIT(16)
207 +#define TRANSFORM_FLIP_VERT BIT(17)
209 +struct mailbox_set_plane {
210 + struct rpi_firmware_property_tag_header tag;
211 + struct set_plane plane;
214 +struct mailbox_blank_display {
215 + struct rpi_firmware_property_tag_header tag1;
217 + struct rpi_firmware_property_tag_header tag2;
221 +struct mailbox_display_pwr {
222 + struct rpi_firmware_property_tag_header tag1;
227 +struct mailbox_get_edid {
228 + struct rpi_firmware_property_tag_header tag1;
230 + u32 display_number;
234 +struct set_timings {
239 + u32 clock; /* in kHz */
260 +#define TIMINGS_FLAGS_H_SYNC_POS BIT(0)
261 +#define TIMINGS_FLAGS_H_SYNC_NEG 0
262 +#define TIMINGS_FLAGS_V_SYNC_POS BIT(1)
263 +#define TIMINGS_FLAGS_V_SYNC_NEG 0
264 +#define TIMINGS_FLAGS_INTERLACE BIT(2)
266 +#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4)
267 +#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4)
268 +#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4)
269 +#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4)
270 +#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4)
271 +#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4)
273 +/* Limited range RGB flag. Not set corresponds to full range. */
274 +#define TIMINGS_FLAGS_RGB_LIMITED BIT(8)
275 +/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */
276 +#define TIMINGS_FLAGS_DVI BIT(9)
278 +#define TIMINGS_FLAGS_DBL_CLK BIT(10)
281 +struct mailbox_set_mode {
282 + struct rpi_firmware_property_tag_header tag1;
283 + struct set_timings timings;
286 +static const struct vc_image_format {
287 + u32 drm; /* DRM_FORMAT_* */
288 + u32 vc_image; /* VC_IMAGE_* */
290 +} vc_image_formats[] = {
292 + .drm = DRM_FORMAT_XRGB8888,
293 + .vc_image = VC_IMAGE_XRGB8888,
296 + .drm = DRM_FORMAT_ARGB8888,
297 + .vc_image = VC_IMAGE_ARGB8888,
300 + * FIXME: Need to resolve which DRM format goes to which vc_image format
301 + * for the remaining RGBA and RGBX formats.
303 + * .drm = DRM_FORMAT_ABGR8888,
304 + * .vc_image = VC_IMAGE_RGBA8888,
307 + * .drm = DRM_FORMAT_XBGR8888,
308 + * .vc_image = VC_IMAGE_RGBA8888,
312 + .drm = DRM_FORMAT_RGB565,
313 + .vc_image = VC_IMAGE_RGB565,
316 + .drm = DRM_FORMAT_RGB888,
317 + .vc_image = VC_IMAGE_BGR888,
320 + .drm = DRM_FORMAT_BGR888,
321 + .vc_image = VC_IMAGE_RGB888,
324 + .drm = DRM_FORMAT_YUV422,
325 + .vc_image = VC_IMAGE_YUV422PLANAR,
328 + .drm = DRM_FORMAT_YUV420,
329 + .vc_image = VC_IMAGE_YUV420,
332 + .drm = DRM_FORMAT_YVU420,
333 + .vc_image = VC_IMAGE_YUV420,
337 + .drm = DRM_FORMAT_NV12,
338 + .vc_image = VC_IMAGE_YUV420SP,
341 + .drm = DRM_FORMAT_NV21,
342 + .vc_image = VC_IMAGE_YUV420SP,
346 + .drm = DRM_FORMAT_P030,
347 + .vc_image = VC_IMAGE_YUV10COL,
351 +static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
355 + for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) {
356 + if (vc_image_formats[i].drm == drm_format)
357 + return &vc_image_formats[i];
363 +/* The firmware delivers a vblank interrupt to us through the SMI
364 + * hardware, which has only this one register.
367 +#define SMIDSW0 0x14
368 +#define SMIDSW1 0x1C
369 +#define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
371 +/* Flag to denote that the firmware is giving multiple display callbacks */
372 +#define SMI_NEW 0xabcd0000
374 +#define vc4_crtc vc4_kms_crtc
375 +#define to_vc4_crtc to_vc4_kms_crtc
377 + struct drm_crtc base;
378 + struct drm_encoder *encoder;
379 + struct drm_connector *connector;
380 + void __iomem *regs;
382 + struct drm_pending_vblank_event *event;
383 + bool vblank_enabled;
384 + u32 display_number;
388 +static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
390 + return container_of(crtc, struct vc4_crtc, base);
393 +struct vc4_fkms_encoder {
394 + struct drm_encoder base;
396 + bool rgb_range_selectable;
400 +static inline struct vc4_fkms_encoder *
401 +to_vc4_fkms_encoder(struct drm_encoder *encoder)
403 + return container_of(encoder, struct vc4_fkms_encoder, base);
406 +/* "Broadcast RGB" property.
407 + * Allows overriding of HDMI full or limited range RGB
409 +#define VC4_BROADCAST_RGB_AUTO 0
410 +#define VC4_BROADCAST_RGB_FULL 1
411 +#define VC4_BROADCAST_RGB_LIMITED 2
413 +/* VC4 FKMS connector KMS struct */
414 +struct vc4_fkms_connector {
415 + struct drm_connector base;
417 + /* Since the connector is attached to just the one encoder,
418 + * this is the reference to it so we can do the best_encoder()
421 + struct drm_encoder *encoder;
422 + struct vc4_dev *vc4_dev;
423 + u32 display_number;
426 + struct drm_property *broadcast_rgb_property;
429 +static inline struct vc4_fkms_connector *
430 +to_vc4_fkms_connector(struct drm_connector *connector)
432 + return container_of(connector, struct vc4_fkms_connector, base);
435 +/* VC4 FKMS connector state */
436 +struct vc4_fkms_connector_state {
437 + struct drm_connector_state base;
442 +#define to_vc4_fkms_connector_state(x) \
443 + container_of(x, struct vc4_fkms_connector_state, base)
445 +static u32 vc4_get_display_type(u32 display_number)
447 + const u32 display_types[] = {
448 + /* The firmware display (DispmanX) IDs map to specific types in
451 + DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */
452 + DRM_MODE_ENCODER_DSI, /* AUX_LCD */
453 + DRM_MODE_ENCODER_TMDS, /* HDMI0 */
454 + DRM_MODE_ENCODER_TVDAC, /* VEC */
455 + DRM_MODE_ENCODER_NONE, /* FORCE_LCD */
456 + DRM_MODE_ENCODER_NONE, /* FORCE_TV */
457 + DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */
458 + DRM_MODE_ENCODER_TMDS, /* HDMI1 */
459 + DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */
461 + return display_number > ARRAY_SIZE(display_types) - 1 ?
462 + DRM_MODE_ENCODER_NONE : display_types[display_number];
465 +/* Firmware's structure for making an FB mbox call. */
467 + u32 xres, yres, xres_virtual, yres_virtual;
469 + u32 xoffset, yoffset;
475 +struct vc4_fkms_plane {
476 + struct drm_plane base;
477 + struct fbinfo_s *fbinfo;
478 + dma_addr_t fbinfo_bus_addr;
480 + struct mailbox_set_plane mb;
483 +static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
485 + return (struct vc4_fkms_plane *)plane;
488 +static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
490 + struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
491 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
492 + struct mailbox_set_plane blank_mb = {
493 + .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 },
495 + .display = vc4_plane->mb.plane.display,
496 + .plane_id = vc4_plane->mb.plane.plane_id,
499 + static const char * const plane_types[] = {
506 + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s",
507 + plane->base.id, plane->name, plane_types[plane->type],
508 + blank ? "blank" : "unblank");
511 + ret = rpi_firmware_property_list(vc4->firmware, &blank_mb,
514 + ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb,
515 + sizeof(vc4_plane->mb));
517 + WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware",
522 +static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
523 + unsigned int *left, unsigned int *right,
524 + unsigned int *top, unsigned int *bottom)
526 + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
527 + struct drm_connector_state *conn_state;
528 + struct drm_connector *conn;
531 + *left = vc4_state->margins.left;
532 + *right = vc4_state->margins.right;
533 + *top = vc4_state->margins.top;
534 + *bottom = vc4_state->margins.bottom;
536 + /* We have to interate over all new connector states because
537 + * vc4_fkms_crtc_get_margins() might be called before
538 + * vc4_fkms_crtc_atomic_check() which means margins info in
539 + * vc4_crtc_state might be outdated.
541 + for_each_new_connector_in_state(state->state, conn, conn_state, i) {
542 + if (conn_state->crtc != state->crtc)
545 + *left = conn_state->tv.margins.left;
546 + *right = conn_state->tv.margins.right;
547 + *top = conn_state->tv.margins.top;
548 + *bottom = conn_state->tv.margins.bottom;
553 +static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
554 + struct set_plane *plane)
556 + unsigned int left, right, top, bottom;
557 + int adjhdisplay, adjvdisplay;
558 + struct drm_crtc_state *crtc_state;
560 + crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
563 + vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
565 + if (!left && !right && !top && !bottom)
568 + if (left + right >= crtc_state->mode.hdisplay ||
569 + top + bottom >= crtc_state->mode.vdisplay)
572 + adjhdisplay = crtc_state->mode.hdisplay - (left + right);
573 + plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
574 + (int)crtc_state->mode.hdisplay);
575 + plane->dst_x += left;
576 + if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left))
577 + plane->dst_x = crtc_state->mode.hdisplay - left;
579 + adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
580 + plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
581 + (int)crtc_state->mode.vdisplay);
582 + plane->dst_y += top;
583 + if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top))
584 + plane->dst_y = crtc_state->mode.vdisplay - top;
586 + plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
587 + crtc_state->mode.hdisplay);
588 + plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
589 + crtc_state->mode.vdisplay);
591 + if (!plane->dst_w || !plane->dst_h)
597 +static void vc4_plane_atomic_update(struct drm_plane *plane,
598 + struct drm_plane_state *old_state)
600 + struct drm_plane_state *state = plane->state;
603 + * Do NOT set now, as we haven't checked if the crtc is active or not.
604 + * Set from vc4_plane_set_blank instead.
606 + * If the CRTC is on (or going to be on) and we're enabled,
607 + * then unblank. Otherwise, stay blank until CRTC enable.
609 + if (state->crtc->state->active)
610 + vc4_plane_set_blank(plane, false);
613 +static void vc4_plane_atomic_disable(struct drm_plane *plane,
614 + struct drm_plane_state *old_state)
616 + struct drm_plane_state *state = plane->state;
617 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
619 + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
620 + plane->base.id, plane->name,
623 + vc4_plane->mb.plane.vc_image_type,
626 + vc4_plane_set_blank(plane, true);
629 +static bool plane_enabled(struct drm_plane_state *state)
631 + return state->fb && state->crtc;
634 +static int vc4_plane_to_mb(struct drm_plane *plane,
635 + struct mailbox_set_plane *mb,
636 + struct drm_plane_state *state)
638 + struct drm_framebuffer *fb = state->fb;
639 + struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
640 + const struct drm_format_info *drm_fmt = fb->format;
641 + const struct vc_image_format *vc_fmt =
642 + vc4_get_vc_image_fmt(drm_fmt->format);
643 + int num_planes = fb->format->num_planes;
644 + unsigned int rotation;
646 + mb->plane.vc_image_type = vc_fmt->vc_image;
647 + mb->plane.width = fb->width;
648 + mb->plane.height = fb->height;
649 + mb->plane.pitch = fb->pitches[0];
650 + mb->plane.src_w = state->src_w;
651 + mb->plane.src_h = state->src_h;
652 + mb->plane.src_x = state->src_x;
653 + mb->plane.src_y = state->src_y;
654 + mb->plane.dst_w = state->crtc_w;
655 + mb->plane.dst_h = state->crtc_h;
656 + mb->plane.dst_x = state->crtc_x;
657 + mb->plane.dst_y = state->crtc_y;
658 + mb->plane.alpha = state->alpha >> 8;
659 + mb->plane.layer = state->normalized_zpos ?
660 + state->normalized_zpos : -127;
661 + mb->plane.num_planes = num_planes;
662 + mb->plane.is_vu = vc_fmt->is_vu;
663 + mb->plane.planes[0] = bo->paddr + fb->offsets[0];
665 + rotation = drm_rotation_simplify(state->rotation,
666 + DRM_MODE_ROTATE_0 |
667 + DRM_MODE_REFLECT_X |
668 + DRM_MODE_REFLECT_Y);
670 + mb->plane.transform = TRANSFORM_NO_ROTATE;
671 + if (rotation & DRM_MODE_REFLECT_X)
672 + mb->plane.transform |= TRANSFORM_FLIP_HRIZ;
673 + if (rotation & DRM_MODE_REFLECT_Y)
674 + mb->plane.transform |= TRANSFORM_FLIP_VERT;
676 + vc4_fkms_margins_adj(state, &mb->plane);
678 + if (num_planes > 1) {
679 + /* Assume this must be YUV */
680 + /* Makes assumptions on the stride for the chroma planes as we
681 + * can't easily plumb in non-standard pitches.
683 + mb->plane.planes[1] = bo->paddr + fb->offsets[1];
684 + if (num_planes > 2)
685 + mb->plane.planes[2] = bo->paddr + fb->offsets[2];
687 + mb->plane.planes[2] = 0;
689 + /* Special case the YUV420 with U and V as line interleaved
690 + * planes as we have special handling for that case.
692 + if (num_planes == 3 &&
693 + (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1])
694 + mb->plane.vc_image_type = VC_IMAGE_YUV420_S;
696 + switch (state->color_encoding) {
698 + case DRM_COLOR_YCBCR_BT601:
699 + if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE)
700 + mb->plane.color_encoding =
701 + VC_IMAGE_YUVINFO_CSC_ITUR_BT601;
703 + mb->plane.color_encoding =
704 + VC_IMAGE_YUVINFO_CSC_JPEG_JFIF;
706 + case DRM_COLOR_YCBCR_BT709:
707 + /* Currently no support for a full range BT709 */
708 + mb->plane.color_encoding =
709 + VC_IMAGE_YUVINFO_CSC_ITUR_BT709;
711 + case DRM_COLOR_YCBCR_BT2020:
712 + /* Currently no support for a full range BT2020 */
713 + mb->plane.color_encoding =
714 + VC_IMAGE_YUVINFO_CSC_REC_2020;
718 + mb->plane.planes[1] = 0;
719 + mb->plane.planes[2] = 0;
721 + mb->plane.planes[3] = 0;
723 + switch (fourcc_mod_broadcom_mod(fb->modifier)) {
724 + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
725 + switch (mb->plane.vc_image_type) {
726 + case VC_IMAGE_XRGB8888:
727 + mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32;
729 + case VC_IMAGE_ARGB8888:
730 + mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32;
732 + case VC_IMAGE_RGB565:
733 + mb->plane.vc_image_type = VC_IMAGE_TF_RGB565;
737 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
738 + switch (mb->plane.vc_image_type) {
739 + case VC_IMAGE_YUV420SP:
740 + mb->plane.vc_image_type = VC_IMAGE_YUV_UV;
742 + /* VC_IMAGE_YUV10COL could be included in here, but it is only
743 + * valid as a SAND128 format, so the table at the top will have
744 + * already set the correct format.
747 + /* Note that the column pitch is passed across in lines, not
750 + mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier);
754 + 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",
755 + plane->base.id, plane->name,
758 + mb->plane.vc_image_type,
767 + mb->plane.planes[0],
768 + mb->plane.planes[1],
769 + mb->plane.planes[2],
772 + state->normalized_zpos);
777 +static int vc4_plane_atomic_check(struct drm_plane *plane,
778 + struct drm_plane_state *state)
780 + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
782 + if (!plane_enabled(state))
785 + return vc4_plane_to_mb(plane, &vc4_plane->mb, state);
788 +/* Called during init to allocate the plane's atomic state. */
789 +static void vc4_plane_reset(struct drm_plane *plane)
791 + struct vc4_plane_state *vc4_state;
793 + WARN_ON(plane->state);
795 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
799 + __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
802 +static void vc4_plane_destroy(struct drm_plane *plane)
804 + drm_plane_cleanup(plane);
807 +static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
811 + /* Support T_TILING for RGB formats only. */
813 + case DRM_FORMAT_XRGB8888:
814 + case DRM_FORMAT_ARGB8888:
815 + case DRM_FORMAT_RGB565:
816 + switch (modifier) {
817 + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
818 + case DRM_FORMAT_MOD_LINEAR:
823 + case DRM_FORMAT_NV12:
824 + switch (fourcc_mod_broadcom_mod(modifier)) {
825 + case DRM_FORMAT_MOD_LINEAR:
826 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
831 + case DRM_FORMAT_P030:
832 + switch (fourcc_mod_broadcom_mod(modifier)) {
833 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
838 + case DRM_FORMAT_NV21:
839 + case DRM_FORMAT_RGB888:
840 + case DRM_FORMAT_BGR888:
841 + case DRM_FORMAT_YUV422:
842 + case DRM_FORMAT_YUV420:
843 + case DRM_FORMAT_YVU420:
845 + return (modifier == DRM_FORMAT_MOD_LINEAR);
849 +static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
851 + struct vc4_plane_state *vc4_state;
853 + if (WARN_ON(!plane->state))
856 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
860 + __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
862 + return &vc4_state->base;
865 +static const struct drm_plane_funcs vc4_plane_funcs = {
866 + .update_plane = drm_atomic_helper_update_plane,
867 + .disable_plane = drm_atomic_helper_disable_plane,
868 + .destroy = vc4_plane_destroy,
869 + .set_property = NULL,
870 + .reset = vc4_plane_reset,
871 + .atomic_duplicate_state = vc4_plane_duplicate_state,
872 + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
873 + .format_mod_supported = vc4_fkms_format_mod_supported,
876 +static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
877 + .prepare_fb = drm_gem_fb_prepare_fb,
878 + .cleanup_fb = NULL,
879 + .atomic_check = vc4_plane_atomic_check,
880 + .atomic_update = vc4_plane_atomic_update,
881 + .atomic_disable = vc4_plane_atomic_disable,
884 +static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
885 + enum drm_plane_type type,
889 + struct drm_plane *plane = NULL;
890 + struct vc4_fkms_plane *vc4_plane;
891 + u32 formats[ARRAY_SIZE(vc_image_formats)];
892 + unsigned int default_zpos = 0;
893 + u32 num_formats = 0;
895 + static const uint64_t modifiers[] = {
896 + DRM_FORMAT_MOD_LINEAR,
897 + /* VC4_T_TILED should come after linear, because we
898 + * would prefer to scan out linear (less bus traffic).
900 + DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
901 + DRM_FORMAT_MOD_BROADCOM_SAND128,
902 + DRM_FORMAT_MOD_INVALID,
906 + vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
913 + for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++)
914 + formats[num_formats++] = vc_image_formats[i].drm;
916 + plane = &vc4_plane->base;
917 + ret = drm_universal_plane_init(dev, plane, 0,
919 + formats, num_formats, modifiers,
922 + /* FIXME: Do we need to be checking return values from all these calls?
924 + drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
926 + drm_plane_create_alpha_property(plane);
927 + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
928 + DRM_MODE_ROTATE_0 |
929 + DRM_MODE_ROTATE_180 |
930 + DRM_MODE_REFLECT_X |
931 + DRM_MODE_REFLECT_Y);
932 + drm_plane_create_color_properties(plane,
933 + BIT(DRM_COLOR_YCBCR_BT601) |
934 + BIT(DRM_COLOR_YCBCR_BT709) |
935 + BIT(DRM_COLOR_YCBCR_BT2020),
936 + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
937 + BIT(DRM_COLOR_YCBCR_FULL_RANGE),
938 + DRM_COLOR_YCBCR_BT709,
939 + DRM_COLOR_YCBCR_LIMITED_RANGE);
942 + * Default frame buffer setup is with FB on -127, and raspistill etc
943 + * tend to drop overlays on layer 2. Cursor plane was on layer +127.
945 + * For F-KMS the mailbox call allows for a s8.
946 + * Remap zpos 0 to -127 for the background layer, but leave all the
947 + * other layers as requested by KMS.
951 + case DRM_PLANE_TYPE_PRIMARY:
954 + case DRM_PLANE_TYPE_OVERLAY:
957 + case DRM_PLANE_TYPE_CURSOR:
961 + drm_plane_create_zpos_property(plane, default_zpos, 0, 127);
963 + /* Prepare the static elements of the mailbox structure */
964 + vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE;
965 + vc4_plane->mb.tag.buf_size = sizeof(struct set_plane);
966 + vc4_plane->mb.tag.req_resp_size = 0;
967 + vc4_plane->mb.plane.display = display_num;
968 + vc4_plane->mb.plane.plane_id = plane_id;
969 + vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127;
974 + vc4_plane_destroy(plane);
976 + return ERR_PTR(ret);
979 +static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
981 + struct drm_device *dev = crtc->dev;
982 + struct vc4_dev *vc4 = to_vc4_dev(dev);
983 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
984 + struct drm_display_mode *mode = &crtc->state->adjusted_mode;
985 + struct vc4_fkms_encoder *vc4_encoder =
986 + to_vc4_fkms_encoder(vc4_crtc->encoder);
987 + struct mailbox_set_mode mb = {
988 + .tag1 = { RPI_FIRMWARE_SET_TIMING,
989 + sizeof(struct set_timings), 0},
991 + union hdmi_infoframe frame;
994 + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode);
996 + DRM_ERROR("couldn't fill AVI infoframe\n");
1000 + 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",
1001 + vc4_crtc->display_number, mode->name, mode->clock,
1002 + mode->hdisplay, mode->hsync_start, mode->hsync_end,
1003 + mode->htotal, mode->hskew, mode->vdisplay,
1004 + mode->vsync_start, mode->vsync_end, mode->vtotal,
1005 + mode->vscan, drm_mode_vrefresh(mode),
1006 + mode->picture_aspect_ratio, mode->flags);
1007 + mb.timings.display = vc4_crtc->display_number;
1009 + mb.timings.clock = mode->clock;
1010 + mb.timings.hdisplay = mode->hdisplay;
1011 + mb.timings.hsync_start = mode->hsync_start;
1012 + mb.timings.hsync_end = mode->hsync_end;
1013 + mb.timings.htotal = mode->htotal;
1014 + mb.timings.hskew = mode->hskew;
1015 + mb.timings.vdisplay = mode->vdisplay;
1016 + mb.timings.vsync_start = mode->vsync_start;
1017 + mb.timings.vsync_end = mode->vsync_end;
1018 + mb.timings.vtotal = mode->vtotal;
1019 + mb.timings.vscan = mode->vscan;
1020 + mb.timings.vrefresh = drm_mode_vrefresh(mode);
1021 + mb.timings.flags = 0;
1022 + if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1023 + mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS;
1024 + if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1025 + mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS;
1027 + switch (frame.avi.picture_aspect) {
1029 + case HDMI_PICTURE_ASPECT_NONE:
1030 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE;
1032 + case HDMI_PICTURE_ASPECT_4_3:
1033 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3;
1035 + case HDMI_PICTURE_ASPECT_16_9:
1036 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9;
1038 + case HDMI_PICTURE_ASPECT_64_27:
1039 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27;
1041 + case HDMI_PICTURE_ASPECT_256_135:
1042 + mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135;
1046 + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1047 + mb.timings.flags |= TIMINGS_FLAGS_INTERLACE;
1048 + if (mode->flags & DRM_MODE_FLAG_DBLCLK)
1049 + mb.timings.flags |= TIMINGS_FLAGS_DBL_CLK;
1051 + mb.timings.video_id_code = frame.avi.video_code;
1053 + if (!vc4_encoder->hdmi_monitor) {
1054 + mb.timings.flags |= TIMINGS_FLAGS_DVI;
1056 + struct vc4_fkms_connector_state *conn_state =
1057 + to_vc4_fkms_connector_state(vc4_crtc->connector->state);
1059 + if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) {
1060 + /* See CEA-861-E - 5.1 Default Encoding Parameters */
1061 + if (drm_default_rgb_quant_range(mode) ==
1062 + HDMI_QUANTIZATION_RANGE_LIMITED)
1063 + mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
1065 + if (conn_state->broadcast_rgb ==
1066 + VC4_BROADCAST_RGB_LIMITED)
1067 + mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED;
1069 + /* If not using the default range, then do not provide
1070 + * a VIC as the HDMI spec requires that we do not
1071 + * signal the opposite of the defined range in the AVI
1074 + if (!!(mb.timings.flags & TIMINGS_FLAGS_RGB_LIMITED) !=
1075 + (drm_default_rgb_quant_range(mode) ==
1076 + HDMI_QUANTIZATION_RANGE_LIMITED))
1077 + mb.timings.video_id_code = 0;
1082 + * FIXME: To implement
1083 + * switch(mode->flag & DRM_MODE_FLAG_3D_MASK) {
1084 + * case DRM_MODE_FLAG_3D_NONE:
1085 + * case DRM_MODE_FLAG_3D_FRAME_PACKING:
1086 + * case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
1087 + * case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
1088 + * case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
1089 + * case DRM_MODE_FLAG_3D_L_DEPTH:
1090 + * case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
1091 + * case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1092 + * case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1096 + ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
1099 +static void vc4_crtc_disable(struct drm_crtc *crtc,
1100 + struct drm_atomic_state *state)
1102 + struct drm_device *dev = crtc->dev;
1103 + struct drm_plane *plane;
1105 + DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n",
1107 + drm_crtc_vblank_off(crtc);
1109 + /* Always turn the planes off on CRTC disable. In DRM, planes
1110 + * are enabled/disabled through the update/disable hooks
1111 + * above, and the CRTC enable/disable independently controls
1112 + * whether anything scans out at all, but the firmware doesn't
1113 + * give us a CRTC-level control for that.
1116 + drm_atomic_crtc_for_each_plane(plane, crtc)
1117 + vc4_plane_atomic_disable(plane, plane->state);
1120 + * Make sure we issue a vblank event after disabling the CRTC if
1121 + * someone was waiting it.
1123 + if (crtc->state->event) {
1124 + unsigned long flags;
1126 + spin_lock_irqsave(&dev->event_lock, flags);
1127 + drm_crtc_send_vblank_event(crtc, crtc->state->event);
1128 + crtc->state->event = NULL;
1129 + spin_unlock_irqrestore(&dev->event_lock, flags);
1133 +static void vc4_crtc_consume_event(struct drm_crtc *crtc)
1135 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1136 + struct drm_device *dev = crtc->dev;
1137 + unsigned long flags;
1139 + if (!crtc->state->event)
1142 + crtc->state->event->pipe = drm_crtc_index(crtc);
1144 + WARN_ON(drm_crtc_vblank_get(crtc) != 0);
1146 + spin_lock_irqsave(&dev->event_lock, flags);
1147 + vc4_crtc->event = crtc->state->event;
1148 + crtc->state->event = NULL;
1149 + spin_unlock_irqrestore(&dev->event_lock, flags);
1152 +static void vc4_crtc_enable(struct drm_crtc *crtc,
1153 + struct drm_atomic_state *state)
1155 + struct drm_plane *plane;
1157 + DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n",
1159 + drm_crtc_vblank_on(crtc);
1160 + vc4_crtc_consume_event(crtc);
1162 + /* Unblank the planes (if they're supposed to be displayed). */
1163 + drm_atomic_crtc_for_each_plane(plane, crtc)
1164 + if (plane->state->fb)
1165 + vc4_plane_set_blank(plane, plane->state->visible);
1168 +static enum drm_mode_status
1169 +vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
1171 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1172 + struct drm_device *dev = crtc->dev;
1173 + struct vc4_dev *vc4 = to_vc4_dev(dev);
1174 + struct vc4_fkms *fkms = vc4->fkms;
1176 + /* Do not allow doublescan modes from user space */
1177 + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
1178 + DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
1180 + return MODE_NO_DBLESCAN;
1183 + /* Disable refresh rates > defined threshold (default 85Hz) as limited
1186 + if (drm_mode_vrefresh(mode) > fkms_max_refresh_rate)
1187 + return MODE_BAD_VVALUE;
1189 + /* Limit the pixel clock based on the HDMI clock limits from the
1192 + switch (vc4_crtc->display_number) {
1193 + case 2: /* HDMI0 */
1194 + if (fkms->cfg.max_pixel_clock[0] &&
1195 + mode->clock > fkms->cfg.max_pixel_clock[0])
1196 + return MODE_CLOCK_HIGH;
1198 + case 7: /* HDMI1 */
1199 + if (fkms->cfg.max_pixel_clock[1] &&
1200 + mode->clock > fkms->cfg.max_pixel_clock[1])
1201 + return MODE_CLOCK_HIGH;
1205 + /* Pi4 can't generate odd horizontal timings on HDMI, so reject modes
1206 + * that would set them.
1208 + if (fkms->bcm2711 &&
1209 + (vc4_crtc->display_number == 2 || vc4_crtc->display_number == 7) &&
1210 + !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
1211 + ((mode->hdisplay | /* active */
1212 + (mode->hsync_start - mode->hdisplay) | /* front porch */
1213 + (mode->hsync_end - mode->hsync_start) | /* sync pulse */
1214 + (mode->htotal - mode->hsync_end)) & 1)) /* back porch */ {
1215 + DRM_DEBUG_KMS("[CRTC:%d] Odd timing rejected %u %u %u %u.\n",
1216 + crtc->base.id, mode->hdisplay, mode->hsync_start,
1217 + mode->hsync_end, mode->htotal);
1218 + return MODE_H_ILLEGAL;
1224 +static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
1225 + struct drm_crtc_state *state)
1227 + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
1228 + struct drm_connector *conn;
1229 + struct drm_connector_state *conn_state;
1232 + DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
1234 + for_each_new_connector_in_state(state->state, conn, conn_state, i) {
1235 + if (conn_state->crtc != crtc)
1238 + vc4_state->margins.left = conn_state->tv.margins.left;
1239 + vc4_state->margins.right = conn_state->tv.margins.right;
1240 + vc4_state->margins.top = conn_state->tv.margins.top;
1241 + vc4_state->margins.bottom = conn_state->tv.margins.bottom;
1247 +static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
1248 + struct drm_crtc_state *old_state)
1250 + DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n",
1252 + if (crtc->state->active && old_state->active && crtc->state->event)
1253 + vc4_crtc_consume_event(crtc);
1256 +static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
1258 + struct drm_crtc *crtc = &vc4_crtc->base;
1259 + struct drm_device *dev = crtc->dev;
1260 + unsigned long flags;
1262 + spin_lock_irqsave(&dev->event_lock, flags);
1263 + if (vc4_crtc->event) {
1264 + drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
1265 + vc4_crtc->event = NULL;
1266 + drm_crtc_vblank_put(crtc);
1268 + spin_unlock_irqrestore(&dev->event_lock, flags);
1271 +static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
1273 + struct vc4_crtc **crtc_list = data;
1275 + u32 stat = readl(crtc_list[0]->regs + SMICS);
1276 + irqreturn_t ret = IRQ_NONE;
1279 + if (stat & SMICS_INTERRUPTS) {
1280 + writel(0, crtc_list[0]->regs + SMICS);
1282 + chan = readl(crtc_list[0]->regs + SMIDSW0);
1284 + if ((chan & 0xFFFF0000) != SMI_NEW) {
1285 + /* Older firmware. Treat the one interrupt as vblank/
1286 + * complete for all crtcs.
1288 + for (i = 0; crtc_list[i]; i++) {
1289 + if (crtc_list[i]->vblank_enabled)
1290 + drm_crtc_handle_vblank(&crtc_list[i]->base);
1291 + vc4_crtc_handle_page_flip(crtc_list[i]);
1295 + writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
1296 + if (crtc_list[0]->vblank_enabled)
1297 + drm_crtc_handle_vblank(&crtc_list[0]->base);
1298 + vc4_crtc_handle_page_flip(crtc_list[0]);
1301 + if (crtc_list[1]) {
1302 + /* Check for the secondary display too */
1303 + chan = readl(crtc_list[0]->regs + SMIDSW1);
1306 + writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
1308 + if (crtc_list[1]->vblank_enabled)
1309 + drm_crtc_handle_vblank(&crtc_list[1]->base);
1310 + vc4_crtc_handle_page_flip(crtc_list[1]);
1315 + ret = IRQ_HANDLED;
1321 +static int vc4_fkms_page_flip(struct drm_crtc *crtc,
1322 + struct drm_framebuffer *fb,
1323 + struct drm_pending_vblank_event *event,
1325 + struct drm_modeset_acquire_ctx *ctx)
1327 + if (flags & DRM_MODE_PAGE_FLIP_ASYNC) {
1328 + DRM_ERROR("Async flips aren't allowed\n");
1332 + return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
1335 +static struct drm_crtc_state *
1336 +vc4_fkms_crtc_duplicate_state(struct drm_crtc *crtc)
1338 + struct vc4_crtc_state *vc4_state, *old_vc4_state;
1340 + vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
1344 + old_vc4_state = to_vc4_crtc_state(crtc->state);
1345 + vc4_state->margins = old_vc4_state->margins;
1347 + __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
1348 + return &vc4_state->base;
1352 +vc4_fkms_crtc_reset(struct drm_crtc *crtc)
1355 + __drm_atomic_helper_crtc_destroy_state(crtc->state);
1357 + crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
1359 + crtc->state->crtc = crtc;
1362 +static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
1364 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1366 + DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n",
1368 + vc4_crtc->vblank_enabled = true;
1373 +static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
1375 + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
1377 + DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n",
1379 + vc4_crtc->vblank_enabled = false;
1382 +static const struct drm_crtc_funcs vc4_crtc_funcs = {
1383 + .set_config = drm_atomic_helper_set_config,
1384 + .destroy = drm_crtc_cleanup,
1385 + .page_flip = vc4_fkms_page_flip,
1386 + .set_property = NULL,
1387 + .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
1388 + .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
1389 + .reset = vc4_fkms_crtc_reset,
1390 + .atomic_duplicate_state = vc4_fkms_crtc_duplicate_state,
1391 + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
1392 + .enable_vblank = vc4_fkms_enable_vblank,
1393 + .disable_vblank = vc4_fkms_disable_vblank,
1396 +static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
1397 + .mode_set_nofb = vc4_crtc_mode_set_nofb,
1398 + .mode_valid = vc4_crtc_mode_valid,
1399 + .atomic_check = vc4_crtc_atomic_check,
1400 + .atomic_flush = vc4_crtc_atomic_flush,
1401 + .atomic_enable = vc4_crtc_enable,
1402 + .atomic_disable = vc4_crtc_disable,
1405 +static const struct of_device_id vc4_firmware_kms_dt_match[] = {
1406 + { .compatible = "raspberrypi,rpi-firmware-kms" },
1407 + { .compatible = "raspberrypi,rpi-firmware-kms-2711",
1408 + .data = (void *)1 },
1412 +static enum drm_connector_status
1413 +vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
1415 + DRM_DEBUG_KMS("connector detect.\n");
1416 + return connector_status_connected;
1419 +/* Queries the firmware to populate a drm_mode structure for this display */
1420 +static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector,
1421 + struct drm_display_mode *mode)
1423 + struct vc4_dev *vc4 = fkms_connector->vc4_dev;
1424 + struct set_timings timings = { 0 };
1427 + timings.display = fkms_connector->display_number;
1429 + ret = rpi_firmware_property(vc4->firmware,
1430 + RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings,
1432 + if (ret || !timings.clock)
1433 + /* No mode returned - abort */
1436 + /* Equivalent to DRM_MODE macro. */
1437 + memset(mode, 0, sizeof(*mode));
1438 + strncpy(mode->name, "FIXED_MODE", sizeof(mode->name));
1440 + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
1441 + mode->clock = timings.clock;
1442 + mode->hdisplay = timings.hdisplay;
1443 + mode->hsync_start = timings.hsync_start;
1444 + mode->hsync_end = timings.hsync_end;
1445 + mode->htotal = timings.htotal;
1447 + mode->vdisplay = timings.vdisplay;
1448 + mode->vsync_start = timings.vsync_start;
1449 + mode->vsync_end = timings.vsync_end;
1450 + mode->vtotal = timings.vtotal;
1451 + mode->vscan = timings.vscan;
1453 + if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS)
1454 + mode->flags |= DRM_MODE_FLAG_PHSYNC;
1456 + mode->flags |= DRM_MODE_FLAG_NHSYNC;
1458 + if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS)
1459 + mode->flags |= DRM_MODE_FLAG_PVSYNC;
1461 + mode->flags |= DRM_MODE_FLAG_NVSYNC;
1463 + if (timings.flags & TIMINGS_FLAGS_INTERLACE)
1464 + mode->flags |= DRM_MODE_FLAG_INTERLACE;
1469 +static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block,
1472 + struct vc4_fkms_connector *fkms_connector =
1473 + (struct vc4_fkms_connector *)data;
1474 + struct vc4_dev *vc4 = fkms_connector->vc4_dev;
1475 + struct mailbox_get_edid mb = {
1476 + .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY,
1479 + .display_number = fkms_connector->display_number,
1483 + ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
1486 + memcpy(buf, mb.edid, len);
1491 +static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
1493 + struct vc4_fkms_connector *fkms_connector =
1494 + to_vc4_fkms_connector(connector);
1495 + struct drm_encoder *encoder = fkms_connector->encoder;
1496 + struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
1497 + struct drm_display_mode fw_mode;
1498 + struct drm_display_mode *mode;
1499 + struct edid *edid;
1502 + if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) {
1503 + drm_mode_debug_printmodeline(&fw_mode);
1504 + mode = drm_mode_duplicate(connector->dev,
1506 + drm_mode_probed_add(connector, mode);
1507 + num_modes = 1; /* 1 mode */
1509 + edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block,
1512 + /* FIXME: Can we do CEC?
1513 + * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
1518 + vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
1520 + drm_connector_update_edid_property(connector, edid);
1521 + num_modes = drm_add_edid_modes(connector, edid);
1528 +/* This is the DSI panel resolution. Use this as a default should the firmware
1529 + * not respond to our request for the timings.
1531 +static const struct drm_display_mode lcd_mode = {
1532 + DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
1534 + 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0,
1535 + 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0,
1539 +static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector)
1541 + struct vc4_fkms_connector *fkms_connector =
1542 + to_vc4_fkms_connector(connector);
1543 + struct drm_display_mode *mode;
1544 + struct drm_display_mode fw_mode;
1546 + if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock)
1547 + mode = drm_mode_duplicate(connector->dev,
1550 + mode = drm_mode_duplicate(connector->dev,
1554 + DRM_ERROR("Failed to create a new display mode\n");
1558 + drm_mode_probed_add(connector, mode);
1560 + /* We have one mode */
1564 +static struct drm_encoder *
1565 +vc4_fkms_connector_best_encoder(struct drm_connector *connector)
1567 + struct vc4_fkms_connector *fkms_connector =
1568 + to_vc4_fkms_connector(connector);
1569 + DRM_DEBUG_KMS("best_connector.\n");
1570 + return fkms_connector->encoder;
1573 +static void vc4_fkms_connector_destroy(struct drm_connector *connector)
1575 + DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n",
1576 + connector->base.id);
1577 + drm_connector_unregister(connector);
1578 + drm_connector_cleanup(connector);
1582 + * vc4_connector_duplicate_state - duplicate connector state
1583 + * @connector: digital connector
1585 + * Allocates and returns a copy of the connector state (both common and
1586 + * digital connector specific) for the specified connector.
1588 + * Returns: The newly allocated connector state, or NULL on failure.
1590 +struct drm_connector_state *
1591 +vc4_connector_duplicate_state(struct drm_connector *connector)
1593 + struct vc4_fkms_connector_state *state;
1595 + state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
1599 + __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
1600 + return &state->base;
1604 + * vc4_connector_atomic_get_property - hook for connector->atomic_get_property.
1605 + * @connector: Connector to get the property for.
1606 + * @state: Connector state to retrieve the property from.
1607 + * @property: Property to retrieve.
1608 + * @val: Return value for the property.
1610 + * Returns the atomic property value for a digital connector.
1612 +int vc4_connector_atomic_get_property(struct drm_connector *connector,
1613 + const struct drm_connector_state *state,
1614 + struct drm_property *property,
1617 + struct vc4_fkms_connector *fkms_connector =
1618 + to_vc4_fkms_connector(connector);
1619 + struct vc4_fkms_connector_state *vc4_conn_state =
1620 + to_vc4_fkms_connector_state(state);
1622 + if (property == fkms_connector->broadcast_rgb_property) {
1623 + *val = vc4_conn_state->broadcast_rgb;
1625 + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
1626 + property->base.id, property->name);
1634 + * vc4_connector_atomic_set_property - hook for connector->atomic_set_property.
1635 + * @connector: Connector to set the property for.
1636 + * @state: Connector state to set the property on.
1637 + * @property: Property to set.
1638 + * @val: New value for the property.
1640 + * Sets the atomic property value for a digital connector.
1642 +int vc4_connector_atomic_set_property(struct drm_connector *connector,
1643 + struct drm_connector_state *state,
1644 + struct drm_property *property,
1647 + struct vc4_fkms_connector *fkms_connector =
1648 + to_vc4_fkms_connector(connector);
1649 + struct vc4_fkms_connector_state *vc4_conn_state =
1650 + to_vc4_fkms_connector_state(state);
1652 + if (property == fkms_connector->broadcast_rgb_property) {
1653 + vc4_conn_state->broadcast_rgb = val;
1657 + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n",
1658 + property->base.id, property->name);
1662 +static void vc4_hdmi_connector_reset(struct drm_connector *connector)
1664 + drm_atomic_helper_connector_reset(connector);
1665 + drm_atomic_helper_connector_tv_reset(connector);
1668 +static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
1669 + .detect = vc4_fkms_connector_detect,
1670 + .fill_modes = drm_helper_probe_single_connector_modes,
1671 + .destroy = vc4_fkms_connector_destroy,
1672 + .reset = vc4_hdmi_connector_reset,
1673 + .atomic_duplicate_state = vc4_connector_duplicate_state,
1674 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1675 + .atomic_get_property = vc4_connector_atomic_get_property,
1676 + .atomic_set_property = vc4_connector_atomic_set_property,
1679 +static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
1680 + .get_modes = vc4_fkms_connector_get_modes,
1681 + .best_encoder = vc4_fkms_connector_best_encoder,
1684 +static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = {
1685 + .get_modes = vc4_fkms_lcd_connector_get_modes,
1686 + .best_encoder = vc4_fkms_connector_best_encoder,
1689 +static const struct drm_prop_enum_list broadcast_rgb_names[] = {
1690 + { VC4_BROADCAST_RGB_AUTO, "Automatic" },
1691 + { VC4_BROADCAST_RGB_FULL, "Full" },
1692 + { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" },
1696 +vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector)
1698 + struct drm_device *dev = fkms_connector->base.dev;
1699 + struct drm_property *prop;
1701 + prop = fkms_connector->broadcast_rgb_property;
1703 + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
1705 + broadcast_rgb_names,
1706 + ARRAY_SIZE(broadcast_rgb_names));
1710 + fkms_connector->broadcast_rgb_property = prop;
1713 + drm_object_attach_property(&fkms_connector->base.base, prop, 0);
1716 +static struct drm_connector *
1717 +vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
1720 + struct drm_connector *connector = NULL;
1721 + struct vc4_fkms_connector *fkms_connector;
1722 + struct vc4_fkms_connector_state *conn_state = NULL;
1723 + struct vc4_dev *vc4_dev = to_vc4_dev(dev);
1726 + DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num);
1728 + fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
1730 + if (!fkms_connector)
1731 + return ERR_PTR(-ENOMEM);
1734 + * Allocate enough memory to hold vc4_fkms_connector_state,
1736 + conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL);
1737 + if (!conn_state) {
1738 + kfree(fkms_connector);
1739 + return ERR_PTR(-ENOMEM);
1742 + connector = &fkms_connector->base;
1744 + fkms_connector->encoder = encoder;
1745 + fkms_connector->display_number = display_num;
1746 + fkms_connector->display_type = vc4_get_display_type(display_num);
1747 + fkms_connector->vc4_dev = vc4_dev;
1749 + __drm_atomic_helper_connector_reset(connector,
1750 + &conn_state->base);
1752 + if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) {
1753 + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
1754 + DRM_MODE_CONNECTOR_DSI);
1755 + drm_connector_helper_add(connector,
1756 + &vc4_fkms_lcd_conn_helper_funcs);
1757 + connector->interlace_allowed = 0;
1758 + } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) {
1759 + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
1760 + DRM_MODE_CONNECTOR_Composite);
1761 + drm_connector_helper_add(connector,
1762 + &vc4_fkms_lcd_conn_helper_funcs);
1763 + connector->interlace_allowed = 1;
1765 + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
1766 + DRM_MODE_CONNECTOR_HDMIA);
1767 + drm_connector_helper_add(connector,
1768 + &vc4_fkms_connector_helper_funcs);
1769 + connector->interlace_allowed = 1;
1772 + ret = drm_mode_create_tv_margin_properties(dev);
1776 + drm_connector_attach_tv_margin_properties(connector);
1778 + connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
1779 + DRM_CONNECTOR_POLL_DISCONNECT);
1781 + connector->doublescan_allowed = 0;
1783 + vc4_attach_broadcast_rgb_property(fkms_connector);
1785 + drm_connector_attach_encoder(connector, encoder);
1791 + vc4_fkms_connector_destroy(connector);
1793 + return ERR_PTR(ret);
1796 +static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
1798 + DRM_DEBUG_KMS("Encoder_destroy\n");
1799 + drm_encoder_cleanup(encoder);
1802 +static const struct drm_encoder_funcs vc4_fkms_encoder_funcs = {
1803 + .destroy = vc4_fkms_encoder_destroy,
1806 +static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power)
1808 + struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder);
1809 + struct vc4_dev *vc4 = to_vc4_dev(encoder->dev);
1811 + struct mailbox_display_pwr pwr = {
1812 + .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, },
1813 + .display = vc4_encoder->display_num,
1814 + .state = power ? 1 : 0,
1817 + rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr));
1820 +static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
1822 + vc4_fkms_display_power(encoder, true);
1823 + DRM_DEBUG_KMS("Encoder_enable\n");
1826 +static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
1828 + vc4_fkms_display_power(encoder, false);
1829 + DRM_DEBUG_KMS("Encoder_disable\n");
1832 +static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
1833 + .enable = vc4_fkms_encoder_enable,
1834 + .disable = vc4_fkms_encoder_disable,
1837 +static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
1838 + int display_idx, int display_ref,
1839 + struct vc4_crtc **ret_crtc)
1841 + struct vc4_dev *vc4 = to_vc4_dev(drm);
1842 + struct vc4_crtc *vc4_crtc;
1843 + struct vc4_fkms_encoder *vc4_encoder;
1844 + struct drm_crtc *crtc;
1845 + struct drm_plane *destroy_plane, *temp;
1846 + struct mailbox_blank_display blank = {
1847 + .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, },
1848 + .display = display_idx,
1849 + .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, },
1852 + struct drm_plane *planes[PLANES_PER_CRTC];
1855 + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
1858 + crtc = &vc4_crtc->base;
1860 + vc4_crtc->display_number = display_ref;
1861 + vc4_crtc->display_type = vc4_get_display_type(display_ref);
1863 + /* Blank the firmware provided framebuffer */
1864 + rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank));
1866 + for (i = 0; i < PLANES_PER_CRTC; i++) {
1867 + planes[i] = vc4_fkms_plane_init(drm,
1869 + DRM_PLANE_TYPE_PRIMARY :
1870 + (i == PLANES_PER_CRTC - 1) ?
1871 + DRM_PLANE_TYPE_CURSOR :
1872 + DRM_PLANE_TYPE_OVERLAY,
1874 + i + (display_idx * PLANES_PER_CRTC)
1876 + if (IS_ERR(planes[i])) {
1877 + dev_err(dev, "failed to construct plane %u\n", i);
1878 + ret = PTR_ERR(planes[i]);
1883 + drm_crtc_init_with_planes(drm, crtc, planes[0],
1884 + planes[PLANES_PER_CRTC - 1], &vc4_crtc_funcs,
1886 + drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
1888 + /* Update the possible_crtcs mask for the overlay plane(s) */
1889 + for (i = 1; i < (PLANES_PER_CRTC - 1); i++)
1890 + planes[i]->possible_crtcs = drm_crtc_mask(crtc);
1892 + vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
1895 + vc4_crtc->encoder = &vc4_encoder->base;
1897 + vc4_encoder->display_num = display_ref;
1898 + vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc);
1900 + drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
1901 + vc4_crtc->display_type, NULL);
1902 + drm_encoder_helper_add(&vc4_encoder->base,
1903 + &vc4_fkms_encoder_helper_funcs);
1905 + vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base,
1907 + if (IS_ERR(vc4_crtc->connector)) {
1908 + ret = PTR_ERR(vc4_crtc->connector);
1909 + goto err_destroy_encoder;
1912 + *ret_crtc = vc4_crtc;
1916 +err_destroy_encoder:
1917 + vc4_fkms_encoder_destroy(vc4_crtc->encoder);
1918 + list_for_each_entry_safe(destroy_plane, temp,
1919 + &drm->mode_config.plane_list, head) {
1920 + if (destroy_plane->possible_crtcs == 1 << drm_crtc_index(crtc))
1921 + destroy_plane->funcs->destroy(destroy_plane);
1927 +static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
1929 + struct platform_device *pdev = to_platform_device(dev);
1930 + struct drm_device *drm = dev_get_drvdata(master);
1931 + struct vc4_dev *vc4 = to_vc4_dev(drm);
1932 + struct device_node *firmware_node;
1933 + const struct of_device_id *match;
1934 + struct vc4_crtc **crtc_list;
1935 + u32 num_displays, display_num;
1936 + struct vc4_fkms *fkms;
1940 + vc4->firmware_kms = true;
1942 + fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL);
1946 + match = of_match_device(vc4_firmware_kms_dt_match, dev);
1950 + fkms->bcm2711 = true;
1952 + firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
1953 + vc4->firmware = rpi_firmware_get(firmware_node);
1954 + if (!vc4->firmware) {
1955 + DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
1956 + return -EPROBE_DEFER;
1958 + of_node_put(firmware_node);
1960 + ret = rpi_firmware_property(vc4->firmware,
1961 + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
1962 + &num_displays, sizeof(u32));
1964 + /* If we fail to get the number of displays, then
1965 + * assume old firmware that doesn't have the mailbox call, so just
1970 + DRM_WARN("Unable to determine number of displays - assuming 1\n");
1974 + ret = rpi_firmware_property(vc4->firmware,
1975 + RPI_FIRMWARE_GET_DISPLAY_CFG,
1976 + &fkms->cfg, sizeof(fkms->cfg));
1980 + /* The firmware works in Hz. This will be compared against kHz, so div
1981 + * 1000 now rather than multiple times later.
1983 + fkms->cfg.max_pixel_clock[0] /= 1000;
1984 + fkms->cfg.max_pixel_clock[1] /= 1000;
1986 + /* Allocate a list, with space for a NULL on the end */
1987 + crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1),
1992 + for (display_num = 0; display_num < num_displays; display_num++) {
1993 + display_id = display_num;
1994 + ret = rpi_firmware_property(vc4->firmware,
1995 + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
1996 + &display_id, sizeof(display_id));
1997 + /* FIXME: Determine the correct error handling here.
1998 + * Should we fail to create the one "screen" but keep the
1999 + * others, or fail the whole thing?
2002 + DRM_ERROR("Failed to get display id %u\n", display_num);
2004 + ret = vc4_fkms_create_screen(dev, drm, display_num, display_id,
2005 + &crtc_list[display_num]);
2007 + DRM_ERROR("Oh dear, failed to create display %u\n",
2011 + if (num_displays > 0) {
2012 + /* Map the SMI interrupt reg */
2013 + crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0);
2014 + if (IS_ERR(crtc_list[0]->regs))
2015 + DRM_ERROR("Oh dear, failed to map registers\n");
2017 + writel(0, crtc_list[0]->regs + SMICS);
2018 + ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
2019 + vc4_crtc_irq_handler, 0,
2020 + "vc4 firmware kms", crtc_list);
2022 + DRM_ERROR("Oh dear, failed to register IRQ\n");
2024 + DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n");
2029 + platform_set_drvdata(pdev, crtc_list);
2034 +static void vc4_fkms_unbind(struct device *dev, struct device *master,
2037 + struct platform_device *pdev = to_platform_device(dev);
2038 + struct vc4_crtc **crtc_list = dev_get_drvdata(dev);
2041 + for (i = 0; crtc_list[i]; i++) {
2042 + vc4_fkms_connector_destroy(crtc_list[i]->connector);
2043 + vc4_fkms_encoder_destroy(crtc_list[i]->encoder);
2044 + drm_crtc_cleanup(&crtc_list[i]->base);
2047 + platform_set_drvdata(pdev, NULL);
2050 +static const struct component_ops vc4_fkms_ops = {
2051 + .bind = vc4_fkms_bind,
2052 + .unbind = vc4_fkms_unbind,
2055 +static int vc4_fkms_probe(struct platform_device *pdev)
2057 + return component_add(&pdev->dev, &vc4_fkms_ops);
2060 +static int vc4_fkms_remove(struct platform_device *pdev)
2062 + component_del(&pdev->dev, &vc4_fkms_ops);
2066 +struct platform_driver vc4_firmware_kms_driver = {
2067 + .probe = vc4_fkms_probe,
2068 + .remove = vc4_fkms_remove,
2070 + .name = "vc4_firmware_kms",
2071 + .of_match_table = vc4_firmware_kms_dt_match,
2074 --- a/drivers/gpu/drm/vc4/vc4_kms.c
2075 +++ b/drivers/gpu/drm/vc4/vc4_kms.c
2076 @@ -154,6 +154,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru
2077 struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
2078 struct drm_color_ctm *ctm = ctm_state->ctm;
2080 + if (vc4->firmware_kms)
2083 if (ctm_state->fifo) {
2084 HVS_WRITE(SCALER_OLEDCOEF2,
2085 VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]),
2086 @@ -315,14 +318,14 @@ vc4_atomic_complete_commit(struct drm_at
2087 for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
2088 struct vc4_crtc_state *vc4_crtc_state;
2090 - if (!new_crtc_state->commit)
2091 + if (!new_crtc_state->commit || vc4->firmware_kms)
2094 vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
2095 vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
2098 - if (vc4->hvs->hvs5)
2099 + if (vc4->hvs && vc4->hvs->hvs5)
2100 clk_set_min_rate(hvs->core_clk, 500000000);
2102 drm_atomic_helper_wait_for_fences(dev, state, false);
2103 @@ -333,10 +336,12 @@ vc4_atomic_complete_commit(struct drm_at
2105 vc4_ctm_commit(vc4, state);
2107 - if (vc4->hvs->hvs5)
2108 - vc5_hvs_pv_muxing_commit(vc4, state);
2110 - vc4_hvs_pv_muxing_commit(vc4, state);
2111 + if (!vc4->firmware_kms) {
2112 + if (vc4->hvs->hvs5)
2113 + vc5_hvs_pv_muxing_commit(vc4, state);
2115 + vc4_hvs_pv_muxing_commit(vc4, state);
2118 drm_atomic_helper_commit_planes(dev, state, 0);
2120 @@ -352,7 +357,7 @@ vc4_atomic_complete_commit(struct drm_at
2122 drm_atomic_helper_commit_cleanup_done(state);
2124 - if (vc4->hvs->hvs5)
2125 + if (vc4->hvs && vc4->hvs->hvs5)
2126 clk_set_min_rate(hvs->core_clk, 0);
2128 drm_atomic_state_put(state);
2129 @@ -413,7 +418,8 @@ static int vc4_atomic_commit(struct drm_
2130 * drm_atomic_helper_setup_commit() from auto-completing
2131 * commit->flip_done.
2133 - state->legacy_cursor_update = false;
2134 + if (!vc4->firmware_kms)
2135 + state->legacy_cursor_update = false;
2136 ret = drm_atomic_helper_setup_commit(state, nonblock);
2139 @@ -778,6 +784,7 @@ static int vc4_hvs_channels_obj_init(str
2140 static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
2141 struct drm_atomic_state *state)
2143 + struct vc4_dev *vc4 = to_vc4_dev(state->dev);
2144 struct vc4_hvs_state *hvs_new_state;
2145 struct drm_crtc_state *old_crtc_state, *new_crtc_state;
2146 struct drm_crtc *crtc;
2147 @@ -795,6 +802,9 @@ static int vc4_pv_muxing_atomic_check(st
2148 struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
2149 unsigned int matching_channels;
2151 + if (vc4->firmware_kms)
2154 /* Nothing to do here, let's skip it */
2155 if (old_crtc_state->enable == new_crtc_state->enable)
2157 @@ -913,6 +923,7 @@ int vc4_kms_load(struct drm_device *dev)
2158 dev->mode_config.preferred_depth = 24;
2159 dev->mode_config.async_page_flip = true;
2160 dev->mode_config.allow_fb_modifiers = true;
2161 + dev->mode_config.normalize_zpos = true;
2163 ret = vc4_ctm_obj_init(vc4);
2166 +++ b/drivers/gpu/drm/vc4/vc_image_types.h
2170 + * Copyright (c) 2012, Broadcom Europe Ltd
2172 + * Values taken from vc_image_types.h released by Broadcom at
2173 + * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h
2174 + * and vc_image_structs.h at
2175 + * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h
2177 + * This program is free software; you can redistribute it and/or modify
2178 + * it under the terms of the GNU General Public License version 2 as
2179 + * published by the Free Software Foundation.
2183 + VC_IMAGE_MIN = 0, //bounds for error checking
2185 + VC_IMAGE_RGB565 = 1,
2191 + /* 4bpp palettised image */
2193 + /* A separated format of 16 colour/light shorts followed by 16 z
2197 + /* 16 colours followed by 16 z values */
2199 + /* A separated format of 16 material/colour/light shorts followed by
2203 + /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
2205 + /* 32-bit format holding 18 bits of 6.6.6 RGB */
2207 + /* 4bpp palettised image with embedded palette */
2208 + VC_IMAGE_PAL4_OBSOLETE,
2209 + /* 8bpp palettised image with embedded palette */
2210 + VC_IMAGE_PAL8_OBSOLETE,
2211 + /* RGB888 with an alpha byte after each pixel */
2213 + /* a line of Y (32-byte padded), a line of U (16-byte padded), and a
2214 + * line of V (16-byte padded)
2217 + /* RGB565 with a transparent patch */
2219 + /* Compressed (4444) version of RGBA32 */
2221 + /* VCIII codec format */
2223 + /* VCIII T-format RGBA8888 */
2224 + VC_IMAGE_TF_RGBA32,
2225 + /* VCIII T-format RGBx8888 */
2226 + VC_IMAGE_TF_RGBX32,
2227 + /* VCIII T-format float */
2228 + VC_IMAGE_TF_FLOAT,
2229 + /* VCIII T-format RGBA4444 */
2230 + VC_IMAGE_TF_RGBA16,
2231 + /* VCIII T-format RGB5551 */
2232 + VC_IMAGE_TF_RGBA5551,
2233 + /* VCIII T-format RGB565 */
2234 + VC_IMAGE_TF_RGB565,
2235 + /* VCIII T-format 8-bit luma and 8-bit alpha */
2237 + /* VCIII T-format 8 bit generic sample */
2239 + /* VCIII T-format 8-bit palette */
2241 + /* VCIII T-format 4-bit palette */
2243 + /* VCIII T-format Ericsson Texture Compressed */
2245 + /* RGB888 with R & B swapped */
2247 + /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after
2248 + * each row of pixels
2250 + VC_IMAGE_BGR888_NP,
2251 + /* Bayer image, extra defines which variant is being used */
2253 + /* General wrapper for codec images e.g. JPEG from camera */
2255 + /* VCIII codec format */
2256 + VC_IMAGE_YUV_UV32,
2257 + /* VCIII T-format 8-bit luma */
2259 + /* VCIII T-format 8-bit alpha */
2261 + /* VCIII T-format 16-bit generic sample */
2262 + VC_IMAGE_TF_SHORT,
2263 + /* VCIII T-format 1bpp black/white */
2266 + /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
2268 + /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on
2269 + * a per line basis)
2271 + VC_IMAGE_YUV422PLANAR,
2272 + /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
2273 + VC_IMAGE_ARGB8888,
2274 + /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
2275 + VC_IMAGE_XRGB8888,
2277 + /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */
2278 + VC_IMAGE_YUV422YUYV,
2279 + VC_IMAGE_YUV422YVYU,
2280 + VC_IMAGE_YUV422UYVY,
2281 + VC_IMAGE_YUV422VYUY,
2283 + /* 32bpp like RGBA32 but with unused alpha */
2285 + /* 32bpp, corresponding to RGBA with unused alpha */
2286 + VC_IMAGE_RGBX8888,
2287 + /* 32bpp, corresponding to BGRA with unused alpha */
2288 + VC_IMAGE_BGRX8888,
2290 + /* Y as a plane, then UV byte interleaved in plane with same pitch,
2293 + VC_IMAGE_YUV420SP,
2295 + /* Y, U, & V planes separately 4:4:4 */
2296 + VC_IMAGE_YUV444PLANAR,
2298 + /* T-format 8-bit U - same as TF_Y8 buf from U plane */
2300 + /* T-format 8-bit U - same as TF_Y8 buf from V plane */
2303 + /* YUV4:2:0 planar, 16bit values */
2304 + VC_IMAGE_YUV420_16,
2305 + /* YUV4:2:0 codec format, 16bit values */
2306 + VC_IMAGE_YUV_UV_16,
2307 + /* YUV4:2:0 with U,V in side-by-side format */
2308 + VC_IMAGE_YUV420_S,
2309 + /* 10-bit YUV 420 column image format */
2310 + VC_IMAGE_YUV10COL,
2311 + /* 32-bpp, 10-bit R/G/B, 2-bit Alpha */
2312 + VC_IMAGE_RGBA1010102,
2314 + VC_IMAGE_MAX, /* bounds for error checking */
2315 + VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
2319 + /* Unknown or unset - defaults to BT601 interstitial */
2320 + VC_IMAGE_YUVINFO_UNSPECIFIED = 0,
2322 + /* colour-space conversions data [4 bits] */
2324 + /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
2325 + VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1,
2326 + /* ITU-R BT.709-3 [HDTV] */
2327 + VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2,
2329 + VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3,
2330 + /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
2331 + VC_IMAGE_YUVINFO_CSC_FCC = 4,
2332 + /* Society of Motion Picture and Television Engineers 240M (1999) */
2333 + VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5,
2334 + /* ITU-R BT.470-2 System M */
2335 + VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6,
2336 + /* ITU-R BT.470-2 System B,G */
2337 + VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,
2338 + /* JPEG JFIF, but with 16..255 luma */
2339 + VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8,
2341 + VC_IMAGE_YUVINFO_CSC_REC_2020 = 9,
2343 --- a/include/soc/bcm2835/raspberrypi-firmware.h
2344 +++ b/include/soc/bcm2835/raspberrypi-firmware.h
2345 @@ -75,6 +75,7 @@ enum rpi_firmware_property_tag {
2346 RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
2347 RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
2348 RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
2349 + RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023,
2350 RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
2351 RPI_FIRMWARE_GET_THROTTLED = 0x00030046,
2352 RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047,
2353 @@ -148,6 +149,11 @@ enum rpi_firmware_property_tag {
2355 RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
2357 + RPI_FIRMWARE_SET_PLANE = 0x00048015,
2358 + RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017,
2359 + RPI_FIRMWARE_SET_TIMING = 0x00048017,
2360 + RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018,
2361 + RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019,
2362 RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
2363 RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,