From nobody Mon Feb 9 07:58:22 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 F0C15219A7C for ; Mon, 17 Feb 2025 11:48:44 +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=1739792927; cv=none; b=ph5rzkP1XPQxwiGfW2DrjOvHCwWj6YMId7z625MecfBAM3Le97RhcITRDXoXlN5rLJP8GvxI+11sBls5eYeQLwiwRhbRIyOSXVHerCcOSs23AFWIPWpp6WqP4XacXXnBsJHacfZ1kV/22fiJf7eFEqJynIHklKuNAMPqIE7yE7Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739792927; c=relaxed/simple; bh=dRTXT3uzhYit7zM3zBnkk0O1vIi6AqwtDXwnUSVAN8A=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=PepKnWisveMEukYBrOVyuW+XHRy3jhaJ+D1ubJ1oBW91myJsCO+upBRnEwqSjbpDCkBm2WqteeRASTuJX3rmSrxQ4ZfsEyta0KvY0A170HpxRRvD9UAVHOUEWMRC7iOqRIMGWN11S+4qpEChx3sgJm88hkoRK+KjzFtdylNDG/Y= 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.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> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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/Docume= ntation/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 =20 + "^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 =3D <1>; ranges =3D <0x0 0x1e789000 0x1000>; =20 + lpc_pcc: lpc-pcc@0 { + compatible =3D "aspeed,ast2600-lpc-pcc"; + reg =3D <0x0 0x140>; + interrupts =3D ; + pcc-ports =3D <0x80>; + }; + lpc_ctrl: lpc-ctrl@80 { compatible =3D "aspeed,ast2600-lpc-ctrl"; reg =3D <0x80 0x80>; --=20 2.34.1 From nobody Mon Feb 9 07:58:22 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 7BB0D21A445 for ; Mon, 17 Feb 2025 11:48:47 +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=1739792929; cv=none; b=HiJ+U3vPK9DYjimmbwp6Cp6i89PRUhkzM7qZ0HelMm/r0eQJEIUmeMBr2hh7fU5luvaI2oh28S2r3vJPDgAcMzJUo7L9jiF3UYjEErXuUTdaeGSAmxTzKuUisivG1YIFBEryftOCk0njbwharocrm/Kw13jWigmwlktLnai6M58= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739792929; c=relaxed/simple; bh=MvPXd3qEcQgukfVZwr/MRiMr3l0GliqXl4CwHKQSIJk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=SNIY/NazBjsN6blg/QWo5ywbPehjMeHB21MMrfIM+NnV3jvwSQI3mU8bvgoqSSvHprLxrEpax5DXtbvs0i6zTFpMPE6SciLKZn14ABiX5edNjiX3kQsCA09dDrU1EFrr3h+AqdTG16kGDRV8wjw34mmmHLZOBGMyCCp5O/OQuFU= 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.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> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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/as= peed/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 =3D "disabled"; }; =20 + lpc_pcc: lpc-pcc@0 { + compatible =3D "aspeed,ast2600-lpc-pcc"; + reg =3D <0x0 0x140>; + interrupts =3D ; + status =3D "disabled"; + }; + lhc: lhc@a0 { compatible =3D "aspeed,ast2600-lhc"; reg =3D <0xa0 0x24 0xc8 0x8>; --=20 2.34.1 From nobody Mon Feb 9 07:58:22 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 61AD921A45F for ; Mon, 17 Feb 2025 11:48:49 +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=1739792931; cv=none; b=Y7JaD2016WPQnO3lhwj8xEkKjqO6IsCzmBN7CAMYMKuoRW8fUV+vJKIVlADqKscYY29kk5mrHeu5PAnTKssVzMhvJOsNUsT+Qy+38ZoEg21HZomBiyMAnDF1AFcr4olT5dQTPIS72aMXyq1L2s6wMH6NTUlH84CLKs/js4FrFpc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1739792931; c=relaxed/simple; bh=xvrDZJRM4xmbhqMN1TbnjLdRnKjs3lAuKwYqnhNEqc8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MZZOV+xQL3ZUEQxcm6QwAlIIIJZJGHC1FGpbTvAkN09yI8wBCMo75calMmeRd5Lg2nYkP8+2vH8bwEFRf67S/xLikmrH6vcc0Fag2yUm9/Z/9ix+LgZuoFN9Xhb+kAFqn0f3kLVL5REDFFkGNIE3c2uPk7P9hF7ZRHmrH0QzTZ8= 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.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> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. =20 +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 =20 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) +=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_LPC_PCC) +=3D aspeed-lpc-pcc.o diff --git a/drivers/soc/aspeed/aspeed-lpc-pcc.c b/drivers/soc/aspeed/aspee= d-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 =3D 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 =3D wait_event_interruptible(pcc->wq, + !kfifo_is_empty(&pcc->fifo)); + if (rc =3D=3D -ERESTARTSYS) + return -EINTR; + } + + rc =3D 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 =3D container_of(file->private_data, struct a= speed_pcc_ctrl, mdev); + + poll_wait(file, &pcc->wq, pt); + + return !kfifo_is_empty(&pcc->fifo) ? POLLIN : 0; +} + +static const struct file_operations pcc_fops =3D { + .owner =3D THIS_MODULE, + .read =3D aspeed_pcc_file_read, + .poll =3D 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 =3D (struct aspeed_pcc_ctrl *)arg; + struct kfifo *fifo =3D &pcc->fifo; + + regmap_write_bits(pcc->regmap, PCCR2, PCCR2_INT_STATUS_DMA_DONE, PCCR2_IN= T_STATUS_DMA_DONE); + + regmap_read(pcc->regmap, PCCR6, ®); + wptr =3D (reg & PCCR6_DMA_CUR_ADDR) - (pcc->dma.addr & PCCR6_DMA_CUR_ADDR= ); + rptr =3D pcc->dma.rptr; + + do { + if (kfifo_is_full(fifo)) + kfifo_skip(fifo); + + kfifo_put(fifo, pcc->dma.virt[rptr]); + + rptr =3D (rptr + 1) % pcc->dma.size; + } while (rptr !=3D wptr); + + pcc->dma.rptr =3D 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 =3D (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]=3D11b to enable ACCEPT response for SNPWADR */ + hicrb_en =3D 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 *d= ev) +{ + int rc; + + rc =3D 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 =3D PAGE_SIZE; + + dev =3D &pdev->dev; + + pcc =3D devm_kzalloc(&pdev->dev, sizeof(*pcc), GFP_KERNEL); + if (!pcc) + return -ENOMEM; + + pcc->regmap =3D 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 =3D of_property_read_u32(dev->of_node, "pcc-ports", &pcc->port); + if (rc) { + dev_err(dev, "no pcc ports configured\n"); + return -ENODEV; + } + + rc =3D 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 =3D PCC_DMA_BUFSZ; + pcc->dma.virt =3D 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 =3D roundup(pcc->dma.size, PAGE_SIZE); + rc =3D 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 =3D aspeed_pcc_disable(pcc); + if (rc) { + dev_err(dev, "Couldn't disable PCC\n"); + goto err_free_kfifo; + } + + pcc->irq =3D platform_get_irq(pdev, 0); + if (pcc->irq < 0) { + dev_err(dev, "Couldn't get IRQ\n"); + rc =3D -ENODEV; + goto err_free_kfifo; + } + + rc =3D devm_request_irq(dev, pcc->irq, aspeed_pcc_isr, 0, DEVICE_NAME, pc= c); + 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 =3D 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 =3D dev; + pcc->mdev.minor =3D MISC_DYNAMIC_MINOR; + pcc->mdev.name =3D devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, + pcc->mdev_id); + pcc->mdev.fops =3D &pcc_fops; + rc =3D misc_register(&pcc->mdev); + if (rc) { + dev_err(dev, "Couldn't register misc device\n"); + goto err_free_kfifo; + } + + rc =3D 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 =3D &pdev->dev; + struct aspeed_pcc_ctrl *pcc =3D dev_get_drvdata(dev); + + kfifo_free(&pcc->fifo); + misc_deregister(&pcc->mdev); +} + +static const struct of_device_id aspeed_pcc_table[] =3D { + { .compatible =3D "aspeed,ast2600-lpc-pcc" }, + { }, +}; + +static struct platform_driver aspeed_pcc_driver =3D { + .driver =3D { + .name =3D "aspeed-pcc", + .of_match_table =3D aspeed_pcc_table, + }, + .probe =3D aspeed_pcc_probe, + .remove =3D 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"); --=20 2.34.1