[PATCH] fsi: master: Add link_disable function

Eddie James eajames at linux.ibm.com
Tue Feb 18 07:04:05 AEDT 2020


The master driver needs to disable links that don't have slaves or links
that fail to be accessed. To do this, add a link_disable function and
use it in the failure path for slave break and init.

Signed-off-by: Eddie James <eajames at linux.ibm.com>
---
 drivers/fsi/fsi-core.c          | 13 ++++++-
 drivers/fsi/fsi-master-aspeed.c | 30 ++++++++++++++++
 drivers/fsi/fsi-master-hub.c    | 22 ++++++++++++
 drivers/fsi/fsi-master.h        |  1 +
 drivers/fsi/fsi2spim.c          | 63 +++++++++++++++++++++++++++++++++
 5 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 drivers/fsi/fsi2spim.c

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 8244da8a7241..d81ee9f582a5 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -1154,6 +1154,14 @@ static int fsi_master_write(struct fsi_master *master, int link,
 	return rc;
 }
 
+static int fsi_master_link_disable(struct fsi_master *master, int link)
+{
+	if (master->link_disable)
+		return master->link_disable(master, link);
+
+	return 0;
+}
+
 static int fsi_master_link_enable(struct fsi_master *master, int link)
 {
 	if (master->link_enable)
@@ -1194,10 +1202,13 @@ static int fsi_master_scan(struct fsi_master *master)
 		if (rc) {
 			dev_dbg(&master->dev,
 				"break to link %d failed: %d\n", link, rc);
+			fsi_master_link_disable(master, link);
 			continue;
 		}
 
-		fsi_slave_init(master, link, 0);
+		rc = fsi_slave_init(master, link, 0);
+		if (rc)
+			fsi_master_link_disable(master, link);
 	}
 
 	return 0;
diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c
index f49742b310c2..7ce5d9eb6c78 100644
--- a/drivers/fsi/fsi-master-aspeed.c
+++ b/drivers/fsi/fsi-master-aspeed.c
@@ -299,6 +299,35 @@ static int aspeed_master_write(struct fsi_master *master, int link,
 	return 0;
 }
 
+static int aspeed_master_link_disable(struct fsi_master *master, int link)
+{
+	struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);
+	int idx, bit, ret;
+	__be32 reg, result;
+
+	idx = link / 32;
+	bit = link % 32;
+
+	reg = cpu_to_be32(0x80000000 >> bit);
+
+	ret = opb_writel(aspeed, ctrl_base + FSI_MCENP0 + (4 * idx), reg);
+	if (ret)
+		return ret;
+
+	mdelay(FSI_LINK_ENABLE_SETUP_TIME);
+
+	ret = opb_readl(aspeed, ctrl_base + FSI_MENP0 + (4 * idx), &result);
+	if (ret)
+		return ret;
+
+	if (result & reg) {
+		dev_err(aspeed->dev, "%s failed: %08x\n", __func__, result);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 static int aspeed_master_link_enable(struct fsi_master *master, int link)
 {
 	struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);
@@ -491,6 +520,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev)
 	aspeed->master.write = aspeed_master_write;
 	aspeed->master.send_break = aspeed_master_break;
 	aspeed->master.term = aspeed_master_term;
+	aspeed->master.link_disable = aspeed_master_link_disable;
 	aspeed->master.link_enable = aspeed_master_link_enable;
 
 	dev_set_drvdata(&pdev->dev, aspeed);
diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c
index def35cf92571..26617fd5e2de 100644
--- a/drivers/fsi/fsi-master-hub.c
+++ b/drivers/fsi/fsi-master-hub.c
@@ -77,6 +77,27 @@ static int hub_master_break(struct fsi_master *master, int link)
 	return hub_master_write(master, link, 0, addr, &cmd, sizeof(cmd));
 }
 
+static int hub_master_link_disable(struct fsi_master *master, int link)
+{
+	struct fsi_master_hub *hub = to_fsi_master_hub(master);
+	int idx, bit;
+	__be32 reg;
+	int rc;
+
+	idx = link / 32;
+	bit = link % 32;
+
+	reg = cpu_to_be32(0x80000000 >> bit);
+
+	rc = fsi_device_write(hub->upstream, FSI_MCENP0 + (4 * idx), &reg, 4);
+
+	mdelay(FSI_LINK_ENABLE_SETUP_TIME);
+
+	fsi_device_read(hub->upstream, FSI_MENP0 + (4 * idx), &reg, 4);
+
+	return rc;
+}
+
 static int hub_master_link_enable(struct fsi_master *master, int link)
 {
 	struct fsi_master_hub *hub = to_fsi_master_hub(master);
@@ -228,6 +249,7 @@ static int hub_master_probe(struct device *dev)
 	hub->master.read = hub_master_read;
 	hub->master.write = hub_master_write;
 	hub->master.send_break = hub_master_break;
+	hub->master.link_disable = hub_master_link_disable;
 	hub->master.link_enable = hub_master_link_enable;
 
 	dev_set_drvdata(dev, hub);
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index 6e8d4d4d5149..7ecb86a678f9 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -130,6 +130,7 @@ struct fsi_master {
 				uint32_t addr, const void *val, size_t size);
 	int		(*term)(struct fsi_master *, int link, uint8_t id);
 	int		(*send_break)(struct fsi_master *, int link);
+	int		(*link_disable)(struct fsi_master *, int link);
 	int		(*link_enable)(struct fsi_master *, int link);
 	int		(*link_config)(struct fsi_master *, int link,
 				       u8 t_send_delay, u8 t_echo_delay);
diff --git a/drivers/fsi/fsi2spim.c b/drivers/fsi/fsi2spim.c
new file mode 100644
index 000000000000..88a34468ef3b
--- /dev/null
+++ b/drivers/fsi/fsi2spim.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) IBM Corporation 2020
+ */
+
+#include <linux/fsi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#define FSI_ENGID_FSI2SPIM	0x23
+
+static int fsi2spim_probe(struct device *dev)
+{
+	int rc;
+	struct spi_controller *ctlr;
+	struct fsi_spi *ctx;
+
+	ctlr = spi_alloc_master(dev, sizeof(*ctx));
+	if (!ctlr)
+		return -ENOMEM;
+
+	ctlr->dev.of_node = dev->of_node;
+	ctlr->num_chipselect = 4;
+	ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
+	ctlr->max_transfer_size = fsi_spi_max_transfer_size;
+	ctlr->transfer_one_message = fsi_spi_transfer_one_message;
+
+	ctx = spi_controller_get_devdata(ctlr);
+	ctx->dev = &ctlr->dev;
+	ctx->fsi = to_fsi_dev(dev);
+
+	rc = devm_spi_register_controller(dev, ctlr);
+	if (rc)
+		spi_controller_put(ctlr);
+
+	return rc;
+}
+
+static int fsi2spim_remove(struct device *dev)
+{
+	return 0;
+}
+
+static const struct fsi_device_id fsi2spim_ids[] = {
+	{ FSI_ENGID_FSI2SPIM, FSI_VERSION_ANY },
+	{ }
+};
+
+static struct fsi_driver fsi2spim_driver = {
+	.id_table = fsi2spim_ids,
+	.drv = {
+		.name = "fsi2spim",
+		.bus = &fsi_bus_type,
+		.probe = fsi2spim_probe,
+		.remove = fsi2spim_remove,
+	},
+};
+
+module_fsi_driver(fsi2spim_driver);
+
+MODULE_AUTHOR("Eddie James <eajames at linux.ibm.com>");
+MODULE_DESCRIPTION("FSI2SPIM Bridge Driver");
+MODULE_LICENSE("GPL");
-- 
2.24.0



More information about the openbmc mailing list