diff options
author | Simon Glass <sjg@chromium.org> | 2023-07-15 21:39:18 -0600 |
---|---|---|
committer | Bin Meng <bmeng@tinylab.org> | 2023-07-17 17:23:15 +0800 |
commit | e2d934b4dae97493db2a74211a82b433776e2000 (patch) | |
tree | 3d2ffdbdd2d0ffebba1ad40d6fe504d96140cf15 | |
parent | 085f8db6b98dfdd8c1707797003d677ce654904f (diff) | |
download | u-boot-e2d934b4dae97493db2a74211a82b433776e2000.zip u-boot-e2d934b4dae97493db2a74211a82b433776e2000.tar.gz u-boot-e2d934b4dae97493db2a74211a82b433776e2000.tar.bz2 |
x86: video: Add a driver for QEMU bochs emulation
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>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
-rw-r--r-- | drivers/video/Kconfig | 30 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/bochs.c | 123 | ||||
-rw-r--r-- | drivers/video/bochs.h | 36 |
4 files changed, 190 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 4976295..2ba4f5e 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 f99d7e3..a926370 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 0000000..2136b51 --- /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 0000000..4c8ec83 --- /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 |