diff --git a/MAINTAINERS b/MAINTAINERS
index 4016b3db13af..6afe1b8c6555 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4011,6 +4011,12 @@ S: Maintained
F: Documentation/devicetree/bindings/crypto/aspeed,*
F: drivers/crypto/aspeed/
+ASPEED PCI BMC DEVICE DRIVER
+M: Grégoire Layet <git@gregoirelayet.com>
+M: Tan Siewert <tan.siewert@9elements.com>
+S: Maintained
+F: drivers/mfd/aspeed-pci-core.c
+
ASPEED PECI CONTROLLER
M: Iwona Winiarska <iwona.winiarska@intel.com>
L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 763ce6a34782..dd780f72d169 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2573,5 +2573,17 @@ config MFD_MAX7360
additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_ASPEED_PCI_BMC_DEVICE
+ tristate "ASPEED BMC PCIe device"
+ depends on PCI
+ select MFD_CORE
+ help
+ Host-side driver for the ASPEED AST2600 BMC PCIe device found on
+ BMC expansion cards. Exposes two 8250-compatible VUART
+ ports.
+
+ If unsure, say N. Choose M here if this machine has an
+ AST2600-based BMC expansion card on its PCIe bus.
+
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index dd4bb7e77c33..a364b1b5936b 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -303,3 +303,5 @@ obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o
obj-$(CONFIG_MFD_LOONGSON_SE) += loongson-se.o
+
+obj-$(CONFIG_MFD_ASPEED_PCI_BMC_DEVICE) += aspeed-pci-core.o
diff --git a/drivers/mfd/aspeed-pci-core.c b/drivers/mfd/aspeed-pci-core.c
new file mode 100644
index 000000000000..ad6732133ec5
--- /dev/null
+++ b/drivers/mfd/aspeed-pci-core.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) ASPEED Technology Inc.
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+#include <linux/mfd/core.h>
+
+#define ASPEED_BMC_MULTI_MSI 32
+#define ASPEED_BMC_PCI_DEVICE_ID 0x2402
+#define ASPEED_BMC_REVISION_AST2700 0x27
+#define ASPEED_BMC_VUART 2
+
+#define DRIVER_NAME "ast2600-pci-core"
+
+static const unsigned int vuart_msi_index[ASPEED_BMC_VUART] = { 16, 17 };
+static const u16 vuart_port_addr[ASPEED_BMC_VUART] = { 0x3f8, 0x2f8 };
+
+struct aspeed_pci_bmc_dev {
+ struct plat_serial8250_port uart[ASPEED_BMC_VUART + 1];
+ struct mfd_cell cell;
+};
+
+static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev,
+ struct aspeed_pci_bmc_dev *pci_bmc_dev)
+{
+ resource_size_t bar = pci_resource_start(pdev, 1);
+ struct plat_serial8250_port *port;
+ u16 vuart_ioport;
+ unsigned int i;
+
+ for (i = 0; i < ASPEED_BMC_VUART; i++) {
+ port = &pci_bmc_dev->uart[i];
+
+ /* ASPEED BMC device shift addresses by 2 to the left */
+ vuart_ioport = vuart_port_addr[i] << 2;
+
+ port->mapbase = bar + vuart_ioport;
+ port->uartclk = 115200 * 16;
+ port->irq = pci_irq_vector(pdev, vuart_msi_index[i]);
+ port->iotype = UPIO_MEM32;
+ port->type = PORT_16550A;
+ port->flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+ port->regshift = 2;
+ }
+
+ pci_bmc_dev->cell = (struct mfd_cell) {
+ .name = "serial8250",
+ .platform_data = pci_bmc_dev->uart,
+ .pdata_size = sizeof(pci_bmc_dev->uart),
+ };
+
+ return 0;
+}
+
+static void aspeed_bmc_pci_free_irqs(void *pdev)
+{
+ pci_free_irq_vectors(pdev);
+}
+
+static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct aspeed_pci_bmc_dev *pci_bmc_dev;
+ int rc = 0;
+
+ if (pdev->revision == ASPEED_BMC_REVISION_AST2700)
+ return dev_err_probe(dev, -ENODEV, "AST2700 detected but not supported\n");
+
+ pci_bmc_dev = devm_kzalloc(dev, sizeof(*pci_bmc_dev), GFP_KERNEL);
+ if (!pci_bmc_dev)
+ return -ENOMEM;
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return dev_err_probe(dev, rc, "failed to enable device\n");
+
+ pci_set_master(pdev);
+
+ rc = pci_alloc_irq_vectors(pdev, ASPEED_BMC_MULTI_MSI, ASPEED_BMC_MULTI_MSI, PCI_IRQ_MSI);
+ if (rc < 0)
+ return dev_err_probe(dev, rc, "failed to allocate %d MSI vectors\n",
+ ASPEED_BMC_MULTI_MSI);
+
+ rc = devm_add_action_or_reset(dev, aspeed_bmc_pci_free_irqs, pdev);
+ if (rc)
+ return rc;
+
+ aspeed_pci_bmc_device_setup_vuart(pdev, pci_bmc_dev);
+
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
+ &pci_bmc_dev->cell, 1, &pdev->resource[1],
+ 0, NULL);
+}
+
+static struct pci_device_id aspeed_bmc_dev_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ASPEED, ASPEED_BMC_PCI_DEVICE_ID),
+ .class = PCI_CLASS_OTHERS << 16,
+ .class_mask = 0xFFFF00
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, aspeed_bmc_dev_pci_ids);
+
+static struct pci_driver aspeed_host_bmc_dev_driver = {
+ .name = DRIVER_NAME,
+ .id_table = aspeed_bmc_dev_pci_ids,
+ .probe = aspeed_pci_host_bmc_device_probe,
+};
+
+module_pci_driver(aspeed_host_bmc_dev_driver);
+
+MODULE_AUTHOR("Grégoire Layet <gregoire.layet@9elements.com>");
+MODULE_DESCRIPTION("Host-side driver for the ASPEED BMC PCIe device");
+MODULE_LICENSE("GPL");--
2.54.0