
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@chromium.org ---
drivers/video/Kconfig | 30 ++++++++++ drivers/video/Makefile | 2 + drivers/video/bochs.c | 130 +++++++++++++++++++++++++++++++++++++++++ drivers/video/bochs.h | 36 ++++++++++++ 4 files changed, 198 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 9a95b7a4c792..5fd42807179f 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 Boschs 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 a609e35d22e8..11d872ddf41d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -28,6 +28,8 @@ obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o
endif
+obj-$(CONFIG_VIDEO_BOCHS) += bochs.o + obj-${CONFIG_EXYNOS_FB} += exynos/ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ obj-${CONFIG_VIDEO_STM32} += stm32/ diff --git a/drivers/video/bochs.c b/drivers/video/bochs.c new file mode 100644 index 000000000000..7ea29a0ed177 --- /dev/null +++ b/drivers/video/bochs.c @@ -0,0 +1,130 @@ +// 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_linear_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); + + log_debug("QEMU VGA: bochs @ %p: %d MiB FB at %lx\n", mmio, mem / SZ_1M, + fb); + + /* 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; + + 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_linear_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; +} + +static const struct udevice_id bochs_video_ids[] = { + { .compatible = "bochs-fb" }, + { } +}; + +U_BOOT_DRIVER(bochs_video) = { + .name = "bochs_video", + .id = UCLASS_VIDEO, + .of_match = bochs_video_ids, + .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