Hi Simon, On Sun, Apr 30, 2023 at 10:32 AM Simon Glass <s...@chromium.org> wrote: > > 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 <s...@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);
mem is uninitialized yet at this point, until (see below) > + > + /* 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; it reaches this line > + > + 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 Regards, Bin