[PATCH v5 45/46] x86: video: Add a driver for QEMU bochs emulation

Simon Glass sjg at chromium.org
Sun Jul 16 05:39:18 CEST 2023


Bochs is convenient with QEMU on x86 since it does not require a video
BIOS. Add a driver for it.

Signed-off-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Bin Meng <bmeng.cn at gmail.com>
---

(no changes since v2)

Changes in v2:
- Bring in to qemu series
- Rebase to -next
- Drop unused of_match
- Fix Boschs typo
- Rename bochs_init_linear_fb() function to drop 'linear'
- Fix uninited variable

 drivers/video/Kconfig  |  30 ++++++++++
 drivers/video/Makefile |   1 +
 drivers/video/bochs.c  | 123 +++++++++++++++++++++++++++++++++++++++++
 drivers/video/bochs.h  |  36 ++++++++++++
 4 files changed, 190 insertions(+)
 create mode 100644 drivers/video/bochs.c
 create mode 100644 drivers/video/bochs.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 49762950719e..2ba4f5eac7f3 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -278,6 +278,36 @@ config VIDCONSOLE_AS_NAME
 	  possible to update the environment, the breakage may be confusing for
 	  users. This option will be removed around the end of 2020.
 
+config VIDEO_BOCHS
+	bool "Enable Bochs video emulation for QEMU"
+	depends on X86
+	help
+	  Enable this to use the Bochs video support provided in the QEMU
+	  emulator. This appears as a PCI device which U-Boot can set up to
+	  provide a frame buffer.
+
+if VIDEO_BOCHS
+
+config VIDEO_BOCHS_SIZE_X
+	int "Width of display (X resolution)"
+	default 1280
+	help
+	  Sets the width of the 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_BOCHS_SIZE_Y
+	int "High of display (Y resolution)"
+	default 1024
+	help
+	  Sets the height of the 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 VIDEO_COREBOOT
 	bool "Enable coreboot framebuffer driver support"
 	depends on X86
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index f99d7e3c3d90..a9263709084d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_OSD) += video_osd-uclass.o
 obj-$(CONFIG_SANDBOX_OSD) += sandbox_osd.o
 obj-$(CONFIG_VIDEO_ARM_MALIDP) += mali_dp.o
 obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o
+obj-$(CONFIG_VIDEO_BOCHS) += bochs.o
 obj-$(CONFIG_VIDEO_BROADWELL_IGD) += broadwell_igd.o
 obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
 obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/video/bochs.c b/drivers/video/bochs.c
new file mode 100644
index 000000000000..2136b5119368
--- /dev/null
+++ b/drivers/video/bochs.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Modified from coreboot bochs.c
+ */
+
+#define LOG_CATEGORY	UCLASS_VIDEO
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <video.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <linux/sizes.h>
+#include "bochs.h"
+
+static int xsize = CONFIG_VIDEO_BOCHS_SIZE_X;
+static int ysize = CONFIG_VIDEO_BOCHS_SIZE_Y;
+
+static void bochs_write(void *mmio, int index, int val)
+{
+	writew(val, mmio + MMIO_BASE + index * 2);
+}
+
+static int bochs_read(void *mmio, int index)
+{
+	return readw(mmio + MMIO_BASE + index * 2);
+}
+
+static void bochs_vga_write(int index, uint8_t val)
+{
+	outb(val, VGA_INDEX);
+}
+
+static int bochs_init_fb(struct udevice *dev)
+{
+	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+	ulong fb;
+	void *mmio;
+	int id, mem;
+
+	log_debug("probing %s at PCI %x\n", dev->name, dm_pci_get_bdf(dev));
+	fb = dm_pci_read_bar32(dev, 0);
+	if (!fb)
+		return log_msg_ret("fb", -EIO);
+
+	/* MMIO bar supported since qemu 3.0+ */
+	mmio = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_2, 0, 0, PCI_REGION_TYPE,
+			      PCI_REGION_MEM);
+
+	if (!mmio)
+		return log_msg_ret("map", -EIO);
+
+	/* bochs dispi detection */
+	id = bochs_read(mmio, INDEX_ID);
+	if ((id & 0xfff0) != ID0) {
+		log_debug("ID mismatch\n");
+		return -EPROTONOSUPPORT;
+	}
+	mem = bochs_read(mmio, INDEX_VIDEO_MEMORY_64K) * SZ_64K;
+	log_debug("QEMU VGA: bochs @ %p: %d MiB FB at %lx\n", mmio, mem / SZ_1M,
+		  fb);
+
+	uc_priv->xsize = xsize;
+	uc_priv->ysize = ysize;
+	uc_priv->bpix = VIDEO_BPP32;
+
+	/* setup video mode */
+	bochs_write(mmio, INDEX_ENABLE,  0);
+	bochs_write(mmio, INDEX_BANK,  0);
+	bochs_write(mmio, INDEX_BPP, VNBITS(uc_priv->bpix));
+	bochs_write(mmio, INDEX_XRES, xsize);
+	bochs_write(mmio, INDEX_YRES, ysize);
+	bochs_write(mmio, INDEX_VIRT_WIDTH, xsize);
+	bochs_write(mmio, INDEX_VIRT_HEIGHT, ysize);
+	bochs_write(mmio, INDEX_X_OFFSET, 0);
+	bochs_write(mmio, INDEX_Y_OFFSET, 0);
+	bochs_write(mmio, INDEX_ENABLE, ENABLED | LFB_ENABLED);
+
+	bochs_vga_write(0, 0x20);	/* disable blanking */
+
+	plat->base = fb;
+
+	return 0;
+}
+
+static int bochs_video_probe(struct udevice *dev)
+{
+	int ret;
+
+	ret = bochs_init_fb(dev);
+	if (ret)
+		return log_ret(ret);
+
+	return 0;
+}
+
+static int bochs_video_bind(struct udevice *dev)
+{
+	struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+
+	/* Set the maximum supported resolution */
+	uc_plat->size = 2560 * 1600 * 4;
+	log_debug("%s: Frame buffer size %x\n", __func__, uc_plat->size);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bochs_video) = {
+	.name	= "bochs_video",
+	.id	= UCLASS_VIDEO,
+	.bind	= bochs_video_bind,
+	.probe	= bochs_video_probe,
+};
+
+static struct pci_device_id bochs_video_supported[] = {
+	{ PCI_DEVICE(0x1234, 0x1111) },
+	{ },
+};
+
+U_BOOT_PCI_DEVICE(bochs_video, bochs_video_supported);
diff --git a/drivers/video/bochs.h b/drivers/video/bochs.h
new file mode 100644
index 000000000000..4c8ec83a550e
--- /dev/null
+++ b/drivers/video/bochs.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Modified from coreboot bochs.c
+ */
+
+#ifndef __BOCHS_H
+#define __BOCHS_H
+
+#define VGA_INDEX	0x3c0
+
+#define IOPORT_INDEX	0x01ce
+#define IOPORT_DATA	0x01cf
+
+enum {
+	INDEX_ID,
+	INDEX_XRES,
+	INDEX_YRES,
+	INDEX_BPP,
+	INDEX_ENABLE,
+	INDEX_BANK,
+	INDEX_VIRT_WIDTH,
+	INDEX_VIRT_HEIGHT,
+	INDEX_X_OFFSET,
+	INDEX_Y_OFFSET,
+	INDEX_VIDEO_MEMORY_64K
+};
+
+#define ID0		0xb0c0
+
+#define ENABLED		BIT(0)
+#define LFB_ENABLED	BIT(6)
+#define NOCLEARMEM	BIT(7)
+
+#define MMIO_BASE	0x500
+
+#endif
-- 
2.41.0.455.g037347b96a-goog



More information about the U-Boot mailing list