From nobody Fri Oct 10 21:10:20 2025 Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9799325BEF0 for ; Fri, 13 Jun 2025 06:44:06 +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=1749797048; cv=none; b=Spp+paW6V4yELnhFbd8ZRnNbhUc4s8uIqnJCOYePq/zoDe9snxV/liHHZxt+eWMBN7IjcdpeqTA23+d5uYJhthO8rL1IStW/TfKGYnL+4HlvaNzysfyINEeFhFyk1Dn3yMiAm/EJt492lQ3/0qjUqB8T78P1OaQ+O/0fnnYOJtw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749797048; c=relaxed/simple; bh=PEKi0DGSwdKIODhslH3SRmuFPbO/SNtjwACOkygV81k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GzqkZQtlvyxG9QCfVxpUIwiOOGUpV1ExpoxjZ7r3Ra2CXf+HPLadxcoLRs8cqoUXtJXktBMWE1mOmaztE7P7DOyroB2mb0I/FHR76mFwMezPwo6TI/kikQONNSPKwyqJD84lqBYcWDSG4UGwGaU4yzgvkP/sbaF7IiSmf2kuEnU= 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.68.149]) by gateway (Coremail) with SMTP id _____8AxLOKyyEtoqYwVAQ--.10707S3; Fri, 13 Jun 2025 14:44:02 +0800 (CST) Received: from localhost.localdomain (unknown [223.64.68.149]) by front1 (Coremail) with SMTP id qMiowMBx3MSlyEto29MYAQ--.8851S5; Fri, 13 Jun 2025 14:43:57 +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 v4 3/3] ipmi: Add Loongson-2K BMC support Date: Fri, 13 Jun 2025 14:43:41 +0800 Message-ID: <705a60677e848449f414206ae56515c767c12d8c.1749731531.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: qMiowMBx3MSlyEto29MYAQ--.8851S5 X-CM-SenderInfo: p2kr3uplqex0o6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBj93XoW3Ar1xAw48JrW5Gr15uF48uFX_yoW3uw1rp3 Waya43Cr48tF47K39rZryDWFyrCwnxW3Wrtr47W34ruFWj9w1vgrn2yaySyry7ta40q3y3 JrZxArW3WF13JwcCm3ZEXasCq-sJn29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUBYb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r126r13M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Cr0_Gr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6rxl6s0DM2kKe7AKxVWUAVWUtwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07AIYI kI8VC2zVCFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWrXVW3 AwAv7VC2z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI4 8JMxkF7I0En4kS14v26r126r1DMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j 6r4UMxCIbckI1I0E14v26r126r1DMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwV AFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv2 0xvE14v26ryj6F1UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20EY4 v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AK xVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU0XzstUUUUU== 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 | +-------------------------------------------------------------------------+ Reviewed-by: Huacai Chen 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 | 189 +++++++++++++++++++++++++++++++ 4 files changed, 200 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,8 @@ 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..7b360056f9c5 --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_ls2k.c @@ -0,0 +1,189 @@ +// 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_K= CS_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