From nobody Tue Apr 7 11:16:38 2026 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A390F38423D; Fri, 13 Mar 2026 10:08:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396498; cv=none; b=gU/L3jkI/8zrzAq329Uv3XgnTtY7wLgakzjRS+FSpPfgGry/f5gMzk+MP1vouYrHYjqXZdIYUXP2hgA+2w8ISBEDiQNLBWlsbpv9fg/Pju9hmPfgomC9oq5CYluQ7mc9vSLXFD5edsfWsgKShQuGu6wHFNAFddeTgfHV1TLGXbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396498; c=relaxed/simple; bh=cX0+TYSUBKoylJRqFstuVfh4bOO8RZJolgiew1xGVtM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=kGKTqXmt5sJBZ2S81qrHnCIpPcfGv0+UqiMiX9O0rff+FDKdbObRhmUHnru8TxacAmtMGG2F3eMoA81FouMlBO54fHm4VWSRG028z4vsiBxVyeHCwWfr83VaWmBK8jiBBpEqu7flxHNiWcQm3nmWCfB67AzsgjwAKsVK3qbwPHU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 13 Mar 2026 18:08:12 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 13 Mar 2026 18:08:12 +0800 From: aspeedyh Date: Fri, 13 Mar 2026 18:07:36 +0800 Subject: [PATCH 1/7] dt-bindings: soc: aspeed: Add AST2600 eSPI controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260313-upstream_espi-v1-1-9504428e1f43@aspeedtech.com> References: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> In-Reply-To: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , "Andrew Jeffery" , Ryan Chen , Philipp Zabel CC: , , , , , , aspeedyh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773396491; l=2633; i=yh_chung@aspeedtech.com; s=20260313; h=from:subject:message-id; bh=cX0+TYSUBKoylJRqFstuVfh4bOO8RZJolgiew1xGVtM=; b=PUEJ+M2Nits91wx+TswvF6gJSlfKAGjDKkzDIcVwArjw8jrWaV+Qx8qHXzgwlBTNIAeAVoX78 8knw1gDRx/oA4BXT+fpRLDOVbo/5ZHo24B5cj88KAVBN4vOp/TH3apZ X-Developer-Key: i=yh_chung@aspeedtech.com; a=ed25519; pk=o71dz0J8lpN+v0f3Mk4gT9PfVngADPC1Pex4aK6VigM= Introduce the device-tree bindings for the Enhanced Serial Peripheral Interface (eSPI) controller found on AST2600 BMC SoCs. The controller operates as the BMC-side eSPI slave and provides the peripheral, virtual wire, out-of-band, and flash channels used for host-BMC communication. Signed-off-by: aspeedyh --- .../bindings/soc/aspeed/aspeed,ast2600-espi.yaml | 74 ++++++++++++++++++= ++++ 1 file changed, 74 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/aspeed/aspeed,ast2600-es= pi.yaml b/Documentation/devicetree/bindings/soc/aspeed/aspeed,ast2600-espi.= yaml new file mode 100644 index 000000000000..e22a10111138 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/aspeed/aspeed,ast2600-espi.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2026 Aspeed Technology Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/aspeed/aspeed,ast2600-espi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASPEED AST2600 eSPI Controller + +maintainers: + - Yun-Hsuan Chung + - Ryan Chen + +description: | + The ASPEED AST2600 BMC SoC provides an Enhanced Serial Peripheral + Interface (eSPI) controller used for host-BMC communication. + + The controller supports the eSPI channels used for peripheral, + virtual wire, out-of-band, and flash communication. + +properties: + compatible: + const: aspeed,ast2600-espi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: + Interrupt from the GIC for the eSPI controller. + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + pinctrl-names: + const: default + + pinctrl-0: + maxItems: 1 + + aspeed,flash-dma-mode: + type: boolean + description: + Enable DMA support for eSPI flash channel + +required: + - compatible + - reg + - interrupts + - clocks + - resets + - pinctrl-names + - pinctrl-0 + +additionalProperties: false + +examples: + - | + #include + #include + espi: espi@1e6ee000 { + compatible =3D "aspeed,ast2600-espi"; + reg =3D <0x1e6ee000 0x1000>; + interrupts =3D ; + clocks =3D <&syscon ASPEED_CLK_GATE_ESPICLK>; + resets =3D <&syscon 57>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pinctrl_espi_default>; + aspeed,flash-dma-mode; + }; --=20 2.34.1 From nobody Tue Apr 7 11:16:38 2026 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E8C2938C430; Fri, 13 Mar 2026 10:08:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396501; cv=none; b=H7WdquXhWrZ6b388uzQIUa2r3swVSPrqSt5ongtmhW0D/VvK+DgYviIstxL4rkgB3ryX8FqGUGE/LWum7rclcs03Hq344zp9EoDFz+CmJOE+MjXzY458VgytlHjD5et+WjRl7ua/CEW9KCi8fwcbdUXDuCJqB61dRKbvzgpXzB0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396501; c=relaxed/simple; bh=/rOqnxX9j6h03fyAsdgGIl0qi1TFF1cLQusaF8+cqak=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=fw2hNN/sR9sD2WhCqjLSCJAoDB9rXVxqaJ3X6MqhRLmcrYt/mm8atInRE6WIzFAOkdJvUtNDj3CvPiloITDFBHiROgrE5U78y91nVGP0IEPAryPVPJh7Inb5Hbjgi+wax8xmdh9MiJxEUYlyl8autxPTSMnKxhGqpFgCtQzW5PA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 13 Mar 2026 18:08:12 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 13 Mar 2026 18:08:12 +0800 From: aspeedyh Date: Fri, 13 Mar 2026 18:07:37 +0800 Subject: [PATCH 2/7] soc: aspeed: Introduce core eSPI controller support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260313-upstream_espi-v1-2-9504428e1f43@aspeedtech.com> References: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> In-Reply-To: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , "Andrew Jeffery" , Ryan Chen , Philipp Zabel CC: , , , , , , aspeedyh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773396491; l=6557; i=yh_chung@aspeedtech.com; s=20260313; h=from:subject:message-id; bh=/rOqnxX9j6h03fyAsdgGIl0qi1TFF1cLQusaF8+cqak=; b=5SvpJyitqQ/Sx4PNe6gIxvhFpoq9dxYazoMvAYRv+z8OBP3B9Zc8w/Sqvr7TWuG9zU+vo/kOk QG8th6cPJrqD8/Qv/n8WgOgvejoRO9ZTD/PsY7YToonQZebIY04/ypY X-Developer-Key: i=yh_chung@aspeedtech.com; a=ed25519; pk=o71dz0J8lpN+v0f3Mk4gT9PfVngADPC1Pex4aK6VigM= Add core eSPI controller support and common code for ASPEED SoCs. The eSPI engine is a slave device in BMC to communicate with the Host over the eSPI interface. The initial support includes basic eSPI driver probe/remove operations, and provides operators for ASPEED SoCs to implement their own eSPI slave device drivers that are different among SoC models. Signed-off-by: aspeedyh --- drivers/soc/aspeed/Kconfig | 7 ++ drivers/soc/aspeed/Makefile | 1 + drivers/soc/aspeed/espi/Makefile | 1 + drivers/soc/aspeed/espi/aspeed-espi.c | 143 ++++++++++++++++++++++++++++++= ++++ drivers/soc/aspeed/espi/aspeed-espi.h | 27 +++++++ 5 files changed, 179 insertions(+) diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig index f579ee0b5afa..677812fab11a 100644 --- a/drivers/soc/aspeed/Kconfig +++ b/drivers/soc/aspeed/Kconfig @@ -52,6 +52,13 @@ config ASPEED_SOCINFO help Say yes to support decoding of ASPEED BMC information. =20 +config ASPEED_ESPI + tristate "ASPEED eSPI slave driver" + help + Enable driver support for Aspeed eSPI controller. The eSPI controller + plays as a slave device in BMC to communicate with the Host over the + eSPI interface using peripheral, virtual wire, out of band, and flash + channels. endmenu =20 endif diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile index b35d74592964..79d794de428a 100644 --- a/drivers/soc/aspeed/Makefile +++ b/drivers/soc/aspeed/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) +=3D aspeed-lpc-snoop.o obj-$(CONFIG_ASPEED_UART_ROUTING) +=3D aspeed-uart-routing.o obj-$(CONFIG_ASPEED_P2A_CTRL) +=3D aspeed-p2a-ctrl.o obj-$(CONFIG_ASPEED_SOCINFO) +=3D aspeed-socinfo.o +obj-$(CONFIG_ASPEED_ESPI) +=3D espi/ diff --git a/drivers/soc/aspeed/espi/Makefile b/drivers/soc/aspeed/espi/Mak= efile new file mode 100644 index 000000000000..d96dc030e23b --- /dev/null +++ b/drivers/soc/aspeed/espi/Makefile @@ -0,0 +1 @@ +obj-y +=3D aspeed-espi.o diff --git a/drivers/soc/aspeed/espi/aspeed-espi.c b/drivers/soc/aspeed/esp= i/aspeed-espi.c new file mode 100644 index 000000000000..15d58b38bbe4 --- /dev/null +++ b/drivers/soc/aspeed/espi/aspeed-espi.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Unified Aspeed eSPI driver framework for different generation SoCs + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aspeed-espi.h" + +struct aspeed_espi_ops { + void (*espi_pre_init)(struct aspeed_espi *espi); + void (*espi_post_init)(struct aspeed_espi *espi); + void (*espi_deinit)(struct aspeed_espi *espi); + irqreturn_t (*espi_isr)(int irq, void *espi); +}; + +static const struct of_device_id aspeed_espi_of_matches[] =3D { + { } +}; +MODULE_DEVICE_TABLE(of, aspeed_espi_of_matches); + +static int aspeed_espi_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct aspeed_espi *espi; + struct resource *res; + struct device *dev; + int rc; + + dev =3D &pdev->dev; + espi =3D devm_kzalloc(dev, sizeof(*espi), GFP_KERNEL); + if (!espi) + return -ENOMEM; + + espi->dev =3D dev; + match =3D of_match_device(aspeed_espi_of_matches, dev); + if (!match) + return -ENODEV; + + espi->pdev =3D pdev; + espi->ops =3D match->data; + if (!espi->ops || !espi->ops->espi_isr) + return -EINVAL; + + res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "cannot get resource\n"); + return -ENODEV; + } + + espi->regs =3D devm_ioremap_resource(dev, res); + if (IS_ERR(espi->regs)) { + dev_err(dev, "cannot map registers\n"); + return PTR_ERR(espi->regs); + } + + espi->irq =3D platform_get_irq(pdev, 0); + if (espi->irq < 0) { + dev_err(dev, "cannot get IRQ number\n"); + return espi->irq; + } + + espi->rst =3D devm_reset_control_get_optional(dev, NULL); + if (IS_ERR(espi->rst)) { + dev_err(dev, "cannot get reset control\n"); + return PTR_ERR(espi->rst); + } + + espi->clk =3D devm_clk_get(dev, NULL); + if (IS_ERR(espi->clk)) { + dev_err(dev, "cannot get clock control\n"); + return PTR_ERR(espi->clk); + } + + rc =3D clk_prepare_enable(espi->clk); + if (rc) { + dev_err(dev, "cannot enable clocks\n"); + return rc; + } + + if (espi->ops->espi_pre_init) + espi->ops->espi_pre_init(espi); + + rc =3D devm_request_irq(dev, espi->irq, espi->ops->espi_isr, 0, + dev_name(dev), espi); + if (rc) { + dev_err(dev, "cannot request IRQ\n"); + goto err_deinit; + } + + if (espi->ops->espi_post_init) + espi->ops->espi_post_init(espi); + + platform_set_drvdata(pdev, espi); + + dev_info(dev, "module loaded\n"); + + return 0; + +err_deinit: + if (espi->ops->espi_deinit) + espi->ops->espi_deinit(espi); + clk_disable_unprepare(espi->clk); + + return rc; +} + +static void aspeed_espi_remove(struct platform_device *pdev) +{ + struct aspeed_espi *espi; + + espi =3D platform_get_drvdata(pdev); + + if (!espi) + return; + + if (espi->ops->espi_deinit) + espi->ops->espi_deinit(espi); + + clk_disable_unprepare(espi->clk); +} + +static struct platform_driver aspeed_espi_driver =3D { + .driver =3D { + .name =3D "aspeed-espi", + .of_match_table =3D aspeed_espi_of_matches, + }, + .probe =3D aspeed_espi_probe, + .remove =3D aspeed_espi_remove, +}; + +module_platform_driver(aspeed_espi_driver); + +MODULE_AUTHOR("Aspeed Technology Inc."); +MODULE_DESCRIPTION("Aspeed eSPI controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/aspeed/espi/aspeed-espi.h b/drivers/soc/aspeed/esp= i/aspeed-espi.h new file mode 100644 index 000000000000..f4ad7f61fef6 --- /dev/null +++ b/drivers/soc/aspeed/espi/aspeed-espi.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Unified eSPI driver header file and data structures + * Copyright 2026 Aspeed Technology Inc. + */ +#ifndef ASPEED_ESPI_H +#define ASPEED_ESPI_H + +#include +#include +#include +#include + +#define DEVICE_NAME "aspeed-espi" + +struct aspeed_espi { + struct platform_device *pdev; + struct device *dev; + void __iomem *regs; + struct reset_control *rst; + struct clk *clk; + int dev_id; + int irq; + const struct aspeed_espi_ops *ops; +}; + +#endif --=20 2.34.1 From nobody Tue Apr 7 11:16:38 2026 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 99A062F691F; Fri, 13 Mar 2026 10:08:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396504; cv=none; b=cLUxg1ldH7oNf7osCBBJlnk8nSvc+hxc78GpuHOYUvEPQblSUrnimdHuaoe0Q1n05E/VcMxHIbKo35cryIaP+nnsUqoxUjij1ZZ1/loR5g6+iBFees1celyHrMJKI2SSgbsWaJWBF1FUZrBK9iiLX0dcCyPCQ+qvxyJ2GCDHGvE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396504; c=relaxed/simple; bh=uPUSEpMtPwe/OxAok3JqcRQkaItbwtrK4e9obTKykTA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=F7anNTq0a9f06JtAESEJyQxm1oiKcZOK8YJEOKy0Z8KAtxuY0C+LtiSX6k8i4sstwDWvfjXvtg8yoNxHOSvJYLwZv1P0C2C6VF5eIpboWXoaMlu4WPxJS+1KYgVJKL4nNToqDbpu8HxHI9CtX6fxSumO0LKW3q6Tn+qOJU5XbKc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 13 Mar 2026 18:08:12 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 13 Mar 2026 18:08:12 +0800 From: aspeedyh Date: Fri, 13 Mar 2026 18:07:38 +0800 Subject: [PATCH 3/7] soc: aspeed: Add AST2600 peripheral channel port I/O support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260313-upstream_espi-v1-3-9504428e1f43@aspeedtech.com> References: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> In-Reply-To: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , "Andrew Jeffery" , Ryan Chen , Philipp Zabel CC: , , , , , , aspeedyh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773396491; l=19063; i=yh_chung@aspeedtech.com; s=20260313; h=from:subject:message-id; bh=uPUSEpMtPwe/OxAok3JqcRQkaItbwtrK4e9obTKykTA=; b=O9+MCrlq/J2gFEtsK5GXWNrlTOz+Km7Qy+Zy/W5IOXqwalsK6aSGcBcpqtb4sB71h7vgxDx2/ P5plA/VZUeqAQnEmGpKXFvERgaDSGBhe8avNRh53/FLgpp+E64VH6n4 X-Developer-Key: i=yh_chung@aspeedtech.com; a=ed25519; pk=o71dz0J8lpN+v0f3Mk4gT9PfVngADPC1Pex4aK6VigM= Add initial support for the AST2600 eSPI peripheral channel handling of port I/O transactions used for LPC-style accesses. This patch does not yet implement peripheral memory read or write cycles. Support for those transactions will be added in a follow-up patch once the remaining transport and buffer handling pieces are in place. Signed-off-by: aspeedyh --- drivers/soc/aspeed/espi/Makefile | 2 +- drivers/soc/aspeed/espi/aspeed-espi.c | 24 +++ drivers/soc/aspeed/espi/ast2600-espi.c | 139 ++++++++++++++++ drivers/soc/aspeed/espi/ast2600-espi.h | 291 +++++++++++++++++++++++++++++= ++++ 4 files changed, 455 insertions(+), 1 deletion(-) diff --git a/drivers/soc/aspeed/espi/Makefile b/drivers/soc/aspeed/espi/Mak= efile index d96dc030e23b..30f9dbf92a0f 100644 --- a/drivers/soc/aspeed/espi/Makefile +++ b/drivers/soc/aspeed/espi/Makefile @@ -1 +1 @@ -obj-y +=3D aspeed-espi.o +obj-y +=3D aspeed-espi.o ast2600-espi.o diff --git a/drivers/soc/aspeed/espi/aspeed-espi.c b/drivers/soc/aspeed/esp= i/aspeed-espi.c index 15d58b38bbe4..e369738119bc 100644 --- a/drivers/soc/aspeed/espi/aspeed-espi.c +++ b/drivers/soc/aspeed/espi/aspeed-espi.c @@ -13,15 +13,28 @@ #include =20 #include "aspeed-espi.h" +#include "ast2600-espi.h" =20 struct aspeed_espi_ops { void (*espi_pre_init)(struct aspeed_espi *espi); void (*espi_post_init)(struct aspeed_espi *espi); void (*espi_deinit)(struct aspeed_espi *espi); + int (*espi_perif_probe)(struct aspeed_espi *espi); + int (*espi_perif_remove)(struct aspeed_espi *espi); irqreturn_t (*espi_isr)(int irq, void *espi); }; =20 +static const struct aspeed_espi_ops aspeed_espi_ast2600_ops =3D { + .espi_pre_init =3D ast2600_espi_pre_init, + .espi_post_init =3D ast2600_espi_post_init, + .espi_deinit =3D ast2600_espi_deinit, + .espi_perif_probe =3D ast2600_espi_perif_probe, + .espi_perif_remove =3D ast2600_espi_perif_remove, + .espi_isr =3D ast2600_espi_isr, +}; + static const struct of_device_id aspeed_espi_of_matches[] =3D { + { .compatible =3D "aspeed,ast2600-espi", .data =3D &aspeed_espi_ast2600_o= ps }, { } }; MODULE_DEVICE_TABLE(of, aspeed_espi_of_matches); @@ -88,6 +101,14 @@ static int aspeed_espi_probe(struct platform_device *pd= ev) if (espi->ops->espi_pre_init) espi->ops->espi_pre_init(espi); =20 + if (espi->ops->espi_perif_probe) { + rc =3D espi->ops->espi_perif_probe(espi); + if (rc) { + dev_err(dev, "cannot init peripheral channel, rc=3D%d\n", rc); + goto err_deinit; + } + } + rc =3D devm_request_irq(dev, espi->irq, espi->ops->espi_isr, 0, dev_name(dev), espi); if (rc) { @@ -121,6 +142,9 @@ static void aspeed_espi_remove(struct platform_device *= pdev) if (!espi) return; =20 + if (espi->ops->espi_perif_remove) + espi->ops->espi_perif_remove(espi); + if (espi->ops->espi_deinit) espi->ops->espi_deinit(espi); =20 diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/es= pi/ast2600-espi.c new file mode 100644 index 000000000000..8effd0404d1f --- /dev/null +++ b/drivers/soc/aspeed/espi/ast2600-espi.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright Aspeed Technology Inc. + */ +#include +#include +#include + +#include "aspeed-espi.h" +#include "ast2600-espi.h" + +static void ast2600_espi_perif_isr(struct aspeed_espi *espi) +{ + u32 sts; + + sts =3D readl(espi->regs + ESPI_INT_STS); + + if (sts & ESPI_INT_STS_PERIF_PC_RX_CMPLT) + writel(ESPI_INT_STS_PERIF_PC_RX_CMPLT, espi->regs + ESPI_INT_STS); +} + +static void ast2600_espi_perif_sw_reset(struct aspeed_espi *espi) +{ + u32 reg; + + reg =3D readl(espi->regs + ESPI_CTRL); + reg &=3D ~(ESPI_CTRL_PERIF_NP_TX_SW_RST + | ESPI_CTRL_PERIF_NP_RX_SW_RST + | ESPI_CTRL_PERIF_PC_TX_SW_RST + | ESPI_CTRL_PERIF_PC_RX_SW_RST + | ESPI_CTRL_PERIF_NP_TX_DMA_EN + | ESPI_CTRL_PERIF_PC_TX_DMA_EN + | ESPI_CTRL_PERIF_PC_RX_DMA_EN + | ESPI_CTRL_PERIF_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + + udelay(1); + + reg |=3D (ESPI_CTRL_PERIF_NP_TX_SW_RST + | ESPI_CTRL_PERIF_NP_RX_SW_RST + | ESPI_CTRL_PERIF_PC_TX_SW_RST + | ESPI_CTRL_PERIF_PC_RX_SW_RST); + writel(reg, espi->regs + ESPI_CTRL); +} + +static void ast2600_espi_perif_reset(struct aspeed_espi *espi) +{ + u32 reg; + + writel(ESPI_INT_EN_PERIF, espi->regs + ESPI_INT_EN_CLR); + writel(ESPI_INT_STS_PERIF, espi->regs + ESPI_INT_STS); + + writel(0x0, espi->regs + ESPI_MMBI_INT_EN); + writel(0xffffffff, espi->regs + ESPI_MMBI_INT_STS); + + reg =3D readl(espi->regs + ESPI_CTRL2); + reg &=3D ~(ESPI_CTRL2_MCYC_RD_DIS_WDT | ESPI_CTRL2_MCYC_WR_DIS_WDT); + writel(reg, espi->regs + ESPI_CTRL2); + + reg =3D readl(espi->regs + ESPI_CTRL); + reg &=3D ~(ESPI_CTRL_PERIF_NP_TX_DMA_EN + | ESPI_CTRL_PERIF_PC_TX_DMA_EN + | ESPI_CTRL_PERIF_PC_RX_DMA_EN + | ESPI_CTRL_PERIF_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + + reg =3D readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_PERIF_SW_RDY; + writel(reg, espi->regs + ESPI_CTRL); +} + +int ast2600_espi_perif_probe(struct aspeed_espi *espi) +{ + ast2600_espi_perif_reset(espi); + return 0; +} + +int ast2600_espi_perif_remove(struct aspeed_espi *espi) +{ + u32 reg; + + writel(ESPI_INT_EN_PERIF, espi->regs + ESPI_INT_EN_CLR); + + reg =3D readl(espi->regs + ESPI_CTRL2); + reg |=3D (ESPI_CTRL2_MCYC_RD_DIS | ESPI_CTRL2_MCYC_WR_DIS); + writel(reg, espi->regs + ESPI_CTRL2); + + reg =3D readl(espi->regs + ESPI_CTRL); + reg &=3D ~(ESPI_CTRL_PERIF_NP_TX_DMA_EN + | ESPI_CTRL_PERIF_PC_TX_DMA_EN + | ESPI_CTRL_PERIF_PC_RX_DMA_EN + | ESPI_CTRL_PERIF_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + return 0; +} + +/* global control */ +irqreturn_t ast2600_espi_isr(int irq, void *arg) +{ + struct aspeed_espi *espi; + u32 sts; + + espi =3D (struct aspeed_espi *)arg; + sts =3D readl(espi->regs + ESPI_INT_STS); + + if (!sts) + return IRQ_NONE; + + if (sts & ESPI_INT_STS_PERIF) + ast2600_espi_perif_isr(espi); + + if (sts & ESPI_INT_STS_RST_DEASSERT) { + /* this will clear all interrupt enable and status */ + reset_control_assert(espi->rst); + reset_control_deassert(espi->rst); + + ast2600_espi_perif_sw_reset(espi); + ast2600_espi_perif_reset(espi); + + /* re-enable eSPI_RESET# interrupt */ + writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); + } + + return IRQ_HANDLED; +} + +void ast2600_espi_pre_init(struct aspeed_espi *espi) +{ + writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); +} + +void ast2600_espi_post_init(struct aspeed_espi *espi) +{ + writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); +} + +void ast2600_espi_deinit(struct aspeed_espi *espi) +{ + writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN_CLR); +} diff --git a/drivers/soc/aspeed/espi/ast2600-espi.h b/drivers/soc/aspeed/es= pi/ast2600-espi.h new file mode 100644 index 000000000000..309479ee1187 --- /dev/null +++ b/drivers/soc/aspeed/espi/ast2600-espi.h @@ -0,0 +1,291 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Register definitions for Aspeed AST2600 eSPI controller + * Copyright 2026 Aspeed Technology Inc. + */ +#ifndef AST2600_ESPI_H +#define AST2600_ESPI_H + +#include +#include +#include "aspeed-espi.h" + +/* registers */ +#define ESPI_CTRL 0x000 +#define ESPI_CTRL_FLASH_TX_SW_RST BIT(31) +#define ESPI_CTRL_FLASH_RX_SW_RST BIT(30) +#define ESPI_CTRL_OOB_TX_SW_RST BIT(29) +#define ESPI_CTRL_OOB_RX_SW_RST BIT(28) +#define ESPI_CTRL_PERIF_NP_TX_SW_RST BIT(27) +#define ESPI_CTRL_PERIF_NP_RX_SW_RST BIT(26) +#define ESPI_CTRL_PERIF_PC_TX_SW_RST BIT(25) +#define ESPI_CTRL_PERIF_PC_RX_SW_RST BIT(24) +#define ESPI_CTRL_FLASH_TX_DMA_EN BIT(23) +#define ESPI_CTRL_FLASH_RX_DMA_EN BIT(22) +#define ESPI_CTRL_OOB_TX_DMA_EN BIT(21) +#define ESPI_CTRL_OOB_RX_DMA_EN BIT(20) +#define ESPI_CTRL_PERIF_NP_TX_DMA_EN BIT(19) +#define ESPI_CTRL_PERIF_PC_TX_DMA_EN BIT(17) +#define ESPI_CTRL_PERIF_PC_RX_DMA_EN BIT(16) +#define ESPI_CTRL_FLASH_EDAF_MODE GENMASK(11, 10) +#define ESPI_CTRL_VW_GPIO_SW BIT(9) +#define ESPI_CTRL_FLASH_SW_RDY BIT(7) +#define ESPI_CTRL_OOB_SW_RDY BIT(4) +#define ESPI_CTRL_VW_SW_RDY BIT(3) +#define ESPI_CTRL_PERIF_SW_RDY BIT(1) +#define ESPI_STS 0x004 +#define ESPI_INT_STS 0x008 +#define ESPI_INT_STS_RST_DEASSERT BIT(31) +#define ESPI_INT_STS_OOB_RX_TMOUT BIT(23) +#define ESPI_INT_STS_VW_SYSEVT1 BIT(22) +#define ESPI_INT_STS_FLASH_TX_ERR BIT(21) +#define ESPI_INT_STS_OOB_TX_ERR BIT(20) +#define ESPI_INT_STS_FLASH_TX_ABT BIT(19) +#define ESPI_INT_STS_OOB_TX_ABT BIT(18) +#define ESPI_INT_STS_PERIF_NP_TX_ABT BIT(17) +#define ESPI_INT_STS_PERIF_PC_TX_ABT BIT(16) +#define ESPI_INT_STS_FLASH_RX_ABT BIT(15) +#define ESPI_INT_STS_OOB_RX_ABT BIT(14) +#define ESPI_INT_STS_PERIF_NP_RX_ABT BIT(13) +#define ESPI_INT_STS_PERIF_PC_RX_ABT BIT(12) +#define ESPI_INT_STS_PERIF_NP_TX_ERR BIT(11) +#define ESPI_INT_STS_PERIF_PC_TX_ERR BIT(10) +#define ESPI_INT_STS_VW_GPIO BIT(9) +#define ESPI_INT_STS_VW_SYSEVT BIT(8) +#define ESPI_INT_STS_FLASH_TX_CMPLT BIT(7) +#define ESPI_INT_STS_FLASH_RX_CMPLT BIT(6) +#define ESPI_INT_STS_OOB_TX_CMPLT BIT(5) +#define ESPI_INT_STS_OOB_RX_CMPLT BIT(4) +#define ESPI_INT_STS_PERIF_NP_TX_CMPLT BIT(3) +#define ESPI_INT_STS_PERIF_PC_TX_CMPLT BIT(1) +#define ESPI_INT_STS_PERIF_PC_RX_CMPLT BIT(0) +#define ESPI_INT_EN 0x00c +#define ESPI_INT_EN_RST_DEASSERT BIT(31) +#define ESPI_INT_EN_OOB_RX_TMOUT BIT(23) +#define ESPI_INT_EN_VW_SYSEVT1 BIT(22) +#define ESPI_INT_EN_FLASH_TX_ERR BIT(21) +#define ESPI_INT_EN_OOB_TX_ERR BIT(20) +#define ESPI_INT_EN_FLASH_TX_ABT BIT(19) +#define ESPI_INT_EN_OOB_TX_ABT BIT(18) +#define ESPI_INT_EN_PERIF_NP_TX_ABT BIT(17) +#define ESPI_INT_EN_PERIF_PC_TX_ABT BIT(16) +#define ESPI_INT_EN_FLASH_RX_ABT BIT(15) +#define ESPI_INT_EN_OOB_RX_ABT BIT(14) +#define ESPI_INT_EN_PERIF_NP_RX_ABT BIT(13) +#define ESPI_INT_EN_PERIF_PC_RX_ABT BIT(12) +#define ESPI_INT_EN_PERIF_NP_TX_ERR BIT(11) +#define ESPI_INT_EN_PERIF_PC_TX_ERR BIT(10) +#define ESPI_INT_EN_VW_GPIO BIT(9) +#define ESPI_INT_EN_VW_SYSEVT BIT(8) +#define ESPI_INT_EN_FLASH_TX_CMPLT BIT(7) +#define ESPI_INT_EN_FLASH_RX_CMPLT BIT(6) +#define ESPI_INT_EN_OOB_TX_CMPLT BIT(5) +#define ESPI_INT_EN_OOB_RX_CMPLT BIT(4) +#define ESPI_INT_EN_PERIF_NP_TX_CMPLT BIT(3) +#define ESPI_INT_EN_PERIF_PC_TX_CMPLT BIT(1) +#define ESPI_INT_EN_PERIF_PC_RX_CMPLT BIT(0) +#define ESPI_PERIF_PC_RX_DMA 0x010 +#define ESPI_PERIF_PC_RX_CTRL 0x014 +#define ESPI_PERIF_PC_RX_CTRL_SERV_PEND BIT(31) +#define ESPI_PERIF_PC_RX_CTRL_LEN GENMASK(23, 12) +#define ESPI_PERIF_PC_RX_CTRL_TAG GENMASK(11, 8) +#define ESPI_PERIF_PC_RX_CTRL_CYC GENMASK(7, 0) +#define ESPI_PERIF_PC_RX_DATA 0x018 +#define ESPI_PERIF_PC_TX_DMA 0x020 +#define ESPI_PERIF_PC_TX_CTRL 0x024 +#define ESPI_PERIF_PC_TX_CTRL_TRIG_PEND BIT(31) +#define ESPI_PERIF_PC_TX_CTRL_LEN GENMASK(23, 12) +#define ESPI_PERIF_PC_TX_CTRL_TAG GENMASK(11, 8) +#define ESPI_PERIF_PC_TX_CTRL_CYC GENMASK(7, 0) +#define ESPI_PERIF_PC_TX_DATA 0x028 +#define ESPI_PERIF_NP_TX_DMA 0x030 +#define ESPI_PERIF_NP_TX_CTRL 0x034 +#define ESPI_PERIF_NP_TX_CTRL_TRIG_PEND BIT(31) +#define ESPI_PERIF_NP_TX_CTRL_LEN GENMASK(23, 12) +#define ESPI_PERIF_NP_TX_CTRL_TAG GENMASK(11, 8) +#define ESPI_PERIF_NP_TX_CTRL_CYC GENMASK(7, 0) +#define ESPI_PERIF_NP_TX_DATA 0x038 +#define ESPI_OOB_RX_DMA 0x040 +#define ESPI_OOB_RX_CTRL 0x044 +#define ESPI_OOB_RX_CTRL_SERV_PEND BIT(31) +#define ESPI_OOB_RX_CTRL_LEN GENMASK(23, 12) +#define ESPI_OOB_RX_CTRL_TAG GENMASK(11, 8) +#define ESPI_OOB_RX_CTRL_CYC GENMASK(7, 0) +#define ESPI_OOB_RX_DATA 0x048 +#define ESPI_OOB_TX_DMA 0x050 +#define ESPI_OOB_TX_CTRL 0x054 +#define ESPI_OOB_TX_CTRL_TRIG_PEND BIT(31) +#define ESPI_OOB_TX_CTRL_LEN GENMASK(23, 12) +#define ESPI_OOB_TX_CTRL_TAG GENMASK(11, 8) +#define ESPI_OOB_TX_CTRL_CYC GENMASK(7, 0) +#define ESPI_OOB_TX_DATA 0x058 +#define ESPI_FLASH_RX_DMA 0x060 +#define ESPI_FLASH_RX_CTRL 0x064 +#define ESPI_FLASH_RX_CTRL_SERV_PEND BIT(31) +#define ESPI_FLASH_RX_CTRL_LEN GENMASK(23, 12) +#define ESPI_FLASH_RX_CTRL_TAG GENMASK(11, 8) +#define ESPI_FLASH_RX_CTRL_CYC GENMASK(7, 0) +#define ESPI_FLASH_RX_DATA 0x068 +#define ESPI_FLASH_TX_DMA 0x070 +#define ESPI_FLASH_TX_CTRL 0x074 +#define ESPI_FLASH_TX_CTRL_TRIG_PEND BIT(31) +#define ESPI_FLASH_TX_CTRL_LEN GENMASK(23, 12) +#define ESPI_FLASH_TX_CTRL_TAG GENMASK(11, 8) +#define ESPI_FLASH_TX_CTRL_CYC GENMASK(7, 0) +#define ESPI_FLASH_TX_DATA 0x078 +#define ESPI_CTRL2 0x080 +#define ESPI_CTRL2_VW_TX_SORT BIT(30) +#define ESPI_CTRL2_MCYC_RD_DIS_WDT BIT(11) +#define ESPI_CTRL2_MCYC_WR_DIS_WDT BIT(10) +#define ESPI_CTRL2_MCYC_RD_DIS BIT(6) +#define ESPI_CTRL2_MMBI_RD_DIS ESPI_CTRL2_MCYC_RD_DIS +#define ESPI_CTRL2_MCYC_WR_DIS BIT(4) +#define ESPI_CTRL2_MMBI_WR_DIS ESPI_CTRL2_MCYC_WR_DIS +#define ESPI_PERIF_MCYC_SADDR 0x084 +#define ESPI_PERIF_MMBI_SADDR ESPI_PERIF_MCYC_SADDR +#define ESPI_PERIF_MCYC_TADDR 0x088 +#define ESPI_PERIF_MMBI_TADDR ESPI_PERIF_MCYC_TADDR +#define ESPI_PERIF_MCYC_MASK 0x08c +#define ESPI_PERIF_MMBI_MASK ESPI_PERIF_MCYC_MASK +#define ESPI_FLASH_EDAF_TADDR 0x090 +#define ESPI_FLASH_EDAF_TADDR_BASE GENMASK(31, 24) +#define ESPI_FLASH_EDAF_TADDR_MASK GENMASK(15, 8) +#define ESPI_VW_SYSEVT_INT_EN 0x094 +#define ESPI_VW_SYSEVT 0x098 +#define ESPI_VW_SYSEVT_HOST_RST_ACK BIT(27) +#define ESPI_VW_SYSEVT_RST_CPU_INIT BIT(26) +#define ESPI_VW_SYSEVT_SLV_BOOT_STS BIT(23) +#define ESPI_VW_SYSEVT_NON_FATAL_ERR BIT(22) +#define ESPI_VW_SYSEVT_FATAL_ERR BIT(21) +#define ESPI_VW_SYSEVT_SLV_BOOT_DONE BIT(20) +#define ESPI_VW_SYSEVT_OOB_RST_ACK BIT(16) +#define ESPI_VW_SYSEVT_NMI_OUT BIT(10) +#define ESPI_VW_SYSEVT_SMI_OUT BIT(9) +#define ESPI_VW_SYSEVT_HOST_RST_WARN BIT(8) +#define ESPI_VW_SYSEVT_OOB_RST_WARN BIT(6) +#define ESPI_VW_SYSEVT_PLTRSTN BIT(5) +#define ESPI_VW_SYSEVT_SUSPEND BIT(4) +#define ESPI_VW_SYSEVT_S5_SLEEP BIT(2) +#define ESPI_VW_SYSEVT_S4_SLEEP BIT(1) +#define ESPI_VW_SYSEVT_S3_SLEEP BIT(0) +#define ESPI_VW_GPIO_VAL 0x09c +#define ESPI_GEN_CAP_N_CONF 0x0a0 +#define ESPI_CH0_CAP_N_CONF 0x0a4 +#define ESPI_CH1_CAP_N_CONF 0x0a8 +#define ESPI_CH2_CAP_N_CONF 0x0ac +#define ESPI_CH3_CAP_N_CONF 0x0b0 +#define ESPI_CH3_CAP_N_CONF2 0x0b4 +#define ESPI_VW_GPIO_DIR 0x0c0 +#define ESPI_VW_GPIO_GRP 0x0c4 +#define ESPI_INT_EN_CLR 0x0fc +#define ESPI_VW_SYSEVT1_INT_EN 0x100 +#define ESPI_VW_SYSEVT1 0x104 +#define ESPI_VW_SYSEVT1_SUSPEND_ACK BIT(20) +#define ESPI_VW_SYSEVT1_SUSPEND_WARN BIT(0) +#define ESPI_VW_SYSEVT_INT_T0 0x110 +#define ESPI_VW_SYSEVT_INT_T1 0x114 +#define ESPI_VW_SYSEVT_INT_T2 0x118 +#define ESPI_VW_SYSEVT_INT_STS 0x11c +#define ESPI_VW_SYSEVT1_INT_T0 0x120 +#define ESPI_VW_SYSEVT1_INT_T1 0x124 +#define ESPI_VW_SYSEVT1_INT_T2 0x128 +#define ESPI_VW_SYSEVT1_INT_STS 0x12c +#define ESPI_OOB_RX_DESC_NUM 0x130 +#define ESPI_OOB_RX_DESC_RPTR 0x134 +#define ESPI_OOB_RX_DESC_RPTR_UPDATE BIT(31) +#define ESPI_OOB_RX_DESC_RPTR_RP GENMASK(11, 0) +#define ESPI_OOB_RX_DESC_WPTR 0x138 +#define ESPI_OOB_RX_DESC_WPTR_RECV_EN BIT(31) +#define ESPI_OOB_RX_DESC_WPTR_SP GENMASK(27, 16) +#define ESPI_OOB_RX_DESC_WPTR_WP GENMASK(11, 0) +#define ESPI_OOB_TX_DESC_NUM 0x140 +#define ESPI_OOB_TX_DESC_RPTR 0x144 +#define ESPI_OOB_TX_DESC_RPTR_UPDATE BIT(31) +#define ESPI_OOB_TX_DESC_WPTR 0x148 +#define ESPI_OOB_TX_DESC_WPTR_SEND_EN BIT(31) +#define ESPI_MMBI_CTRL 0x800 +#define ESPI_MMBI_CTRL_INST_SZ GENMASK(10, 8) +#define ESPI_MMBI_CTRL_TOTAL_SZ GENMASK(6, 4) +#define ESPI_MMBI_CTRL_EN BIT(0) +#define ESPI_MMBI_INT_STS 0x808 +#define ESPI_MMBI_INT_EN 0x80c +#define ESPI_MMBI_HOST_RWP(x) (0x810 + ((x) << 3)) + +/* collect ESPI_INT_EN bits for convenience */ +#define ESPI_INT_EN_PERIF \ + (ESPI_INT_EN_PERIF_NP_TX_ABT | \ + ESPI_INT_EN_PERIF_PC_TX_ABT | \ + ESPI_INT_EN_PERIF_NP_RX_ABT | \ + ESPI_INT_EN_PERIF_PC_RX_ABT | \ + ESPI_INT_EN_PERIF_NP_TX_ERR | \ + ESPI_INT_EN_PERIF_PC_TX_ERR | \ + ESPI_INT_EN_PERIF_NP_TX_CMPLT | \ + ESPI_INT_EN_PERIF_PC_TX_CMPLT | \ + ESPI_INT_EN_PERIF_PC_RX_CMPLT) + +#define ESPI_INT_EN_VW \ + (ESPI_INT_EN_VW_SYSEVT1 | \ + ESPI_INT_EN_VW_GPIO | \ + ESPI_INT_EN_VW_SYSEVT) + +#define ESPI_INT_EN_OOB \ + (ESPI_INT_EN_OOB_RX_TMOUT | \ + ESPI_INT_EN_OOB_TX_ERR | \ + ESPI_INT_EN_OOB_TX_ABT | \ + ESPI_INT_EN_OOB_RX_ABT | \ + ESPI_INT_EN_OOB_TX_CMPLT | \ + ESPI_INT_EN_OOB_RX_CMPLT) + +#define ESPI_INT_EN_FLASH \ + (ESPI_INT_EN_FLASH_TX_ERR | \ + ESPI_INT_EN_FLASH_TX_ABT | \ + ESPI_INT_EN_FLASH_RX_ABT | \ + ESPI_INT_EN_FLASH_TX_CMPLT | \ + ESPI_INT_EN_FLASH_RX_CMPLT) + +/* collect ESPI_INT_STS bits for convenience */ +#define ESPI_INT_STS_PERIF \ + (ESPI_INT_STS_PERIF_NP_TX_ABT | \ + ESPI_INT_STS_PERIF_PC_TX_ABT | \ + ESPI_INT_STS_PERIF_NP_RX_ABT | \ + ESPI_INT_STS_PERIF_PC_RX_ABT | \ + ESPI_INT_STS_PERIF_NP_TX_ERR | \ + ESPI_INT_STS_PERIF_PC_TX_ERR | \ + ESPI_INT_STS_PERIF_NP_TX_CMPLT | \ + ESPI_INT_STS_PERIF_PC_TX_CMPLT | \ + ESPI_INT_STS_PERIF_PC_RX_CMPLT) + +#define ESPI_INT_STS_VW \ + (ESPI_INT_STS_VW_SYSEVT1 | \ + ESPI_INT_STS_VW_GPIO | \ + ESPI_INT_STS_VW_SYSEVT) + +#define ESPI_INT_STS_OOB \ + (ESPI_INT_STS_OOB_RX_TMOUT | \ + ESPI_INT_STS_OOB_TX_ERR | \ + ESPI_INT_STS_OOB_TX_ABT | \ + ESPI_INT_STS_OOB_RX_ABT | \ + ESPI_INT_STS_OOB_TX_CMPLT | \ + ESPI_INT_STS_OOB_RX_CMPLT) + +#define ESPI_INT_STS_FLASH \ + (ESPI_INT_STS_FLASH_TX_ERR | \ + ESPI_INT_STS_FLASH_TX_ABT | \ + ESPI_INT_STS_FLASH_RX_ABT | \ + ESPI_INT_STS_FLASH_TX_CMPLT | \ + ESPI_INT_STS_FLASH_RX_CMPLT) + +/* function operators */ +void ast2600_espi_pre_init(struct aspeed_espi *espi); +void ast2600_espi_post_init(struct aspeed_espi *espi); +void ast2600_espi_deinit(struct aspeed_espi *espi); +int ast2600_espi_perif_probe(struct aspeed_espi *espi); +int ast2600_espi_perif_remove(struct aspeed_espi *espi); +int ast2600_espi_vw_probe(struct aspeed_espi *espi); +int ast2600_espi_vw_remove(struct aspeed_espi *espi); +int ast2600_espi_oob_probe(struct aspeed_espi *espi); +int ast2600_espi_oob_remove(struct aspeed_espi *espi); +int ast2600_espi_flash_probe(struct aspeed_espi *espi); +int ast2600_espi_flash_remove(struct aspeed_espi *espi); +irqreturn_t ast2600_espi_isr(int irq, void *arg); +#endif --=20 2.34.1 From nobody Tue Apr 7 11:16:38 2026 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4C92838C430; Fri, 13 Mar 2026 10:08:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396506; cv=none; b=b119MIphd6Li8tls97ptRtK2rrHyOnaMqbXtgAf6nNIs+rW8HX7+3JSC63yGjQgYWZWv4VXzAr1a5W4mkZIcJvoX61vccbEiRc9O/E28fJbTANoaBQfTzTet0pUER3wYhVbjAqur8G+mrQnZybM7at5tzd++/DUWCvwDT6mZ2Ss= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396506; c=relaxed/simple; bh=/gT8PPPSgtivGqhJGfnX1C479G896inIVlPTIjaL2gM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=XjNZw3ZayXR5sXFH8vXigV3fgul9EN45eeizZUIBBWjr+mxVNUcsC5HijNw6B2caV3+amBIAtqCeLBFXl/QTgZ/1GebPqW34KBS713/GLgGnYLbXP4BxEF5hi5EGVE2r1Sa0QwJPzRNWmuT4IRqc96Rv4F7SY/TugiMU16qVwGI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 13 Mar 2026 18:08:12 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 13 Mar 2026 18:08:12 +0800 From: aspeedyh Date: Fri, 13 Mar 2026 18:07:39 +0800 Subject: [PATCH 4/7] soc: aspeed: Add eSPI TAFS backend support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260313-upstream_espi-v1-4-9504428e1f43@aspeedtech.com> References: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> In-Reply-To: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , "Andrew Jeffery" , Ryan Chen , Philipp Zabel CC: , , , , , , aspeedyh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773396491; l=9656; i=yh_chung@aspeedtech.com; s=20260313; h=from:subject:message-id; bh=/gT8PPPSgtivGqhJGfnX1C479G896inIVlPTIjaL2gM=; b=pxfbLJ5IQCgYFbhg75xnoNK6S8Q8zbJPNxdm67mqkgFlS/68AfZMbE0wPvAWUgbB5c4zuFNam et7tGN1vxpDA2PCTQqswpq2p1woMCldapD6gBYeT15WXSuBwMFvXtvY X-Developer-Key: i=yh_chung@aspeedtech.com; a=ed25519; pk=o71dz0J8lpN+v0f3Mk4gT9PfVngADPC1Pex4aK6VigM= eSPI Target Attached Flash Sharing (TAFS) refers to sharing the storage mounted on eSPI devices to host via eSPI Flash Channel. Add support for TAFS storage handling by creating a storage read/write interface conceptually like Logical Unit Number (LUN) for driver to route storage requests to the specified TAFS backend. Signed-off-by: aspeedyh --- drivers/soc/aspeed/espi/espi_storage.c | 322 +++++++++++++++++++++++++++++= ++++ drivers/soc/aspeed/espi/espi_storage.h | 32 ++++ 2 files changed, 354 insertions(+) diff --git a/drivers/soc/aspeed/espi/espi_storage.c b/drivers/soc/aspeed/es= pi/espi_storage.c new file mode 100644 index 000000000000..71038e9bdd52 --- /dev/null +++ b/drivers/soc/aspeed/espi/espi_storage.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * eSPI TAFS back storage interface + */ + +#include +#include +#include +#include +#include +#include + +#include "espi_storage.h" + +/* + * aspeed_espi_lun: use an existing block device or file as backend storag= e for eSPI flash channel. + * + * Typical path: + * host <-> eSPI bus <-> eSPI slave protocol + * <-> aspeed_espi_lun_*() helpers + * <-> backend block device (e.g., /dev/mmcblk0p3) + */ + +int aspeed_espi_lun_open(struct aspeed_espi_lun *lun, const char *path, + bool initially_ro, bool cdrom) +{ + unsigned int blksize, blkbits; + loff_t size, num_sectors; + struct inode *inode; + struct file *filp; + int ro; + int rc; + + filp =3D NULL; + ro =3D initially_ro; + + if (!lun || !path) { + pr_err("espi_lun_open: invalid args lun=3D%p path=3D%p\n", lun, + path); + return -EINVAL; + } + + pr_info("espi_lun_open: path=3D%s ro=3D%d cdrom=3D%d\n", path, ro, cdrom); + + /* Try R/W first, fallback to R/O if failed */ + if (!ro) { + filp =3D filp_open(path, O_RDWR | O_LARGEFILE, 0); + if (PTR_ERR(filp) =3D=3D -EROFS || PTR_ERR(filp) =3D=3D -EACCES) { + pr_err("espi_lun_open: open rw failed rc=3D%ld, back to ro\n", + PTR_ERR(filp)); + ro =3D 1; + } + } + + if (ro) { + filp =3D filp_open(path, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR_OR_NULL(filp)) { + rc =3D filp ? PTR_ERR(filp) : -ENODEV; + pr_err("espi_lun_open: open ro failed rc=3D%d\n", rc); + return rc; + } + pr_info("espi_lun_open: open ro ok filp=3D%p\n", filp); + } + + if (!(filp->f_mode & FMODE_WRITE)) + ro =3D 1; + + pr_info("espi_lun_open: filp=3D%p f_inode=3D%p f_mode=3D0x%x\n", filp, + filp ? filp->f_inode : NULL, filp ? filp->f_mode : 0); + + inode =3D filp->f_mapping->host; + + pr_info("espi_lun_open: inode=3D%p mode=3D0%o\n", inode, + inode ? inode->i_mode : 0); + if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) { + rc =3D -EINVAL; + goto out_put; + } + + if (!(filp->f_mode & FMODE_CAN_READ)) { + rc =3D -EACCES; + goto out_put; + } + if (!(filp->f_mode & FMODE_CAN_WRITE)) + ro =3D true; + + size =3D i_size_read(inode); + if (size < 0) { + pr_info("unable to find file size: %s\n", path); + rc =3D (int)size; + goto out_put; + } + + pr_info("espi_lun_open: size=3D%lld\n", size); + + if (cdrom) { + blksize =3D 2048; + blkbits =3D 11; + } else if (S_ISBLK(inode->i_mode)) { + blksize =3D bdev_logical_block_size(I_BDEV(inode)); + pr_info("espi_lun_open: blksize=3D%d\n", blksize); + blkbits =3D blksize_bits(blksize); + pr_info("espi_lun_open: bdev=3D%d\n", blkbits); + } else { + blksize =3D 512; + blkbits =3D 9; + } + + pr_info("espi_lun_open: blksize=3D%u blkbits=3D%u\n", blksize, blkbits); + num_sectors =3D size >> blkbits; + if (num_sectors < 1) { + pr_info("file too small: %s\n", path); + rc =3D -ETOOSMALL; + goto out_put; + } + + lun->blksize =3D blksize; + lun->blkbits =3D blkbits; + lun->ro =3D ro; + lun->filp =3D filp; + lun->file_length =3D size; + lun->num_sectors =3D num_sectors; + + lun->cdrom =3D cdrom; + + return 0; + +out_put: + fput(filp); + return rc; +} +EXPORT_SYMBOL_GPL(aspeed_espi_lun_open); + +void aspeed_espi_lun_close(struct aspeed_espi_lun *lun) +{ + if (!lun) + return; + + if (lun->filp) { + fput(lun->filp); + lun->filp =3D NULL; + } +} +EXPORT_SYMBOL_GPL(aspeed_espi_lun_close); + +int aspeed_espi_lun_rw(struct aspeed_espi_lun *lun, bool write, sector_t s= ector, + unsigned int nsect, void *buf) +{ + ssize_t done; + loff_t pos; + size_t len; + + if (!lun || !lun->filp || !buf) + return -EINVAL; + + if (write && lun->ro) + return -EROFS; + + if (sector >=3D lun->num_sectors || nsect > lun->num_sectors - sector) + return -EINVAL; + + pos =3D (loff_t)sector << lun->blkbits; + len =3D (size_t)nsect << lun->blkbits; + + if (write) + done =3D kernel_write(lun->filp, buf, len, &pos); + else + done =3D kernel_read(lun->filp, buf, len, &pos); + + if (done !=3D len) + return done < 0 ? (int)done : -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(aspeed_espi_lun_rw); + +int aspeed_espi_lun_read(struct aspeed_espi_lun *lun, sector_t sector, + unsigned int nsect, void *buf) +{ + return aspeed_espi_lun_rw(lun, false, sector, nsect, buf); +} +EXPORT_SYMBOL_GPL(aspeed_espi_lun_read); + +int aspeed_espi_lun_write(struct aspeed_espi_lun *lun, sector_t sector, + unsigned int nsect, void *buf) +{ + return aspeed_espi_lun_rw(lun, true, sector, nsect, buf); +} +EXPORT_SYMBOL_GPL(aspeed_espi_lun_write); + +/* + * Byte-granular R/W, for eSPI protocol handler use: + * - addr/len are in bytes, allowing arbitrary unaligned access + * - internally handles sector alignment and RMW + */ +int aspeed_espi_lun_rw_bytes(struct aspeed_espi_lun *lun, bool write, u32 = addr, + u32 len, u8 *buf) +{ + u32 blk_mask; + u32 blksize; + u8 *bounce; + u32 done; + int rc; + + done =3D 0; + rc =3D 0; + + if (!lun || !lun->filp || !buf) + return -EINVAL; + + if (!len) + return 0; + + if (write && lun->ro) + return -EROFS; + + blksize =3D lun->blksize; + blk_mask =3D blksize - 1; + + bounce =3D kmalloc(blksize, GFP_KERNEL); + if (!bounce) + return -ENOMEM; + + while (done < len) { + u32 cur_addr =3D addr + done; + u32 off_in_blk =3D cur_addr & blk_mask; + sector_t sector =3D cur_addr >> lun->blkbits; + u32 bytes_this; + u8 *p =3D buf + done; + + /* Process up to the end of this sector */ + bytes_this =3D blksize - off_in_blk; + if (bytes_this > (len - done)) + bytes_this =3D len - done; + + if (!off_in_blk && bytes_this =3D=3D blksize) { + /* Fully aligned sector, use sector API directly */ + if (write) + rc =3D aspeed_espi_lun_write(lun, sector, 1, p); + else + rc =3D aspeed_espi_lun_read(lun, sector, 1, p); + } else { + /* partial sector: read one sector first, then overwrite/extract part */ + rc =3D aspeed_espi_lun_read(lun, sector, 1, bounce); + if (rc) + break; + + if (write) { + memcpy(bounce + off_in_blk, p, bytes_this); + rc =3D aspeed_espi_lun_write(lun, sector, 1, + bounce); + } else { + memcpy(p, bounce + off_in_blk, bytes_this); + } + } + + if (rc) + break; + + done +=3D bytes_this; + } + + kfree(bounce); + return rc; +} +EXPORT_SYMBOL_GPL(aspeed_espi_lun_rw_bytes); + +/* + * Erase: specify range in bytes, implemented as writing 0xFF pattern. + * For eSPI ERASE command use. + */ +int aspeed_espi_lun_erase_bytes(struct aspeed_espi_lun *lun, u32 addr, u32= len) +{ + u8 *pattern; + u32 chunk; + u32 done; + int rc; + + done =3D 0; + rc =3D 0; + + if (!lun || !lun->filp) + return -EINVAL; + + if (!len) + return 0; + + if (lun->ro) + return -EROFS; + + chunk =3D lun->blksize; + if (chunk > len) + chunk =3D len; + + pattern =3D kmalloc(chunk, GFP_KERNEL); + if (!pattern) + return -ENOMEM; + + while (done < len) { + u32 this_len =3D len - done; + + if (this_len > chunk) + this_len =3D chunk; + + memset(pattern, 0xff, this_len); + + rc =3D aspeed_espi_lun_rw_bytes(lun, true, addr + done, this_len, + pattern); + if (rc) + break; + + done +=3D this_len; + } + + kfree(pattern); + return rc; +} +EXPORT_SYMBOL_GPL(aspeed_espi_lun_erase_bytes); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ASPEED eSPI slave storage backend helpers"); +MODULE_AUTHOR("ASPEED"); diff --git a/drivers/soc/aspeed/espi/espi_storage.h b/drivers/soc/aspeed/es= pi/espi_storage.h new file mode 100644 index 000000000000..f0711328b03e --- /dev/null +++ b/drivers/soc/aspeed/espi/espi_storage.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ASPEED_ESPI_STORAGE_H +#define ASPEED_ESPI_STORAGE_H + +#include +#include + +struct aspeed_espi_lun { + struct file *filp; + loff_t file_length; + loff_t num_sectors; + unsigned int blksize; + unsigned int blkbits; + bool ro; + bool cdrom; +}; + +int aspeed_espi_lun_open(struct aspeed_espi_lun *lun, const char *path, + bool initially_ro, bool cdrom); +void aspeed_espi_lun_close(struct aspeed_espi_lun *lun); +int aspeed_espi_lun_rw(struct aspeed_espi_lun *lun, bool write, + sector_t sector, unsigned int nsect, void *buf); +int aspeed_espi_lun_read(struct aspeed_espi_lun *lun, sector_t sector, + unsigned int nsect, void *buf); +int aspeed_espi_lun_write(struct aspeed_espi_lun *lun, sector_t sector, + unsigned int nsect, void *buf); +int aspeed_espi_lun_rw_bytes(struct aspeed_espi_lun *lun, bool write, + u32 addr, u32 len, u8 *buf); +int aspeed_espi_lun_erase_bytes(struct aspeed_espi_lun *lun, + u32 addr, u32 len); + +#endif /* _ASPEED_ESPI_STORAGE_H_ */ --=20 2.34.1 From nobody Tue Apr 7 11:16:38 2026 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 85671345729; Fri, 13 Mar 2026 10:08:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396509; cv=none; b=H3Y6WpUJ8XKhntPaQgpRI29BbcHw2b4ylel3Toy1cv1LEEslAtHLD1Rome/Z4ZLGu9EKsRaFxoqUpvaPmXagL3zIrlrGQD1ze3u5xICOjcO9Vn5dAN2z/MA1ErksJ2g5h9PP+DodoBuaaUoI/ocE4eecqUWI8pbtHcUlcN03+8Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396509; c=relaxed/simple; bh=R/eqy8WdSTvFKjfxkwSMJf1LY2p4PUDk6hGG7OrrdZw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=Pr//ITbQxP8ots1iVxQBY93chmteTvgXsPs9uF23YAbL9YMpOYSacrHL1BadLAJoRWYEW+wM+7NyAD76VBo598xRoLHZhJLs6zy2dXVIYBLqCbXWGOs+jxyvkC0uoCF3Vde0U07Emr5+Mi8YxmThrDOYsbxf1MlW0ncaT6J/2EM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 13 Mar 2026 18:08:12 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 13 Mar 2026 18:08:12 +0800 From: aspeedyh Date: Fri, 13 Mar 2026 18:07:40 +0800 Subject: [PATCH 5/7] soc: aspeed: Add eSPI flash channel support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260313-upstream_espi-v1-5-9504428e1f43@aspeedtech.com> References: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> In-Reply-To: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , "Andrew Jeffery" , Ryan Chen , Philipp Zabel CC: , , , , , , aspeedyh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773396491; l=21460; i=yh_chung@aspeedtech.com; s=20260313; h=from:subject:message-id; bh=R/eqy8WdSTvFKjfxkwSMJf1LY2p4PUDk6hGG7OrrdZw=; b=f4kurhFCFaw+qcsSTwnIQnrVcHGlQfjRd+JqnL81rwfZFoTx/h99zBIib3+lRjnb8N6b1NjHt EZUaf6JX8STBUk+DV8R/CnWxAxwVwa6YnePiEwQK5JkjxpnpFhwXrO7 X-Developer-Key: i=yh_chung@aspeedtech.com; a=ed25519; pk=o71dz0J8lpN+v0f3Mk4gT9PfVngADPC1Pex4aK6VigM= Add flash channel probe/remove and function operators for core to receive/send eSPI flash request packets. Flash channel packets are handled in core to address storage requests via the LUN-like interface. Note eSPI Flash channel may start transaction prior than kernel boots due to host might accesses BIOS image in early stage. Busy checkings are added to avoid resetting the Flash channel during probe if transaction already begun. Signed-off-by: aspeedyh --- drivers/soc/aspeed/espi/Makefile | 2 +- drivers/soc/aspeed/espi/aspeed-espi-comm.h | 62 ++++++++ drivers/soc/aspeed/espi/aspeed-espi.c | 239 +++++++++++++++++++++++++= +++- drivers/soc/aspeed/espi/aspeed-espi.h | 36 +++++ drivers/soc/aspeed/espi/ast2600-espi.c | 165 ++++++++++++++++++++ drivers/soc/aspeed/espi/ast2600-espi.h | 19 ++- 6 files changed, 515 insertions(+), 8 deletions(-) diff --git a/drivers/soc/aspeed/espi/Makefile b/drivers/soc/aspeed/espi/Mak= efile index 30f9dbf92a0f..44f2adc4d358 100644 --- a/drivers/soc/aspeed/espi/Makefile +++ b/drivers/soc/aspeed/espi/Makefile @@ -1 +1 @@ -obj-y +=3D aspeed-espi.o ast2600-espi.o +obj-y +=3D aspeed-espi.o ast2600-espi.o espi_storage.o diff --git a/drivers/soc/aspeed/espi/aspeed-espi-comm.h b/drivers/soc/aspee= d/espi/aspeed-espi-comm.h new file mode 100644 index 000000000000..510b4afee82f --- /dev/null +++ b/drivers/soc/aspeed/espi/aspeed-espi-comm.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Aspeed eSPI protocol packet definitions + * Copyright 2026 Aspeed Technology Inc. + */ +#ifndef __ASPEED_ESPI_COMM_H__ +#define __ASPEED_ESPI_COMM_H__ + +#include +#include +#include + +/* + * eSPI cycle type encoding + * + * Section 5.1 Cycle Types and Packet Format, + * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. + */ +#define ESPI_FLASH_READ 0x00 +#define ESPI_FLASH_WRITE 0x01 +#define ESPI_FLASH_ERASE 0x02 +#define ESPI_FLASH_SUC_CMPLT 0x06 +#define ESPI_FLASH_SUC_CMPLT_D_MIDDLE 0x09 +#define ESPI_FLASH_SUC_CMPLT_D_FIRST 0x0b +#define ESPI_FLASH_SUC_CMPLT_D_LAST 0x0d +#define ESPI_FLASH_SUC_CMPLT_D_ONLY 0x0f +#define ESPI_FLASH_UNSUC_CMPLT 0x0c + +#define ESPI_PLD_LEN_MIN BIT(6) +#define ESPI_MAX_PLD_LEN BIT(12) + +/* + * eSPI packet format structure + * + * Section 5.1 Cycle Types and Packet Format, + * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016. + */ +struct espi_comm_hdr { + u8 cyc; + u8 len_h : 4; + u8 tag : 4; + u8 len_l; +}; + +struct espi_flash_rwe { + u8 cyc; + u8 len_h : 4; + u8 tag : 4; + u8 len_l; + u32 addr_be; + u8 data[]; +} __packed; + +struct espi_flash_cmplt { + u8 cyc; + u8 len_h : 4; + u8 tag : 4; + u8 len_l; + u8 data[]; +} __packed; + +#endif diff --git a/drivers/soc/aspeed/espi/aspeed-espi.c b/drivers/soc/aspeed/esp= i/aspeed-espi.c index e369738119bc..7d58c78ed397 100644 --- a/drivers/soc/aspeed/espi/aspeed-espi.c +++ b/drivers/soc/aspeed/espi/aspeed-espi.c @@ -4,6 +4,7 @@ */ =20 #include +#include #include #include #include @@ -13,7 +14,10 @@ #include =20 #include "aspeed-espi.h" +#include "aspeed-espi-comm.h" #include "ast2600-espi.h" +#include "espi_storage.h" + =20 struct aspeed_espi_ops { void (*espi_pre_init)(struct aspeed_espi *espi); @@ -21,6 +25,16 @@ struct aspeed_espi_ops { void (*espi_deinit)(struct aspeed_espi *espi); int (*espi_perif_probe)(struct aspeed_espi *espi); int (*espi_perif_remove)(struct aspeed_espi *espi); + int (*espi_flash_probe)(struct aspeed_espi *espi); + int (*espi_flash_remove)(struct aspeed_espi *espi); + int (*espi_flash_get_hdr)(struct aspeed_espi *espi, + struct espi_comm_hdr *hdr); + int (*espi_flash_get_pkt)(struct aspeed_espi *espi, void *pkt_buf, + size_t pkt_size); + int (*espi_flash_put_pkt)(struct aspeed_espi *espi, + struct espi_flash_cmplt hdr, void *pkt_buf, + size_t pkt_size); + void (*espi_flash_clr_pkt)(struct aspeed_espi *espi); irqreturn_t (*espi_isr)(int irq, void *espi); }; =20 @@ -30,6 +44,12 @@ static const struct aspeed_espi_ops aspeed_espi_ast2600_= ops =3D { .espi_deinit =3D ast2600_espi_deinit, .espi_perif_probe =3D ast2600_espi_perif_probe, .espi_perif_remove =3D ast2600_espi_perif_remove, + .espi_flash_probe =3D ast2600_espi_flash_probe, + .espi_flash_remove =3D ast2600_espi_flash_remove, + .espi_flash_get_hdr =3D ast2600_espi_flash_get_hdr, + .espi_flash_get_pkt =3D ast2600_espi_flash_get_pkt, + .espi_flash_put_pkt =3D ast2600_espi_flash_put_pkt, + .espi_flash_clr_pkt =3D ast2600_espi_flash_clr_pkt, .espi_isr =3D ast2600_espi_isr, }; =20 @@ -39,6 +59,207 @@ static const struct of_device_id aspeed_espi_of_matches= [] =3D { }; MODULE_DEVICE_TABLE(of, aspeed_espi_of_matches); =20 +static void aspeed_espi_flash_handle_lun(struct aspeed_espi *espi) +{ + u32 cyc, len, tag, pkt_len, addr, offset; + struct espi_flash_cmplt resp_pkt; + struct aspeed_espi_flash *flash; + struct espi_flash_rwe *req_pkt; + struct espi_comm_hdr hdr; + u8 *payload; + u8 *buf; + int rc; + + payload =3D NULL; + buf =3D NULL; + + flash =3D &espi->flash; + if (!flash->lun || !flash->lun->filp) + return; + + rc =3D espi->ops->espi_flash_get_hdr(espi, &hdr); + if (rc) { + dev_err(espi->dev, "espi_flash_handle_lun: get_hdr failed rc=3D%d\n", rc= ); + return; + } + + if (hdr.cyc !=3D ESPI_FLASH_WRITE && hdr.cyc !=3D ESPI_FLASH_READ && + hdr.cyc !=3D ESPI_FLASH_ERASE) { + dev_err(espi->dev, "espi_flash_handle_lun: invalid cyc=3D0x%x\n", + hdr.cyc); + return; + } + + cyc =3D hdr.cyc; + len =3D (hdr.len_h << 8) | hdr.len_l; + tag =3D hdr.tag; + + len =3D len ? len : ESPI_MAX_PLD_LEN; + pkt_len =3D len + sizeof(struct espi_flash_rwe); + + payload =3D kzalloc(pkt_len, GFP_KERNEL); + if (!payload) + return; + + rc =3D espi->ops->espi_flash_get_pkt(espi, payload + sizeof(hdr), pkt_len= - sizeof(hdr)); + if (rc) { + dev_err(espi->dev, "espi_flash_handle_lun: get_pkt failed rc=3D%d\n", rc= ); + goto out_free; + } + + req_pkt =3D (struct espi_flash_rwe *)payload; + req_pkt->cyc =3D hdr.cyc; + req_pkt->len_h =3D hdr.len_h; + req_pkt->len_l =3D hdr.len_l; + req_pkt->tag =3D hdr.tag; + + addr =3D be32_to_cpu(req_pkt->addr_be); + + switch (cyc) { + case ESPI_FLASH_ERASE: + rc =3D aspeed_espi_lun_erase_bytes(flash->lun, addr, len); + resp_pkt.cyc =3D (rc) ? ESPI_FLASH_UNSUC_CMPLT : ESPI_FLASH_SUC_CMPLT; + resp_pkt.len_h =3D 0; + resp_pkt.len_l =3D 0; + resp_pkt.tag =3D tag; + espi->ops->espi_flash_put_pkt(espi, resp_pkt, NULL, 0); + break; + case ESPI_FLASH_WRITE: + rc =3D aspeed_espi_lun_rw_bytes(flash->lun, true, addr, len, + &payload[sizeof(struct espi_flash_rwe)]); + + resp_pkt.cyc =3D (rc) ? ESPI_FLASH_UNSUC_CMPLT : ESPI_FLASH_SUC_CMPLT; + resp_pkt.len_h =3D 0; + resp_pkt.len_l =3D 0; + resp_pkt.tag =3D tag; + espi->ops->espi_flash_put_pkt(espi, resp_pkt, NULL, 0); + break; + case ESPI_FLASH_READ: + buf =3D kzalloc(len, GFP_KERNEL); + if (!buf) + goto out_free; + + rc =3D aspeed_espi_lun_rw_bytes(flash->lun, false, addr, len, buf); + if (rc) { + resp_pkt.cyc =3D ESPI_FLASH_UNSUC_CMPLT; + resp_pkt.len_h =3D 0; + resp_pkt.len_l =3D 0; + resp_pkt.tag =3D tag; + espi->ops->espi_flash_put_pkt(espi, resp_pkt, NULL, 0); + } else { + if (len <=3D ESPI_PLD_LEN_MIN) { + resp_pkt.cyc =3D ESPI_FLASH_SUC_CMPLT_D_ONLY; + resp_pkt.tag =3D tag; + resp_pkt.len_h =3D (len >> 8) & 0xff; + resp_pkt.len_l =3D len & 0xff; + espi->ops->espi_flash_put_pkt(espi, resp_pkt, buf, len); + } else { + resp_pkt.cyc =3D ESPI_FLASH_SUC_CMPLT_D_FIRST; + resp_pkt.tag =3D tag; + resp_pkt.len_h =3D (ESPI_PLD_LEN_MIN >> 8) & 0xff; + resp_pkt.len_l =3D ESPI_PLD_LEN_MIN & 0xff; + espi->ops->espi_flash_put_pkt(espi, resp_pkt, buf, + ESPI_PLD_LEN_MIN); + offset =3D ESPI_PLD_LEN_MIN; + len -=3D ESPI_PLD_LEN_MIN; + + while (len > ESPI_PLD_LEN_MIN) { + resp_pkt.cyc =3D ESPI_FLASH_SUC_CMPLT_D_MIDDLE; + espi->ops->espi_flash_put_pkt(espi, resp_pkt, + &buf[offset], + ESPI_PLD_LEN_MIN); + offset +=3D ESPI_PLD_LEN_MIN; + len -=3D ESPI_PLD_LEN_MIN; + } + + resp_pkt.cyc =3D ESPI_FLASH_SUC_CMPLT_D_LAST; + resp_pkt.len_h =3D (len >> 8) & 0xff; + resp_pkt.len_l =3D len & 0xff; + espi->ops->espi_flash_put_pkt(espi, resp_pkt, + &buf[offset], len); + } + } + break; + default: + dev_err(espi->dev, "espi_flash_handle_lun: unsupported cyc=3D0x%x\n", cy= c); + break; + } + espi->ops->espi_flash_clr_pkt(espi); +out_free: + kfree(buf); + kfree(payload); +} + +static void aspeed_espi_flash_rx_work(struct work_struct *work) +{ + struct aspeed_espi_flash *flash =3D container_of(work, struct aspeed_espi= _flash, rx_work); + struct aspeed_espi *espi =3D container_of(flash, struct aspeed_espi, flas= h); + + mutex_lock(&flash->tx_mtx); + aspeed_espi_flash_handle_lun(espi); + mutex_unlock(&flash->tx_mtx); +} + +static int aspeed_espi_flash_probe(struct aspeed_espi *espi) +{ + struct aspeed_espi_flash *flash; + struct device *dev; + + flash =3D &espi->flash; + dev =3D espi->dev; + + flash->dma.enable =3D of_property_read_bool(dev->of_node, "aspeed,flash-d= ma-mode"); + if (flash->dma.enable) { + flash->dma.tx_virt =3D dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.t= x_addr, + GFP_KERNEL); + if (!flash->dma.tx_virt) { + dev_err(dev, "cannot allocate DMA TX buffer\n"); + return -ENOMEM; + } + + flash->dma.rx_virt =3D dmam_alloc_coherent(dev, PAGE_SIZE, &flash->dma.r= x_addr, + GFP_KERNEL); + if (!flash->dma.rx_virt) { + dev_err(dev, "cannot allocate DMA RX buffer\n"); + return -ENOMEM; + } + } + + mutex_init(&flash->tx_mtx); + INIT_WORK(&flash->rx_work, aspeed_espi_flash_rx_work); + + mutex_init(&espi->flash.lun_mtx); + espi->flash.lun =3D NULL; + espi->flash.lun_path[0] =3D '\0'; + espi->flash.lun_ro =3D false; + + return espi->ops->espi_flash_probe(espi); +} + +static void aspeed_espi_flash_remove(struct aspeed_espi *espi) +{ + struct aspeed_espi_flash *flash; + + flash =3D &espi->flash; + + if (espi->ops->espi_flash_remove) + espi->ops->espi_flash_remove(espi); + + cancel_work_sync(&flash->rx_work); + + if (flash->dma.enable) { + dmam_free_coherent(espi->dev, PAGE_SIZE, flash->dma.tx_virt, flash->dma.= tx_addr); + dmam_free_coherent(espi->dev, PAGE_SIZE, flash->dma.rx_virt, flash->dma.= rx_addr); + } + + mutex_destroy(&flash->lun_mtx); + mutex_destroy(&flash->tx_mtx); + + flash->lun =3D NULL; + flash->lun_path[0] =3D '\0'; + flash->lun_ro =3D false; +} + static int aspeed_espi_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -109,11 +330,17 @@ static int aspeed_espi_probe(struct platform_device *= pdev) } } =20 + rc =3D aspeed_espi_flash_probe(espi); + if (rc) { + dev_err(dev, "cannot init flash channel, rc=3D%d\n", rc); + goto err_remove_perif; + } + rc =3D devm_request_irq(dev, espi->irq, espi->ops->espi_isr, 0, dev_name(dev), espi); if (rc) { dev_err(dev, "cannot request IRQ\n"); - goto err_deinit; + goto err_remove_flash; } =20 if (espi->ops->espi_post_init) @@ -125,12 +352,16 @@ static int aspeed_espi_probe(struct platform_device *= pdev) =20 return 0; =20 +err_remove_flash: + aspeed_espi_flash_remove(espi); +err_remove_perif: + if (espi->ops->espi_perif_remove) + espi->ops->espi_perif_remove(espi); err_deinit: if (espi->ops->espi_deinit) espi->ops->espi_deinit(espi); clk_disable_unprepare(espi->clk); - - return rc; + return dev_err_probe(dev, rc, "%s failed\n", __func__); } =20 static void aspeed_espi_remove(struct platform_device *pdev) @@ -142,6 +373,8 @@ static void aspeed_espi_remove(struct platform_device *= pdev) if (!espi) return; =20 + aspeed_espi_flash_remove(espi); + if (espi->ops->espi_perif_remove) espi->ops->espi_perif_remove(espi); =20 diff --git a/drivers/soc/aspeed/espi/aspeed-espi.h b/drivers/soc/aspeed/esp= i/aspeed-espi.h index f4ad7f61fef6..7598bc622b95 100644 --- a/drivers/soc/aspeed/espi/aspeed-espi.h +++ b/drivers/soc/aspeed/espi/aspeed-espi.h @@ -9,9 +9,44 @@ #include #include #include +#include +#include #include +#include =20 #define DEVICE_NAME "aspeed-espi" +#define ASPEED_ESPI_LUN_PATH_MAX 256 + +enum aspeed_tafs_mode { + TAFS_MODE_SW =3D 1, +}; + +struct aspeed_espi_lun; + +struct aspeed_espi_flash { + struct { + enum aspeed_tafs_mode mode; + phys_addr_t taddr; + resource_size_t size; + } tafs; + + struct { + bool enable; + void *tx_virt; + dma_addr_t tx_addr; + void *rx_virt; + dma_addr_t rx_addr; + } dma; + + struct mutex tx_mtx; /* protects tx virt/addr */ + + struct work_struct rx_work; + + struct mutex lun_mtx; /* protects lun metadata r/w */ + struct aspeed_espi_lun *lun; + char lun_path[ASPEED_ESPI_LUN_PATH_MAX]; + bool lun_ro; +}; =20 struct aspeed_espi { struct platform_device *pdev; @@ -21,6 +56,7 @@ struct aspeed_espi { struct clk *clk; int dev_id; int irq; + struct aspeed_espi_flash flash; const struct aspeed_espi_ops *ops; }; =20 diff --git a/drivers/soc/aspeed/espi/ast2600-espi.c b/drivers/soc/aspeed/es= pi/ast2600-espi.c index 8effd0404d1f..c3ea01866b45 100644 --- a/drivers/soc/aspeed/espi/ast2600-espi.c +++ b/drivers/soc/aspeed/espi/ast2600-espi.c @@ -7,6 +7,7 @@ #include =20 #include "aspeed-espi.h" +#include "aspeed-espi-comm.h" #include "ast2600-espi.h" =20 static void ast2600_espi_perif_isr(struct aspeed_espi *espi) @@ -93,6 +94,166 @@ int ast2600_espi_perif_remove(struct aspeed_espi *espi) return 0; } =20 +static void ast2600_espi_flash_isr(struct aspeed_espi *espi) +{ + struct aspeed_espi_flash *flash; + u32 sts; + + flash =3D &espi->flash; + + sts =3D readl(espi->regs + ESPI_INT_STS); + + if (sts & ESPI_INT_STS_FLASH_RX_CMPLT) { + writel(ESPI_INT_STS_FLASH_RX_CMPLT, espi->regs + ESPI_INT_STS); + queue_work(system_wq, &flash->rx_work); + } +} + +static void ast2600_espi_flash_reset(struct aspeed_espi *espi) +{ + struct aspeed_espi_flash *flash; + u32 reg; + + flash =3D &espi->flash; + + writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); + writel(ESPI_INT_STS_FLASH, espi->regs + ESPI_INT_STS); + + reg =3D readl(espi->regs + ESPI_CTRL); + reg &=3D ~(ESPI_CTRL_FLASH_TX_SW_RST + | ESPI_CTRL_FLASH_RX_SW_RST + | ESPI_CTRL_FLASH_TX_DMA_EN + | ESPI_CTRL_FLASH_RX_DMA_EN + | ESPI_CTRL_FLASH_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + + udelay(1); + + reg |=3D (ESPI_CTRL_FLASH_TX_SW_RST | ESPI_CTRL_FLASH_RX_SW_RST); + writel(reg, espi->regs + ESPI_CTRL); + + flash->tafs.mode =3D TAFS_MODE_SW; + reg =3D readl(espi->regs + ESPI_CTRL) & ~ESPI_CTRL_FLASH_TAFS_MODE; + reg |=3D FIELD_PREP(ESPI_CTRL_FLASH_TAFS_MODE, flash->tafs.mode); + writel(reg, espi->regs + ESPI_CTRL); + + if (flash->dma.enable) { + writel(flash->dma.tx_addr, espi->regs + ESPI_FLASH_TX_DMA); + writel(flash->dma.rx_addr, espi->regs + ESPI_FLASH_RX_DMA); + + reg =3D readl(espi->regs + ESPI_CTRL) + | ESPI_CTRL_FLASH_TX_DMA_EN + | ESPI_CTRL_FLASH_RX_DMA_EN; + writel(reg, espi->regs + ESPI_CTRL); + } + + writel(ESPI_INT_EN_FLASH_RX_CMPLT, espi->regs + ESPI_INT_EN); + + reg =3D readl(espi->regs + ESPI_CTRL) | ESPI_CTRL_FLASH_SW_RDY; + writel(reg, espi->regs + ESPI_CTRL); +} + +int ast2600_espi_flash_probe(struct aspeed_espi *espi) +{ + u32 regs; + + regs =3D readl(espi->regs + ESPI_STS); + if (regs & (ESPI_STS_FLASH_TX_BUSY | ESPI_STS_FLASH_RX_BUSY)) { + dev_warn(espi->dev, "eSPI flash channel is busy, deferring...\n"); + return -EPROBE_DEFER; + } + + ast2600_espi_flash_reset(espi); + return 0; +} + +int ast2600_espi_flash_remove(struct aspeed_espi *espi) +{ + struct aspeed_espi_flash *flash; + u32 reg; + + flash =3D &espi->flash; + + writel(ESPI_INT_EN_FLASH, espi->regs + ESPI_INT_EN_CLR); + + reg =3D readl(espi->regs + ESPI_CTRL); + reg &=3D ~(ESPI_CTRL_FLASH_TX_DMA_EN + | ESPI_CTRL_FLASH_RX_DMA_EN + | ESPI_CTRL_FLASH_SW_RDY); + writel(reg, espi->regs + ESPI_CTRL); + + return 0; +} + +int ast2600_espi_flash_get_hdr(struct aspeed_espi *espi, + struct espi_comm_hdr *hdr) +{ + u32 reg, len; + + reg =3D readl(espi->regs + ESPI_FLASH_RX_CTRL); + hdr->cyc =3D FIELD_GET(ESPI_FLASH_RX_CTRL_CYC, reg); + hdr->tag =3D FIELD_GET(ESPI_FLASH_RX_CTRL_TAG, reg); + len =3D FIELD_GET(ESPI_FLASH_RX_CTRL_LEN, reg); + hdr->len_h =3D (len >> 8) & 0xff; + hdr->len_l =3D len & 0xff; + + return 0; +} + +int ast2600_espi_flash_get_pkt(struct aspeed_espi *espi, void *pkt_buf, + size_t pkt_size) +{ + u32 i; + u8 *pkt; + + pkt =3D (u8 *)pkt_buf; + + if (espi->flash.dma.enable) { + memcpy(pkt, espi->flash.dma.rx_virt, pkt_size); + } else { + for (i =3D 0; i < pkt_size; ++i) + pkt[i] =3D readl(espi->regs + ESPI_FLASH_RX_DATA) & 0xff; + } + + return 0; +} + +int ast2600_espi_flash_put_pkt(struct aspeed_espi *espi, + struct espi_flash_cmplt hdr, void *pkt_buf, + size_t pkt_size) +{ + u32 i, cyc, tag, len, reg; + u8 *pkt; + + pkt =3D (u8 *)pkt_buf; + + if (pkt_buf && pkt_size > 0) { + if (espi->flash.dma.enable) { + memcpy(espi->flash.dma.tx_virt, pkt, pkt_size); + dma_wmb(); + } else { + for (i =3D 0; i < pkt_size; ++i) + writel(pkt[i], espi->regs + ESPI_FLASH_TX_DATA); + } + } + + cyc =3D hdr.cyc; + tag =3D hdr.tag; + len =3D (hdr.len_h << 8) | hdr.len_l; + reg =3D FIELD_PREP(ESPI_FLASH_TX_CTRL_CYC, cyc) | + FIELD_PREP(ESPI_FLASH_TX_CTRL_TAG, tag) | + FIELD_PREP(ESPI_FLASH_TX_CTRL_LEN, len) | + ESPI_FLASH_TX_CTRL_TRIG_PEND; + writel(reg, espi->regs + ESPI_FLASH_TX_CTRL); + + return 0; +} + +void ast2600_espi_flash_clr_pkt(struct aspeed_espi *espi) +{ + writel(ESPI_FLASH_RX_CTRL_SERV_PEND, espi->regs + ESPI_FLASH_RX_CTRL); +} + /* global control */ irqreturn_t ast2600_espi_isr(int irq, void *arg) { @@ -108,6 +269,9 @@ irqreturn_t ast2600_espi_isr(int irq, void *arg) if (sts & ESPI_INT_STS_PERIF) ast2600_espi_perif_isr(espi); =20 + if (sts & ESPI_INT_STS_FLASH_RX_CMPLT) + ast2600_espi_flash_isr(espi); + if (sts & ESPI_INT_STS_RST_DEASSERT) { /* this will clear all interrupt enable and status */ reset_control_assert(espi->rst); @@ -115,6 +279,7 @@ irqreturn_t ast2600_espi_isr(int irq, void *arg) =20 ast2600_espi_perif_sw_reset(espi); ast2600_espi_perif_reset(espi); + ast2600_espi_flash_reset(espi); =20 /* re-enable eSPI_RESET# interrupt */ writel(ESPI_INT_EN_RST_DEASSERT, espi->regs + ESPI_INT_EN); diff --git a/drivers/soc/aspeed/espi/ast2600-espi.h b/drivers/soc/aspeed/es= pi/ast2600-espi.h index 309479ee1187..251999dba73f 100644 --- a/drivers/soc/aspeed/espi/ast2600-espi.h +++ b/drivers/soc/aspeed/espi/ast2600-espi.h @@ -9,6 +9,7 @@ #include #include #include "aspeed-espi.h" +#include "aspeed-espi-comm.h" =20 /* registers */ #define ESPI_CTRL 0x000 @@ -27,13 +28,15 @@ #define ESPI_CTRL_PERIF_NP_TX_DMA_EN BIT(19) #define ESPI_CTRL_PERIF_PC_TX_DMA_EN BIT(17) #define ESPI_CTRL_PERIF_PC_RX_DMA_EN BIT(16) -#define ESPI_CTRL_FLASH_EDAF_MODE GENMASK(11, 10) +#define ESPI_CTRL_FLASH_TAFS_MODE GENMASK(11, 10) #define ESPI_CTRL_VW_GPIO_SW BIT(9) #define ESPI_CTRL_FLASH_SW_RDY BIT(7) #define ESPI_CTRL_OOB_SW_RDY BIT(4) #define ESPI_CTRL_VW_SW_RDY BIT(3) #define ESPI_CTRL_PERIF_SW_RDY BIT(1) #define ESPI_STS 0x004 +#define ESPI_STS_FLASH_TX_BUSY BIT(23) +#define ESPI_STS_FLASH_RX_BUSY BIT(22) #define ESPI_INT_STS 0x008 #define ESPI_INT_STS_RST_DEASSERT BIT(31) #define ESPI_INT_STS_OOB_RX_TMOUT BIT(23) @@ -147,9 +150,9 @@ #define ESPI_PERIF_MMBI_TADDR ESPI_PERIF_MCYC_TADDR #define ESPI_PERIF_MCYC_MASK 0x08c #define ESPI_PERIF_MMBI_MASK ESPI_PERIF_MCYC_MASK -#define ESPI_FLASH_EDAF_TADDR 0x090 -#define ESPI_FLASH_EDAF_TADDR_BASE GENMASK(31, 24) -#define ESPI_FLASH_EDAF_TADDR_MASK GENMASK(15, 8) +#define ESPI_FLASH_TAFS_TADDR 0x090 +#define ESPI_FLASH_TAFS_TADDR_BASE GENMASK(31, 24) +#define ESPI_FLASH_TAFS_TADDR_MASK GENMASK(15, 8) #define ESPI_VW_SYSEVT_INT_EN 0x094 #define ESPI_VW_SYSEVT 0x098 #define ESPI_VW_SYSEVT_HOST_RST_ACK BIT(27) @@ -287,5 +290,13 @@ int ast2600_espi_oob_probe(struct aspeed_espi *espi); int ast2600_espi_oob_remove(struct aspeed_espi *espi); int ast2600_espi_flash_probe(struct aspeed_espi *espi); int ast2600_espi_flash_remove(struct aspeed_espi *espi); +int ast2600_espi_flash_get_hdr(struct aspeed_espi *espi, + struct espi_comm_hdr *hdr); +int ast2600_espi_flash_get_pkt(struct aspeed_espi *espi, void *pkt_buf, + size_t pkt_size); +int ast2600_espi_flash_put_pkt(struct aspeed_espi *espi, + struct espi_flash_cmplt hdr, void *pkt_buf, + size_t pkt_size); +void ast2600_espi_flash_clr_pkt(struct aspeed_espi *espi); irqreturn_t ast2600_espi_isr(int irq, void *arg); #endif --=20 2.34.1 From nobody Tue Apr 7 11:16:38 2026 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9FDB538F622; Fri, 13 Mar 2026 10:08:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396513; cv=none; b=qaQyC/ybqRx2jhYmbP6d8JX8/2jfLbxq3FePFioWDxmKhG0MLQFYqBS9Al9m7XEiPTIFLiCx8Y6Lk72e8N3fMzI/sNYxGQgwBuIFwLjSgYnxPhfizJUPPIrVDGXA3BUSAvT640EnQ64INzC/6MOYhfIZPoA//LpeAaz+oK9xCbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396513; c=relaxed/simple; bh=78sBqzD/xgUaZNF42FudqCrohUeibR7beHp9FUjNNAs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=EUZ4Zugre4aL98ZsX9FZ9sh8HEKxGnnGri+QMIbAsjL3AT/uuhcnhZYEOu7Sh+GN46ql2RMNK+Uxf5EU5lu+HYzg1m6ZglkOcVbmsagXaxtTJxKjsZpb0HU8tlZkUU3j41aA7nY1Qm0pMc5nJKPQBOrYpvtrJ4cTOu1Kv0x6p/0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 13 Mar 2026 18:08:12 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 13 Mar 2026 18:08:12 +0800 From: aspeedyh Date: Fri, 13 Mar 2026 18:07:41 +0800 Subject: [PATCH 6/7] soc: aspeed: Add sysfs controls for flash backend selection Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260313-upstream_espi-v1-6-9504428e1f43@aspeedtech.com> References: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> In-Reply-To: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , "Andrew Jeffery" , Ryan Chen , Philipp Zabel CC: , , , , , , aspeedyh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773396491; l=6770; i=yh_chung@aspeedtech.com; s=20260313; h=from:subject:message-id; bh=78sBqzD/xgUaZNF42FudqCrohUeibR7beHp9FUjNNAs=; b=QGkIR8fhoTHKqHX7qiGYNnqJAwkWw+OA6BoXb4376Fz9jYQGG7DV9cJp65M1QyLvL9AJD+q8M 11B5HHphtSQDoNhDjDx6Jkwl5ne3yiNzTyotfRqUcwsySxms7ps06WA X-Developer-Key: i=yh_chung@aspeedtech.com; a=ed25519; pk=o71dz0J8lpN+v0f3Mk4gT9PfVngADPC1Pex4aK6VigM= add following attributes to select backend storage for eSPI TAFS LUN interface: - flash_lun_path: specify path of backend storage for eSPI TAFS to share with host. - flash_lun_readonly: set flash LUN to read-only or read-write mode to block host write operations. - flash_lun_enable: open storage according to flash_lun_path as file for eSPI TAFS access. Example usage: - Select /dev/mtdblock8 as backend storage for eSPI TAFS LUN interface echo /dev/mtdblock8 > \ /sys/bus/platform/devices/1e6ee000.espi/flash_lun_path - Set LUN to read-only mode to block host write operations echo 1 > /sys/bus/platform/devices/1e6ee000.espi/flash_lun_readonly - Enable flash LUN for eSPI TAFS access echo 1 > /sys/bus/platform/devices/1e6ee000.espi/flash_lun_enable Signed-off-by: aspeedyh --- drivers/soc/aspeed/espi/aspeed-espi.c | 218 ++++++++++++++++++++++++++++++= ++++ 1 file changed, 218 insertions(+) diff --git a/drivers/soc/aspeed/espi/aspeed-espi.c b/drivers/soc/aspeed/esp= i/aspeed-espi.c index 7d58c78ed397..2c8f9641174d 100644 --- a/drivers/soc/aspeed/espi/aspeed-espi.c +++ b/drivers/soc/aspeed/espi/aspeed-espi.c @@ -12,12 +12,224 @@ #include #include #include +#include +#include +#include =20 #include "aspeed-espi.h" #include "aspeed-espi-comm.h" #include "ast2600-espi.h" #include "espi_storage.h" =20 +static ssize_t flash_lun_path_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aspeed_espi_flash *flash; + struct aspeed_espi *espi; + ssize_t rc; + + espi =3D dev_get_drvdata(dev); + + if (!espi) + return -ENODEV; + + flash =3D &espi->flash; + + mutex_lock(&flash->lun_mtx); + rc =3D scnprintf(buf, PAGE_SIZE, "%s\n", flash->lun_path); + mutex_unlock(&flash->lun_mtx); + + return rc; +} + +static ssize_t flash_lun_path_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char tmp[ASPEED_ESPI_LUN_PATH_MAX]; + struct aspeed_espi_flash *flash; + struct aspeed_espi *espi; + size_t len; + + espi =3D dev_get_drvdata(dev); + if (!espi) + return -ENODEV; + + flash =3D &espi->flash; + + len =3D strnlen(buf, count); + if (len && buf[len - 1] =3D=3D '\n') + len--; + + if (len >=3D sizeof(tmp)) + return -ENAMETOOLONG; + + memcpy(tmp, buf, len); + tmp[len] =3D '\0'; + + mutex_lock(&flash->lun_mtx); + if (flash->lun && flash->lun->filp) { + mutex_unlock(&flash->lun_mtx); + return -EBUSY; + } + + strscpy(flash->lun_path, tmp, sizeof(flash->lun_path)); + dev_info(dev, "flash lun path set to %s\n", flash->lun_path); + mutex_unlock(&flash->lun_mtx); + + return count; +} + +static ssize_t flash_lun_readonly_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aspeed_espi_flash *flash; + struct aspeed_espi *espi; + ssize_t rc; + + espi =3D dev_get_drvdata(dev); + if (!espi) + return -ENODEV; + + flash =3D &espi->flash; + + mutex_lock(&flash->lun_mtx); + rc =3D scnprintf(buf, PAGE_SIZE, "%u\n", flash->lun_ro); + mutex_unlock(&flash->lun_mtx); + + return rc; +} + +static ssize_t flash_lun_readonly_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aspeed_espi_flash *flash; + struct aspeed_espi *espi; + bool ro; + int rc; + + espi =3D dev_get_drvdata(dev); + if (!espi) + return -ENODEV; + + flash =3D &espi->flash; + + rc =3D kstrtobool(buf, &ro); + if (rc) + return rc; + + mutex_lock(&flash->lun_mtx); + if (flash->lun && flash->lun->filp) { + mutex_unlock(&flash->lun_mtx); + return -EBUSY; + } + + flash->lun_ro =3D ro; + dev_info(dev, "flash lun readonly set to %u\n", flash->lun_ro); + mutex_unlock(&flash->lun_mtx); + + return count; +} + +static ssize_t flash_lun_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aspeed_espi_flash *flash; + struct aspeed_espi *espi; + bool enabled; + ssize_t rc; + + espi =3D dev_get_drvdata(dev); + if (!espi) + return -ENODEV; + + flash =3D &espi->flash; + + mutex_lock(&flash->lun_mtx); + enabled =3D flash->lun && flash->lun->filp; + mutex_unlock(&flash->lun_mtx); + + rc =3D scnprintf(buf, PAGE_SIZE, "%u\n", enabled); + return rc; +} + +static ssize_t flash_lun_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aspeed_espi_flash *flash; + struct aspeed_espi *espi; + bool enable; + int rc =3D 0; + + espi =3D dev_get_drvdata(dev); + if (!espi) + return -ENODEV; + + flash =3D &espi->flash; + + rc =3D kstrtobool(buf, &enable); + if (rc) + return rc; + + mutex_lock(&flash->lun_mtx); + if (!flash->lun) { + flash->lun =3D devm_kzalloc(dev, sizeof(*flash->lun), GFP_KERNEL); + if (!flash->lun) { + rc =3D -ENOMEM; + goto out_unlock; + } + } + + if (enable) { + if (flash->lun->filp) + goto out_unlock; + if (!flash->lun_path[0]) { + rc =3D -EINVAL; + goto out_unlock; + } + + dev_info(dev, "flash lun enable: path=3D%s ro=3D%u\n", + flash->lun_path, flash->lun_ro); + mutex_lock(&flash->tx_mtx); + rc =3D aspeed_espi_lun_open(flash->lun, flash->lun_path, + flash->lun_ro, false); + mutex_unlock(&flash->tx_mtx); + } else { + if (!flash->lun->filp) + goto out_unlock; + + dev_info(dev, "flash lun disable\n"); + mutex_lock(&flash->tx_mtx); + aspeed_espi_lun_close(flash->lun); + mutex_unlock(&flash->tx_mtx); + } + +out_unlock: + mutex_unlock(&flash->lun_mtx); + if (rc) { + dev_err(dev, "flash lun enable=3D%u failed: %d\n", enable, rc); + return rc; + } + + return count; +} + +static DEVICE_ATTR_RW(flash_lun_path); +static DEVICE_ATTR_RW(flash_lun_readonly); +static DEVICE_ATTR_RW(flash_lun_enable); + +static struct attribute *aspeed_espi_flash_attrs[] =3D { + &dev_attr_flash_lun_path.attr, + &dev_attr_flash_lun_readonly.attr, + &dev_attr_flash_lun_enable.attr, + NULL, +}; + +static const struct attribute_group aspeed_espi_flash_attr_group =3D { + .attrs =3D aspeed_espi_flash_attrs, +}; =20 struct aspeed_espi_ops { void (*espi_pre_init)(struct aspeed_espi *espi); @@ -336,6 +548,12 @@ static int aspeed_espi_probe(struct platform_device *p= dev) goto err_remove_perif; } =20 + rc =3D devm_device_add_group(dev, &aspeed_espi_flash_attr_group); + if (rc) { + dev_err(dev, "cannot add flash LUN sysfs group, rc=3D%d\n", rc); + goto err_remove_flash; + } + rc =3D devm_request_irq(dev, espi->irq, espi->ops->espi_isr, 0, dev_name(dev), espi); if (rc) { --=20 2.34.1 From nobody Tue Apr 7 11:16:38 2026 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A4BD538F645; Fri, 13 Mar 2026 10:08:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396516; cv=none; b=UUfYPsZKweSgDhXbeXY7ZkISvWdofMIgmneBzpxaRz3QANy17VMqimy+Y5eIl9DepRELMJChF9/vvOymAG6um4SNKFY1r1QclcBTjd0vGN9BVedkU2LKT9dNR4xounOokNTpvxHIeqlasYbw52ZnR4mdAmTtiCtGilA/7ub+DFM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773396516; c=relaxed/simple; bh=X4P9bqw/tIokZle3LT7wc0YRJfPr51Mfgbm0e+Wf97I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=azxfiqq9eWsdJr90YhQTDZKASyvsGbv4r/48AlF5X/FSVxPkUexhYaON1XZPwCktndJvavyf/vwZK780BSwDteM4dJeDZNskcQgB7R1w8VE0SgklguFOz0P7vXDFwUyzEPHBfQ398ZWVHiCg1eqtYlTSX04knhZJnNYUi/SwdMw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Fri, 13 Mar 2026 18:08:12 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Fri, 13 Mar 2026 18:08:12 +0800 From: aspeedyh Date: Fri, 13 Mar 2026 18:07:42 +0800 Subject: [PATCH 7/7] arm: dts: aspeed: Add eSPI node for AST2600 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20260313-upstream_espi-v1-7-9504428e1f43@aspeedtech.com> References: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> In-Reply-To: <20260313-upstream_espi-v1-0-9504428e1f43@aspeedtech.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , "Andrew Jeffery" , Ryan Chen , Philipp Zabel CC: , , , , , , aspeedyh X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773396491; l=1060; i=yh_chung@aspeedtech.com; s=20260313; h=from:subject:message-id; bh=X4P9bqw/tIokZle3LT7wc0YRJfPr51Mfgbm0e+Wf97I=; b=kK0C0gMsRBFk9Iv1JxhBwvqxNK7ufbtGNrD4kw1oHLHc35n/Xyibin/aLRLMjakvBubMHuRUp n8kx0NtlapOC4TQXotHHwzP3cvScPvveTms/jil7qyQOqdBRtdJO8C3 X-Developer-Key: i=yh_chung@aspeedtech.com; a=ed25519; pk=o71dz0J8lpN+v0f3Mk4gT9PfVngADPC1Pex4aK6VigM= Add the AST2600 eSPI controller node with the register region, interrupt, clock, reset and pinctrl properties. Signed-off-by: aspeedyh --- arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/as= peed/aspeed-g6.dtsi index 189bc3bbb47c..84aec45f39e7 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi @@ -408,6 +408,17 @@ adc1: adc@1e6e9100 { status =3D "disabled"; }; =20 + espi: espi@1e6ee000 { + compatible =3D "aspeed,ast2600-espi"; + reg =3D <0x1e6ee000 0x1000>; + interrupts =3D ; + clocks =3D <&syscon ASPEED_CLK_GATE_ESPICLK>; + resets =3D <&syscon 57>; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&pinctrl_espi_default>; + status =3D "disabled"; + }; + sbc: secure-boot-controller@1e6f2000 { compatible =3D "aspeed,ast2600-sbc"; reg =3D <0x1e6f2000 0x1000>; --=20 2.34.1