[PATCH u-boot aspeed-dev-v2019.04 6/7] Add FSI driver
Joel Stanley
joel at jms.id.au
Wed Oct 30 17:32:24 AEDT 2019
FSI is the Flexible Service Interface, an i2c-like bus used on IBM POWER
processors for boot control, monitoring and debug. The ASPEED AST2600
contains a FSI master that can be used to talk to slaves on this bus.
The u-boot driver is a light porting of the work in progress Linux
driver. It allows basic reading and writing across the FSI link, as well
as control of the bus speed divisor.
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
drivers/misc/Kconfig | 6 +
drivers/misc/Makefile | 1 +
drivers/misc/aspeed-fsi.c | 556 ++++++++++++++++++++++++++++++++++++++
include/aspeed_fsi.h | 14 +
4 files changed, 577 insertions(+)
create mode 100644 drivers/misc/aspeed-fsi.c
create mode 100644 include/aspeed_fsi.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e149d81fcc50..f73ab0755276 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -25,6 +25,12 @@ config ASPEED_H2X
help
Select this to enable AHB to PCIe bu Bridge driver for Aspeed SoC.
+config ASPEED_FSI
+ bool "Enable ASPEED FSI driver"
+ depends on ARCH_ASPEED
+ help
+ Support the FSI master present in the ASPEED system on chips.
+
config ALTERA_SYSID
bool "Altera Sysid support"
depends on MISC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 61214bf9f17d..68713f149450 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -65,3 +65,4 @@ obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o
+obj-$(CONFIG_ASPEED_FSI) += aspeed-fsi.o
diff --git a/drivers/misc/aspeed-fsi.c b/drivers/misc/aspeed-fsi.c
new file mode 100644
index 000000000000..c41053252b10
--- /dev/null
+++ b/drivers/misc/aspeed-fsi.c
@@ -0,0 +1,556 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) IBM Corporation 2018
+// FSI master driver for AST2600
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+
+#include <common.h>
+#include <clk.h>
+
+#include <dm/device.h>
+#include <dm/fdtaddr.h>
+
+/* Control Registers */
+#define FSI_MMODE 0x0 /* R/W: mode */
+#define FSI_MDLYR 0x4 /* R/W: delay */
+#define FSI_MCRSP 0x8 /* R/W: clock rate */
+#define FSI_MENP0 0x10 /* R/W: enable */
+#define FSI_MLEVP0 0x18 /* R: plug detect */
+#define FSI_MSENP0 0x18 /* S: Set enable */
+#define FSI_MCENP0 0x20 /* C: Clear enable */
+#define FSI_MAEB 0x70 /* R: Error address */
+#define FSI_MVER 0x74 /* R: master version/type */
+#define FSI_MSTAP0 0xd0 /* R: Port status */
+#define FSI_MRESP0 0xd0 /* W: Port reset */
+#define FSI_MESRB0 0x1d0 /* R: Master error status */
+#define FSI_MRESB0 0x1d0 /* W: Reset bridge */
+#define FSI_MSCSB0 0x1d4 /* R: Master sub command stack */
+#define FSI_MATRB0 0x1d8 /* R: Master address trace */
+#define FSI_MDTRB0 0x1dc /* R: Master data trace */
+#define FSI_MECTRL 0x2e0 /* W: Error control */
+
+/* MMODE: Mode control */
+#define FSI_MMODE_EIP 0x80000000 /* Enable interrupt polling */
+#define FSI_MMODE_ECRC 0x40000000 /* Enable error recovery */
+#define FSI_MMODE_RELA 0x20000000 /* Enable relative address commands */
+#define FSI_MMODE_EPC 0x10000000 /* Enable parity checking */
+#define FSI_MMODE_P8_TO_LSB 0x00000010 /* Timeout value LSB */
+ /* MSB=1, LSB=0 is 0.8 ms */
+ /* MSB=0, LSB=1 is 0.9 ms */
+#define FSI_MMODE_CRS0SHFT 18 /* Clk rate selection 0 shift */
+#define FSI_MMODE_CRS0MASK 0x3ff /* Clk rate selection 0 mask */
+#define FSI_MMODE_CRS1SHFT 8 /* Clk rate selection 1 shift */
+#define FSI_MMODE_CRS1MASK 0x3ff /* Clk rate selection 1 mask */
+
+/* MRESB: Reset brindge */
+#define FSI_MRESB_RST_GEN 0x80000000 /* General reset */
+#define FSI_MRESB_RST_ERR 0x40000000 /* Error Reset */
+
+/* MRESB: Reset port */
+#define FSI_MRESP_RST_ALL_MASTER 0x20000000 /* Reset all FSI masters */
+#define FSI_MRESP_RST_ALL_LINK 0x10000000 /* Reset all FSI port contr. */
+#define FSI_MRESP_RST_MCR 0x08000000 /* Reset FSI master reg. */
+#define FSI_MRESP_RST_PYE 0x04000000 /* Reset FSI parity error */
+#define FSI_MRESP_RST_ALL 0xfc000000 /* Reset any error */
+
+/* MECTRL: Error control */
+#define FSI_MECTRL_EOAE 0x8000 /* Enable machine check when */
+ /* master 0 in error */
+#define FSI_MECTRL_P8_AUTO_TERM 0x4000 /* Auto terminate */
+
+#define FSI_ENGID_HUB_MASTER 0x1c
+#define FSI_HUB_LINK_OFFSET 0x80000
+#define FSI_HUB_LINK_SIZE 0x80000
+#define FSI_HUB_MASTER_MAX_LINKS 8
+
+#define FSI_LINK_ENABLE_SETUP_TIME 10 /* in mS */
+
+#define FSI_NUM_DEBUGFS_ENTRIES 17
+
+#define DEFAULT_DIVISOR 14
+
+struct fsi_master_aspeed;
+
+struct fsi_master_aspeed {
+ struct udevice *dev;
+ void __iomem *base;
+ struct clk clk;
+};
+
+#define to_fsi_master_aspeed(m) \
+ container_of(m, struct fsi_master_aspeed, master)
+
+/* Control register (size 0x400) */
+static const u32 ctrl_base = 0x80000000;
+
+static const u32 fsi_base = 0xa0000000;
+
+#define OPB_FSI_VER 0x00
+#define OPB_TRIGGER 0x04
+#define OPB_CTRL_BASE 0x08
+#define OPB_FSI_BASE 0x0c
+#define OPB_CLK_SYNC 0x3c
+#define OPB_IRQ_CLEAR 0x40
+#define OPB_IRQ_MASK 0x44
+#define OPB_IRQ_STATUS 0x48
+
+#define OPB0_SELECT 0x10
+#define OPB0_RW 0x14
+#define OPB0_XFER_SIZE 0x18
+#define OPB0_FSI_ADDR 0x1c
+#define OPB0_FSI_DATA_W 0x20
+#define OPB0_STATUS 0x80
+/* half world */
+#define STATUS_HW_ACK BIT(0)
+/* full word */
+#define STATUS_FW_ACK BIT(1)
+#define STATUS_ERR_ACK BIT(2)
+#define OPB0_FSI_DATA_R 0x84
+
+#define OPB0_W_ENDIAN 0x4c
+#define OPB0_R_ENDIAN 0x5c
+
+/* OPB_IRQ_MASK */
+#define OPB1_XFER_ACK_EN BIT(17)
+#define OPB0_XFER_ACK_EN BIT(16)
+
+#define OPB_IRQ_CH0_DMA_EOT BIT(0)
+#define OPB_IRQ_CH1_DMA_EOT BIT(1)
+#define OPB_IRQ_CH2_DMA_EOT BIT(2)
+#define OPB_IRQ_CH3_DMA_EOT BIT(3)
+#define OPB_IRQ_CH0_DMA_FIFO_FULL BIT(4)
+#define OPB_IRQ_CH1_DMA_FIFO_FULL BIT(5)
+#define OPB_IRQ_CH2_DMA_FIFO_FULL BIT(6)
+#define OPB_IRQ_CH3_DMA_FIFO_FULL BIT(7)
+#define OPB_IRQ_CH0_DMA_FIFO_EMPTY BIT(8)
+#define OPB_IRQ_CH1_DMA_FIFO_EMPTY BIT(9)
+#define OPB_IRQ_CH2_DMA_FIFO_EMPTY BIT(10)
+#define OPB_IRQ_CH3_DMA_FIFO_EMPTY BIT(11)
+#define OPB_IRQ_CH0_DMA_TCONT_DONE BIT(12)
+#define OPB_IRQ_CH1_DMA_TCONT_DONE BIT(13)
+#define OPB_IRQ_CH2_DMA_TCONT_DONE BIT(14)
+#define OPB_IRQ_CH3_DMA_TCONT_DONE BIT(15)
+#define OPB_IRQ_OPB1_XFER_ACK BIT(16)
+#define OPB_IRQ_OPB0_XFER_ACK BIT(17)
+#define OPB_IRQ_SLAVE0 BIT(18)
+#define OPB_IRQ_SLAVE1 BIT(19)
+#define OPB_IRQ_SLAVE2 BIT(20)
+#define OPB_IRQ_SLAVE3 BIT(21)
+#define OPB_IRQ_SLAVE4 BIT(22)
+#define OPB_IRQ_SLAVE5 BIT(23)
+#define OPB_IRQ_SLAVE6 BIT(24)
+#define OPB_IRQ_SLAVE7 BIT(25)
+#define OPB_IRQ_ANY_HOTPLUG BIT(26)
+#define OPB_IRQ_ANY_PORT_ERROR BIT(27)
+#define OPB_IRQ_ANY_MST_ERROR BIT(28)
+
+/* OPB_RW */
+#define CMD_READ BIT(0)
+#define CMD_WRITE 0
+
+/* OPBx_XFER_SIZE */
+#define XFER_WORD (BIT(1) | BIT(0))
+#define XFER_NIBBLE (BIT(0))
+#define XFER_BYTE (0)
+
+#define trace_aspeed_fsi_opb_write(addr, val, size, status, reg) \
+ debug("aspeed_opb_write: addr %08x val %08x size %d status %08d reg %08d\n", \
+ addr, val, size, status, reg)
+
+#define trace_aspeed_fsi_opb_read(addr, size, result, status, reg) \
+ debug("aspeed_opb_read: addr %08x size %d result %08x status %08d reg %08d\n", \
+ addr, size, result, status, reg)
+
+#define trace_aspeed_fsi_opb_error(mresp0, mstap0, mesrb0) \
+ debug("aspeed_opb_error: mresp %08d mstap %08x mesrb %08x\n", \
+ mresp0, mstap0, mesrb0)
+
+#define trace_aspeed_fsi_opb_error_enabled() (_DEBUG)
+
+static u32 opb_write(struct fsi_master_aspeed *aspeed, uint32_t addr,
+ uint32_t val, size_t size)
+{
+ void __iomem *base = aspeed->base;
+ u32 reg, ret, status;
+
+ /* TODO: implement other sizes, see 0x18 */
+ WARN_ON(size != 4);
+
+ writel(CMD_WRITE, base + OPB0_RW);
+ writel(XFER_WORD, base + OPB0_XFER_SIZE);
+ writel(addr, base + OPB0_FSI_ADDR);
+ writel(val, base + OPB0_FSI_DATA_W);
+ writel(0x1, base + OPB_IRQ_CLEAR);
+ writel(0x1, base + OPB_TRIGGER);
+
+ ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
+ (reg & OPB0_XFER_ACK_EN) != 0,
+ 10000);
+
+ status = readl(base + OPB0_STATUS);
+
+ trace_aspeed_fsi_opb_write(addr, val, size, status, reg);
+
+ /* Return error when poll timed out */
+ if (ret)
+ return ret;
+
+ /* Command failed, master will reset */
+ if (status & STATUS_ERR_ACK)
+ return -EIO;
+
+ return 0;
+}
+
+static int opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,
+ size_t size, u32 *out)
+{
+ void __iomem *base = aspeed->base;
+ u32 result, reg;
+ int status, ret;
+
+ /* TODO: implement other sizes, see 0x18 */
+ WARN_ON(size != 4);
+
+ writel(CMD_READ, base + OPB0_RW);
+ writel(XFER_WORD, base + OPB0_XFER_SIZE);
+ writel(addr, base + OPB0_FSI_ADDR);
+ writel(0x1, base + OPB_IRQ_CLEAR);
+ writel(0x1, base + OPB_TRIGGER);
+
+ ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
+ (reg & OPB0_XFER_ACK_EN) != 0,
+ 10000);
+
+ status = readl(base + OPB0_STATUS);
+
+ result = readl(base + OPB0_FSI_DATA_R);
+
+ trace_aspeed_fsi_opb_read(addr, size, result,
+ readl(base + OPB0_STATUS),
+ reg);
+
+ /* Return error when poll timed out */
+ if (ret)
+ return ret;
+
+ /* Command failed, master will reset */
+ if (status & STATUS_ERR_ACK)
+ return -EIO;
+
+ if (out)
+ *out = result;
+
+ return 0;
+}
+
+static int check_errors(struct fsi_master_aspeed *aspeed, int err)
+{
+ int ret;
+
+ if (trace_aspeed_fsi_opb_error_enabled()) {
+ __be32 mresp0, mstap0, mesrb0;
+
+ opb_read(aspeed, ctrl_base + FSI_MRESP0, 4, &mresp0);
+ opb_read(aspeed, ctrl_base + FSI_MSTAP0, 4, &mstap0);
+ opb_read(aspeed, ctrl_base + FSI_MESRB0, 4, &mesrb0);
+
+ trace_aspeed_fsi_opb_error(
+ be32_to_cpu(mresp0),
+ be32_to_cpu(mstap0),
+ be32_to_cpu(mesrb0));
+ };
+
+ if (err == -EIO) {
+ /* Check MAEB (0x70) ? */
+
+ /* Then clear errors in master */
+ ret = opb_write(aspeed, ctrl_base + 0xd0,
+ cpu_to_be32(0x20000000), 4);
+ if (ret) {
+ /* TODO: log? return different code? */
+ return ret;
+ }
+ /* TODO: confirm that 0x70 was okay */
+ }
+
+ /* This will pass through timeout errors */
+ return err;
+}
+
+int aspeed_fsi_read(struct fsi_master_aspeed *aspeed, int link,
+ uint32_t addr, void *val, size_t size)
+{
+ int ret;
+
+ addr += link * FSI_HUB_LINK_SIZE;
+ ret = opb_read(aspeed, fsi_base + addr, size, val);
+
+ ret = check_errors(aspeed, ret);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int aspeed_fsi_write(struct fsi_master_aspeed *aspeed, int link,
+ uint8_t id, uint32_t addr, const void *val, size_t size)
+{
+ int ret;
+
+ if (id != 0)
+ return -EINVAL;
+
+ addr += link * FSI_HUB_LINK_SIZE;
+ ret = opb_write(aspeed, fsi_base + addr, *(uint32_t *)val, size);
+
+ ret = check_errors(aspeed, ret);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int aspeed_fsi_link_enable(struct fsi_master_aspeed *aspeed, int link)
+{
+ int idx, bit, ret;
+ __be32 reg, result;
+
+ idx = link / 32;
+ bit = link % 32;
+
+ reg = cpu_to_be32(0x80000000 >> bit);
+
+ result = opb_write(aspeed, ctrl_base + FSI_MSENP0 + (4 * idx),
+ reg, 4);
+
+ mdelay(FSI_LINK_ENABLE_SETUP_TIME);
+
+ ret = opb_read(aspeed, ctrl_base + FSI_MENP0 + (4 * idx),
+ 4, &result);
+ if (ret)
+ return ret;
+
+ if (result != reg) {
+ dev_err(aspeed->dev, "%s failed: %08x\n", __func__, result);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int aspeed_fsi_break(struct fsi_master_aspeed *aspeed, int link)
+{
+ uint32_t addr;
+ __be32 cmd;
+ int rc;
+
+ addr = 0x0;
+ cmd = cpu_to_be32(0xc0de0000);
+
+ dev_dbg(aspeed->dev, "sending break to link %d\n", link);
+
+ rc = aspeed_fsi_write(aspeed, link, 0, addr, &cmd, 4);
+
+ dev_dbg(aspeed->dev, "break done (%d)\n", rc);
+
+ return rc;
+}
+
+void aspeed_fsi_status(struct fsi_master_aspeed *aspeed)
+{
+ __be32 mmode, mresp0, mstap0, mesrb0;
+
+ printf("%s\n", aspeed->dev->name);
+
+ opb_read(aspeed, ctrl_base + FSI_MMODE, 4, &mmode);
+ opb_read(aspeed, ctrl_base + FSI_MRESP0, 4, &mresp0);
+ opb_read(aspeed, ctrl_base + FSI_MSTAP0, 4, &mstap0);
+ opb_read(aspeed, ctrl_base + FSI_MESRB0, 4, &mesrb0);
+
+ printf("mmode %08x\n", be32_to_cpu(mmode));
+ printf("mresp %08x\n", be32_to_cpu(mresp0));
+ printf("mresp %08x\n", be32_to_cpu(mstap0));
+ printf("mresp %08x\n", be32_to_cpu(mesrb0));
+}
+
+int aspeed_fsi_divisor(struct fsi_master_aspeed *aspeed, uint16_t divisor)
+{
+ __be32 reg;
+ int rc;
+
+ rc = opb_read(aspeed, ctrl_base, 4, ®);
+ if (rc)
+ return rc;
+
+ if (!divisor)
+ return (be32_to_cpu(reg) >> 18) & 0x3ff;
+
+ if (divisor > 0x3ff)
+ return -EINVAL;
+
+ reg &= ~(0x3ff << 18);
+ reg |= (divisor & 0x3ff) << 18;
+
+ return 0;
+}
+
+/* mmode encoders */
+static inline u32 fsi_mmode_crs0(u32 x)
+{
+ return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;
+}
+
+static inline u32 fsi_mmode_crs1(u32 x)
+{
+ return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;
+}
+
+static int aspeed_fsi_init(struct fsi_master_aspeed *aspeed)
+{
+ __be32 reg;
+
+ reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
+ | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
+ opb_write(aspeed, ctrl_base + FSI_MRESP0, reg, 4);
+
+ /* Initialize the MFSI (hub master) engine */
+ reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
+ | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
+ opb_write(aspeed, ctrl_base + FSI_MRESP0, reg, 4);
+
+ reg = cpu_to_be32(FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM);
+ opb_write(aspeed, ctrl_base + FSI_MECTRL, reg, 4);
+
+ reg = cpu_to_be32(FSI_MMODE_ECRC | FSI_MMODE_EPC | FSI_MMODE_RELA
+ | fsi_mmode_crs0(DEFAULT_DIVISOR)
+ | fsi_mmode_crs1(DEFAULT_DIVISOR)
+ | FSI_MMODE_P8_TO_LSB);
+ opb_write(aspeed, ctrl_base + FSI_MMODE, reg, 4);
+
+ reg = cpu_to_be32(0xffff0000);
+ opb_write(aspeed, ctrl_base + FSI_MDLYR, reg, 4);
+
+ reg = cpu_to_be32(~0);
+ opb_write(aspeed, ctrl_base + FSI_MSENP0, reg, 4);
+
+ /* Leave enabled long enough for master logic to set up */
+ mdelay(FSI_LINK_ENABLE_SETUP_TIME);
+
+ opb_write(aspeed, ctrl_base + FSI_MCENP0, reg, 4);
+
+ opb_read(aspeed, ctrl_base + FSI_MAEB, 4, NULL);
+
+ reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK);
+ opb_write(aspeed, ctrl_base + FSI_MRESP0, reg, 4);
+
+ opb_read(aspeed, ctrl_base + FSI_MLEVP0, 4, NULL);
+
+ /* Reset the master bridge */
+ reg = cpu_to_be32(FSI_MRESB_RST_GEN);
+ opb_write(aspeed, ctrl_base + FSI_MRESB0, reg, 4);
+
+ reg = cpu_to_be32(FSI_MRESB_RST_ERR);
+ opb_write(aspeed, ctrl_base + FSI_MRESB0, reg, 4);
+
+ return 0;
+}
+
+static int aspeed_fsi_probe(struct udevice *dev)
+{
+ struct fsi_master_aspeed *aspeed = dev_get_priv(dev);
+ int ret, links, reg;
+ __be32 raw;
+
+ printf("%s\n", __func__);
+
+ aspeed->dev = dev;
+
+ aspeed->base = (void *)devfdt_get_addr(dev);
+
+ ret = clk_get_by_index(dev, 0, &aspeed->clk);
+ if (ret < 0) {
+ dev_err(dev, "Can't get clock for %s: %d\n", dev->name, ret);
+ return ret;
+ }
+
+ ret = clk_enable(&aspeed->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable fsi clock (%d)\n", ret);
+ return ret;
+ }
+
+ printf("%s %d\n", __func__, __LINE__);
+
+ writel(0x1, aspeed->base + OPB_CLK_SYNC);
+ writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN,
+ aspeed->base + OPB_IRQ_MASK);
+
+ writel(ctrl_base, aspeed->base + OPB_CTRL_BASE);
+ writel(fsi_base, aspeed->base + OPB_FSI_BASE);
+
+ /* Set read data order */
+ writel(0x00030b1b, aspeed->base + OPB0_R_ENDIAN);
+
+ /* Set write data order */
+ writel(0x0011bb1b, aspeed->base + OPB0_W_ENDIAN);
+ writel(0xffaa5500, aspeed->base + 0x50);
+
+ /*
+ * Select OPB0 for all operations.
+ * Will need to be reworked when enabling DMA or anything that uses
+ * OPB1.
+ */
+ writel(0x1, aspeed->base + OPB0_SELECT);
+
+ printf("%s %d\n", __func__, __LINE__);
+
+ ret = opb_read(aspeed, ctrl_base + FSI_MVER, 4, &raw);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read hub version\n");
+ goto err;
+ }
+
+ printf("%s %d\n", __func__, __LINE__);
+
+ reg = be32_to_cpu(raw);
+ links = (reg >> 8) & 0xff;
+ dev_info(&pdev->dev, "hub version %08x (%d links)\n", reg, links);
+
+ aspeed_fsi_init(aspeed);
+
+ printf("%s: probe done\n", __func__);
+
+ return 0;
+
+err:
+ clk_disable(&aspeed->clk);
+ return ret;
+}
+
+static int aspeed_fsi_remove(struct udevice *dev)
+{
+ struct fsi_master_aspeed *aspeed = dev_get_priv(dev);
+
+ clk_disable(&aspeed->clk);
+
+ return 0;
+}
+
+static const struct udevice_id aspeed_fsi_ids[] = {
+ { .compatible = "aspeed,ast2600-fsi-master" },
+ { }
+};
+
+U_BOOT_DRIVER(aspeed_fsi) = {
+ .name = "aspeed_fsi",
+ .id = UCLASS_MISC,
+ .of_match = aspeed_fsi_ids,
+ .probe = aspeed_fsi_probe,
+ .remove = aspeed_fsi_remove,
+ .priv_auto_alloc_size = sizeof(struct fsi_master_aspeed),
+};
diff --git a/include/aspeed_fsi.h b/include/aspeed_fsi.h
new file mode 100644
index 000000000000..c8d6616ef8e1
--- /dev/null
+++ b/include/aspeed_fsi.h
@@ -0,0 +1,14 @@
+struct fsi_master_aspeed;
+
+int aspeed_fsi_read(struct fsi_master_aspeed *aspeed, int link,
+ uint32_t addr, void *val, size_t size);
+
+int aspeed_fsi_write(struct fsi_master_aspeed *aspeed, int link,
+ uint32_t addr, const void *val, size_t size);
+
+int aspeed_fsi_break(struct fsi_master_aspeed *aspeed, int link);
+
+int aspeed_fsi_status(struct fsi_master_aspeed *aspeed);
+
+int aspeed_fsi_divisor(struct fsi_master_aspeed *aspeed, uint16_t divisor);
+
--
2.23.0
More information about the openbmc
mailing list