[PATCH v8 3/4] qemu: add MMIO driver for QFW

Asherah Connor ashe at kivikakk.ee
Fri Mar 19 08:21:42 CET 2021


Add MMIO driver for QFW.

Note that there is no consumer as of this patch.

Signed-off-by: Asherah Connor <ashe at kivikakk.ee>
Reviewed-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Bin Meng <bmeng.cn at gmail.com>
---

(no changes since v5)

Changes in v5:
* Split MMIO driver into its own commit.
* Add CONFIG_QFW_MMIO for selection by arch/board.

 drivers/misc/Kconfig    |   7 +++
 drivers/misc/Makefile   |   1 +
 drivers/misc/qfw_mmio.c | 119 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 127 insertions(+)
 create mode 100644 drivers/misc/qfw_mmio.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3a254eba4b..c650471ff7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -378,6 +378,13 @@ config QFW_PIO
 	  Hidden option to enable PIO QEMU fw_cfg interface. This will be
 	  selected by the appropriate QEMU board.
 
+config QFW_MMIO
+	bool
+	depends on QFW
+	help
+	  Hidden option to enable MMIO QEMU fw_cfg interface. This will be
+	  selected by the appropriate QEMU board.
+
 config I2C_EEPROM
 	bool "Enable driver for generic I2C-attached EEPROMs"
 	depends on MISC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2864b84af9..0c67d43a5d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
 ifdef CONFIG_QFW
 obj-y += qfw.o
 obj-$(CONFIG_QFW_PIO) += qfw_pio.o
+obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o
 obj-$(CONFIG_SANDBOX) += qfw_sandbox.o
 endif
 obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
diff --git a/drivers/misc/qfw_mmio.c b/drivers/misc/qfw_mmio.c
new file mode 100644
index 0000000000..f397384054
--- /dev/null
+++ b/drivers/misc/qfw_mmio.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MMIO interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest at gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe at kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+struct qfw_mmio {
+	/*
+	 * Each access to the 64-bit data register can be 8/16/32/64 bits wide.
+	 */
+	union {
+		u8 data8;
+		u16 data16;
+		u32 data32;
+		u64 data64;
+	};
+	u16 selector;
+	u8 padding[6];
+	u64 dma;
+};
+
+struct qfw_mmio_plat {
+	volatile struct qfw_mmio *mmio;
+};
+
+static void qfw_mmio_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+				   void *address)
+{
+	struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+	/*
+	 * writing FW_CFG_INVALID will cause read operation to resume at last
+	 * offset, otherwise read will start at offset 0
+	 *
+	 * Note: on platform where the control register is MMIO, the register
+	 * is big endian.
+	 */
+	if (entry != FW_CFG_INVALID)
+		plat->mmio->selector = cpu_to_be16(entry);
+
+	/* the endianness of data register is string-preserving */
+	while (size >= 8) {
+		*(u64 *)address = plat->mmio->data64;
+		address += 8;
+		size -= 8;
+	}
+	while (size >= 4) {
+		*(u32 *)address = plat->mmio->data32;
+		address += 4;
+		size -= 4;
+	}
+	while (size >= 2) {
+		*(u16 *)address = plat->mmio->data16;
+		address += 2;
+		size -= 2;
+	}
+	while (size >= 1) {
+		*(u8 *)address = plat->mmio->data8;
+		address += 1;
+		size -= 1;
+	}
+}
+
+/* Read configuration item using fw_cfg DMA interface */
+static void qfw_mmio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+	struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+	/* the DMA address register is big-endian */
+	plat->mmio->dma = cpu_to_be64((uintptr_t)dma);
+
+	while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR);
+}
+
+static int qfw_mmio_of_to_plat(struct udevice *dev)
+{
+	struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+	plat->mmio = map_physmem(dev_read_addr(dev),
+				 sizeof(struct qfw_mmio),
+				 MAP_NOCACHE);
+
+	return 0;
+}
+
+static int qfw_mmio_probe(struct udevice *dev)
+{
+	return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_mmio_ops = {
+	.read_entry_io = qfw_mmio_read_entry_io,
+	.read_entry_dma = qfw_mmio_read_entry_dma,
+};
+
+static const struct udevice_id qfw_mmio_ids[] = {
+	{ .compatible = "qemu,fw-cfg-mmio" },
+	{}
+};
+
+U_BOOT_DRIVER(qfw_mmio) = {
+	.name	= "qfw_mmio",
+	.id	= UCLASS_QFW,
+	.of_match	= qfw_mmio_ids,
+	.plat_auto	= sizeof(struct qfw_mmio_plat),
+	.of_to_plat	= qfw_mmio_of_to_plat,
+	.probe	= qfw_mmio_probe,
+	.ops	= &qfw_mmio_ops,
+};
-- 
2.20.1



More information about the U-Boot mailing list