From nobody Tue Dec 16 22:30:10 2025 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4F09E224AF6 for ; Thu, 29 May 2025 12:23:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=114.242.206.163 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748521435; cv=none; b=P18/MDdhsPETYFUZw1k961gsLDxbmZXw2qbCv/fksEFAh8Wqo5dlEVaGC9z9+OcQmD72AZwdmLEbJ9iWKJssx+baIB71OFoYfSjmm9FBnWYcamuDxGDsPzTSV6JEhHxNDJMRTjMyAsP3iyopttaKmbin0xeRUEsFeZui33ME668= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748521435; c=relaxed/simple; bh=3NT3baZD+yDJpuWwdd77kHSk2rPk/x6FAdk6nVYe7b4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OphwT6HaGBEtATi7RoS27yEi/IoiZNRW+bC+3q+glzhijE0/0iXYQd7Dr8bMQ8DPSo1BoeJeaAbJO/BMDKgidV+YT5hi5jiD1DHkxntG7VhmBSL41l+S+i+UE0hMjNDNB5kFbD7thgBzXwwPMa3XksEuj99d81ZF4MjEUxgp1io= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn; spf=pass smtp.mailfrom=loongson.cn; arc=none smtp.client-ip=114.242.206.163 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=loongson.cn Received: from loongson.cn (unknown [223.64.69.3]) by gateway (Coremail) with SMTP id _____8DxjXLSUThosRkCAQ--.21716S3; Thu, 29 May 2025 20:23:46 +0800 (CST) Received: from localhost.localdomain (unknown [223.64.69.3]) by front1 (Coremail) with SMTP id qMiowMDxu8TFUTho4J76AA--.53528S4; Thu, 29 May 2025 20:23:43 +0800 (CST) From: Binbin Zhou To: Binbin Zhou , Huacai Chen , Lee Jones , Corey Minyard Cc: Huacai Chen , Xuerui Wang , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, openipmi-developer@lists.sourceforge.net, jeffbai@aosc.io, kexybiscuit@aosc.io, wangyao@lemote.com, Binbin Zhou , Chong Qiao Subject: [PATCH v3 2/3] ipmi: Add Loongson-2K BMC support Date: Thu, 29 May 2025 20:23:23 +0800 Message-ID: <01805f8d1b9c8e6564a2d6d83964f78ed29b8f1f.1748505446.git.zhoubinbin@loongson.cn> X-Mailer: git-send-email 2.47.1 In-Reply-To: References: 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 X-CM-TRANSID: qMiowMDxu8TFUTho4J76AA--.53528S4 X-CM-SenderInfo: p2kr3uplqex0o6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBj93XoW3Ar17uFW5uw1xJF17tFWftFc_yoW3urWfp3 Waya43Cr48tF47K397ZryDWFyrAwnxW3Wrtr47W34ruFWj9w1vgr1vya4Syry7ta40q3y3 JrZ8ArW3WF13JwcCm3ZEXasCq-sJn29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUB0b4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1Y6r17M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_ GcCE3s1ln4kS14v26r126r1DM2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2 x26I8E6xACxx1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1q6rW5 McIj6I8E87Iv67AKxVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr4 1lc7CjxVAaw2AFwI0_JF0_Jw1l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_ Gr1l4IxYO2xFxVAFwI0_JF0_Jw1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67 AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8I cVAFwI0_Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAvwI 8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87Iv6xkF7I0E14v2 6r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxU4Xo7DUUUU Content-Type: text/plain; charset="utf-8" This patch adds Loongson-2K BMC IPMI support. According to the existing design, we use software simulation to implement the KCS interface registers: Stauts/Command/Data_Out/Data_In. Also since both host side and BMC side read and write kcs status, fifo flag is used to ensure data consistency. The single KCS message block is as follows: +-------------------------------------------------------------------------+ |FIFO flags| KCS register data | CMD data | KCS version | WR REQ | WR ACK | +-------------------------------------------------------------------------+ Co-developed-by: Chong Qiao Signed-off-by: Chong Qiao Signed-off-by: Binbin Zhou --- drivers/char/ipmi/Makefile | 1 + drivers/char/ipmi/ipmi_si.h | 7 ++ drivers/char/ipmi/ipmi_si_intf.c | 3 + drivers/char/ipmi/ipmi_si_ls2k.c | 190 +++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 drivers/char/ipmi/ipmi_si_ls2k.c diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index e0944547c9d0..17308dd6be20 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -8,6 +8,7 @@ ipmi_si-y :=3D ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o = ipmi_bt_sm.o \ ipmi_si_mem_io.o ipmi_si-$(CONFIG_HAS_IOPORT) +=3D ipmi_si_port_io.o ipmi_si-$(CONFIG_PCI) +=3D ipmi_si_pci.o +ipmi_si-$(CONFIG_MFD_LS2K_BMC) +=3D ipmi_si_ls2k.o ipmi_si-$(CONFIG_PARISC) +=3D ipmi_si_parisc.o =20 obj-$(CONFIG_IPMI_HANDLER) +=3D ipmi_msghandler.o diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index 508c3fd45877..f38ea4f4c891 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -101,6 +101,13 @@ void ipmi_si_pci_shutdown(void); static inline void ipmi_si_pci_init(void) { } static inline void ipmi_si_pci_shutdown(void) { } #endif +#ifdef CONFIG_MFD_LS2K_BMC +void ipmi_si_ls2k_init(void); +void ipmi_si_ls2k_shutdown(void); +#else +static inline void ipmi_si_ls2k_init(void) { } +static inline void ipmi_si_ls2k_shutdown(void) { } +#endif #ifdef CONFIG_PARISC void ipmi_si_parisc_init(void); void ipmi_si_parisc_shutdown(void); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_i= ntf.c index 7fe891783a37..c13d5132fffc 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2120,6 +2120,7 @@ static int __init init_ipmi_si(void) =20 ipmi_si_pci_init(); =20 + ipmi_si_ls2k_init(); ipmi_si_parisc_init(); =20 mutex_lock(&smi_infos_lock); @@ -2334,6 +2335,8 @@ static void cleanup_ipmi_si(void) =20 ipmi_si_pci_shutdown(); =20 + ipmi_si_ls2k_shutdown(); + ipmi_si_parisc_shutdown(); =20 ipmi_si_platform_shutdown(); diff --git a/drivers/char/ipmi/ipmi_si_ls2k.c b/drivers/char/ipmi/ipmi_si_l= s2k.c new file mode 100644 index 000000000000..71159e9882b7 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_ls2k.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Loongson-2K BMC IPMI + * + * Copyright (C) 2024-2025 Loongson Technology Corporation Limited. + * + * Authors: + * Chong Qiao + * Binbin Zhou + */ + +#include +#include +#include +#include + +#include "ipmi_si.h" + +#define LS2K_KCS_FIFO_IBFH 0x0 +#define LS2K_KCS_FIFO_IBFT 0x1 +#define LS2K_KCS_FIFO_OBFH 0x2 +#define LS2K_KCS_FIFO_OBFT 0x3 + +/* KCS registers */ +#define LS2K_KCS_REG_STS 0x4 +#define LS2K_KCS_REG_DATA_OUT 0x5 +#define LS2K_KCS_REG_DATA_IN 0x6 +#define LS2K_KCS_REG_CMD 0x8 + +#define LS2K_KCS_CMD_DATA 0xa +#define LS2K_KCS_VERSION 0xb +#define LS2K_KCS_WR_REQ 0xc +#define LS2K_KCS_WR_ACK 0x10 + +#define LS2K_KCS_STS_OBF BIT(0) +#define LS2K_KCS_STS_IBF BIT(1) +#define LS2K_KCS_STS_SMS_ATN BIT(2) +#define LS2K_KCS_STS_CMD BIT(3) + +#define LS2K_KCS_DATA_MASK (LS2K_KCS_STS_OBF | LS2K_KCS_STS_IBF | LS2K_KCS= _STS_CMD) + +static bool ls2k_registered; + +static unsigned char ls2k_mem_inb_v0(const struct si_sm_io *io, unsigned i= nt offset) +{ + void __iomem *addr =3D io->addr; + int reg_offset; + + if (offset & BIT(0)) { + reg_offset =3D LS2K_KCS_REG_STS; + } else { + writeb(readb(addr + LS2K_KCS_REG_STS) & ~LS2K_KCS_STS_OBF, + addr + LS2K_KCS_REG_STS); + reg_offset =3D LS2K_KCS_REG_DATA_OUT; + } + + return readb(addr + reg_offset); +} + +static unsigned char ls2k_mem_inb_v1(const struct si_sm_io *io, unsigned i= nt offset) +{ + void __iomem *addr =3D io->addr; + unsigned char inb =3D 0, cmd; + bool obf, ibf; + + obf =3D readb(addr + LS2K_KCS_FIFO_OBFH) ^ readb(addr + LS2K_KCS_FIFO_OBF= T); + ibf =3D readb(addr + LS2K_KCS_FIFO_IBFH) ^ readb(addr + LS2K_KCS_FIFO_IBF= T); + cmd =3D readb(addr + LS2K_KCS_CMD_DATA); + + if (offset & BIT(0)) { + inb =3D readb(addr + LS2K_KCS_REG_STS) & ~LS2K_KCS_DATA_MASK; + inb |=3D FIELD_PREP(LS2K_KCS_STS_OBF, obf) + | FIELD_PREP(LS2K_KCS_STS_IBF, ibf) + | FIELD_PREP(LS2K_KCS_STS_CMD, cmd); + } else { + inb =3D readb(addr + LS2K_KCS_REG_DATA_OUT); + writeb(readb(addr + LS2K_KCS_FIFO_OBFH), addr + LS2K_KCS_FIFO_OBFT); + } + + return inb; +} + +static void ls2k_mem_outb_v0(const struct si_sm_io *io, unsigned int offse= t, + unsigned char val) +{ + void __iomem *addr =3D io->addr; + unsigned char sts =3D readb(addr + LS2K_KCS_REG_STS); + int reg_offset; + + if (sts & LS2K_KCS_STS_IBF) + return; + + if (offset & BIT(0)) { + reg_offset =3D LS2K_KCS_REG_CMD; + sts |=3D LS2K_KCS_STS_CMD; + } else { + reg_offset =3D LS2K_KCS_REG_DATA_IN; + sts &=3D ~LS2K_KCS_STS_CMD; + } + + writew(val, addr + reg_offset); + writeb(sts | LS2K_KCS_STS_IBF, addr + LS2K_KCS_REG_STS); + writel(readl(addr + LS2K_KCS_WR_REQ) + 1, addr + LS2K_KCS_WR_REQ); +} + +static void ls2k_mem_outb_v1(const struct si_sm_io *io, unsigned int offse= t, + unsigned char val) +{ + void __iomem *addr =3D io->addr; + unsigned char ibfh, ibft; + int reg_offset; + + ibfh =3D readb(addr + LS2K_KCS_FIFO_IBFH); + ibft =3D readb(addr + LS2K_KCS_FIFO_IBFT); + + if (ibfh ^ ibft) + return; + + reg_offset =3D (offset & BIT(0)) ? LS2K_KCS_REG_CMD : LS2K_KCS_REG_DATA_I= N; + writew(val, addr + reg_offset); + + writeb(offset & BIT(0), addr + LS2K_KCS_CMD_DATA); + writeb(!ibft, addr + LS2K_KCS_FIFO_IBFH); + writel(readl(addr + LS2K_KCS_WR_REQ) + 1, addr + LS2K_KCS_WR_REQ); +} + +static void ls2k_mem_cleanup(struct si_sm_io *io) +{ + if (io->addr) + iounmap(io->addr); +} + +static int ipmi_ls2k_mem_setup(struct si_sm_io *io) +{ + unsigned char version; + + io->addr =3D ioremap(io->addr_data, io->regspacing); + if (!io->addr) + return -EIO; + + version =3D readb(io->addr + LS2K_KCS_VERSION); + + io->inputb =3D version ? ls2k_mem_inb_v1 : ls2k_mem_inb_v0; + io->outputb =3D version ? ls2k_mem_outb_v1 : ls2k_mem_outb_v0; + io->io_cleanup =3D ls2k_mem_cleanup; + + return 0; +} + +static int ipmi_ls2k_probe(struct platform_device *pdev) +{ + struct si_sm_io io; + + memset(&io, 0, sizeof(io)); + + io.si_info =3D &ipmi_kcs_si_info; + io.io_setup =3D ipmi_ls2k_mem_setup; + io.addr_data =3D pdev->resource[0].start; + io.regspacing =3D resource_size(&pdev->resource[0]); + io.dev =3D &pdev->dev; + + dev_dbg(&pdev->dev, "addr 0x%lx, spacing %d.\n", io.addr_data, io.regspac= ing); + + return ipmi_si_add_smi(&io); +} + +static void ipmi_ls2k_remove(struct platform_device *pdev) +{ + ipmi_si_remove_by_dev(&pdev->dev); +} + +struct platform_driver ipmi_ls2k_platform_driver =3D { + .driver =3D { + .name =3D "ls2k-ipmi-si", + }, + .probe =3D ipmi_ls2k_probe, + .remove =3D ipmi_ls2k_remove, +}; + +void ipmi_si_ls2k_init(void) +{ + platform_driver_register(&ipmi_ls2k_platform_driver); + ls2k_registered =3D true; +} + +void ipmi_si_ls2k_shutdown(void) +{ + if (ls2k_registered) + platform_driver_unregister(&ipmi_ls2k_platform_driver); +} --=20 2.47.1