diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch | 762 |
1 files changed, 0 insertions, 762 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch deleted file mode 100644 index c409dec50..000000000 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch +++ /dev/null @@ -1,762 +0,0 @@ -From e6e186acacc16fd95251b2d0fb024993a66ffa0a Mon Sep 17 00:00:00 2001 -From: Haiyue Wang <haiyue.wang@linux.intel.com> -Date: Sat, 24 Feb 2018 11:12:32 +0800 -Subject: [PATCH] Add AST2500 eSPI driver - -When PCH works under eSPI mode, the PMC (Power Management Controller) in -PCH is waiting for SUS_ACK from BMC after it alerts SUS_WARN. It is in -dead loop if no SUS_ACK assert. This is the basic requirement for the BMC -works as eSPI slave. - -Also for the host power on / off actions, from BMC side, the following VW -(Virtual Wire) messages are done in firmware: -1. SLAVE_BOOT_LOAD_DONE / SLAVE_BOOT_LOAD_STATUS -2. SUS_ACK -3. OOB_RESET_ACK -4. HOST_RESET_ACK - -Also, it provides monitoring interface of PLTRST_N signal through -/dev/espi-pltrstn - -Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com> -Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> -Signed-off-by: James Feist <james.feist@linux.intel.com> -Signed-off-by: Vernon Mauery <vernon.mauery@intel.com> ---- - .../devicetree/bindings/misc/aspeed,espi-slave.txt | 20 + - Documentation/misc-devices/espi-slave.rst | 118 ++++++ - arch/arm/boot/dts/aspeed-g5.dtsi | 4 + - arch/arm/boot/dts/aspeed-g6.dtsi | 14 + - drivers/misc/Kconfig | 8 + - drivers/misc/Makefile | 1 + - drivers/misc/aspeed-espi-slave.c | 468 +++++++++++++++++++++ - include/dt-bindings/clock/ast2600-clock.h | 1 + - 8 files changed, 634 insertions(+) - create mode 100644 Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt - create mode 100644 Documentation/misc-devices/espi-slave.rst - create mode 100644 drivers/misc/aspeed-espi-slave.c - -diff --git a/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt b/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt -new file mode 100644 -index 000000000000..f72d9ae32f3e ---- /dev/null -+++ b/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt -@@ -0,0 +1,20 @@ -+ASPEED eSPI Slave Controller -+ -+Required properties: -+ - compatible: must be one of: -+ - "aspeed,ast2500-espi-slave" -+ - "aspeed,ast2600-espi-slave" -+ -+ - reg: physical base address of the controller and length of memory mapped -+ region -+ -+ - interrupts: interrupt generated by the controller -+ -+Example: -+ -+ espi: espi@1e6ee000 { -+ compatible = "aspeed,ast2500-espi-slave"; -+ reg = <0x1e6ee000 0x100>; -+ interrupts = <23>; -+ status = "disabled"; -+}; -diff --git a/Documentation/misc-devices/espi-slave.rst b/Documentation/misc-devices/espi-slave.rst -new file mode 100644 -index 000000000000..887a69a7130a ---- /dev/null -+++ b/Documentation/misc-devices/espi-slave.rst -@@ -0,0 +1,118 @@ -+.. SPDX-License-Identifier: GPL-2.0 -+ -+========== -+eSPI Slave -+========== -+ -+:Author: Haiyue Wang <haiyue.wang@linux.intel.com> -+ -+The PCH (**eSPI master**) provides the eSPI to support connection of a -+BMC (**eSPI slave**) to the platform. -+ -+The LPC and eSPI interfaces are mutually exclusive. Both use the same -+pins, but on power-up, a HW strap determines if the eSPI or the LPC bus -+is operational. Once selected, it’s not possible to change to the other -+interface. -+ -+``eSPI Channels and Supported Transactions`` -+ +------+---------------------+----------------------+--------------------+ -+ | CH # | Channel | Posted Cycles | Non-Posted Cycles | -+ +======+=====================+======================+====================+ -+ | 0 | Peripheral | Memory Write, | Memory Read, | -+ | | | Completions | I/O Read/Write | -+ +------+---------------------+----------------------+--------------------+ -+ | 1 | Virtual Wire | Virtual Wire GET/PUT | N/A | -+ +------+---------------------+----------------------+--------------------+ -+ | 2 | Out-of-Band Message | SMBus Packet GET/PUT | N/A | -+ +------+---------------------+----------------------+--------------------+ -+ | 3 | Flash Access | N/A | Flash Read, Write, | -+ | | | | Erase | -+ +------+---------------------+----------------------+--------------------+ -+ | N/A | General | Register Accesses | N/A | -+ +------+---------------------+----------------------+--------------------+ -+ -+Virtual Wire Channel (Channel 1) Overview -+----------------------------------------- -+ -+The Virtual Wire channel uses a standard message format to communicate -+several types of signals between the components on the platform:: -+ -+ - Sideband and GPIO Pins: System events and other dedicated signals -+ between the PCH and eSPI slave. These signals are tunneled between the -+ two components over eSPI. -+ -+ - Serial IRQ Interrupts: Interrupts are tunneled from the eSPI slave to -+ the PCH. Both edge and triggered interrupts are supported. -+ -+When PCH runs on eSPI mode, from BMC side, the following VW messages are -+done in firmware:: -+ -+ 1. SLAVE_BOOT_LOAD_DONE / SLAVE_BOOT_LOAD_STATUS -+ 2. SUS_ACK -+ 3. OOB_RESET_ACK -+ 4. HOST_RESET_ACK -+ -+``eSPI Virtual Wires (VW)`` -+ +----------------------+---------+---------------------------------------+ -+ |Virtual Wire |PCH Pin |Comments | -+ | |Direction| | -+ +======================+=========+=======================================+ -+ |SUS_WARN# |Output |PCH pin is a GPIO when eSPI is enabled.| -+ | | |eSPI controller receives as VW message.| -+ +----------------------+---------+---------------------------------------+ -+ |SUS_ACK# |Input |PCH pin is a GPIO when eSPI is enabled.| -+ | | |eSPI controller receives as VW message.| -+ +----------------------+---------+---------------------------------------+ -+ |SLAVE_BOOT_LOAD_DONE |Input |Sent when the BMC has completed its | -+ | | |boot process as an indication to | -+ | | |eSPI-MC to continue with the G3 to S0 | -+ | | |exit. | -+ | | |The eSPI Master waits for the assertion| -+ | | |of this virtual wire before proceeding | -+ | | |with the SLP_S5# deassertion. | -+ | | |The intent is that it is never changed | -+ | | |except on a G3 exit - it is reset on a | -+ | | |G3 entry. | -+ +----------------------+---------+---------------------------------------+ -+ |SLAVE_BOOT_LOAD_STATUS|Input |Sent upon completion of the Slave Boot | -+ | | |Load from the attached flash. A stat of| -+ | | |1 indicates that the boot code load was| -+ | | |successful and that the integrity of | -+ | | |the image is intact. | -+ +----------------------+---------+---------------------------------------+ -+ |HOST_RESET_WARN |Output |Sent from the MC just before the Host | -+ | | |is about to enter reset. Upon receiving| -+ | | |, the BMC must flush and quiesce its | -+ | | |upstream Peripheral Channel request | -+ | | |queues and assert HOST_RESET_ACK VWire.| -+ | | |The MC subsequently completes any | -+ | | |outstanding posted transactions or | -+ | | |completions and then disables the | -+ | | |Peripheral Channel via a write to | -+ | | |the Slave's Configuration Register. | -+ +----------------------+---------+---------------------------------------+ -+ |HOST_RESET_ACK |Input |ACK for the HOST_RESET_WARN message | -+ +----------------------+---------+---------------------------------------+ -+ |OOB_RESET_WARN |Output |Sent from the MC just before the OOB | -+ | | |processor is about to enter reset. Upon| -+ | | |receiving, the BMC must flush and | -+ | | |quiesce its OOB Channel upstream | -+ | | |request queues and assert OOB_RESET_ACK| -+ | | |VWire. The-MC subsequently completes | -+ | | |any outstanding posted transactions or | -+ | | |completions and then disables the OOB | -+ | | |Channel via a write to the Slave's | -+ | | |Configuration Register. | -+ +----------------------+---------+---------------------------------------+ -+ |OOB_RESET_ACK |Input |ACK for OOB_RESET_WARN message | -+ +----------------------+---------+---------------------------------------+ -+ -+`Intel C620 Series Chipset Platform Controller Hub -+<https://www.intel.com/content/www/us/en/chipsets/c620-series-chipset-datasheet.html>`_ -+ -+ -- 17. Enhanced Serial Peripheral Interface -+ -+ -+`Enhanced Serial Peripheral Interface (eSPI) -+- Interface Base Specification (for Client and Server Platforms) -+<https://www.intel.com/content/dam/support/us/en/documents/software/chipset-software/327432-004_espi_base_specification_rev1.0.pdf>`_ -diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi -index 26d885d2bd8a..7b798c49cb95 100644 ---- a/arch/arm/boot/dts/aspeed-g5.dtsi -+++ b/arch/arm/boot/dts/aspeed-g5.dtsi -@@ -336,6 +336,7 @@ - clocks = <&syscon ASPEED_CLK_APB>; - interrupt-controller; - #interrupt-cells = <2>; -+ status = "disabled"; - }; - - sgpio: sgpio@1e780200 { -@@ -432,6 +433,9 @@ - reg = <0x1e6ee000 0x100>; - interrupts = <23>; - status = "disabled"; -+ clocks = <&syscon ASPEED_CLK_GATE_ESPICLK>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_espi_default>; - }; - - lpc: lpc@1e789000 { -diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi -index 825e64ce317a..315d35c15208 100644 ---- a/arch/arm/boot/dts/aspeed-g6.dtsi -+++ b/arch/arm/boot/dts/aspeed-g6.dtsi -@@ -4,6 +4,7 @@ - #include <dt-bindings/interrupt-controller/arm-gic.h> - #include <dt-bindings/clock/ast2600-clock.h> - #include <dt-bindings/interrupt-controller/aspeed-scu-ic.h> -+#include <dt-bindings/gpio/aspeed-gpio.h> - - / { - model = "Aspeed BMC"; -@@ -708,6 +709,19 @@ - status = "disabled"; - }; - -+ espi: espi@1e6ee000 { -+ compatible = "aspeed,ast2600-espi-slave"; -+ reg = <0x1e6ee000 0x200>; -+ interrupts-extended = <&gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>, -+ <&gpio0 ASPEED_GPIO(W, 7) IRQ_TYPE_EDGE_FALLING>; -+ status = "disabled"; -+ clocks = <&syscon ASPEED_CLK_GATE_ESPICLK>; -+ resets = <&syscon ASPEED_RESET_ESPI>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pinctrl_espi_default>, -+ <&pinctrl_espialt_default>; -+ }; -+ - i2c: bus@1e78a000 { - compatible = "simple-bus"; - #address-cells = <1>; -diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 06a2b753cc7c..0f9b5a356c93 100644 ---- a/drivers/misc/Kconfig -+++ b/drivers/misc/Kconfig -@@ -433,6 +433,14 @@ config VEXPRESS_SYSCFG - bus. System Configuration interface is one of the possible means - of generating transactions on this bus. - -+config ASPEED_ESPI_SLAVE -+ depends on ARCH_ASPEED || COMPILE_TEST -+ depends on REGMAP_MMIO -+ tristate "Aspeed ast2500 eSPI slave device driver" -+ ---help--- -+ Control Aspeed ast2500 eSPI slave controller to handle event -+ which needs the firmware's processing. -+ - config PCI_ENDPOINT_TEST - depends on PCI - select CRC32 -diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index b9e6d4c3e906..53864687e8fd 100644 ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -51,6 +51,7 @@ obj-$(CONFIG_GENWQE) += genwqe/ - obj-$(CONFIG_ECHO) += echo/ - obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o - obj-$(CONFIG_CXL_BASE) += cxl/ -+obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o - obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o - obj-$(CONFIG_OCXL) += ocxl/ - obj-y += cardreader/ -diff --git a/drivers/misc/aspeed-espi-slave.c b/drivers/misc/aspeed-espi-slave.c -new file mode 100644 -index 000000000000..87bc81948694 ---- /dev/null -+++ b/drivers/misc/aspeed-espi-slave.c -@@ -0,0 +1,468 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2015-2019, Intel Corporation. -+ -+#include <linux/clk.h> -+#include <linux/fs.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/regmap.h> -+#include <linux/reset.h> -+#include <linux/sched/signal.h> -+#include <linux/spinlock.h> -+#include <linux/uaccess.h> -+ -+#define ASPEED_ESPI_CTRL 0x00 -+#define ASPEED_ESPI_CTRL_SW_RESET GENMASK(31, 24) -+#define ASPEED_ESPI_CTRL_OOB_CHRDY BIT(4) -+#define ASPEED_ESPI_INT_STS 0x08 -+#define ASPEED_ESPI_HW_RESET BIT(31) -+#define ASPEED_ESPI_VW_SYSEVT1 BIT(22) -+#define ASPEED_ESPI_VW_SYSEVT BIT(8) -+#define ASPEED_ESPI_INT_EN 0x0C -+#define ASPEED_ESPI_DATA_PORT 0x28 -+#define ASPEED_ESPI_SYSEVT_INT_EN 0x94 -+#define ASPEED_ESPI_SYSEVT 0x98 -+#define ASPEED_ESPI_SYSEVT_HOST_RST_ACK BIT(27) -+#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS BIT(23) -+#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE BIT(20) -+#define ASPEED_ESPI_SYSEVT_OOB_RST_ACK BIT(16) -+#define ASPEED_ESPI_SYSEVT_INT_T0 0x110 -+#define ASPEED_ESPI_SYSEVT_INT_T1 0x114 -+#define ASPEED_ESPI_SYSEVT_INT_T2 0x118 -+#define ASPEED_ESPI_SYSEVT_INT_STS 0x11C -+#define ASPEED_ESPI_SYSEVT_HOST_RST_WARN BIT(8) -+#define ASPEED_ESPI_SYSEVT_OOB_RST_WARN BIT(6) -+#define ASPEED_ESPI_SYSEVT_PLTRSTN BIT(5) -+#define ASPEED_ESPI_SYSEVT1_INT_EN 0x100 -+#define ASPEED_ESPI_SYSEVT1 0x104 -+#define ASPEED_ESPI_SYSEVT1_SUS_ACK BIT(20) -+#define ASPEED_ESPI_SYSEVT1_INT_T0 0x120 -+#define ASPEED_ESPI_SYSEVT1_INT_T1 0x124 -+#define ASPEED_ESPI_SYSEVT1_INT_T2 0x128 -+#define ASPEED_ESPI_SYSEVT1_INT_STS 0x12C -+#define ASPEED_ESPI_SYSEVT1_SUS_WARN BIT(0) -+ -+#define ASPEED_ESPI_INT_MASK \ -+ (ASPEED_ESPI_HW_RESET | \ -+ ASPEED_ESPI_VW_SYSEVT1 | \ -+ ASPEED_ESPI_VW_SYSEVT) -+ -+/* -+ * Setup Interrupt Type / Enable of System Event from Master -+ * T2 T1 T0 -+ * 1) HOST_RST_WARN : Dual Edge 1 0 0 -+ * 2) OOB_RST_WARN : Dual Edge 1 0 0 -+ * 3) PLTRSTN : Dual Edge 1 0 0 -+ */ -+#define ASPEED_ESPI_SYSEVT_INT_T0_MASK 0 -+#define ASPEED_ESPI_SYSEVT_INT_T1_MASK 0 -+#define ASPEED_ESPI_SYSEVT_INT_T2_MASK \ -+ (ASPEED_ESPI_SYSEVT_HOST_RST_WARN | \ -+ ASPEED_ESPI_SYSEVT_OOB_RST_WARN | \ -+ ASPEED_ESPI_SYSEVT_PLTRSTN) -+#define ASPEED_ESPI_SYSEVT_INT_MASK \ -+ (ASPEED_ESPI_SYSEVT_INT_T0_MASK | \ -+ ASPEED_ESPI_SYSEVT_INT_T1_MASK | \ -+ ASPEED_ESPI_SYSEVT_INT_T2_MASK) -+ -+/* -+ * Setup Interrupt Type / Enable of System Event 1 from Master -+ * T2 T1 T0 -+ * 1) SUS_WARN : Rising Edge 0 0 1 -+ */ -+#define ASPEED_ESPI_SYSEVT1_INT_T0_MASK ASPEED_ESPI_SYSEVT1_SUS_WARN -+#define ASPEED_ESPI_SYSEVT1_INT_T1_MASK 0 -+#define ASPEED_ESPI_SYSEVT1_INT_T2_MASK 0 -+#define ASPEED_ESPI_SYSEVT1_INT_MASK \ -+ (ASPEED_ESPI_SYSEVT1_INT_T0_MASK | \ -+ ASPEED_ESPI_SYSEVT1_INT_T1_MASK | \ -+ ASPEED_ESPI_SYSEVT1_INT_T2_MASK) -+ -+struct aspeed_espi { -+ struct regmap *map; -+ struct clk *clk; -+ struct device *dev; -+ struct reset_control *reset; -+ int irq; -+ int rst_irq; -+ -+ /* for PLTRST_N signal monitoring interface */ -+ struct miscdevice pltrstn_miscdev; -+ spinlock_t pltrstn_lock; /* for PLTRST_N signal sampling */ -+ wait_queue_head_t pltrstn_waitq; -+ char pltrstn; -+}; -+ -+static void aspeed_espi_sys_event(struct aspeed_espi *priv) -+{ -+ u32 sts, evt; -+ -+ regmap_read(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, &sts); -+ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt); -+ -+ dev_dbg(priv->dev, "sys: sts = %08x, evt = %08x\n", sts, evt); -+ -+ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) { -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT, -+ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS | -+ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE); -+ dev_dbg(priv->dev, "Setting espi slave boot done\n"); -+ } -+ if (sts & ASPEED_ESPI_SYSEVT_HOST_RST_WARN && -+ evt & ASPEED_ESPI_SYSEVT_HOST_RST_WARN) { -+ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT, -+ ASPEED_ESPI_SYSEVT_HOST_RST_ACK, -+ ASPEED_ESPI_SYSEVT_HOST_RST_ACK); -+ dev_dbg(priv->dev, "SYSEVT_HOST_RST_WARN: acked\n"); -+ } -+ if (sts & ASPEED_ESPI_SYSEVT_OOB_RST_WARN && -+ evt & ASPEED_ESPI_SYSEVT_OOB_RST_WARN) { -+ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT, -+ ASPEED_ESPI_SYSEVT_OOB_RST_ACK, -+ ASPEED_ESPI_SYSEVT_OOB_RST_ACK); -+ dev_dbg(priv->dev, "SYSEVT_OOB_RST_WARN: acked\n"); -+ } -+ if (sts & ASPEED_ESPI_SYSEVT_PLTRSTN || priv->pltrstn == 'U') { -+ priv->pltrstn = (evt & ASPEED_ESPI_SYSEVT_PLTRSTN) ? '1' : '0'; -+ wake_up_interruptible(&priv->pltrstn_waitq); -+ dev_dbg(priv->dev, "SYSEVT_PLTRSTN: %c\n", priv->pltrstn); -+ } -+ -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, sts); -+} -+ -+static void aspeed_espi_sys_event1(struct aspeed_espi *priv) -+{ -+ u32 sts, evt; -+ -+ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, &sts); -+ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt); -+ -+ dev_dbg(priv->dev, "sys event1: sts = %08x, evt = %08x\n", sts, evt); -+ -+ if (sts & ASPEED_ESPI_SYSEVT1_SUS_WARN && -+ evt & ASPEED_ESPI_SYSEVT1_SUS_WARN) { -+ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT1, -+ ASPEED_ESPI_SYSEVT1_SUS_ACK, -+ ASPEED_ESPI_SYSEVT1_SUS_ACK); -+ dev_dbg(priv->dev, "SYSEVT1_SUS_WARN: acked\n"); -+ } -+ -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, sts); -+} -+ -+static void aspeed_espi_boot_ack(struct aspeed_espi *priv) -+{ -+ u32 evt; -+ -+ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt); -+ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) { -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT, -+ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS | -+ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE); -+ dev_dbg(priv->dev, "Setting espi slave boot done\n"); -+ } -+ -+ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt); -+ if (evt & ASPEED_ESPI_SYSEVT1_SUS_WARN && -+ !(evt & ASPEED_ESPI_SYSEVT1_SUS_ACK)) { -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1, -+ evt | ASPEED_ESPI_SYSEVT1_SUS_ACK); -+ dev_dbg(priv->dev, "Boot SYSEVT1_SUS_WARN: acked\n"); -+ } -+} -+ -+static irqreturn_t aspeed_espi_irq(int irq, void *arg) -+{ -+ struct aspeed_espi *priv = arg; -+ u32 sts, sts_handled = 0; -+ -+ regmap_read(priv->map, ASPEED_ESPI_INT_STS, &sts); -+ -+ dev_dbg(priv->dev, "INT_STS: 0x%08x\n", sts); -+ -+ if (sts & ASPEED_ESPI_VW_SYSEVT) { -+ aspeed_espi_sys_event(priv); -+ sts_handled |= ASPEED_ESPI_VW_SYSEVT; -+ } -+ -+ if (sts & ASPEED_ESPI_VW_SYSEVT1) { -+ aspeed_espi_sys_event1(priv); -+ sts_handled |= ASPEED_ESPI_VW_SYSEVT1; -+ } -+ -+ if (sts & ASPEED_ESPI_HW_RESET) { -+ if (priv->rst_irq < 0) { -+ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, -+ ASPEED_ESPI_CTRL_SW_RESET, 0); -+ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, -+ ASPEED_ESPI_CTRL_SW_RESET, -+ ASPEED_ESPI_CTRL_SW_RESET); -+ } -+ -+ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, -+ ASPEED_ESPI_CTRL_OOB_CHRDY, -+ ASPEED_ESPI_CTRL_OOB_CHRDY); -+ aspeed_espi_boot_ack(priv); -+ sts_handled |= ASPEED_ESPI_HW_RESET; -+ } -+ -+ regmap_write(priv->map, ASPEED_ESPI_INT_STS, sts); -+ -+ return sts != sts_handled ? IRQ_NONE : IRQ_HANDLED; -+} -+ -+static void aspeed_espi_config_irq(struct aspeed_espi *priv) -+{ -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T0, -+ ASPEED_ESPI_SYSEVT_INT_T0_MASK); -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T1, -+ ASPEED_ESPI_SYSEVT_INT_T1_MASK); -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T2, -+ ASPEED_ESPI_SYSEVT_INT_T2_MASK); -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_EN, -+ ASPEED_ESPI_SYSEVT_INT_MASK); -+ -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T0, -+ ASPEED_ESPI_SYSEVT1_INT_T0_MASK); -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T1, -+ ASPEED_ESPI_SYSEVT1_INT_T1_MASK); -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T2, -+ ASPEED_ESPI_SYSEVT1_INT_T2_MASK); -+ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_EN, -+ ASPEED_ESPI_SYSEVT1_INT_MASK); -+ -+ regmap_write(priv->map, ASPEED_ESPI_INT_EN, ASPEED_ESPI_INT_MASK); -+} -+ -+static irqreturn_t aspeed_espi_reset_isr(int irq, void *arg) -+{ -+ struct aspeed_espi *priv = arg; -+ -+ reset_control_assert(priv->reset); -+ reset_control_deassert(priv->reset); -+ -+ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, -+ ASPEED_ESPI_CTRL_SW_RESET, 0); -+ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, -+ ASPEED_ESPI_CTRL_SW_RESET, ASPEED_ESPI_CTRL_SW_RESET); -+ -+ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL, -+ ASPEED_ESPI_CTRL_OOB_CHRDY, 0); -+ -+ aspeed_espi_config_irq(priv); -+ -+ return IRQ_HANDLED; -+} -+ -+static inline struct aspeed_espi *to_aspeed_espi(struct file *filp) -+{ -+ return container_of(filp->private_data, struct aspeed_espi, -+ pltrstn_miscdev); -+} -+ -+static int aspeed_espi_pltrstn_open(struct inode *inode, struct file *filp) -+{ -+ if ((filp->f_flags & O_ACCMODE) != O_RDONLY) -+ return -EACCES; -+ -+ return 0; -+} -+ -+static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf, -+ size_t count, loff_t *offset) -+{ -+ struct aspeed_espi *priv = to_aspeed_espi(filp); -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ char old_sample; -+ int ret = 0; -+ -+ spin_lock_irqsave(&priv->pltrstn_lock, flags); -+ -+ add_wait_queue(&priv->pltrstn_waitq, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ old_sample = priv->pltrstn; -+ -+ do { -+ char new_sample = priv->pltrstn; -+ -+ if (filp->f_flags & O_NONBLOCK || old_sample != new_sample) { -+ ret = put_user(new_sample, (unsigned long __user *)buf); -+ if (!ret) -+ ret = sizeof(new_sample); -+ } else if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ } -+ -+ if (!ret) { -+ spin_unlock_irqrestore(&priv->pltrstn_lock, flags); -+ schedule(); -+ spin_lock_irqsave(&priv->pltrstn_lock, flags); -+ } -+ } while (!ret); -+ -+ remove_wait_queue(&priv->pltrstn_waitq, &wait); -+ set_current_state(TASK_RUNNING); -+ -+ spin_unlock_irqrestore(&priv->pltrstn_lock, flags); -+ -+ return ret; -+} -+ -+static const struct file_operations aspeed_espi_pltrstn_fops = { -+ .owner = THIS_MODULE, -+ .open = aspeed_espi_pltrstn_open, -+ .read = aspeed_espi_pltrstn_read, -+}; -+ -+static const struct regmap_config aspeed_espi_regmap_cfg = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .max_register = ASPEED_ESPI_SYSEVT1_INT_STS, -+}; -+ -+static int aspeed_espi_probe(struct platform_device *pdev) -+{ -+ struct aspeed_espi *priv; -+ struct resource *res; -+ void __iomem *regs; -+ u32 ctrl; -+ int ret; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ dev_set_drvdata(&pdev->dev, priv); -+ priv->dev = &pdev->dev; -+ -+ priv->map = devm_regmap_init_mmio(&pdev->dev, regs, -+ &aspeed_espi_regmap_cfg); -+ if (IS_ERR(priv->map)) -+ return PTR_ERR(priv->map); -+ -+ spin_lock_init(&priv->pltrstn_lock); -+ init_waitqueue_head(&priv->pltrstn_waitq); -+ priv->pltrstn = 'U'; /* means it's not reported yet from master */ -+ -+ priv->irq = platform_get_irq(pdev, 0); -+ if (priv->irq < 0) -+ return priv->irq; -+ -+ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_espi_irq, 0, -+ "aspeed-espi-irq", priv); -+ if (ret) -+ return ret; -+ -+ if (of_device_is_compatible(pdev->dev.of_node, -+ "aspeed,ast2600-espi-slave")) { -+ priv->rst_irq = platform_get_irq(pdev, 1); -+ if (priv->rst_irq < 0) -+ return priv->rst_irq; -+ -+ ret = devm_request_irq(&pdev->dev, priv->rst_irq, -+ aspeed_espi_reset_isr, 0, -+ "aspeed-espi-rst-irq", priv); -+ if (ret) -+ return ret; -+ -+ priv->reset = devm_reset_control_get(&pdev->dev, NULL); -+ if (IS_ERR(priv->reset)) -+ return PTR_ERR(priv->reset); -+ } else { -+ priv->rst_irq = -ENOTSUPP; -+ } -+ -+ priv->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(priv->clk)) { -+ ret = PTR_ERR(priv->clk); -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "couldn't get clock\n"); -+ return ret; -+ } -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(&pdev->dev, "couldn't enable clock\n"); -+ return ret; -+ } -+ -+ /* -+ * We check that the regmap works on this very first access, but as this -+ * is an MMIO-backed regmap, subsequent regmap access is not going to -+ * fail and we skip error checks from this point. -+ */ -+ ret = regmap_read(priv->map, ASPEED_ESPI_CTRL, &ctrl); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to read ctrl register\n"); -+ goto err_clk_disable_out; -+ } -+ regmap_write(priv->map, ASPEED_ESPI_CTRL, -+ ctrl | ASPEED_ESPI_CTRL_OOB_CHRDY); -+ -+ priv->pltrstn_miscdev.minor = MISC_DYNAMIC_MINOR; -+ priv->pltrstn_miscdev.name = "espi-pltrstn"; -+ priv->pltrstn_miscdev.fops = &aspeed_espi_pltrstn_fops; -+ priv->pltrstn_miscdev.parent = &pdev->dev; -+ -+ ret = misc_register(&priv->pltrstn_miscdev); -+ if (ret) { -+ dev_err(&pdev->dev, "Unable to register device\n"); -+ goto err_clk_disable_out; -+ } -+ -+ aspeed_espi_config_irq(priv); -+ aspeed_espi_boot_ack(priv); -+ -+ dev_info(&pdev->dev, "eSPI registered, irq %d\n", priv->irq); -+ -+ return 0; -+ -+err_clk_disable_out: -+ clk_disable_unprepare(priv->clk); -+ -+ return ret; -+} -+ -+static int aspeed_espi_remove(struct platform_device *pdev) -+{ -+ struct aspeed_espi *priv = dev_get_drvdata(&pdev->dev); -+ -+ misc_deregister(&priv->pltrstn_miscdev); -+ clk_disable_unprepare(priv->clk); -+ -+ return 0; -+} -+ -+static const struct of_device_id of_espi_match_table[] = { -+ { .compatible = "aspeed,ast2500-espi-slave" }, -+ { .compatible = "aspeed,ast2600-espi-slave" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, of_espi_match_table); -+ -+static struct platform_driver aspeed_espi_driver = { -+ .driver = { -+ .name = KBUILD_MODNAME, -+ .of_match_table = of_match_ptr(of_espi_match_table), -+ }, -+ .probe = aspeed_espi_probe, -+ .remove = aspeed_espi_remove, -+}; -+module_platform_driver(aspeed_espi_driver); -+ -+MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>"); -+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); -+MODULE_DESCRIPTION("Aspeed eSPI driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h -index 3d90582a813f..1e18364de03d 100644 ---- a/include/dt-bindings/clock/ast2600-clock.h -+++ b/include/dt-bindings/clock/ast2600-clock.h -@@ -104,6 +104,7 @@ - #define ASPEED_RESET_PECI 36 - #define ASPEED_RESET_MII 35 - #define ASPEED_RESET_I2C 34 -+#define ASPEED_RESET_ESPI 32 - #define ASPEED_RESET_H2X 31 - #define ASPEED_RESET_GP_MCU 30 - #define ASPEED_RESET_DP_MCU 29 --- -2.7.4 - |