summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-01-19 05:41:44 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2021-01-19 05:41:44 +0100
commitb5d3c4c00dff9211fb271e644ae5e98aa0a0853e (patch)
tree8f9d871b2a51b27ad345bece85ce59ee4e8d6c52
parent2ea982543a2570af2f7629e08bb6d3ff28b07e3a (diff)
parentaa3cdd7c55bfcbbc2da56220a809b5ac39ac3346 (diff)
downloadbarebox-b5d3c4c00dff9211fb271e644ae5e98aa0a0853e.tar.gz
barebox-b5d3c4c00dff9211fb271e644ae5e98aa0a0853e.tar.xz
Merge branch 'for-next/video'
-rw-r--r--Documentation/boards/mips/qemu-malta.rst4
-rw-r--r--arch/mips/configs/qemu-malta_defconfig4
-rw-r--r--drivers/video/Kconfig3
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/bochs/Kconfig24
-rw-r--r--drivers/video/bochs/Makefile5
-rw-r--r--drivers/video/bochs/bochs_hw.c205
-rw-r--r--drivers/video/bochs/bochs_hw.h15
-rw-r--r--drivers/video/bochs/bochs_isa.c31
-rw-r--r--drivers/video/bochs/bochs_pci.c37
-rw-r--r--drivers/video/edid.c11
-rw-r--r--drivers/video/edid.h10
-rw-r--r--drivers/video/sdl.c9
13 files changed, 343 insertions, 17 deletions
diff --git a/Documentation/boards/mips/qemu-malta.rst b/Documentation/boards/mips/qemu-malta.rst
index 2bb81350a1..470be32f1f 100644
--- a/Documentation/boards/mips/qemu-malta.rst
+++ b/Documentation/boards/mips/qemu-malta.rst
@@ -9,7 +9,7 @@ QEMU run string:
.. code-block:: sh
qemu-system-mips -nodefaults -M malta -m 256 \
- -nographic -serial stdio -monitor null \
+ -device VGA -serial stdio -monitor null \
-bios barebox-flash-image
@@ -33,7 +33,7 @@ QEMU run string:
.. code-block:: sh
qemu-system-mipsel -nodefaults -M malta -m 256 \
- -nographic -serial stdio -monitor null \
+ -devica VGA -serial stdio -monitor null \
-bios barebox-flash-image
diff --git a/arch/mips/configs/qemu-malta_defconfig b/arch/mips/configs/qemu-malta_defconfig
index ac0577c217..b9994f392c 100644
--- a/arch/mips/configs/qemu-malta_defconfig
+++ b/arch/mips/configs/qemu-malta_defconfig
@@ -42,6 +42,7 @@ CONFIG_CMD_LOGIN=y
CONFIG_CMD_MENU=y
CONFIG_CMD_MENU_MANAGEMENT=y
CONFIG_CMD_PASSWD=y
+CONFIG_CMD_FBTEST=y
CONFIG_CMD_READLINE=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_CRC=y
@@ -68,6 +69,9 @@ CONFIG_DRIVER_CFI=y
# CONFIG_DRIVER_CFI_BANK_WIDTH_1 is not set
# CONFIG_DRIVER_CFI_BANK_WIDTH_2 is not set
CONFIG_CFI_BUFFER_WRITE=y
+CONFIG_VIDEO=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_DRIVER_VIDEO_BOCHS_PCI=y
CONFIG_GPIO_MALTA_FPGA_I2C=y
CONFIG_PCI=y
CONFIG_PCI_DEBUG=y
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a26bace176..9ec6ea4248 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -98,6 +98,8 @@ config DRIVER_VIDEO_BCM283X
source "drivers/video/imx-ipu-v3/Kconfig"
+source "drivers/video/bochs/Kconfig"
+
config DRIVER_VIDEO_SIMPLEFB
bool "Simple framebuffer support"
depends on OFTREE
@@ -106,7 +108,6 @@ config DRIVER_VIDEO_SIMPLEFB
based on the active barebox framebuffer.
config DRIVER_VIDEO_EDID
- depends on I2C
bool "Add EDID support"
help
This enabled support for reading and parsing EDID data from an attached
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 01fabe8809..28d0fe205b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -24,4 +24,4 @@ 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
obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o
-
+obj-$(CONFIG_DRIVER_VIDEO_BOCHS) += bochs/
diff --git a/drivers/video/bochs/Kconfig b/drivers/video/bochs/Kconfig
new file mode 100644
index 0000000000..ae5d38a8ad
--- /dev/null
+++ b/drivers/video/bochs/Kconfig
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRIVER_VIDEO_BOCHS
+ select DRIVER_VIDEO_EDID
+ bool
+
+config DRIVER_VIDEO_BOCHS_PCI
+ bool "bochs dispi / QEMU standard VGA PCI driver"
+ select DRIVER_VIDEO_BOCHS
+ depends on PCI
+ help
+ Say yes here if you have a PCI VGA display controller that
+ implements the bochs dispi VBE extension. This is a very simple
+ interface to drive the graphical output of virtual machines
+ like bochs, VirtualBox and Qemu (-device VGA).
+
+config DRIVER_VIDEO_BOCHS_ISA
+ bool "bochs dispi / QEMU standard VGA ISA driver"
+ select DRIVER_VIDEO_BOCHS
+ help
+ Say yes here if you have a ISA (I/O ports) VGA display controller that
+ implements the bochs dispi VBE extension. This is a very simple
+ interface to drive the graphical output of virtual machines
+ like bochs, VirtualBox and Qemu (-device isa-vga).
diff --git a/drivers/video/bochs/Makefile b/drivers/video/bochs/Makefile
new file mode 100644
index 0000000000..3ab7ade8a1
--- /dev/null
+++ b/drivers/video/bochs/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += bochs_hw.o
+obj-$(CONFIG_DRIVER_VIDEO_BOCHS_PCI) += bochs_pci.o
+obj-$(CONFIG_DRIVER_VIDEO_BOCHS_ISA) += bochs_isa.o
diff --git a/drivers/video/bochs/bochs_hw.c b/drivers/video/bochs/bochs_hw.c
new file mode 100644
index 0000000000..252350aebb
--- /dev/null
+++ b/drivers/video/bochs/bochs_hw.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright (c) 2020 Ahmad Fatoum, Pengutronix
+/*
+ * Driver for VGA with the Bochs VBE / QEMU stdvga extensions.
+ *
+ * Based on the Linux v5.11-rc1 bochs-dispi DRM driver.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <linux/pci.h>
+#include <fb.h>
+#include "../edid.h"
+#include "bochs_hw.h"
+
+#define VBE_DISPI_INDEX_ID 0x0
+#define VBE_DISPI_INDEX_XRES 0x1
+#define VBE_DISPI_INDEX_YRES 0x2
+#define VBE_DISPI_INDEX_BPP 0x3
+#define VBE_DISPI_INDEX_ENABLE 0x4
+#define VBE_DISPI_INDEX_BANK 0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+#define VBE_DISPI_INDEX_X_OFFSET 0x8
+#define VBE_DISPI_INDEX_Y_OFFSET 0x9
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
+
+#define VBE_DISPI_ENABLED 0x01
+#define VBE_DISPI_GETCAPS 0x02
+#define VBE_DISPI_8BIT_DAC 0x20
+#define VBE_DISPI_LFB_ENABLED 0x40
+#define VBE_DISPI_NOCLEARMEM 0x80
+
+/* Offsets for accessing ioports via PCI BAR1 (MMIO) */
+#define VGA_MMIO_OFFSET (0x400 - 0x3c0)
+#define VBE_MMIO_OFFSET 0x500
+
+struct bochs {
+ struct fb_info fb;
+ void __iomem *fb_map;
+ void __iomem *mmio;
+};
+
+static void bochs_vga_writeb(struct bochs *bochs, u16 ioport, u8 val)
+{
+ if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df))
+ return;
+
+ if (bochs->mmio) {
+ int offset = ioport + VGA_MMIO_OFFSET;
+ writeb(val, bochs->mmio + offset);
+ } else {
+ outb(val, ioport);
+ }
+}
+
+static u16 bochs_dispi_read(struct bochs *bochs, u16 reg)
+{
+ u16 ret = 0;
+
+ if (bochs->mmio) {
+ int offset = VBE_MMIO_OFFSET + (reg << 1);
+ ret = readw(bochs->mmio + offset);
+ } else {
+ outw(reg, VBE_DISPI_IOPORT_INDEX);
+ ret = inw(VBE_DISPI_IOPORT_DATA);
+ }
+ return ret;
+}
+
+static void bochs_dispi_write(struct bochs *bochs, u16 reg, u16 val)
+{
+ if (bochs->mmio) {
+ int offset = VBE_MMIO_OFFSET + (reg << 1);
+ writew(val, bochs->mmio + offset);
+ } else {
+ outw(reg, VBE_DISPI_IOPORT_INDEX);
+ outw(val, VBE_DISPI_IOPORT_DATA);
+ }
+}
+
+static void bochs_fb_enable(struct fb_info *fb)
+{
+ struct bochs *bochs = fb->priv;
+
+ bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, 0);
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, fb->bits_per_pixel);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, fb->xres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, fb->yres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK, 0);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, fb->xres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT, fb->yres);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, 0);
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, 0);
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
+ VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED );
+}
+
+static void bochs_fb_disable(struct fb_info *fb)
+{
+ struct bochs *bochs = fb->priv;
+
+ bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
+ bochs_dispi_read(bochs, VBE_DISPI_INDEX_ENABLE) &
+ ~VBE_DISPI_ENABLED);
+}
+
+static struct fb_ops bochs_fb_ops = {
+ .fb_enable = bochs_fb_enable,
+ .fb_disable = bochs_fb_disable,
+};
+
+static int bochs_hw_load_edid(struct bochs *bochs)
+{
+ u8 *edid;
+ int i;
+
+ edid = xzalloc(EDID_LENGTH);
+
+ for (i = 0; i <= EDID_HEADER_END; i++)
+ edid[i] = readb(bochs->mmio + i);
+
+ /* check header to detect whenever edid support is enabled in qemu */
+ if (!edid_check_header(edid)) {
+ free(edid);
+ return -EILSEQ;
+ }
+
+ for (i = EDID_HEADER_END + 1; i < EDID_LENGTH; i++)
+ edid[i] = readb(bochs->mmio + i);
+
+ bochs->fb.edid_data = edid;
+ return 0;
+}
+
+static int bochs_hw_read_version(struct bochs *bochs)
+{
+ u16 ver;
+
+ ver = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID);
+
+ if ((ver & 0xB0C0) != 0xB0C0)
+ return -ENODEV;
+
+ return ver & 0xF;
+}
+
+int bochs_hw_probe(struct device_d *dev, void __iomem *fb_map, void __iomem *mmio)
+{
+ struct bochs *bochs;
+ struct fb_info *fb;
+ int ret;
+
+ bochs = xzalloc(sizeof(*bochs));
+
+ bochs->fb_map = IOMEM(fb_map);
+ bochs->mmio = IOMEM(mmio);
+
+ ret = bochs_hw_read_version(bochs);
+ if (ret < 0) {
+ free(bochs);
+ return ret;
+ }
+
+ dev_info(dev, "detected bochs dispi v%u\n", ret);
+
+ fb = &bochs->fb;
+ fb->screen_base = bochs->fb_map;
+
+ fb->bits_per_pixel = 16;
+ fb->red.length = 5;
+ fb->green.length = 6;
+ fb->blue.length = 5;
+ fb->red.offset = 11;
+ fb->green.offset = 5;
+ fb->blue.offset = 0;
+
+ /* EDID is only exposed over PCI */
+ ret = -ENODEV;
+
+ if (mmio) {
+ ret = bochs_hw_load_edid(bochs);
+ if (ret)
+ dev_warn(dev, "couldn't read EDID information\n");
+ }
+
+ if (ret) {
+ fb->mode = xzalloc(sizeof(*fb->mode));
+ fb->modes.modes = fb->mode;
+ fb->modes.num_modes = 1;
+
+ fb->mode->name = "640x480";
+ fb->mode->xres = 640;
+ fb->mode->yres = 480;
+ }
+
+ fb->priv = bochs;
+ fb->fbops = &bochs_fb_ops;
+
+ return register_framebuffer(fb);
+}
diff --git a/drivers/video/bochs/bochs_hw.h b/drivers/video/bochs/bochs_hw.h
new file mode 100644
index 0000000000..420b58f4da
--- /dev/null
+++ b/drivers/video/bochs/bochs_hw.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef BOCHS_HW_H
+#define BOCHS_HW_H
+
+#include <linux/compiler.h>
+
+#define VBE_DISPI_IOPORT_INDEX 0x01CE
+#define VBE_DISPI_IOPORT_DATA 0x01CF
+
+struct device_d;
+
+int bochs_hw_probe(struct device_d *dev, void *fb_map, void __iomem *mmio);
+
+#endif
diff --git a/drivers/video/bochs/bochs_isa.c b/drivers/video/bochs/bochs_isa.c
new file mode 100644
index 0000000000..f273ac5f74
--- /dev/null
+++ b/drivers/video/bochs/bochs_isa.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright (c) 2020 Ahmad Fatoum, Pengutronix
+/*
+ * ISA driver entry point for VGA with the Bochs VBE / QEMU stdvga extensions.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <linux/ioport.h>
+#include "bochs_hw.h"
+
+static int bochs_isa_detect(void)
+{
+ struct device_d *dev;
+ int ret;
+
+ outw(0, VBE_DISPI_IOPORT_INDEX);
+ ret = inw(VBE_DISPI_IOPORT_DATA);
+
+ if ((ret & 0xB0C0) != 0xB0C0)
+ return -ENODEV;
+
+ dev = device_alloc("bochs-dispi", 0);
+
+ ret = platform_device_register(dev);
+ if (ret)
+ return ret;
+
+ return bochs_hw_probe(dev, (void *)0xe0000000, NULL);
+}
+device_initcall(bochs_isa_detect);
diff --git a/drivers/video/bochs/bochs_pci.c b/drivers/video/bochs/bochs_pci.c
new file mode 100644
index 0000000000..28785e1c06
--- /dev/null
+++ b/drivers/video/bochs/bochs_pci.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright (c) 2020 Ahmad Fatoum, Pengutronix
+/*
+ * PCI driver entry point for VGA with the Bochs VBE / QEMU stdvga extensions.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <linux/pci.h>
+#include "bochs_hw.h"
+
+static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ void __iomem *fb_map, *mmio;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ fb_map = pci_iomap(pdev, 0);
+ mmio = pci_iomap(pdev, 2);
+
+ return bochs_hw_probe(&pdev->dev, fb_map, mmio);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(bochs_pci_tbl) = {
+ /* https://github.com/qemu/qemu/blob/master/docs/specs/standard-vga.txt */
+ { PCI_DEVICE(0x1234, 0x1111) },
+};
+
+static struct pci_driver bochs_pci_driver = {
+ .name = "bochs-dispi",
+ .probe = bochs_pci_probe,
+ .id_table = bochs_pci_tbl,
+};
+device_pci_driver(bochs_pci_driver);
diff --git a/drivers/video/edid.c b/drivers/video/edid.c
index bee4594118..1baff7317b 100644
--- a/drivers/video/edid.c
+++ b/drivers/video/edid.c
@@ -223,19 +223,19 @@ static int edid_checksum(unsigned char *edid)
return err;
}
-static int edid_check_header(unsigned char *edid)
+bool edid_check_header(unsigned char *edid)
{
- int i, err = 1, fix = check_edid(edid);
+ int i, fix = check_edid(edid);
if (fix)
fix_edid(edid, fix);
for (i = 0; i < 8; i++) {
if (edid[i] != edid_v1_header[i])
- err = 0;
+ return false;
}
- return err;
+ return true;
}
/*
@@ -858,6 +858,9 @@ void *edid_read_i2c(struct i2c_adapter *adapter)
{
u8 *block;
+ if (!IS_ENABLED(CONFIG_I2C))
+ return NULL;
+
block = xmalloc(EDID_LENGTH);
if (edid_do_read_i2c(adapter, block, 0, EDID_LENGTH))
diff --git a/drivers/video/edid.h b/drivers/video/edid.h
index 006d9f2834..60c5b6422e 100644
--- a/drivers/video/edid.h
+++ b/drivers/video/edid.h
@@ -135,4 +135,14 @@
#define DPMS_SUSPEND (1 << 6)
#define DPMS_STANDBY (1 << 7)
+/**
+ * edid_check_header - sanity check the header of the base EDID block
+ * @raw_edid: pointer to raw base EDID block
+ *
+ * Sanity check the header of the base EDID block.
+ *
+ * Return: true if the header is perfect, false if any byte is wrong.
+ */
+bool edid_check_header(unsigned char *edid);
+
#endif /* __EDID_H__ */
diff --git a/drivers/video/sdl.c b/drivers/video/sdl.c
index 8f5b409efb..9811b2cf12 100644
--- a/drivers/video/sdl.c
+++ b/drivers/video/sdl.c
@@ -59,15 +59,6 @@ static int sdlfb_probe(struct device_d *dev)
fb->screen_base = xzalloc(fb->xres * fb->yres *
fb->bits_per_pixel >> 3);
- dev_dbg(dev, "red: length = %d, offset = %d\n",
- fb->red.length, fb->red.offset);
- dev_dbg(dev, "green: length = %d, offset = %d\n",
- fb->green.length, fb->green.offset);
- dev_dbg(dev, "blue: length = %d, offset = %d\n",
- fb->blue.length, fb->blue.offset);
- dev_dbg(dev, "transp: length = %d, offset = %d\n",
- fb->transp.length, fb->transp.offset);
-
/* add runtime hardware info */
dev->priv = fb;