summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
authorAnkita Prasad <ankita.prasad@intel.com>2022-03-04 12:51:58 +0300
committerankita prasad <ankita.prasad@intel.com>2022-03-23 13:20:48 +0300
commite18bf5533c7bdde6392a546372cbf3bb5fd36497 (patch)
treef012175d4c678f7832829ecde6485226fcd52f22 /drivers/soc
parentdea62fa707259a121d2adf0261249a10221e014a (diff)
downloadlinux-e18bf5533c7bdde6392a546372cbf3bb5fd36497.tar.xz
soc: aspeed: Add support for eSPI Virtual Wire
The Aspeed eSPI controller is a slave device to communicate with the master through the Enhanced Serial Peripheral Interface (eSPI). It supports all eSPI channels including the Virtual Wire that is used to transmit the sideband signal information to/from Management Controller (e.g. BMC). Add support for the Virtual Wire channel. Add IOCTL handler to support reading and writing GPIO value over the Virtual Wire channel. Signed-off-by: Ankita Prasad <ankita.prasad@intel.com>
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/aspeed/Makefile2
-rw-r--r--drivers/soc/aspeed/aspeed-espi-slave.c8
-rw-r--r--drivers/soc/aspeed/aspeed-espi-vw.c94
-rw-r--r--drivers/soc/aspeed/aspeed-espi-vw.h20
4 files changed, 123 insertions, 1 deletions
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
index 7e9feefdab9a..0ff455f0d0d1 100644
--- a/drivers/soc/aspeed/Makefile
+++ b/drivers/soc/aspeed/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ASPEED_BMC_MISC) += aspeed-bmc-misc.o
obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi.o
-aspeed-espi-y := aspeed-espi-slave.o aspeed-espi-oob.o
+aspeed-espi-y := aspeed-espi-slave.o aspeed-espi-oob.o aspeed-espi-vw.o
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
diff --git a/drivers/soc/aspeed/aspeed-espi-slave.c b/drivers/soc/aspeed/aspeed-espi-slave.c
index 431cfa383c3d..d638b2c7351a 100644
--- a/drivers/soc/aspeed/aspeed-espi-slave.c
+++ b/drivers/soc/aspeed/aspeed-espi-slave.c
@@ -20,6 +20,7 @@
#include "aspeed-espi-ctrl.h"
#include "aspeed-espi-oob.h"
+#include "aspeed-espi-vw.h"
struct aspeed_espi {
struct regmap *map;
@@ -166,6 +167,7 @@ static irqreturn_t aspeed_espi_irq(int irq, void *arg)
aspeed_espi_boot_ack(priv);
sts_handled |= ASPEED_ESPI_HW_RESET;
aspeed_espi_oob_enable(priv->espi_ctrl->oob);
+ aspeed_espi_vw_enable(priv->espi_ctrl->vw);
}
regmap_write(priv->map, ASPEED_ESPI_INT_STS, sts);
@@ -342,6 +344,11 @@ static int aspeed_espi_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to allocate espi out-of-band channel\n");
return PTR_ERR(espi_ctrl->oob);
}
+ espi_ctrl->vw = aspeed_espi_vw_init(&pdev->dev, espi_ctrl);
+ if (IS_ERR(espi_ctrl->vw)) {
+ dev_err(&pdev->dev, "Failed to allocate espi virtual wire channel\n");
+ return PTR_ERR(espi_ctrl->vw);
+ }
spin_lock_init(&priv->pltrstn_lock);
init_waitqueue_head(&priv->pltrstn_waitq);
@@ -425,6 +432,7 @@ static int aspeed_espi_remove(struct platform_device *pdev)
struct aspeed_espi *priv = dev_get_drvdata(&pdev->dev);
aspeed_espi_oob_free(priv->dev, priv->espi_ctrl->oob);
+ aspeed_espi_vw_fini(priv->dev, priv->espi_ctrl->vw);
misc_deregister(&priv->pltrstn_miscdev);
clk_disable_unprepare(priv->clk);
return 0;
diff --git a/drivers/soc/aspeed/aspeed-espi-vw.c b/drivers/soc/aspeed/aspeed-espi-vw.c
new file mode 100644
index 000000000000..81bfb7f59274
--- /dev/null
+++ b/drivers/soc/aspeed/aspeed-espi-vw.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 ASPEED Technology Inc.
+ */
+#include <linux/aspeed-espi-ioc.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/regmap.h>
+#include <linux/uaccess.h>
+
+#include "aspeed-espi-ctrl.h"
+#include "aspeed-espi-vw.h"
+
+#define VW_MDEV_NAME "aspeed-espi-vw"
+
+static long aspeed_espi_vw_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+ struct aspeed_espi_vw *espi_vw = container_of(fp->private_data,
+ struct aspeed_espi_vw,
+ mdev);
+ struct aspeed_espi_ctrl *espi_ctrl = espi_vw->ctrl;
+ u32 val = 0;
+
+ switch (cmd) {
+ case ASPEED_ESPI_VW_GET_GPIO_VAL:
+ regmap_read(espi_ctrl->map, ASPEED_ESPI_VW_GPIO_VAL, &val);
+ if (put_user(val, (uint32_t __user *)arg))
+ return -EFAULT;
+ break;
+
+ case ASPEED_ESPI_VW_PUT_GPIO_VAL:
+ if (get_user(val, (uint32_t __user *)arg))
+ return -EFAULT;
+ regmap_write(espi_ctrl->map, ASPEED_ESPI_VW_GPIO_VAL, val);
+ break;
+
+ default:
+ return -ENOTTY;
+ };
+
+ return 0;
+}
+
+void aspeed_espi_vw_enable(struct aspeed_espi_vw *espi_vw)
+{
+ struct aspeed_espi_ctrl *espi_ctrl = espi_vw->ctrl;
+
+ regmap_write(espi_ctrl->map, ASPEED_ESPI_INT_STS,
+ ASPEED_ESPI_INT_STS_VW_BITS);
+
+ regmap_update_bits(espi_ctrl->map, ASPEED_ESPI_INT_EN,
+ ASPEED_ESPI_INT_EN_VW_BITS,
+ ASPEED_ESPI_INT_EN_VW_BITS);
+
+ regmap_update_bits(espi_ctrl->map, ASPEED_ESPI_CTRL,
+ ASPEED_ESPI_CTRL_VW_SW_RDY,
+ ASPEED_ESPI_CTRL_VW_SW_RDY);
+}
+
+static const struct file_operations aspeed_espi_vw_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = aspeed_espi_vw_ioctl,
+};
+
+void *aspeed_espi_vw_init(struct device *dev, struct aspeed_espi_ctrl *espi_ctrl)
+{
+ int rc;
+ struct aspeed_espi_vw *espi_vw;
+
+ espi_vw = devm_kzalloc(dev, sizeof(*espi_vw), GFP_KERNEL);
+ if (!espi_vw)
+ return ERR_PTR(-ENOMEM);
+
+ espi_vw->ctrl = espi_ctrl;
+
+ espi_vw->mdev.parent = dev;
+ espi_vw->mdev.minor = MISC_DYNAMIC_MINOR;
+ espi_vw->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s", VW_MDEV_NAME);
+ espi_vw->mdev.fops = &aspeed_espi_vw_fops;
+ rc = misc_register(&espi_vw->mdev);
+ if (rc) {
+ dev_err(dev, "cannot register device\n");
+ return ERR_PTR(rc);
+ }
+
+ aspeed_espi_vw_enable(espi_vw);
+
+ return espi_vw;
+}
+
+void aspeed_espi_vw_fini(struct device *dev, struct aspeed_espi_vw *espi_vw)
+{
+ misc_deregister(&espi_vw->mdev);
+}
diff --git a/drivers/soc/aspeed/aspeed-espi-vw.h b/drivers/soc/aspeed/aspeed-espi-vw.h
new file mode 100644
index 000000000000..4532e4e13d43
--- /dev/null
+++ b/drivers/soc/aspeed/aspeed-espi-vw.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2022 ASPEED Technology Inc.
+ */
+#ifndef _ASPEED_ESPI_VW_H_
+#define _ASPEED_ESPI_VW_H_
+
+struct aspeed_espi_vw {
+ int irq;
+ int irq_reset;
+
+ struct miscdevice mdev;
+ struct aspeed_espi_ctrl *ctrl;
+};
+
+void aspeed_espi_vw_enable(struct aspeed_espi_vw *espi_vw);
+void *aspeed_espi_vw_init(struct device *dev, struct aspeed_espi_ctrl *espi_ctrl);
+void aspeed_espi_vw_fini(struct device *dev, struct aspeed_espi_vw *espi_vw);
+
+#endif