mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <ahmad@a3f.at>
To: barebox@lists.infradead.org
Cc: Adrian Negreanu <adrian.negreanu@nxp.com>
Subject: [PATCH v2 4/4] video: add support for QEMU ramfb
Date: Mon, 30 Jan 2023 08:27:07 +0100	[thread overview]
Message-ID: <20230130072707.2423294-5-ahmad@a3f.at> (raw)
In-Reply-To: <20230130072707.2423294-1-ahmad@a3f.at>

From: Adrian Negreanu <adrian.negreanu@nxp.com>

QEMU's ramfb is a very simple Qemu fw_cfg protocol, where the guest
need only write a video settings structure to /etc/ramfb to get
DMA from the framebuffer working. We don't yet have FS support
for fw_cfg, so we use the character device interface.

As barebox display mode handling only supports selecting predefined
modes and has no accommodation yet for arbitrary resolution support
like on QEMU, for now we just provide a fixed 640x480@XRGB8888 mode.

Tested with:

	qemu-system-aarch64 -M virt -vga none -device ramfb \
		-kernel images/barebox-dt-2nd.img -cpu cortex-a57 -serial mon:stdio

Signed-off-by: Adrian Negreanu <adrian.negreanu@nxp.com>
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - rebased on new /dev/fw_cfg API
  - remove Kconfig resolution setup as no other driver does this
  - replace own PACKED definition with __packed
  - use <video/fourcc.h> instead of duplicating DMA_FORMAT_* definitions
  - allocate etc/ramfb buffer with dma_alloc
  - map framebuffer coherent
  - replaces RISC-V example in commit message with arm64, because that's
    what I last tested with (probably too old qemu for RISC-V on my side)
---
 drivers/video/Kconfig  |   6 ++
 drivers/video/Makefile |   1 +
 drivers/video/ramfb.c  | 191 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 198 insertions(+)
 create mode 100644 drivers/video/ramfb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a20b7bbee9b7..01bdaf47bfca 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -123,6 +123,12 @@ config DRIVER_VIDEO_SIMPLEFB
 	  Add support for setting up the kernel's simple framebuffer driver
 	  based on the active barebox framebuffer.
 
+config DRIVER_VIDEO_RAMFB
+	bool "QEMU RamFB support"
+	select QEMU_FW_CFG
+	help
+	  Add support for setting up a QEMU RamFB driver.
+
 config DRIVER_VIDEO_EDID
 	bool "Add EDID support"
 	help
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9ec0420ccad1..d50d2d3ba562 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
 obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
 obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB_CLIENT) += simplefb-client.o
 obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb-fixup.o
+obj-$(CONFIG_DRIVER_VIDEO_RAMFB) += ramfb.o
 obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
 obj-$(CONFIG_DRIVER_VIDEO_EFI_GOP) += efi_gop.o
 obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o
diff --git a/drivers/video/ramfb.c b/drivers/video/ramfb.c
new file mode 100644
index 000000000000..26e01196fc02
--- /dev/null
+++ b/drivers/video/ramfb.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: (C) 2022 Adrian Negreanu
+
+#define pr_fmt(fmt) "ramfb: " fmt
+
+#include <common.h>
+#include <fb.h>
+#include <fcntl.h>
+#include <dma.h>
+#include <init.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fs.h>
+#include <linux/qemu_fw_cfg.h>
+#include <video/fourcc.h>
+
+struct ramfb {
+	int fd;
+	struct fb_info info;
+	dma_addr_t screen_dma;
+	struct fb_videomode mode;
+	u16 etcfb_select;
+};
+
+struct fw_cfg_etc_ramfb {
+	u64 addr;
+	u32 fourcc;
+	u32 flags;
+	u32 width;
+	u32 height;
+	u32 stride;
+} __packed;
+
+static int fw_cfg_find_file(struct device *dev, int fd, const char *filename)
+{
+	size_t filename_len = strlen(filename);
+	ssize_t ret;
+	__be32 count;
+	int i;
+
+	ioctl(fd, FW_CFG_SELECT, &(u16) { FW_CFG_FILE_DIR });
+
+	lseek(fd, 0, SEEK_SET);
+
+	ret = read(fd, &count, sizeof(count));
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < be32_to_cpu(count); i++) {
+		struct fw_cfg_file qfile;
+
+		read(fd, &qfile, sizeof(qfile));
+
+		dev_dbg(dev, "enumerating file %s\n", qfile.name);
+
+		if (memcmp(qfile.name, filename, filename_len))
+			continue;
+
+		return be16_to_cpu(qfile.select);
+	}
+
+	return -ENOENT;
+}
+
+static void ramfb_populate_modes(struct ramfb *ramfb)
+{
+	struct fb_info *info = &ramfb->info;
+
+	ramfb->mode.name = "x8r8g8b8";
+	info->xres = ramfb->mode.xres = 640;
+	info->yres = ramfb->mode.yres = 480;
+
+	info->mode = &ramfb->mode;
+	info->bits_per_pixel = 32;
+	info->red	= (struct fb_bitfield) {16, 8};
+	info->green	= (struct fb_bitfield) {8, 8};
+	info->blue	= (struct fb_bitfield) {0, 8};
+	info->transp	= (struct fb_bitfield) {0, 0};
+}
+
+static int ramfb_activate_var(struct fb_info *fbi)
+{
+	struct ramfb *ramfb = fbi->priv;
+
+	if (fbi->screen_base)
+		dma_free_coherent(fbi->screen_base, ramfb->screen_dma, fbi->screen_size);
+
+	fbi->screen_size = fbi->xres * fbi->yres * fbi->bits_per_pixel;
+	fbi->screen_base = dma_alloc_coherent(fbi->screen_size, &ramfb->screen_dma);
+
+	return 0;
+}
+
+static void ramfb_enable(struct fb_info *fbi)
+{
+	struct ramfb *ramfb = fbi->priv;
+	struct fw_cfg_etc_ramfb *etc_ramfb;
+
+	etc_ramfb = dma_alloc(sizeof(*etc_ramfb));
+
+	etc_ramfb->addr = cpu_to_be64(ramfb->screen_dma);
+	etc_ramfb->fourcc = cpu_to_be32(DRM_FORMAT_XRGB8888);
+	etc_ramfb->flags  = cpu_to_be32(0);
+	etc_ramfb->width  = cpu_to_be32(fbi->xres);
+	etc_ramfb->height = cpu_to_be32(fbi->yres);
+	etc_ramfb->stride = cpu_to_be32(fbi->line_length);
+
+	ioctl(ramfb->fd, FW_CFG_SELECT, &ramfb->etcfb_select);
+
+	pwrite(ramfb->fd, etc_ramfb, sizeof(*etc_ramfb), 0);
+
+	dma_free(etc_ramfb);
+}
+
+static struct fb_ops ramfb_ops = {
+	.fb_activate_var = ramfb_activate_var,
+	.fb_enable = ramfb_enable,
+};
+
+static int ramfb_probe(struct device *parent_dev, int fd)
+{
+	int ret;
+	struct ramfb *ramfb;
+	struct fb_info *fbi;
+
+	ret = -ENODEV;
+
+	ramfb = xzalloc(sizeof(*ramfb));
+
+	ramfb->fd = fd;
+
+	ret = fw_cfg_find_file(parent_dev, fd, "etc/ramfb");
+	if (ret < 0) {
+		dev_err(parent_dev, "ramfb: fw_cfg (etc/ramfb) file not found\n");
+		return -ENODEV;
+	}
+
+	ramfb->etcfb_select = ret;
+	dev_dbg(parent_dev, "etc/ramfb file at slot 0x%x\n", ramfb->etcfb_select);
+
+	fbi = &ramfb->info;
+	fbi->priv = ramfb;
+	fbi->fbops = &ramfb_ops;
+	fbi->dev.parent = parent_dev;
+
+	ramfb_populate_modes(ramfb);
+
+	ret = register_framebuffer(fbi);
+	if (ret < 0) {
+		dev_err(parent_dev, "Unable to register ramfb: %d\n", ret);
+		return ret;
+	}
+
+	dev_info(parent_dev, "ramfb registered\n");
+
+	return 0;
+}
+
+static int ramfb_driver_init(void)
+{
+	struct cdev *cdev;
+	int err = 0;
+
+	for_each_cdev(cdev) {
+		int fd, ret;
+
+		if (!strstarts(cdev->name, "fw_cfg"))
+			continue;
+
+		fd = cdev_fdopen(cdev, O_RDWR);
+		if (fd < 0) {
+			err = fd;
+			continue;
+		}
+
+		ret = ramfb_probe(cdev->dev, fd);
+		if (ret == 0)
+			continue;
+		if (ret != -ENODEV && ret != -ENXIO)
+			err = ret;
+
+		close(fd);
+	}
+
+	return err;
+}
+device_initcall(ramfb_driver_init);
+
+MODULE_AUTHOR("Adrian Negreanu <adrian.negreanu@nxp.com>");
+MODULE_DESCRIPTION("QEMU RamFB driver");
+MODULE_LICENSE("GPL v2");
-- 
2.38.1




  parent reply	other threads:[~2023-01-30 18:23 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-30  7:27 [PATCH v2 0/4] " Ahmad Fatoum
2023-01-30  7:27 ` [PATCH v2 1/4] fs: devfs: implement cdev_fdopen Ahmad Fatoum
2023-01-30  7:27 ` [PATCH v2 2/4] asm-generic: avoid compiler warnings due to PCI_IOBASE Ahmad Fatoum
2023-01-30  7:27 ` [PATCH v2 3/4] firmware: add QEMU FW CFG driver Ahmad Fatoum
2023-01-30  7:27 ` Ahmad Fatoum [this message]
2023-01-31  8:19 ` [PATCH v2 0/4] video: add support for QEMU ramfb Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230130072707.2423294-5-ahmad@a3f.at \
    --to=ahmad@a3f.at \
    --cc=adrian.negreanu@nxp.com \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox