[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), ®, 4);
+
+ mdelay(FSI_LINK_ENABLE_SETUP_TIME);
+
+ fsi_device_read(hub->upstream, FSI_MENP0 + (4 * idx), ®, 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