From patchwork Mon Feb 17 11:48:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Chen X-Patchwork-Id: 13977705 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 079D8C021AA for ; Mon, 17 Feb 2025 12:30:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=c24ZfnpXfvzqiy+e9d45Tbyw532eKgHdJFd17rEpGcA=; b=4z9NtN0RbqaiCcTM73Ub4/5AqX X6IEjVtmZPtSU7Soa9Vau3bG9DIVAPGCG+VYYyGBoux/qp67NSJIB5IZ631G6PwzS5kwAoTVGl6OD Ex1IFEwE8/AtQcC73Zo92TQYmTtyiRBlIWbsUiL5sYU5MwyoGNp+mdBZ8d0LaWw/SWVG1zw2mp54s 4KBzcFqnTJ4D0sL8taFoEa866SRd2imRJd+Gqw6UJQB2OS3QJW/uSEzF3A8iUz5/oGnnVHZ/y/xMk eT9SmtI6bLNfoixxZsrwjyybIA0wf6SnoCnXBj1lXjQm1fagE8M83bzYvd7YqS3yef4Jq0U5ngzYi lgRCV0Sw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tk0GA-00000004SaI-3gr0; Mon, 17 Feb 2025 12:30:02 +0000 Received: from mail.aspeedtech.com ([211.20.114.72] helo=TWMBX01.aspeed.com) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tjzcG-00000004Mob-1XRk for linux-arm-kernel@lists.infradead.org; Mon, 17 Feb 2025 11:48:49 +0000 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.1258.12; Mon, 17 Feb 2025 19:48:33 +0800 Received: from localhost.localdomain (192.168.10.10) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Mon, 17 Feb 2025 19:48:33 +0800 From: Kevin Chen To: , , , , , , , , , CC: Kevin Chen Subject: [PATCH v1 1/3] dt-binding: aspeed: Add LPC PCC controller Date: Mon, 17 Feb 2025 19:48:29 +0800 Message-ID: <20250217114831.3225970-2-kevin_chen@aspeedtech.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250217114831.3225970-1-kevin_chen@aspeedtech.com> References: <20250217114831.3225970-1-kevin_chen@aspeedtech.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250217_034848_406148_371E5CC0 X-CRM114-Status: UNSURE ( 8.73 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add dt-bindings for Aspeed for Aspeed LPC POST code capture controller. Signed-off-by: Kevin Chen --- .../devicetree/bindings/mfd/aspeed-lpc.yaml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/aspeed-lpc.yaml b/Documentation/devicetree/bindings/mfd/aspeed-lpc.yaml index 5dfe77aca167..367847bd7e75 100644 --- a/Documentation/devicetree/bindings/mfd/aspeed-lpc.yaml +++ b/Documentation/devicetree/bindings/mfd/aspeed-lpc.yaml @@ -149,6 +149,35 @@ patternProperties: - interrupts - snoop-ports + "^lpc-pcc@[0-9a-f]+$": + type: object + additionalProperties: false + + description: + The LPC pcc interface allows the BMC to listen on and record the data + bytes written by the Host to the targeted LPC I/O pots. + + properties: + compatible: + items: + - enum: + - aspeed,ast2600-lpc-pcc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + pcc-ports: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: The LPC I/O ports to pcc + + required: + - compatible + - interrupts + - pcc-ports + "^uart-routing@[0-9a-f]+$": $ref: /schemas/soc/aspeed/uart-routing.yaml# description: The UART routing control under LPC register space @@ -176,6 +205,13 @@ examples: #size-cells = <1>; ranges = <0x0 0x1e789000 0x1000>; + lpc_pcc: lpc-pcc@0 { + compatible = "aspeed,ast2600-lpc-pcc"; + reg = <0x0 0x140>; + interrupts = ; + pcc-ports = <0x80>; + }; + lpc_ctrl: lpc-ctrl@80 { compatible = "aspeed,ast2600-lpc-ctrl"; reg = <0x80 0x80>; From patchwork Mon Feb 17 11:48:30 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Chen X-Patchwork-Id: 13977704 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F2684C021A9 for ; Mon, 17 Feb 2025 12:30:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=QcaKv08Qy4UZ66/QiM5RwvtF+D/OXc8+LxCESKR92cw=; b=FxCD5DbEpch9h7ljJGSjQv9oCv Nyu+/IdPKez19bDTftKINkWhQoDOpFEQUQXTeIzZTQgeSmx1smZYExYrX29n6tEO6YDLzIc9H6wOM +MI6Kb5CVHPwI2Utt4pedrHjbIn7Hm+SYOj8OlOqSRTx4Rarv3+KadyOj1CfXzZAFDsmkBgXz3dC9 dLQVvisXcAcdcK7lN3R48Q9Bkvq5zN57/ZDtRPtj2t8Cnulf5NH51jncs5Hp9kCYpUs+Z/4+0Xttn 7GTdMizDBYjq4KP97VF8Sk5FrTrt7+5N9ngWghv1bT7Ejz7lwjiBUwvK0K3FNwd1nyYwTaHvnuEJn yN++GLyQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tk0GC-00000004ScH-0RZd; Mon, 17 Feb 2025 12:30:04 +0000 Received: from mail.aspeedtech.com ([211.20.114.72] helo=TWMBX01.aspeed.com) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tjzcH-00000004Mob-30db for linux-arm-kernel@lists.infradead.org; Mon, 17 Feb 2025 11:48:50 +0000 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.1258.12; Mon, 17 Feb 2025 19:48:33 +0800 Received: from localhost.localdomain (192.168.10.10) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Mon, 17 Feb 2025 19:48:33 +0800 From: Kevin Chen To: , , , , , , , , , CC: Kevin Chen Subject: [PATCH v1 2/3] ARM: dts: aspeed-g6: Add AST2600 LPC PCC support Date: Mon, 17 Feb 2025 19:48:30 +0800 Message-ID: <20250217114831.3225970-3-kevin_chen@aspeedtech.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250217114831.3225970-1-kevin_chen@aspeedtech.com> References: <20250217114831.3225970-1-kevin_chen@aspeedtech.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250217_034849_752692_ECBC56D6 X-CRM114-Status: UNSURE ( 6.48 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The AST2600 has PCC controller in LPC, placed in LPC node. Signed-off-by: Kevin Chen --- arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi index 8ed715bd53aa..87dcacb78692 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed/aspeed-g6.dtsi @@ -626,6 +626,13 @@ lpc_snoop: lpc-snoop@80 { status = "disabled"; }; + lpc_pcc: lpc-pcc@0 { + compatible = "aspeed,ast2600-lpc-pcc"; + reg = <0x0 0x140>; + interrupts = ; + status = "disabled"; + }; + lhc: lhc@a0 { compatible = "aspeed,ast2600-lhc"; reg = <0xa0 0x24 0xc8 0x8>; From patchwork Mon Feb 17 11:48:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Chen X-Patchwork-Id: 13977706 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3482BC021A9 for ; Mon, 17 Feb 2025 12:30:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date :Subject:CC:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=wDYtfnrJr8SdnA7RFhbKz0HlTlGCJrZQzbCc+e/FIXQ=; b=00VJVLD7pb0wi7QEh1wvpjidC/ dAlrtNtCC1mQMrY9fs8lrm/DvgRuImWMhaVnQ/cNMeytKzIWLJ/BBITQH7yOAfSx945Aeoj7+K60R GoMsUqRLMrlNb9anPJ9P3o2t7Z5Svu3hncG2qxIYaueFNsxjiL5LP9ecHAWKSsOhCRzcYeJPc677o p+P4GhW10D+0nHgnZhk9oYWgqBh+orm5kvPb5dRBnEBYVBUnuSDO17yRuRoOPKuZe0+F+aw74VWny joJPemvzFHkA5wA5w3My5U9I1uVHrPEIm1nuJ07iv0dDx7M9xdOD/3lWc7REickwwEvwYuTel7OHl UGIM5ung==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tk0GD-00000004SfM-29G2; Mon, 17 Feb 2025 12:30:05 +0000 Received: from mail.aspeedtech.com ([211.20.114.72] helo=TWMBX01.aspeed.com) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tjzcJ-00000004Mob-0Oz8 for linux-arm-kernel@lists.infradead.org; Mon, 17 Feb 2025 11:48:52 +0000 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.1258.12; Mon, 17 Feb 2025 19:48:33 +0800 Received: from localhost.localdomain (192.168.10.10) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Mon, 17 Feb 2025 19:48:33 +0800 From: Kevin Chen To: , , , , , , , , , CC: Kevin Chen Subject: [PATCH v1 3/3] soc: aspeed: lpc-pcc: Add PCC controller support Date: Mon, 17 Feb 2025 19:48:31 +0800 Message-ID: <20250217114831.3225970-4-kevin_chen@aspeedtech.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250217114831.3225970-1-kevin_chen@aspeedtech.com> References: <20250217114831.3225970-1-kevin_chen@aspeedtech.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250217_034851_147210_169A39B2 X-CRM114-Status: GOOD ( 25.89 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add LPC PCC controller driver to support POST code capture. Signed-off-by: Kevin Chen --- drivers/soc/aspeed/Kconfig | 10 + drivers/soc/aspeed/Makefile | 1 + drivers/soc/aspeed/aspeed-lpc-pcc.c | 439 ++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+) create mode 100644 drivers/soc/aspeed/aspeed-lpc-pcc.c diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig index f579ee0b5afa..dff1a82f4201 100644 --- a/drivers/soc/aspeed/Kconfig +++ b/drivers/soc/aspeed/Kconfig @@ -52,6 +52,16 @@ config ASPEED_SOCINFO help Say yes to support decoding of ASPEED BMC information. +config ASPEED_LPC_PCC + tristate "Aspeed Post Code Capture support" + select REGMAP + select MFD_SYSCON + default ARCH_ASPEED + help + Provides a driver to control the LPC PCC interface, + allowing the BMC to capture post code written by the + the host to an arbitrary LPC I/O port. + endmenu endif diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile index b35d74592964..1692350b3512 100644 --- a/drivers/soc/aspeed/Makefile +++ b/drivers/soc/aspeed/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o +obj-$(CONFIG_ASPEED_LPC_PCC) += aspeed-lpc-pcc.o diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspeed-lpc-pcc.c new file mode 100644 index 000000000000..a9733dc932a2 --- /dev/null +++ b/drivers/soc/aspeed/aspeed-lpc-pcc.c @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME "aspeed-lpc-pcc" + +static DEFINE_IDA(aspeed_pcc_ida); + +#define HICR5 0x80 +#define HICR5_EN_SNP0W BIT(0) +#define HICR5_EN_SNP1W BIT(2) +#define HICR6 0x084 +#define HICR6_EN2BMODE BIT(19) +#define SNPWADR 0x090 +#define PCCR6 0x0c4 +#define PCCR6_DMA_CUR_ADDR GENMASK(27, 0) +#define PCCR4 0x0d0 +#define PCCR4_DMA_ADDRL_MASK GENMASK(31, 0) +#define PCCR4_DMA_ADDRL_SHIFT 0 +#define PCCR5 0x0d4 +#define PCCR5_DMA_ADDRH_MASK GENMASK(27, 24) +#define PCCR5_DMA_ADDRH_SHIFT 24 +#define PCCR5_DMA_LEN_MASK GENMASK(23, 0) +#define PCCR5_DMA_LEN_SHIFT 0 +#define HICRB 0x100 +#define HICRB_ENSNP0D BIT(14) +#define HICRB_ENSNP1D BIT(15) +#define PCCR0 0x130 +#define PCCR0_EN_DMA_INT BIT(31) +#define PCCR0_EN_DMA_MODE BIT(14) +#define PCCR0_ADDR_SEL_MASK GENMASK(13, 12) +#define PCCR0_ADDR_SEL_SHIFT 12 +#define PCCR0_RX_TRIG_LVL_MASK GENMASK(10, 8) +#define PCCR0_RX_TRIG_LVL_SHIFT 8 +#define PCCR0_CLR_RX_FIFO BIT(7) +#define PCCR0_MODE_SEL_MASK GENMASK(5, 4) +#define PCCR0_MODE_SEL_SHIFT 4 +#define PCCR0_EN_RX_TMOUT_INT BIT(2) +#define PCCR0_EN_RX_AVAIL_INT BIT(1) +#define PCCR0_EN BIT(0) +#define PCCR1 0x134 +#define PCCR1_BASE_ADDR_MASK GENMASK(15, 0) +#define PCCR1_BASE_ADDR_SHIFT 0 +#define PCCR1_DONT_CARE_BITS_MASK GENMASK(21, 16) +#define PCCR1_DONT_CARE_BITS_SHIFT 16 +#define PCCR2 0x138 +#define PCCR2_INT_STATUS_PATTERN_B BIT(16) +#define PCCR2_INT_STATUS_PATTERN_A BIT(8) +#define PCCR2_INT_STATUS_DMA_DONE BIT(4) +#define PCCR2_INT_STATUS_DATA_RDY PCCR2_INT_STATUS_DMA_DONE +#define PCCR2_INT_STATUS_RX_OVER BIT(3) +#define PCCR2_INT_STATUS_RX_TMOUT BIT(2) +#define PCCR2_INT_STATUS_RX_AVAIL BIT(1) +#define PCCR3 0x13c +#define PCCR3_FIFO_DATA_MASK GENMASK(7, 0) + +#define PCC_DMA_BUFSZ (256 * SZ_1K) + +enum pcc_fifo_threshold { + PCC_FIFO_THR_1_BYTE, + PCC_FIFO_THR_1_EIGHTH, + PCC_FIFO_THR_2_EIGHTH, + PCC_FIFO_THR_3_EIGHTH, + PCC_FIFO_THR_4_EIGHTH, + PCC_FIFO_THR_5_EIGHTH, + PCC_FIFO_THR_6_EIGHTH, + PCC_FIFO_THR_7_EIGHTH, + PCC_FIFO_THR_8_EIGHTH, +}; + +enum pcc_record_mode { + PCC_REC_1B, + PCC_REC_2B, + PCC_REC_4B, + PCC_REC_FULL, +}; + +enum pcc_port_hbits_select { + PCC_PORT_HBITS_SEL_NONE, + PCC_PORT_HBITS_SEL_45, + PCC_PORT_HBITS_SEL_67, + PCC_PORT_HBITS_SEL_89, +}; + +struct aspeed_pcc_dma { + uint32_t rptr; + uint8_t *virt; + dma_addr_t addr; + uint32_t size; +}; + +struct aspeed_pcc_ctrl { + struct device *dev; + struct regmap *regmap; + int irq; + uint32_t port; + struct aspeed_pcc_dma dma; + struct kfifo fifo; + wait_queue_head_t wq; + struct miscdevice mdev; + int mdev_id; +}; + +static inline bool is_valid_rec_mode(uint32_t mode) +{ + return (mode > PCC_REC_FULL) ? false : true; +} + +static inline bool is_valid_high_bits_select(uint32_t sel) +{ + return (sel > PCC_PORT_HBITS_SEL_89) ? false : true; +} + +static ssize_t aspeed_pcc_file_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + int rc; + unsigned int copied; + struct aspeed_pcc_ctrl *pcc = container_of(file->private_data, + struct aspeed_pcc_ctrl, + mdev); + + if (kfifo_is_empty(&pcc->fifo)) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + rc = wait_event_interruptible(pcc->wq, + !kfifo_is_empty(&pcc->fifo)); + if (rc == -ERESTARTSYS) + return -EINTR; + } + + rc = kfifo_to_user(&pcc->fifo, buffer, count, &copied); + + return rc ? rc : copied; +} + +static __poll_t aspeed_pcc_file_poll(struct file *file, + struct poll_table_struct *pt) +{ + struct aspeed_pcc_ctrl *pcc = container_of(file->private_data, struct aspeed_pcc_ctrl, mdev); + + poll_wait(file, &pcc->wq, pt); + + return !kfifo_is_empty(&pcc->fifo) ? POLLIN : 0; +} + +static const struct file_operations pcc_fops = { + .owner = THIS_MODULE, + .read = aspeed_pcc_file_read, + .poll = aspeed_pcc_file_poll, +}; + +static irqreturn_t aspeed_pcc_dma_isr(int irq, void *arg) +{ + uint32_t reg, rptr, wptr; + struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; + struct kfifo *fifo = &pcc->fifo; + + regmap_write_bits(pcc->regmap, PCCR2, PCCR2_INT_STATUS_DMA_DONE, PCCR2_INT_STATUS_DMA_DONE); + + regmap_read(pcc->regmap, PCCR6, ®); + wptr = (reg & PCCR6_DMA_CUR_ADDR) - (pcc->dma.addr & PCCR6_DMA_CUR_ADDR); + rptr = pcc->dma.rptr; + + do { + if (kfifo_is_full(fifo)) + kfifo_skip(fifo); + + kfifo_put(fifo, pcc->dma.virt[rptr]); + + rptr = (rptr + 1) % pcc->dma.size; + } while (rptr != wptr); + + pcc->dma.rptr = rptr; + + wake_up_interruptible(&pcc->wq); + + return IRQ_HANDLED; +} + +static irqreturn_t aspeed_pcc_isr(int irq, void *arg) +{ + uint32_t sts; + struct aspeed_pcc_ctrl *pcc = (struct aspeed_pcc_ctrl *)arg; + + regmap_read(pcc->regmap, PCCR2, &sts); + + if (!(sts & (PCCR2_INT_STATUS_RX_TMOUT | + PCCR2_INT_STATUS_RX_AVAIL | + PCCR2_INT_STATUS_DMA_DONE))) + return IRQ_NONE; + + return aspeed_pcc_dma_isr(irq, arg); +} + +/* + * A2600-15 AP note + * + * SW workaround to prevent generating Non-Fatal-Error (NFE) + * eSPI response when PCC is used for port I/O byte snooping + * over eSPI. + */ +static int aspeed_a2600_15(struct aspeed_pcc_ctrl *pcc, struct device *dev) +{ + u32 hicr5_en, hicrb_en; + + /* abort if snoop is enabled */ + regmap_read(pcc->regmap, HICR5, &hicr5_en); + if (hicr5_en & (HICR5_EN_SNP0W | HICR5_EN_SNP1W)) { + dev_err(dev, "A2600-15 should be applied with snoop disabled\n"); + return -EPERM; + } + + /* set SNPWADR of snoop device */ + regmap_write(pcc->regmap, SNPWADR, pcc->port | ((pcc->port + 2) << 16)); + + /* set HICRB[15:14]=11b to enable ACCEPT response for SNPWADR */ + hicrb_en = HICRB_ENSNP0D | HICRB_ENSNP1D; + regmap_update_bits(pcc->regmap, HICRB, hicrb_en, hicrb_en); + + /* set HICR6[19] to extend SNPWADR to 2x range */ + regmap_update_bits(pcc->regmap, HICR6, HICR6_EN2BMODE, HICR6_EN2BMODE); + + return 0; +} + +static int aspeed_pcc_enable(struct aspeed_pcc_ctrl *pcc, struct device *dev) +{ + int rc; + + rc = aspeed_a2600_15(pcc, dev); + if (rc) + return rc; + + /* record mode: Set 2-Byte mode. */ + regmap_update_bits(pcc->regmap, PCCR0, + PCCR0_MODE_SEL_MASK, + PCC_REC_2B << PCCR0_MODE_SEL_SHIFT); + + /* port address */ + regmap_update_bits(pcc->regmap, PCCR1, + PCCR1_BASE_ADDR_MASK, + pcc->port << PCCR1_BASE_ADDR_SHIFT); + + /* Set address high bits selection to 0b01 for address bit[5:4] */ + regmap_update_bits(pcc->regmap, PCCR0, + PCCR0_ADDR_SEL_MASK, + PCC_PORT_HBITS_SEL_45 << PCCR0_ADDR_SEL_SHIFT); + + /* Set LPC don't care address to 0x3 for port 80~83h */ + regmap_update_bits(pcc->regmap, PCCR1, + PCCR1_DONT_CARE_BITS_MASK, + 0x3 << PCCR1_DONT_CARE_BITS_SHIFT); + + /* set DMA ring buffer size and enable interrupts */ + regmap_write(pcc->regmap, PCCR4, pcc->dma.addr & 0xffffffff); +#ifdef CONFIG_ARM64 + regmap_update_bits(pcc->regmap, PCCR5, PCCR5_DMA_ADDRH_MASK, + (pcc->dma.addr >> 32) << PCCR5_DMA_ADDRH_SHIFT); +#endif + regmap_update_bits(pcc->regmap, PCCR5, PCCR5_DMA_LEN_MASK, + (pcc->dma.size / 4) << PCCR5_DMA_LEN_SHIFT); + regmap_update_bits(pcc->regmap, PCCR0, + PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE, + PCCR0_EN_DMA_INT | PCCR0_EN_DMA_MODE); + + regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN, PCCR0_EN); + + return 0; +} + +static int aspeed_pcc_disable(struct aspeed_pcc_ctrl *pcc) +{ + /* Disable PCC and DMA Mode for safety */ + regmap_update_bits(pcc->regmap, PCCR0, PCCR0_EN | PCCR0_EN_DMA_MODE, 0); + + /* Clear Rx FIFO. */ + regmap_update_bits(pcc->regmap, PCCR0, PCCR0_CLR_RX_FIFO, 1); + + /* Clear All interrupts status. */ + regmap_write(pcc->regmap, PCCR2, + PCCR2_INT_STATUS_RX_OVER | PCCR2_INT_STATUS_DMA_DONE | + PCCR2_INT_STATUS_PATTERN_A | PCCR2_INT_STATUS_PATTERN_B); + + return 0; +} + +static int aspeed_pcc_probe(struct platform_device *pdev) +{ + int rc; + struct aspeed_pcc_ctrl *pcc; + struct device *dev; + uint32_t fifo_size = PAGE_SIZE; + + dev = &pdev->dev; + + pcc = devm_kzalloc(&pdev->dev, sizeof(*pcc), GFP_KERNEL); + if (!pcc) + return -ENOMEM; + + pcc->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(pcc->regmap)) { + dev_err(dev, "Couldn't get regmap\n"); + return -ENODEV; + } + + rc = of_property_read_u32(dev->of_node, "pcc-ports", &pcc->port); + if (rc) { + dev_err(dev, "no pcc ports configured\n"); + return -ENODEV; + } + + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (rc) { + dev_err(dev, "cannot set 64-bits DMA mask\n"); + return rc; + } + + pcc->dma.size = PCC_DMA_BUFSZ; + pcc->dma.virt = dmam_alloc_coherent(dev, + pcc->dma.size, + &pcc->dma.addr, + GFP_KERNEL); + if (!pcc->dma.virt) { + dev_err(dev, "cannot allocate DMA buffer\n"); + return -ENOMEM; + } + + fifo_size = roundup(pcc->dma.size, PAGE_SIZE); + rc = kfifo_alloc(&pcc->fifo, fifo_size, GFP_KERNEL); + if (rc) { + dev_err(dev, "cannot allocate kFIFO\n"); + return -ENOMEM; + } + + /* Disable PCC to clean up DMA buffer before request IRQ. */ + rc = aspeed_pcc_disable(pcc); + if (rc) { + dev_err(dev, "Couldn't disable PCC\n"); + goto err_free_kfifo; + } + + pcc->irq = platform_get_irq(pdev, 0); + if (pcc->irq < 0) { + dev_err(dev, "Couldn't get IRQ\n"); + rc = -ENODEV; + goto err_free_kfifo; + } + + rc = devm_request_irq(dev, pcc->irq, aspeed_pcc_isr, 0, DEVICE_NAME, pcc); + if (rc < 0) { + dev_err(dev, "Couldn't request IRQ %d\n", pcc->irq); + goto err_free_kfifo; + } + + init_waitqueue_head(&pcc->wq); + + pcc->mdev_id = ida_alloc(&aspeed_pcc_ida, GFP_KERNEL); + if (pcc->mdev_id < 0) { + dev_err(dev, "Couldn't allocate ID\n"); + return pcc->mdev_id; + } + + pcc->mdev.parent = dev; + pcc->mdev.minor = MISC_DYNAMIC_MINOR; + pcc->mdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, + pcc->mdev_id); + pcc->mdev.fops = &pcc_fops; + rc = misc_register(&pcc->mdev); + if (rc) { + dev_err(dev, "Couldn't register misc device\n"); + goto err_free_kfifo; + } + + rc = aspeed_pcc_enable(pcc, dev); + if (rc) { + dev_err(dev, "Couldn't enable PCC\n"); + goto err_dereg_mdev; + } + + dev_set_drvdata(&pdev->dev, pcc); + + return 0; + +err_dereg_mdev: + misc_deregister(&pcc->mdev); + +err_free_kfifo: + kfifo_free(&pcc->fifo); + + return rc; +} + +static void aspeed_pcc_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct aspeed_pcc_ctrl *pcc = dev_get_drvdata(dev); + + kfifo_free(&pcc->fifo); + misc_deregister(&pcc->mdev); +} + +static const struct of_device_id aspeed_pcc_table[] = { + { .compatible = "aspeed,ast2600-lpc-pcc" }, + { }, +}; + +static struct platform_driver aspeed_pcc_driver = { + .driver = { + .name = "aspeed-pcc", + .of_match_table = aspeed_pcc_table, + }, + .probe = aspeed_pcc_probe, + .remove = aspeed_pcc_remove, +}; + +module_platform_driver(aspeed_pcc_driver); + +MODULE_AUTHOR("Chia-Wei Wang "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Driver for Aspeed Post Code Capture");