VirtIO can use various different buses and virtio devices are
commonly implemented as PCI devices. But virtual environments
without PCI support (a common situation in embedded devices
models) might use simple memory mapped device (“virtio-mmio”)
instead of the PCI device.
This adds a transport driver that implements UCLASS_VIRTIO for
virtio over mmio.
Signed-off-by: Tuomas Tynkkynen
Signed-off-by: Bin Meng
---
drivers/virtio/Kconfig | 7 +
drivers/virtio/Makefile | 1 +
drivers/virtio/virtio_mmio.c | 413 +++
drivers/virtio/virtio_mmio.h | 129 ++
4 files changed, 550 insertions(+)
create mode 100644 drivers/virtio/virtio_mmio.c
create mode 100644 drivers/virtio/virtio_mmio.h
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index bdfa96a..60cfaf8 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -11,4 +11,11 @@ config VIRTIO
This option is selected by any driver which implements the virtio
bus, such as CONFIG_VIRTIO_MMIO or CONFIG_VIRTIO_PCI.
+config VIRTIO_MMIO
+ bool "Platform bus driver for memory mapped virtio devices"
+ select VIRTIO
+ help
+ This driver provides support for memory mapped virtio
+ platform device driver.
+
endmenu
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 17d264a..2e48785 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -4,3 +4,4 @@
# Copyright (C) 2018, Bin Meng
obj-y += virtio-uclass.o virtio_ring.o
+obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
new file mode 100644
index 000..8038b46
--- /dev/null
+++ b/drivers/virtio/virtio_mmio.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Tuomas Tynkkynen
+ * Copyright (C) 2018, Bin Meng
+ *
+ * VirtIO memory-maped I/O transport driver
+ * Ported from Linux drivers/virtio/virtio_mmio.c
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "virtio_mmio.h"
+
+static int virtio_mmio_get_config(struct udevice *udev, unsigned int offset,
+ void *buf, unsigned int len)
+{
+ struct virtio_mmio_priv *priv = dev_get_priv(udev);
+ void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
+ u8 b;
+ __le16 w;
+ __le32 l;
+
+ if (priv->version == 1) {
+ u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ ptr[i] = readb(base + offset + i);
+
+ return 0;
+ }
+
+ switch (len) {
+ case 1:
+ b = readb(base + offset);
+ memcpy(buf, , sizeof(b));
+ break;
+ case 2:
+ w = cpu_to_le16(readw(base + offset));
+ memcpy(buf, , sizeof(w));
+ break;
+ case 4:
+ l = cpu_to_le32(readl(base + offset));
+ memcpy(buf, , sizeof(l));
+ break;
+ case 8:
+ l = cpu_to_le32(readl(base + offset));
+ memcpy(buf, , sizeof(l));
+ l = cpu_to_le32(readl(base + offset + sizeof(l)));
+ memcpy(buf + sizeof(l), , sizeof(l));
+ break;
+ default:
+ WARN_ON(true);
+ }
+
+ return 0;
+}
+
+static int virtio_mmio_set_config(struct udevice *udev, unsigned int offset,
+ const void *buf, unsigned int len)
+{
+ struct virtio_mmio_priv *priv = dev_get_priv(udev);
+ void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
+ u8 b;
+ __le16 w;
+ __le32 l;
+
+ if (priv->version == 1) {
+ const u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ writeb(ptr[i], base + offset + i);
+
+ return 0;
+ }
+
+ switch (len) {
+ case 1:
+ memcpy(, buf, sizeof(b));
+ writeb(b, base + offset);
+ break;
+ case 2:
+ memcpy(, buf, sizeof(w));
+ writew(le16_to_cpu(w), base + offset);
+ break;
+ case 4:
+ memcpy(, buf, sizeof(l));
+ writel(le32_to_cpu(l), base + offset);
+ break;
+ case 8:
+ memcpy(, buf, sizeof(l));
+ writel(le32_to_cpu(l), base + offset);
+ memcpy(, buf + sizeof(l), sizeof(l));
+ writel(le32_to_cpu(l), base + offset + sizeof(l));
+ break;
+ default:
+ WARN_ON(true);
+ }
+
+ return 0;
+}
+
+static int virtio_mmio_generation(struct udevice *udev, u32 *counter)
+{
+ struct virtio_mmio_priv *priv = dev_get_priv(udev);
+
+ if (priv->version == 1)
+ *counter = 0;
+ else
+ *counter =