From patchwork Mon Dec 30 09:31:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Binbin Zhou X-Patchwork-Id: 13923758 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 gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 E6A9AE77194 for ; Tue, 31 Dec 2024 10:35:05 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 53B5410E63B; Tue, 31 Dec 2024 10:34:58 +0000 (UTC) Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by gabe.freedesktop.org (Postfix) with ESMTP id 3CF4A10E055 for ; Mon, 30 Dec 2024 09:39:24 +0000 (UTC) Received: from loongson.cn (unknown [223.64.68.63]) by gateway (Coremail) with SMTP id _____8AxUa9naHJnDM9bAA--.50181S3; Mon, 30 Dec 2024 17:31:19 +0800 (CST) Received: from localhost.localdomain (unknown [223.64.68.63]) by front1 (Coremail) with SMTP id qMiowMCxncVkaHJnp74NAA--.4295S3; Mon, 30 Dec 2024 17:31:18 +0800 (CST) From: Binbin Zhou To: Binbin Zhou , Huacai Chen , Lee Jones , Corey Minyard , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter Cc: Huacai Chen , linux-kernel@vger.kernel.org, openipmi-developer@lists.sourceforge.net, dri-devel@lists.freedesktop.org, Xuerui Wang , loongarch@lists.linux.dev, Binbin Zhou , Chong Qiao Subject: [PATCH v1 1/4] mfd: ls2kbmc: Introduce Loongson-2K BMC MFD Core driver Date: Mon, 30 Dec 2024 17:31:08 +0800 Message-ID: <074e91224f0e48861e11954dc80c92de322906a2.1735550269.git.zhoubinbin@loongson.cn> X-Mailer: git-send-email 2.43.5 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: qMiowMCxncVkaHJnp74NAA--.4295S3 X-CM-SenderInfo: p2kr3uplqex0o6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBj93XoW3XrykWrWDAw1kJr4xKFWDJrc_yoW7uw43pF n3Jay5CF4kXF47GrsxWr1UCFsxua9Yya4jqrsrJ34avayay34UZ348tF9xZryDGryq9ry7 tFWYyw1jkFs8JabCm3ZEXasCq-sJn29KB7ZKAUJUUUU7529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUBIb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r126r13M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AK xVW8Jr0_Cr1UM2kKe7AKxVWUXVWUAwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07 AIYIkI8VC2zVCFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWU tVWrXwAv7VC2z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7V AKI48JMxkF7I0En4kS14v26r126r1DMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY 6r1j6r4UMxCIbckI1I0E14v26r1Y6r17MI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7 xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVW8ZVWrXwCIc40Y0x0EwIxGrwCI42IY6xII jxv20xvE14v26r1I6r4UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw2 0EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr1lIxAIcVC2z280aVCY1x02 67AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU8EoGPUUUUU== X-Mailman-Approved-At: Tue, 31 Dec 2024 10:34:56 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The Loongson-2K Board Management Controller provides an PCIe interface to the host to access the feature implemented in the BMC. The BMC is assembled on a server similar to the server machine with Loongson-3C6000 CPUs. It supports multiple sub-devices like DRM. Co-developed-by: Chong Qiao Signed-off-by: Chong Qiao Signed-off-by: Binbin Zhou --- drivers/mfd/Kconfig | 15 ++++ drivers/mfd/Makefile | 2 + drivers/mfd/ls2kbmc-mfd.c | 145 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 drivers/mfd/ls2kbmc-mfd.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ae23b317a64e..97d9d52b7e8a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2414,5 +2414,20 @@ config MFD_RSMU_SPI Additional drivers must be enabled in order to use the functionality of the device. +config MFD_LS2K_BMC + tristate "Loongson-2K Board Management Controller Support" + depends on LOONGARCH + select MFD_CORE + help + Say yes here to add support for the Loongson-2K BMC + which is a Board Management Controller connected to the PCIe bus. + The device supports multiple sub-devices like DRM. + This driver provides common support for accessing the devices; + additional drivers must be enabled in order to use the + functionality of the BMC device. + + This driver can also be built as a module. If so the module + will be called ls2kbmc-mfd. + endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index e057d6d6faef..3faec9638303 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -290,3 +290,5 @@ obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o + +obj-$(CONFIG_MFD_LS2K_BMC) += ls2kbmc-mfd.o diff --git a/drivers/mfd/ls2kbmc-mfd.c b/drivers/mfd/ls2kbmc-mfd.c new file mode 100644 index 000000000000..2912112c41c8 --- /dev/null +++ b/drivers/mfd/ls2kbmc-mfd.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Loongson-2K Board Management Controller (BMC) MFD Core Driver. + * + * Copyright (C) 2024 Loongson Technology Corporation Limited. + * + * Originally written by Chong Qiao + * Rewritten for mainline by Binbin Zhou + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct resource ls2k_display_resources[] = { + { + .name = "ls2kbmc-simplebuf-res", + .start = SZ_16M + SZ_2M, + .end = SZ_16M + SZ_2M + SZ_4M - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource ls2k_ipmi0_resources[] = { + { + .name = "ipmi-res0", + .start = SZ_16M + 0x00f00000, + .end = SZ_16M + 0x00f00000 + 0x1c - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource ls2k_ipmi1_resources[] = { + { + .name = "ipmi-res1", + .start = SZ_16M + 0x00f00000 + 0x1c, + .end = SZ_16M + 0x00f00000 + 0x1c * 2 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource ls2k_ipmi2_resources[] = { + { + .name = "ipmi-res2", + .start = SZ_16M + 0x00f00000 + 0x1c * 2, + .end = SZ_16M + 0x00f00000 + 0x1c * 3 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource ls2k_ipmi3_resources[] = { + { + .name = "ipmi-res3", + .start = SZ_16M + 0x00f00000 + 0x1c * 3, + .end = SZ_16M + 0x00f00000 + 0x1c * 4 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource ls2k_ipmi4_resources[] = { + { + .name = "ipmi-res4", + .start = SZ_16M + 0x00f00000 + 0x1c * 4, + .end = SZ_16M + 0x00f00000 + 0x1c * 5 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct mfd_cell ls2k_bmc_cells[] = { + { + .name = "ls2kbmc-framebuffer", + .num_resources = ARRAY_SIZE(ls2k_display_resources), + .resources = ls2k_display_resources, + }, + { + .name = "ls2k-ipmi-si", + .num_resources = ARRAY_SIZE(ls2k_ipmi0_resources), + .resources = ls2k_ipmi0_resources, + }, + { + .name = "ls2k-ipmi-si", + .num_resources = ARRAY_SIZE(ls2k_ipmi1_resources), + .resources = ls2k_ipmi1_resources, + }, + { + .name = "ls2k-ipmi-si", + .num_resources = ARRAY_SIZE(ls2k_ipmi2_resources), + .resources = ls2k_ipmi2_resources, + }, + { + .name = "ls2k-ipmi-si", + .num_resources = ARRAY_SIZE(ls2k_ipmi3_resources), + .resources = ls2k_ipmi3_resources, + }, + { + .name = "ls2k-ipmi-si", + .num_resources = ARRAY_SIZE(ls2k_ipmi4_resources), + .resources = ls2k_ipmi4_resources, + }, +}; + +static int ls2k_bmc_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int ret = 0; + + ret = pci_enable_device(dev); + if (ret) + return ret; + + ls2k_bmc_cells[0].platform_data = &dev; + ls2k_bmc_cells[0].pdata_size = sizeof(dev); + + return devm_mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO, + ls2k_bmc_cells, ARRAY_SIZE(ls2k_bmc_cells), + &dev->resource[0], 0, NULL); +} + +static void ls2k_bmc_remove(struct pci_dev *dev) +{ + pci_disable_device(dev); +} + +static struct pci_device_id ls2k_bmc_devices[] = { + { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x1a05) }, + { } +}; +MODULE_DEVICE_TABLE(pci, ls2k_bmc_devices); + +static struct pci_driver ls2k_bmc_driver = { + .name = "ls2k-bmc", + .id_table = ls2k_bmc_devices, + .probe = ls2k_bmc_probe, + .remove = ls2k_bmc_remove, +}; + +module_pci_driver(ls2k_bmc_driver); + +MODULE_DESCRIPTION("Loongson-2K BMC driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); From patchwork Mon Dec 30 09:31:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Binbin Zhou X-Patchwork-Id: 13923760 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 gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 C8285E77197 for ; Tue, 31 Dec 2024 10:35:07 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 572E010E63C; Tue, 31 Dec 2024 10:34:58 +0000 (UTC) Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by gabe.freedesktop.org (Postfix) with ESMTP id 24DA110E36E for ; Mon, 30 Dec 2024 09:36:23 +0000 (UTC) Received: from loongson.cn (unknown [223.64.68.63]) by gateway (Coremail) with SMTP id _____8Dxfa9taHJnHM9bAA--.25644S3; Mon, 30 Dec 2024 17:31:25 +0800 (CST) Received: from localhost.localdomain (unknown [223.64.68.63]) by front1 (Coremail) with SMTP id qMiowMCxncVkaHJnp74NAA--.4295S4; Mon, 30 Dec 2024 17:31:19 +0800 (CST) From: Binbin Zhou To: Binbin Zhou , Huacai Chen , Lee Jones , Corey Minyard , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter Cc: Huacai Chen , linux-kernel@vger.kernel.org, openipmi-developer@lists.sourceforge.net, dri-devel@lists.freedesktop.org, Xuerui Wang , loongarch@lists.linux.dev, Binbin Zhou , Chong Qiao Subject: [PATCH v1 2/4] ipmi: Add Loongson-2K BMC support Date: Mon, 30 Dec 2024 17:31:09 +0800 Message-ID: X-Mailer: git-send-email 2.43.5 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: qMiowMCxncVkaHJnp74NAA--.4295S4 X-CM-SenderInfo: p2kr3uplqex0o6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBj93XoW3XFyUJF17Ar45KFW7Ary8CrX_yoW3tw4Upa 15K34kCw48tF47K3srJrykZFWrJr93Wa45tFW7X3yfurW3try0grn2yFy3ZF9rKFyDKF13 tFZ8Ar43WFW7A3gCm3ZEXasCq-sJn29KB7ZKAUJUUUU7529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUBIb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1a6r1DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AK xVW8Jr0_Cr1UM2kKe7AKxVWUXVWUAwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07 AIYIkI8VC2zVCFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWU tVWrXwAv7VC2z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7V AKI48JMxkF7I0En4kS14v26r126r1DMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY 6r1j6r4UMxCIbckI1I0E14v26r1Y6r17MI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7 xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVW8ZVWrXwCIc40Y0x0EwIxGrwCI42IY6xII jxv20xvE14v26ryj6F1UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw2 0EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr1lIxAIcVC2z280aVCY1x02 67AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7IU1mii3UUUUU== X-Mailman-Approved-At: Tue, 31 Dec 2024 10:34:56 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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, I use fifo pointer to ensure data consistency. Therefore I made the whole IPMI driver independent. 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 | 8 + drivers/char/ipmi/ipmi_si_intf.c | 3 + drivers/char/ipmi/ipmi_si_ls2k.c | 250 +++++++++++++++++++++++++++++++ 4 files changed, 262 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..614be45863b4 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -7,6 +7,7 @@ ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o \ ipmi_si_mem_io.o ipmi_si-$(CONFIG_HAS_IOPORT) += ipmi_si_port_io.o +ipmi_si-$(CONFIG_LOONGARCH) += ipmi_si_ls2k.o ipmi_si-$(CONFIG_PCI) += ipmi_si_pci.o ipmi_si-$(CONFIG_PARISC) += ipmi_si_parisc.o diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index a7ead2a4c753..0a4af352a42c 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -101,6 +101,14 @@ static inline void ipmi_si_parisc_init(void) { } static inline void ipmi_si_parisc_shutdown(void) { } #endif +#ifdef CONFIG_LOONGARCH +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 + int ipmi_si_port_setup(struct si_sm_io *io); int ipmi_si_mem_setup(struct si_sm_io *io); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index eea23a3b966e..7227bc61be79 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2108,6 +2108,7 @@ static int __init init_ipmi_si(void) ipmi_si_pci_init(); ipmi_si_parisc_init(); + ipmi_si_ls2k_init(); /* We prefer devices with interrupts, but in the case of a machine with multiple BMCs we assume that there will be several instances @@ -2292,6 +2293,8 @@ static void cleanup_ipmi_si(void) ipmi_si_platform_shutdown(); + ipmi_si_ls2k_shutdown(); + mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) cleanup_one_si(e); diff --git a/drivers/char/ipmi/ipmi_si_ls2k.c b/drivers/char/ipmi/ipmi_si_ls2k.c new file mode 100644 index 000000000000..cb31bb989fca --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_ls2k.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Loongson-2K BMC IPMI + * + * Copyright (C) 2024 Loongson Technology Corporation Limited. + * + * Originally written by Chong Qiao + * Rewritten for mainline by Binbin Zhou + */ + +#include +#include +#include + +#include "ipmi_si.h" + +#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) + +/* Read and write fifo pointers for data consistency. */ +struct ls2k_fifo_flag { + u8 ibfh; + u8 ibft; + u8 obfh; + u8 obft; +}; + +struct ls2k_kcs_reg { + u8 status; + u8 data_out; + s16 data_in; + s16 cmd; +}; + +struct ls2k_kcs_data { + struct ls2k_fifo_flag fifo; + struct ls2k_kcs_reg reg; + u8 cmd_data; + u8 version; + u32 write_req; + u32 write_ack; + u32 reserved[2]; +}; + +static void ls2k_set_obf(struct ls2k_kcs_data *ik, u8 sts) +{ + ik->reg.status = (ik->reg.status & ~LS2K_KCS_STS_OBF) | (sts & BIT(0)); +} + +static void ls2k_set_ibf(struct ls2k_kcs_data *ik, u8 sts) +{ + ik->reg.status = (ik->reg.status & ~LS2K_KCS_STS_IBF) | ((sts & BIT(0)) << 1); +} + +static u8 ls2k_get_ibf(struct ls2k_kcs_data *ik) +{ + return (ik->reg.status >> 1) & BIT(0); +} + +static unsigned char intf_sim_inb_v0(struct ls2k_kcs_data *ik, + unsigned int offset) +{ + u32 inb = 0; + + switch (offset & BIT(0)) { + case 0: + inb = ik->reg.data_out; + ls2k_set_obf(ik, 0); + break; + case 1: + inb = ik->reg.status; + break; + } + + return inb; +} + +static unsigned char intf_sim_inb_v1(struct ls2k_kcs_data *ik, + unsigned int offset) +{ + u32 inb = 0; + int cmd; + bool obf, ibf; + + obf = ik->fifo.obfh != ik->fifo.obft; + ibf = ik->fifo.ibfh != ik->fifo.ibft; + cmd = ik->cmd_data; + + switch (offset & BIT(0)) { + case 0: + inb = ik->reg.data_out; + ik->fifo.obft = ik->fifo.obfh; + break; + case 1: + inb = ik->reg.status & ~LS2K_KCS_DATA_MASK; + inb |= obf | (ibf << 1) | (cmd << 3); + break; + } + + return inb; +} + +static unsigned char ls2k_mem_inb(const struct si_sm_io *io, + unsigned int offset) +{ + struct ls2k_kcs_data *ik = io->addr; + int inb = 0; + + if (ik->version == 0) + inb = intf_sim_inb_v0(ik, offset); + else if (ik->version == 1) + inb = intf_sim_inb_v1(ik, offset); + + return inb; +} + +static void intf_sim_outb_v0(struct ls2k_kcs_data *ik, unsigned int offset, + unsigned char val) +{ + if (ls2k_get_ibf(ik)) + return; + + switch (offset & BIT(0)) { + case 0: + ik->reg.data_in = val; + ik->reg.status &= ~LS2K_KCS_STS_CMD; + break; + + case 1: + ik->reg.cmd = val; + ik->reg.status |= LS2K_KCS_STS_CMD; + break; + } + + ls2k_set_ibf(ik, 1); + ik->write_req++; +} + +static void intf_sim_outb_v1(struct ls2k_kcs_data *ik, unsigned int offset, + unsigned char val) +{ + if (ik->fifo.ibfh != ik->fifo.ibft) + return; + + switch (offset & BIT(0)) { + case 0: + ik->reg.data_in = val; + ik->cmd_data = 0; + break; + + case 1: + ik->reg.cmd = val; + ik->cmd_data = 1; + break; + } + + ik->fifo.ibfh = !ik->fifo.ibft; + ik->write_req++; +} + +static void ls2k_mem_outb(const struct si_sm_io *io, unsigned int offset, + unsigned char val) +{ + struct ls2k_kcs_data *ik = io->addr; + + if (ik->version == 0) + intf_sim_outb_v0(ik, offset, val); + else if (ik->version == 1) + intf_sim_outb_v1(ik, offset, val); +} + +static void ls2k_mem_cleanup(struct si_sm_io *io) +{ + if (io->addr) + iounmap(io->addr); +} + +static int ipmi_ls2k_sim_setup(struct si_sm_io *io) +{ + io->addr = ioremap(io->addr_data, io->regspacing); + if (!io->addr) + return -EIO; + + io->inputb = ls2k_mem_inb; + io->outputb = ls2k_mem_outb; + io->io_cleanup = ls2k_mem_cleanup; + + return 0; +} + +static int ipmi_ls2k_probe(struct platform_device *pdev) +{ + struct si_sm_io io; + + dev_info(&pdev->dev, "probing via ls2k platform"); + memset(&io, 0, sizeof(io)); + + io.addr_source = SI_PLATFORM; + io.si_type = SI_KCS; + io.addr_space = IPMI_MEM_ADDR_SPACE; + io.io_setup = ipmi_ls2k_sim_setup; + io.addr_data = pdev->resource[0].start; + io.regspacing = pdev->resource[0].end - pdev->resource[0].start + 1; + io.regsize = DEFAULT_REGSIZE; + io.regshift = 0; + io.dev = &pdev->dev; + io.irq = 0; + if (io.irq) + io.irq_setup = ipmi_std_irq_setup; + + dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", + &pdev->resource[0], io.regsize, io.regspacing, io.irq); + + 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 = { + .driver = { + .name = "ls2k-ipmi-si", + }, + .probe = ipmi_ls2k_probe, + .remove = ipmi_ls2k_remove, +}; + +static bool platform_registered; +void ipmi_si_ls2k_init(void) +{ + int rv; + + rv = platform_driver_register(&ipmi_ls2k_platform_driver); + if (rv) + pr_err("Unable to register driver: %d\n", rv); + else + platform_registered = true; +} + +void ipmi_si_ls2k_shutdown(void) +{ + if (platform_registered) + platform_driver_unregister(&ipmi_ls2k_platform_driver); +} From patchwork Mon Dec 30 09:31:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Binbin Zhou X-Patchwork-Id: 13923759 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 gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 E1654E7718B for ; Tue, 31 Dec 2024 10:35:06 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4E1FE10E639; Tue, 31 Dec 2024 10:34:58 +0000 (UTC) Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by gabe.freedesktop.org (Postfix) with ESMTP id 20AAE10E36B for ; Mon, 30 Dec 2024 09:36:23 +0000 (UTC) Received: from loongson.cn (unknown [223.64.68.63]) by gateway (Coremail) with SMTP id _____8CxCeFzaHJnPM9bAA--.49583S3; Mon, 30 Dec 2024 17:31:31 +0800 (CST) Received: from localhost.localdomain (unknown [223.64.68.63]) by front1 (Coremail) with SMTP id qMiowMCxncVkaHJnp74NAA--.4295S5; Mon, 30 Dec 2024 17:31:21 +0800 (CST) From: Binbin Zhou To: Binbin Zhou , Huacai Chen , Lee Jones , Corey Minyard , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter Cc: Huacai Chen , linux-kernel@vger.kernel.org, openipmi-developer@lists.sourceforge.net, dri-devel@lists.freedesktop.org, Xuerui Wang , loongarch@lists.linux.dev, Binbin Zhou , Chong Qiao Subject: [PATCH v1 3/4] drm/ls2kbmc: Add support for Loongson-2K BMC display Date: Mon, 30 Dec 2024 17:31:10 +0800 Message-ID: <4d62076ee560b35c653a9fbced8d03ef3bdb3005.1735550269.git.zhoubinbin@loongson.cn> X-Mailer: git-send-email 2.43.5 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: qMiowMCxncVkaHJnp74NAA--.4295S5 X-CM-SenderInfo: p2kr3uplqex0o6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBj9fXoWfWr4kurykGw4xAr48Xry7Jwc_yoW8uF48Xo Z7XF13Xw48Gw1Fq39xGr1ktanavayvga93G345ur4vva1DWw1YyFW7Ww1YvFWxZr1rtr4D Zr1qvF1xJF4xJan5l-sFpf9Il3svdjkaLaAFLSUrUUUU8b8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrn0xqx4xG64xvF2IEw4CE5I8CrVC2j2Jv73VFW2AGmfu7bjvjm3AaLaJ3 UjIYCTnIWjp_UUUYC7kC6x804xWl14x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK8VAvwI 8IcIk0rVWrJVCq3wAFIxvE14AKwVWUAVWUZwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xG Y2AK021l84ACjcxK6xIIjxv20xvE14v26ryj6F1UM28EF7xvwVC0I7IYx2IY6xkF7I0E14 v26r4j6F4UM28EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Gr1j6F4UJwAaw2AFwI0_Jrv_JF1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqjxCEc2 xF0cIa020Ex4CE44I27wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcVAFwI0_ Wrv_ZF1lYx0Ex4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0xvY0x 0EwIxGrwCY1x0262kKe7AKxVWUAVWUtwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkE bVWUJVW8JwCFI7km07C267AKxVWUXVWUAwC20s026c02F40E14v26r1j6r18MI8I3I0E74 80Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_GFv_WrylIxkGc2Ij64vIr41lIxAIcVC0 I7IYx2IY67AKxVW5JVW7JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04 k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4UMIIF0xvEx4A2jsIEc7Cj xVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07j6VbgUUUUU= X-Mailman-Approved-At: Tue, 31 Dec 2024 10:34:56 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Adds a driver for the Loongson-2K BMC display as a sub-function of the BMC device. Display-related scan output buffers, sizes, and display formats are provided through the Loongson-2K BMC MFD driver. Co-developed-by: Chong Qiao Signed-off-by: Chong Qiao Signed-off-by: Binbin Zhou --- drivers/gpu/drm/tiny/Kconfig | 18 + drivers/gpu/drm/tiny/Makefile | 1 + drivers/gpu/drm/tiny/ls2kbmc.c | 636 +++++++++++++++++++++++++++++++++ 3 files changed, 655 insertions(+) create mode 100644 drivers/gpu/drm/tiny/ls2kbmc.c diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index 94cbdb1337c0..5412f639a964 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -171,6 +171,24 @@ config TINYDRM_ILI9486 If M is selected the module will be called ili9486. +config TINYDRM_LS2KBMC + tristate "DRM support for Loongson-2K BMC display" + depends on DRM && MMU + depends on MFD_LS2K_BMC + select APERTURE_HELPERS + select DRM_CLIENT_SELECTION + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER + help + DRM driver for the Loongson-2K BMC display. + + This driver assumes that the display hardware has been initialized + by the Loongson-2K BMC. Since the Loongson-2K BMC does not support + resolution detection now, the scan buffer, size and display format + are fixed and provided by the BMC. + + If M is selected the module will be called ls2kbmc. + config TINYDRM_MI0283QT tristate "DRM support for MI0283QT" depends on DRM && SPI diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile index 4aaf56f8707d..fa4e1646db77 100644 --- a/drivers/gpu/drm/tiny/Makefile +++ b/drivers/gpu/drm/tiny/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_TINYDRM_ILI9163) += ili9163.o obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o obj-$(CONFIG_TINYDRM_ILI9486) += ili9486.o +obj-$(CONFIG_TINYDRM_LS2KBMC) += ls2kbmc.o obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o obj-$(CONFIG_TINYDRM_REPAPER) += repaper.o obj-$(CONFIG_TINYDRM_SHARP_MEMORY) += sharp-memory.o diff --git a/drivers/gpu/drm/tiny/ls2kbmc.c b/drivers/gpu/drm/tiny/ls2kbmc.c new file mode 100644 index 000000000000..909d6c687193 --- /dev/null +++ b/drivers/gpu/drm/tiny/ls2kbmc.c @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * DRM driver for Loongson-2K BMC display + * + * Copyright (C) 2024 Loongson Technology Corporation Limited. + * + * Based on simpledrm + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ls2kbmc_pdata { + struct pci_dev *pdev; + struct simplefb_platform_data pd; +}; + +/* + * Helpers for simplefb_platform_data + */ + +static int +simplefb_get_validated_int(struct drm_device *dev, const char *name, + u32 value) +{ + if (value > INT_MAX) { + drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", + name, value); + return -EINVAL; + } + return (int)value; +} + +static int +simplefb_get_validated_int0(struct drm_device *dev, const char *name, + u32 value) +{ + if (!value) { + drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", + name, value); + return -EINVAL; + } + return simplefb_get_validated_int(dev, name, value); +} + +static const struct drm_format_info * +simplefb_get_validated_format(struct drm_device *dev, const char *format_name) +{ + static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; + const struct simplefb_format *fmt = formats; + const struct simplefb_format *end = fmt + ARRAY_SIZE(formats); + const struct drm_format_info *info; + + if (!format_name) { + drm_err(dev, "simplefb: missing framebuffer format\n"); + return ERR_PTR(-EINVAL); + } + + while (fmt < end) { + if (!strcmp(format_name, fmt->name)) { + info = drm_format_info(fmt->fourcc); + if (!info) + return ERR_PTR(-EINVAL); + return info; + } + ++fmt; + } + + drm_err(dev, "simplefb: unknown framebuffer format %s\n", + format_name); + + return ERR_PTR(-EINVAL); +} + +static int +simplefb_get_width_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int0(dev, "width", pd->width); +} + +static int +simplefb_get_height_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int0(dev, "height", pd->height); +} + +static int +simplefb_get_stride_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int(dev, "stride", pd->stride); +} + +static const struct drm_format_info * +simplefb_get_format_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_format(dev, pd->format); +} + +/* + * ls2kbmc Framebuffer device + */ + +struct ls2kbmc_device { + struct drm_device dev; + + /* simplefb settings */ + struct drm_display_mode mode; + const struct drm_format_info *format; + unsigned int pitch; + + /* memory management */ + struct iosys_map screen_base; + + /* modesetting */ + u32 formats[8]; + struct drm_plane primary_plane; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; + +static struct ls2kbmc_device *ls2kbmc_device_of_dev(struct drm_device *dev) +{ + return container_of(dev, struct ls2kbmc_device, dev); +} + +/* + * Modesetting + */ + +static const u64 ls2kbmc_primary_plane_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static int ls2kbmc_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_shadow_plane_state *new_shadow_plane_state = + to_drm_shadow_plane_state(new_plane_state); + struct drm_framebuffer *new_fb = new_plane_state->fb; + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + struct drm_device *dev = plane->dev; + struct ls2kbmc_device *sdev = ls2kbmc_device_of_dev(dev); + int ret; + + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); + + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + else if (!new_plane_state->visible) + return 0; + + if (new_fb->format != sdev->format) { + void *buf; + + /* format conversion necessary; reserve buffer */ + buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state, + sdev->pitch, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + return 0; +} + +static void ls2kbmc_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_device *dev = plane->dev; + struct ls2kbmc_device *sdev = ls2kbmc_device_of_dev(dev); + struct drm_atomic_helper_damage_iter iter; + struct drm_rect damage; + int ret, idx; + + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return; + + if (!drm_dev_enter(dev, &idx)) + goto out_drm_gem_fb_end_cpu_access; + + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + struct drm_rect dst_clip = plane_state->dst; + struct iosys_map dst = sdev->screen_base; + + if (!drm_rect_intersect(&dst_clip, &damage)) + continue; + + iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip)); + drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, + fb, &damage, &shadow_plane_state->fmtcnv_state); + } + + drm_dev_exit(idx); +out_drm_gem_fb_end_cpu_access: + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); +} + +static void ls2kbmc_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_device *dev = plane->dev; + struct ls2kbmc_device *sdev = ls2kbmc_device_of_dev(dev); + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; + + /* Clear screen to black if disabled */ + iosys_map_memset(&sdev->screen_base, 0, 0, sdev->pitch * sdev->mode.vdisplay); + + drm_dev_exit(idx); +} + +static int ls2kbmc_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane, + struct drm_scanout_buffer *sb) +{ + struct ls2kbmc_device *sdev = ls2kbmc_device_of_dev(plane->dev); + + sb->width = sdev->mode.hdisplay; + sb->height = sdev->mode.vdisplay; + sb->format = sdev->format; + sb->pitch[0] = sdev->pitch; + sb->map[0] = sdev->screen_base; + + return 0; +} + +static const struct drm_plane_helper_funcs ls2kbmc_primary_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = ls2kbmc_primary_plane_helper_atomic_check, + .atomic_update = ls2kbmc_primary_plane_helper_atomic_update, + .atomic_disable = ls2kbmc_primary_plane_helper_atomic_disable, + .get_scanout_buffer = ls2kbmc_primary_plane_helper_get_scanout_buffer, +}; + +static const struct drm_plane_funcs ls2kbmc_primary_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +static enum drm_mode_status ls2kbmc_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + struct ls2kbmc_device *sdev = ls2kbmc_device_of_dev(crtc->dev); + + return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sdev->mode); +} + +/* + * The CRTC is always enabled. Screen updates are performed by + * the primary plane's atomic_update function. Disabling clears + * the screen in the primary plane's atomic_disable function. + */ +static const struct drm_crtc_helper_funcs ls2kbmc_crtc_helper_funcs = { + .mode_valid = ls2kbmc_crtc_helper_mode_valid, + .atomic_check = drm_crtc_helper_atomic_check, +}; + +static const struct drm_crtc_funcs ls2kbmc_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static const struct drm_encoder_funcs ls2kbmc_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int ls2kbmc_connector_helper_get_modes(struct drm_connector *connector) +{ + struct ls2kbmc_device *sdev = ls2kbmc_device_of_dev(connector->dev); + + return drm_connector_helper_get_modes_fixed(connector, &sdev->mode); +} + +static const struct drm_connector_helper_funcs ls2kbmc_connector_helper_funcs = { + .get_modes = ls2kbmc_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs ls2kbmc_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static const struct drm_mode_config_funcs ls2kbmc_mode_config_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +/* + * Init / Cleanup + */ + +static struct drm_display_mode ls2kbmc_mode(unsigned int width, unsigned int height, + unsigned int width_mm, unsigned int height_mm) +{ + const struct drm_display_mode mode = { + DRM_MODE_INIT(60, width, height, width_mm, height_mm) + }; + + return mode; +} + +/* + * DRM driver + */ + +DEFINE_DRM_GEM_FOPS(ls2kbmc_fops); + +static struct drm_driver ls2kbmc_driver = { + DRM_GEM_SHMEM_DRIVER_OPS, + DRM_FBDEV_SHMEM_DRIVER_OPS, + .name = "simpledrm", + .desc = "DRM driver for Loongson-2K BMC", + .date = "20241211", + .major = 1, + .minor = 0, + .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, + .fops = &ls2kbmc_fops, +}; + +/* + * Currently the Loongson-2K0500 BMC hardware does not have an i2c interface to + * adapt to the resolution. + * We set the resolution by presetting "video=1280x1024-16@2M" to the bmc memory. + */ +static int ls2kbmc_get_video_mode(struct pci_dev *pdev, struct simplefb_platform_data *pd) +{ + char *mode; + int depth, ret; + + /* The pci mem bar last 16M is used to store the string. */ + mode = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0) + SZ_16M, SZ_16M); + if (!mode) + return -ENOMEM; + + /*env at last 16M's beginning, first env is video */ + if (!strncmp(mode, "video=", 6)) + mode = mode + 6; + + ret = kstrtoint(strsep(&mode, "x"), 10, &pd->width); + if (ret) + return ret; + + ret = kstrtoint(strsep(&mode, "-"), 10, &pd->height); + if (ret) + return ret; + + ret = kstrtoint(strsep(&mode, "@"), 10, &depth); + if (ret) + return ret; + + pd->stride = pd->width * depth / 8; + pd->format = depth == 32 ? "a8r8g8b8" : "r5g6b5"; + + return 0; +} + +static struct ls2kbmc_device *ls2kbmc_device_create(struct drm_driver *drv, + struct platform_device *pdev, + struct ls2kbmc_pdata *priv) +{ + struct pci_dev *ppdev = priv->pdev; + struct simplefb_platform_data *pd = &priv->pd; + struct ls2kbmc_device *sdev; + struct drm_device *dev; + int width, height, stride; + int width_mm = 0, height_mm = 0; + const struct drm_format_info *format; + struct resource *res, *mem = NULL; + struct drm_plane *primary_plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + unsigned long max_width, max_height; + void __iomem *screen_base; + size_t nformats; + int ret; + + sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct ls2kbmc_device, dev); + if (IS_ERR(sdev)) + return ERR_CAST(sdev); + dev = &sdev->dev; + platform_set_drvdata(pdev, sdev); + + ret = ls2kbmc_get_video_mode(ppdev, pd); + if (ret) { + drm_err(dev, "no simplefb configuration found\n"); + return ERR_PTR(ret); + } + + width = simplefb_get_width_pd(dev, pd); + if (width < 0) + return ERR_PTR(width); + + height = simplefb_get_height_pd(dev, pd); + if (height < 0) + return ERR_PTR(height); + + stride = simplefb_get_stride_pd(dev, pd); + if (stride < 0) + return ERR_PTR(stride); + + if (!stride) { + stride = drm_format_info_min_pitch(format, 0, width); + if (drm_WARN_ON(dev, !stride)) + return ERR_PTR(-EINVAL); + } + + format = simplefb_get_format_pd(dev, pd); + if (IS_ERR(format)) + return ERR_CAST(format); + + /* + * Assume a monitor resolution of 96 dpi if physical dimensions + * are not specified to get a somewhat reasonable screen size. + */ + if (!width_mm) + width_mm = DRM_MODE_RES_MM(width, 96ul); + if (!height_mm) + height_mm = DRM_MODE_RES_MM(height, 96ul); + + sdev->mode = ls2kbmc_mode(width, height, width_mm, height_mm); + sdev->format = format; + sdev->pitch = stride; + + drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sdev->mode)); + drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d byte\n", + &format->format, width, height, stride); + + /* + * Memory management + */ + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return ERR_PTR(-EINVAL); + + ret = aperture_remove_conflicting_pci_devices(ppdev, ls2kbmc_driver.name); + if (ret) { + drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret); + return ERR_PTR(ret); + } + + drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res); + + mem = devm_request_mem_region(&ppdev->dev, res->start, resource_size(res), + drv->name); + if (!mem) { + /* + * We cannot make this fatal. Sometimes this comes from magic + * spaces our resource handlers simply don't know about. Use + * the I/O-memory resource as-is and try to map that instead. + */ + drm_warn(dev, "could not acquire memory region %pr\n", res); + mem = res; + } + + screen_base = devm_ioremap_wc(&ppdev->dev, mem->start, resource_size(mem)); + if (!screen_base) + return ERR_PTR(-ENOMEM); + + iosys_map_set_vaddr_iomem(&sdev->screen_base, screen_base); + + /* + * Modesetting + */ + + ret = drmm_mode_config_init(dev); + if (ret) + return ERR_PTR(ret); + + max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); + max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); + + dev->mode_config.min_width = width; + dev->mode_config.max_width = max_width; + dev->mode_config.min_height = height; + dev->mode_config.max_height = max_height; + dev->mode_config.preferred_depth = format->depth; + dev->mode_config.funcs = &ls2kbmc_mode_config_funcs; + + /* Primary plane */ + + nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, + sdev->formats, ARRAY_SIZE(sdev->formats)); + + primary_plane = &sdev->primary_plane; + ret = drm_universal_plane_init(dev, primary_plane, 0, &ls2kbmc_primary_plane_funcs, + sdev->formats, nformats, + ls2kbmc_primary_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ERR_PTR(ret); + drm_plane_helper_add(primary_plane, &ls2kbmc_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + /* CRTC */ + + crtc = &sdev->crtc; + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &ls2kbmc_crtc_funcs, NULL); + if (ret) + return ERR_PTR(ret); + drm_crtc_helper_add(crtc, &ls2kbmc_crtc_helper_funcs); + + /* Encoder */ + + encoder = &sdev->encoder; + ret = drm_encoder_init(dev, encoder, &ls2kbmc_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ERR_PTR(ret); + encoder->possible_crtcs = drm_crtc_mask(crtc); + + /* Connector */ + + connector = &sdev->connector; + ret = drm_connector_init(dev, connector, &ls2kbmc_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); + if (ret) + return ERR_PTR(ret); + drm_connector_helper_add(connector, &ls2kbmc_connector_helper_funcs); + drm_connector_set_panel_orientation_with_quirk(connector, + DRM_MODE_PANEL_ORIENTATION_UNKNOWN, + width, height); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + + return sdev; +} + +/* + * Platform driver + */ + +static int ls2kbmc_probe(struct platform_device *pdev) +{ + struct ls2kbmc_device *sdev; + struct ls2kbmc_pdata *priv; + struct drm_device *dev; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (IS_ERR(priv)) + return -ENOMEM; + + priv->pdev = *(struct pci_dev **)dev_get_platdata(&pdev->dev); + + sdev = ls2kbmc_device_create(&ls2kbmc_driver, pdev, priv); + if (IS_ERR(sdev)) + return PTR_ERR(sdev); + dev = &sdev->dev; + + ret = drm_dev_register(dev, 0); + if (ret) + return ret; + + drm_client_setup(dev, sdev->format); + + return 0; +} + +static void ls2kbmc_remove(struct platform_device *pdev) +{ + struct ls2kbmc_device *sdev = platform_get_drvdata(pdev); + struct drm_device *dev = &sdev->dev; + + drm_dev_unplug(dev); +} + +static struct platform_driver ls2kbmc_platform_driver = { + .driver = { + .name = "ls2kbmc-framebuffer", + }, + .probe = ls2kbmc_probe, + .remove = ls2kbmc_remove, +}; + +module_platform_driver(ls2kbmc_platform_driver); + +MODULE_DESCRIPTION("DRM driver for Loongson-2K BMC"); +MODULE_LICENSE("GPL"); From patchwork Mon Dec 30 09:31:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Binbin Zhou X-Patchwork-Id: 13923757 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 gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (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 65824E7718B for ; Tue, 31 Dec 2024 10:35:03 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 427C710E637; Tue, 31 Dec 2024 10:34:58 +0000 (UTC) X-Greylist: delayed 302 seconds by postgrey-1.36 at gabe; Mon, 30 Dec 2024 09:36:24 UTC Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by gabe.freedesktop.org (Postfix) with ESMTP id 1F5AF10E055 for ; Mon, 30 Dec 2024 09:36:23 +0000 (UTC) Received: from loongson.cn (unknown [223.64.68.63]) by gateway (Coremail) with SMTP id _____8Dx2uGBaHJnc89bAA--.52560S3; Mon, 30 Dec 2024 17:31:45 +0800 (CST) Received: from localhost.localdomain (unknown [223.64.68.63]) by front1 (Coremail) with SMTP id qMiowMCxbcd5aHJnyL4NAA--.3877S2; Mon, 30 Dec 2024 17:31:38 +0800 (CST) From: Binbin Zhou To: Binbin Zhou , Huacai Chen , Lee Jones , Corey Minyard , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter Cc: Huacai Chen , linux-kernel@vger.kernel.org, openipmi-developer@lists.sourceforge.net, dri-devel@lists.freedesktop.org, Xuerui Wang , loongarch@lists.linux.dev, Binbin Zhou , Chong Qiao Subject: [PATCH v1 4/4] drm/ls2kbmc: Add Loongson-2K BMC reset function support Date: Mon, 30 Dec 2024 17:31:36 +0800 Message-ID: X-Mailer: git-send-email 2.43.5 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: qMiowMCxbcd5aHJnyL4NAA--.3877S2 X-CM-SenderInfo: p2kr3uplqex0o6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBj93XoWxKw4UZrWDJrW3AF1DZr4xAFc_yoWfuF1rpF W5Aa4rtrWUtr1YgrZrX3WUCwsxKwn0qay7GFyIq3Zaya1avryDZFyrtF1fZF1fJrWkAr13 X3ySkFW7uFyDA3gCm3ZEXasCq-sJn29KB7ZKAUJUUUU7529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUBvb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1Y6r17M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Cr0_Gr1UM28EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAF wI0_Gr1j6F4UJwAaw2AFwI0_Jrv_JF1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqjxCEc2 xF0cIa020Ex4CE44I27wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcVAFwI0_ Wrv_ZF1lYx0Ex4A2jsIE14v26F4j6r4UJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2 Ij64vIr41lc7CjxVAaw2AFwI0_JF0_Jw1l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Y z7v_Jr0_Gr1l4IxYO2xFxVAFwI0_Jrv_JF1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x 8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r4a6rW5MIIYrxkI7VAKI48JMIIF0xvE 2Ix0cI8IcVAFwI0_Ar0_tr1lIxAIcVC0I7IYx2IY6xkF7I0E14v26F4j6r4UJwCI42IY6x AIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Cr0_Gr1UMIIF0xvEx4A2jsIE c7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07jVeHDUUUUU= X-Mailman-Approved-At: Tue, 31 Dec 2024 10:34:56 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Since the display is a sub-function of the Loongson-2K BMC, when the BMC reset, the entire BMC PCIe is disconnected, including the display which is interrupted. Not only do you need to save/restore the relevant PCIe registers throughout the reset process, but you also need to re-push the display to the monitor at the end. Co-developed-by: Chong Qiao Signed-off-by: Chong Qiao Signed-off-by: Binbin Zhou --- drivers/gpu/drm/tiny/ls2kbmc.c | 284 ++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/ls2kbmc.c b/drivers/gpu/drm/tiny/ls2kbmc.c index 909d6c687193..4b440f20cb4d 100644 --- a/drivers/gpu/drm/tiny/ls2kbmc.c +++ b/drivers/gpu/drm/tiny/ls2kbmc.c @@ -8,10 +8,12 @@ */ #include +#include #include #include #include #include +#include #include #include @@ -32,9 +34,27 @@ #include #include +#define BMC_RESET_DELAY (60 * HZ) +#define BMC_RESET_WAIT 10000 + +static const u32 index[] = { 0x4, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x24, + 0x30, 0x3c, 0x54, 0x58, 0x78, 0x7c, 0x80 }; +static const u32 cindex[] = { 0x4, 0x10, 0x3c }; + +struct ls2kbmc_pci_data { + u32 d80c; + u32 d71c; + u32 data[14]; + u32 cdata[3]; +}; + struct ls2kbmc_pdata { struct pci_dev *pdev; + struct drm_device *ddev; + struct work_struct bmc_work; + unsigned long reset_time; struct simplefb_platform_data pd; + struct ls2kbmc_pci_data pci_data; }; /* @@ -583,6 +603,265 @@ static struct ls2kbmc_device *ls2kbmc_device_create(struct drm_driver *drv, return sdev; } +static bool ls2kbmc_bar0_addr_is_set(struct pci_dev *ppdev) +{ + u32 addr; + + pci_read_config_dword(ppdev, PCI_BASE_ADDRESS_0, &addr); + addr &= PCI_BASE_ADDRESS_MEM_MASK; + + return addr ? true : false; +} + +static void ls2kbmc_save_pci_data(struct ls2kbmc_pdata *priv) +{ + struct pci_dev *pdev = priv->pdev; + struct pci_dev *parent = pdev->bus->self; + int i; + + for (i = 0; i < ARRAY_SIZE(index); i++) + pci_read_config_dword(parent, index[i], &priv->pci_data.data[i]); + + for (i = 0; i < ARRAY_SIZE(cindex); i++) + pci_read_config_dword(pdev, cindex[i], &priv->pci_data.cdata[i]); + + pci_read_config_dword(parent, 0x80c, &priv->pci_data.d80c); + priv->pci_data.d80c = (priv->pci_data.d80c & ~(3 << 17)) | (1 << 17); + + pci_read_config_dword(parent, 0x71c, &priv->pci_data.d71c); + priv->pci_data.d71c |= 1 << 26; +} + +static bool ls2kbmc_check_pcie_connected(struct pci_dev *parent, struct drm_device *dev) +{ + void __iomem *mmio; + int sts, timeout = 10000; + + mmio = pci_iomap(parent, 0, 0x100); + if (!mmio) + return false; + + writel(readl(mmio) | 0x8, mmio); + while (timeout) { + sts = readl(mmio + 0xc); + if ((sts & 0x11) == 0x11) + break; + mdelay(1); + timeout--; + } + + pci_iounmap(parent, mmio); + + if (!timeout) { + drm_err(dev, "pcie train failed status=0x%x\n", sts); + return false; + } + + return true; +} + +static int ls2kbmc_recove_pci_data(void *data) +{ + struct ls2kbmc_pdata *priv = data; + struct pci_dev *pdev = priv->pdev; + struct drm_device *dev = priv->ddev; + struct pci_dev *parent = pdev->bus->self; + u32 i, timeout, retry = 0; + bool ready; + + pci_write_config_dword(parent, PCI_BASE_ADDRESS_2, 0); + pci_write_config_dword(parent, PCI_BASE_ADDRESS_3, 0); + pci_write_config_dword(parent, PCI_BASE_ADDRESS_4, 0); + + timeout = 10000; + while (timeout) { + ready = ls2kbmc_bar0_addr_is_set(parent); + if (!ready) + break; + mdelay(1); + timeout--; + }; + + if (!timeout) + drm_warn(dev, "bar not clear 0\n"); + +retrain: + for (i = 0; i < ARRAY_SIZE(index); i++) + pci_write_config_dword(parent, index[i], priv->pci_data.data[i]); + + pci_write_config_dword(parent, 0x80c, priv->pci_data.d80c); + pci_write_config_dword(parent, 0x71c, priv->pci_data.d71c); + + /* Check if the pcie is connected */ + ready = ls2kbmc_check_pcie_connected(parent, dev); + if (!ready) + return ready; + + for (i = 0; i < ARRAY_SIZE(cindex); i++) + pci_write_config_dword(pdev, cindex[i], priv->pci_data.cdata[i]); + + drm_info(dev, "pcie recovered done\n"); + + if (!retry) { + /*wait u-boot ddr config */ + mdelay(BMC_RESET_WAIT); + ready = ls2kbmc_bar0_addr_is_set(parent); + if (!ready) { + retry = 1; + goto retrain; + } + } + + return 0; +} + +static int ls2kbmc_push_drm_mode(struct drm_device *dev) +{ + struct ls2kbmc_device *sdev = ls2kbmc_device_of_dev(dev); + struct drm_crtc *crtc = &sdev->crtc; + struct drm_plane *plane = crtc->primary; + struct drm_connector *connector = &sdev->connector; + struct drm_framebuffer *fb = NULL; + struct drm_mode_set set; + struct drm_modeset_acquire_ctx ctx; + int ret; + + mutex_lock(&dev->mode_config.mutex); + connector->funcs->fill_modes(connector, 4096, 4096); + mutex_unlock(&dev->mode_config.mutex); + + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); + + if (plane->state) + fb = plane->state->fb; + else + fb = plane->fb; + + if (!fb) { + drm_dbg(dev, "CRTC doesn't have current FB\n"); + ret = -EINVAL; + goto out; + } + + drm_framebuffer_get(fb); + + set.crtc = crtc; + set.x = 0; + set.y = 0; + set.mode = &sdev->mode; + set.connectors = &connector; + set.num_connectors = 1; + set.fb = fb; + + ret = crtc->funcs->set_config(&set, &ctx); + +out: + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + return ret; +} + +static void ls2kbmc_events_fn(struct work_struct *work) +{ + struct ls2kbmc_pdata *priv = container_of(work, struct ls2kbmc_pdata, bmc_work); + + /* + * The pcie is lost when the BMC resets, + * at which point access to the pcie from other CPUs + * is suspended to prevent a crash. + */ + stop_machine(ls2kbmc_recove_pci_data, priv, NULL); + + drm_info(priv->ddev, "redraw console\n"); + + /* We need to re-push the display due to previous pcie loss. */ + ls2kbmc_push_drm_mode(priv->ddev); +} + +static irqreturn_t ls2kbmc_interrupt(int irq, void *arg) +{ + struct ls2kbmc_pdata *priv = arg; + + if (system_state != SYSTEM_RUNNING) + return IRQ_HANDLED; + + /* skip interrupt in BMC_RESET_DELAY */ + if (time_after(jiffies, priv->reset_time + BMC_RESET_DELAY)) + schedule_work(&priv->bmc_work); + + priv->reset_time = jiffies; + + return IRQ_HANDLED; +} + +#define BMC_RESET_GPIO 14 +#define LOONGSON_GPIO_REG_BASE 0x1fe00500 +#define LOONGSON_GPIO_REG_SIZE 0x18 +#define LOONGSON_GPIO_OEN 0x0 +#define LOONGSON_GPIO_FUNC 0x4 +#define LOONGSON_GPIO_INTPOL 0x10 +#define LOONGSON_GPIO_INTEN 0x14 + +/* The gpio interrupt is a watchdog interrupt that is triggered when the BMC resets. */ +static int ls2kbmc_gpio_reset_handler(struct ls2kbmc_pdata *priv) +{ + int irq, ret = 0; + int gsi = 16 + (BMC_RESET_GPIO & 7); + void __iomem *gpio_base; + + /* Since Loongson-3A hardware does not support GPIO interrupt cascade, + * chip->gpio_to_irq() cannot be implemented, + * here acpi_register_gsi() is used to get gpio irq. + */ + irq = acpi_register_gsi(NULL, gsi, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW); + if (irq < 0) + return irq; + + gpio_base = ioremap(LOONGSON_GPIO_REG_BASE, LOONGSON_GPIO_REG_SIZE); + if (!gpio_base) { + acpi_unregister_gsi(gsi); + return PTR_ERR(gpio_base); + } + + writel(readl(gpio_base + LOONGSON_GPIO_OEN) | BIT(BMC_RESET_GPIO), + gpio_base + LOONGSON_GPIO_OEN); + writel(readl(gpio_base + LOONGSON_GPIO_FUNC) & ~BIT(BMC_RESET_GPIO), + gpio_base + LOONGSON_GPIO_FUNC); + writel(readl(gpio_base + LOONGSON_GPIO_INTPOL) & ~BIT(BMC_RESET_GPIO), + gpio_base + LOONGSON_GPIO_INTPOL); + writel(readl(gpio_base + LOONGSON_GPIO_INTEN) | BIT(BMC_RESET_GPIO), + gpio_base + LOONGSON_GPIO_INTEN); + + ret = request_irq(irq, ls2kbmc_interrupt, IRQF_SHARED | IRQF_TRIGGER_FALLING, + "ls2kbmc gpio", priv); + + acpi_unregister_gsi(gsi); + iounmap(gpio_base); + + return ret; +} + +static int ls2kbmc_pdata_initial(struct platform_device *pdev, struct ls2kbmc_pdata *priv) +{ + int ret; + + priv->pdev = *(struct pci_dev **)dev_get_platdata(&pdev->dev); + + ls2kbmc_save_pci_data(priv); + + INIT_WORK(&priv->bmc_work, ls2kbmc_events_fn); + + ret = request_irq(priv->pdev->irq, ls2kbmc_interrupt, + IRQF_SHARED | IRQF_TRIGGER_RISING, "ls2kbmc pcie", priv); + if (ret) { + pr_err("request_irq(%d) failed\n", priv->pdev->irq); + return ret; + } + + return ls2kbmc_gpio_reset_handler(priv); +} + /* * Platform driver */ @@ -598,12 +877,15 @@ static int ls2kbmc_probe(struct platform_device *pdev) if (IS_ERR(priv)) return -ENOMEM; - priv->pdev = *(struct pci_dev **)dev_get_platdata(&pdev->dev); + ret = ls2kbmc_pdata_initial(pdev, priv); + if (ret) + return ret; sdev = ls2kbmc_device_create(&ls2kbmc_driver, pdev, priv); if (IS_ERR(sdev)) return PTR_ERR(sdev); dev = &sdev->dev; + priv->ddev = &sdev->dev; ret = drm_dev_register(dev, 0); if (ret)