diff mbox series

[v2,2/7] ramfb: Add driver for ramfb display

Message ID 20230822121026.1007105-3-alpernebiyasak@gmail.com
State Changes Requested
Delegated to: Anatolij Gustschin
Headers show
Series Add support for QEMU's ramfb display | expand

Commit Message

Alper Nebi Yasak Aug. 22, 2023, 12:10 p.m. UTC
From: Alexander Graf <agraf@csgraf.de>

QEMU implements multiple ways to expose graphics output to the virt
machine, but most of them are incompatible with hardware virtualization.

The one that does work reliably is ramfb. It's a very simple mechanism
in which the guest reserves a memory region for the frame buffer and then
notifies the host about its location and properties. The host then just
displays the contents of the frame buffer on screen.

This patch implements a trivial version of a ramfb driver - hard coded
to a single resolution set in Kconfig.

Signed-off-by: Alexander Graf <agraf@csgraf.de>
[Alper: Deduplicate depends on DM_VIDEO, drop MAINTAINERS, decouple from
        EFI_LOADER, add .bind(), kconfigurable resolution, struct in .h]
Co-developed-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
---

Changes in v2:
- Remove extra "depends on DM_VIDEO" already in "if VIDEO"
- Drop drivers/video/MAINTAINERS file
- Decouple framebuffer allocation from EFI_LOADER
- Add .bind() method for ramfb driver
- Make resolution configurable with kconfig
- Move struct to qfw.h and add comments for members
- Use RAMFB_* definitions instead of DEFAULT_*

 drivers/video/Kconfig  | 30 +++++++++++++
 drivers/video/Makefile |  1 +
 drivers/video/ramfb.c  | 97 ++++++++++++++++++++++++++++++++++++++++++
 include/qfw.h          | 10 +++++
 4 files changed, 138 insertions(+)
 create mode 100644 drivers/video/ramfb.c

Comments

Simon Glass Aug. 22, 2023, 6:56 p.m. UTC | #1
On Tue, 22 Aug 2023 at 06:10, Alper Nebi Yasak <alpernebiyasak@gmail.com> wrote:
>
> From: Alexander Graf <agraf@csgraf.de>
>
> QEMU implements multiple ways to expose graphics output to the virt
> machine, but most of them are incompatible with hardware virtualization.
>
> The one that does work reliably is ramfb. It's a very simple mechanism
> in which the guest reserves a memory region for the frame buffer and then
> notifies the host about its location and properties. The host then just
> displays the contents of the frame buffer on screen.
>
> This patch implements a trivial version of a ramfb driver - hard coded
> to a single resolution set in Kconfig.
>
> Signed-off-by: Alexander Graf <agraf@csgraf.de>
> [Alper: Deduplicate depends on DM_VIDEO, drop MAINTAINERS, decouple from
>         EFI_LOADER, add .bind(), kconfigurable resolution, struct in .h]
> Co-developed-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
> Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
> ---
>
> Changes in v2:
> - Remove extra "depends on DM_VIDEO" already in "if VIDEO"
> - Drop drivers/video/MAINTAINERS file
> - Decouple framebuffer allocation from EFI_LOADER
> - Add .bind() method for ramfb driver
> - Make resolution configurable with kconfig
> - Move struct to qfw.h and add comments for members
> - Use RAMFB_* definitions instead of DEFAULT_*
>
>  drivers/video/Kconfig  | 30 +++++++++++++
>  drivers/video/Makefile |  1 +
>  drivers/video/ramfb.c  | 97 ++++++++++++++++++++++++++++++++++++++++++
>  include/qfw.h          | 10 +++++
>  4 files changed, 138 insertions(+)
>  create mode 100644 drivers/video/ramfb.c

Reviewed-by: Simon Glass <sjg@chromium.org>
diff mbox series

Patch

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 69f4809cf4a6..6ab46107483e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -849,6 +849,36 @@  config VIDEO_MCDE_SIMPLE
 	  before u-boot starts, and u-boot will simply render to the pre-
 	  allocated frame buffer surface.
 
+config VIDEO_RAMFB
+	bool "QEMU ramfb display driver for in-RAM display"
+	depends on QFW
+	help
+	  Enables a RAM based simple frame buffer driver which uses qfw to
+	  notify the hypervisor about the location of a Frame Buffer allocated
+	  in guest RAM as well as its properties.
+
+if VIDEO_RAMFB
+
+config VIDEO_RAMFB_SIZE_X
+	int "Width of ramfb display (X resolution)"
+	default 1280
+	help
+	  Sets the width of the ramfb display.
+
+	  These two options control the size of the display set up by QEMU.
+	  Typical sizes are 1024 x 768 or 1280 x 1024.
+
+config VIDEO_RAMFB_SIZE_Y
+	int "Height of ramfb display (Y resolution)"
+	default 1024
+	help
+	  Sets the height of the ramfb display.
+
+	  These two options control the size of the display set up by QEMU.
+	  Typical sizes are 1024 x 768 or 1280 x 1024.
+
+endif
+
 config OSD
 	bool "Enable OSD support"
 	depends on DM
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index d13af9f3b19b..775b4e46e600 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -75,6 +75,7 @@  obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o
 obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o
 obj-$(CONFIG_VIDEO_VESA) += vesa.o
 obj-$(CONFIG_VIDEO_SEPS525) += seps525.o
+obj-$(CONFIG_VIDEO_RAMFB) += ramfb.o
 obj-$(CONFIG_VIDEO_ZYNQMP_DPSUB) += zynqmp/
 
 obj-y += bridge/
diff --git a/drivers/video/ramfb.c b/drivers/video/ramfb.c
new file mode 100644
index 000000000000..ba17cac312b6
--- /dev/null
+++ b/drivers/video/ramfb.c
@@ -0,0 +1,97 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2022 Alexander Graf
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <video.h>
+#include <asm/global_data.h>
+#include <qfw.h>
+
+#define fourcc_code(a, b, c, d) ((u32)(a) | ((u32)(b) << 8) | \
+				 ((u32)(c) << 16) | ((u32)(d) << 24))
+#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4')
+
+#define RAMFB_WIDTH	CONFIG_VIDEO_RAMFB_SIZE_X
+#define RAMFB_HEIGHT	CONFIG_VIDEO_RAMFB_SIZE_Y
+#define RAMFB_BPIX	VIDEO_BPP32
+#define RAMFB_FORMAT	VIDEO_X8R8G8B8
+
+static int ramfb_probe(struct udevice *dev)
+{
+	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+	u32 selector;
+	int ret;
+	struct fw_file *file;
+	struct udevice *qfw;
+	struct dm_qfw_ops *ops;
+	struct qfw_dma dma = {};
+	struct ramfb_cfg cfg = {
+		.addr = cpu_to_be64(plat->base),
+		.fourcc = cpu_to_be32(DRM_FORMAT_XRGB8888),
+		.flags = 0,
+		.width = cpu_to_be32(RAMFB_WIDTH),
+		.height = cpu_to_be32(RAMFB_HEIGHT),
+		.stride = 0,
+	};
+
+	if (plat->base == 0)
+		return -EPROBE_DEFER;
+
+	debug("%s: Frame buffer base %lx\n", __func__, plat->base);
+
+	ret = qfw_get_dev(&qfw);
+	if (ret)
+		return -EPROBE_DEFER;
+
+	ops = dm_qfw_get_ops(qfw);
+	if (!ops)
+		return -EPROBE_DEFER;
+
+	file = qfw_find_file(qfw, "etc/ramfb");
+	if (!file) {
+		/* No ramfb available. At least we tried. */
+		return -ENOENT;
+	}
+
+	uc_priv->xsize = RAMFB_WIDTH;
+	uc_priv->ysize = RAMFB_HEIGHT;
+	uc_priv->bpix = RAMFB_BPIX;
+	uc_priv->format = RAMFB_FORMAT;
+	uc_priv->fb = (void *)plat->base;
+	uc_priv->fb_size = plat->size;
+
+	selector = be16_to_cpu(file->cfg.select);
+	dma.length = cpu_to_be32(sizeof(cfg));
+	dma.address = cpu_to_be64((uintptr_t)&cfg);
+	dma.control = cpu_to_be32(FW_CFG_DMA_WRITE | FW_CFG_DMA_SELECT |
+				  (selector << 16));
+
+	barrier();
+
+	/* Send a DMA write request which enables the screen */
+	ops->read_entry_dma(qfw, &dma);
+
+	return 0;
+}
+
+static int ramfb_bind(struct udevice *dev)
+{
+	struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+
+	/* Set the maximum supported resolution */
+	uc_plat->size = RAMFB_WIDTH * RAMFB_HEIGHT * VNBYTES(RAMFB_BPIX);
+	debug("%s: Frame buffer size %x\n", __func__, uc_plat->size);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ramfb) = {
+	.name	= "ramfb",
+	.id	= UCLASS_VIDEO,
+	.probe	= ramfb_probe,
+	.bind   = ramfb_bind,
+};
diff --git a/include/qfw.h b/include/qfw.h
index d3aaa4d54efc..811abac6fd27 100644
--- a/include/qfw.h
+++ b/include/qfw.h
@@ -142,6 +142,16 @@  struct bios_linker_entry {
 	};
 } __packed;
 
+/* ramfb configuration details to read into etc/ramfb fw_cfg file */
+struct ramfb_cfg {
+	__be64 addr;	/* Address of an allocated framebuffer */
+	__be32 fourcc;	/* Pixel format in Linux DRM fourcc code */
+	__be32 flags;	/* Unknown, appears unused */
+	__be32 width;	/* Width of the requested ramfb display */
+	__be32 height;	/* Height of the requested ramfb display */
+	__be32 stride;	/* Number of bytes per line? */
+} __packed;
+
 /* DMA transfer control data between UCLASS_QFW and QEMU. */
 struct qfw_dma {
 	__be32 control;