summaryrefslogtreecommitdiff
path: root/drivers/misc/qfw_pio.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-04-13 09:50:45 -0400
committerTom Rini <trini@konsulko.com>2021-04-13 09:50:45 -0400
commita94ab561e2f49a80d8579930e840b810ab1a1330 (patch)
tree77913e7bd9309afa6b2ddc6f3e3e49827da2025c /drivers/misc/qfw_pio.c
parent3b676a1662ac6b54d1e97ea40a0c41ee0925ffe3 (diff)
parent8c4e3b79bd0bb76eea16869e9666e19047c0d005 (diff)
Merge branch '2021-04-13-assorted-improvements'
- A large assortment of bug fixes, code cleanups and a few feature enhancements.
Diffstat (limited to 'drivers/misc/qfw_pio.c')
-rw-r--r--drivers/misc/qfw_pio.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/misc/qfw_pio.c b/drivers/misc/qfw_pio.c
new file mode 100644
index 00000000000..e2f628d3383
--- /dev/null
+++ b/drivers/misc/qfw_pio.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PIO interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/io.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+/*
+ * PIO ports are correct for x86, which appears to be the only arch that uses
+ * PIO.
+ */
+#define FW_CONTROL_PORT 0x510
+#define FW_DATA_PORT 0x511
+#define FW_DMA_PORT_LOW 0x514
+#define FW_DMA_PORT_HIGH 0x518
+
+static void qfw_pio_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+ void *address)
+{
+ /*
+ * 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 IO port, the
+ * endianness is little endian.
+ */
+ if (entry != FW_CFG_INVALID)
+ outw(cpu_to_le16(entry), FW_CONTROL_PORT);
+
+ /* the endianness of data register is string-preserving */
+ u32 i = 0;
+ u8 *data = address;
+
+ while (size--)
+ data[i++] = inb(FW_DATA_PORT);
+}
+
+/* Read configuration item using fw_cfg DMA interface */
+static void qfw_pio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+ /* the DMA address register is big-endian */
+ outl(cpu_to_be32((uintptr_t)dma), FW_DMA_PORT_HIGH);
+
+ while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR);
+}
+
+static int qfw_pio_probe(struct udevice *dev)
+{
+ return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_pio_ops = {
+ .read_entry_io = qfw_pio_read_entry_io,
+ .read_entry_dma = qfw_pio_read_entry_dma,
+};
+
+U_BOOT_DRIVER(qfw_pio) = {
+ .name = "qfw_pio",
+ .id = UCLASS_QFW,
+ .probe = qfw_pio_probe,
+ .ops = &qfw_pio_ops,
+};