From patchwork Fri Jun 29 09:22:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Petazzoni X-Patchwork-Id: 10495935 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A580A6016C for ; Fri, 29 Jun 2018 09:27:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 985B52998D for ; Fri, 29 Jun 2018 09:27:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8A21F2999B; Fri, 29 Jun 2018 09:27:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D29DD2998D for ; Fri, 29 Jun 2018 09:27:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=ZlqTsd41uxhv3ETQ4rWkUIDhKimo5HbDS6dVfPbCd2Q=; b=i/JKEDZu5B3074o72+sKBYra2k WdO3gcn+IM04szdc1BmExvwtgohfwSdKsAcVDHVKo2GsXqWNeaJSvow+E4EGCLJd+1ZQ/DpG1j4We 2akIsTzc1hnNoubidggiY0Ec7AgzPGexwN1QjWO6eBN0SilWNIW29+ZMxPV+0eYBABdLfQSXDz0TR MAIyX+qhEPf7W+F5IWnwO8fM1JKeqevA84W0RdXlF1ro49fzqASsLuS45fsV6sv9wRwfcgLUk1vXB i3TgzMkK7AhcSBq6z/EDfEFFgJUE1vfyzIr1i57RPxumiTDhO45O82qidYWpMQ15s9/WntXMcmlrh 4TdhC1tg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fYpgK-0001yA-7l; Fri, 29 Jun 2018 09:27:08 +0000 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fYpgI-0001w0-0K for linux-arm-kernel@bombadil.infradead.org; Fri, 29 Jun 2018 09:27:06 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=WD1GphQ5zvI5M0TJsJKUNZcRDV7d0B2RF1UU6VE8ay8=; b=B5ZRgMirAKovXIrM+gj0jvArc 0OFh9R2FgYE42h279jzb6Uixd3hqLCTtp/NxNw74yvsxWI7dtQtSi0Ln4xr9zim/WsNdsy78kPblZ 0latz8S6eVefNnKpozixtdIdXne0dIhJz35dDtxgj4wV1/DTeqjAPyNuiiEUU4p5j8FSzSwVQW7T0 6pEqu/7s9qbZ2YEZBbbW7uMnXcF9viRt33zGi67ng4hM2CfUx5ZB8BqC6gcmSvGxR2cXAur46iZF7 VCF1Bf6quYohzVX6qer0jNpQ+R4T/YT7PAFyZ4zlMPF9fqnB0l9X9aNurpvE1OL4sQ67vZyjwIdet PiRvi8Cvw==; Received: from mail.bootlin.com ([62.4.15.54]) by casper.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fYpcU-0001ls-3k for linux-arm-kernel@lists.infradead.org; Fri, 29 Jun 2018 09:23:13 +0000 Received: by mail.bootlin.com (Postfix, from userid 110) id 8CFF420DE6; Fri, 29 Jun 2018 11:23:01 +0200 (CEST) Received: from localhost (AAubervilliers-681-1-87-188.w90-88.abo.wanadoo.fr [90.88.29.188]) by mail.bootlin.com (Postfix) with ESMTPSA id AC91B20DD9; Fri, 29 Jun 2018 11:22:38 +0200 (CEST) From: Thomas Petazzoni To: Bjorn Helgaas , Lorenzo Pieralisi , linux-pci@vger.kernel.org Subject: [PATCH 3/3] PCI: aardvark: Implement emulated root PCI bridge Date: Fri, 29 Jun 2018 11:22:31 +0200 Message-Id: <20180629092231.32207-4-thomas.petazzoni@bootlin.com> X-Mailer: git-send-email 2.14.4 In-Reply-To: <20180629092231.32207-1-thomas.petazzoni@bootlin.com> References: <20180629092231.32207-1-thomas.petazzoni@bootlin.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180629_102310_318860_593B743A X-CRM114-Status: GOOD ( 23.90 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Russell King , Antoine Tenart , Gregory Clement , Maxime Chevallier , Nadav Haklai , Victor Gu , Thomas Petazzoni , =?UTF-8?q?Miqu=C3=A8l=20Raynal?= , Zachary Zhang , Wilson Ding , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Zachary Zhang The PCI controller in the Marvell Armada 3720 does not implement a root port PCI bridge at the hardware level. This causes a number of problems when using PCIe switches or when the Max Payload size needs to be aligned between the root complex and the endpoint. Implementing an emulated root PCI bridge, like is already done in the pci-mvebu driver for older Marvell platforms allows to solve those issues, and also to support features such as ASR, PME, VC, HP. Signed-off-by: Zachary Zhang [Thomas: convert to the common PCI software bridge logic.] Signed-off-by: Thomas Petazzoni --- drivers/pci/controller/Kconfig | 1 + drivers/pci/controller/pci-aardvark.c | 119 +++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 0c307f804c8d..27b29b3f34e8 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -16,6 +16,7 @@ config PCI_AARDVARK depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN + select PCI_SW_BRIDGE help Add support for Aardvark 64bit PCIe Host Controller. This controller is part of the South Bridge of the Marvel Armada diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index d3172d5d3d35..486c41721c89 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -22,10 +23,13 @@ #include "../pci.h" /* PCIe core registers */ +#define PCIE_CORE_DEV_ID_REG 0x0 #define PCIE_CORE_CMD_STATUS_REG 0x4 #define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0) #define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1) #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) +#define PCIE_CORE_DEV_REV_REG 0x8 +#define PCIE_CORE_PCIEXP_CAP 0xc0 #define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 #define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) #define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5 @@ -41,7 +45,10 @@ #define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK BIT(7) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV BIT(8) - +#define PCIE_CORE_INT_A_ASSERT_ENABLE 1 +#define PCIE_CORE_INT_B_ASSERT_ENABLE 2 +#define PCIE_CORE_INT_C_ASSERT_ENABLE 3 +#define PCIE_CORE_INT_D_ASSERT_ENABLE 4 /* PIO registers base address and register offsets */ #define PIO_BASE_ADDR 0x4000 #define PIO_CTRL (PIO_BASE_ADDR + 0x0) @@ -93,7 +100,9 @@ #define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5) #define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6) #define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10) +#define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30) #define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40) +#define PCIE_MSG_PM_PME_MASK BIT(7) #define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44) #define PCIE_ISR0_MSI_INT_PENDING BIT(24) #define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val)) @@ -207,6 +216,7 @@ struct advk_pcie { struct mutex msi_used_lock; u16 msi_msg; int root_bus_nr; + struct pci_sw_bridge bridge; }; static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg) @@ -433,6 +443,101 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie) return -ETIMEDOUT; } +static pci_sw_bridge_read_status_t +advk_pci_sw_bridge_pcie_read(struct pci_sw_bridge *bridge, + int reg, u32 *value) +{ + struct advk_pcie *pcie = bridge->data; + + switch (reg) { + case PCI_EXP_SLTCTL: + *value = PCI_EXP_SLTSTA_PDS << 16; + return PCI_SW_BRIDGE_HANDLED; + + case PCI_EXP_RTCTL: + *value = (advk_readl(pcie, PCIE_ISR0_MASK_REG) & PCIE_MSG_PM_PME_MASK) ? + PCI_EXP_RTCTL_PMEIE : 0; + return PCI_SW_BRIDGE_HANDLED; + + case PCI_EXP_RTSTA: + *value = (advk_readl(pcie, PCIE_ISR0_REG) & PCIE_MSG_PM_PME_MASK) << 16 | + (advk_readl(pcie, PCIE_MSG_LOG_REG) >> 16); + return PCI_SW_BRIDGE_HANDLED; + + case PCI_CAP_LIST_ID: + case PCI_EXP_DEVCAP: + case PCI_EXP_DEVCTL: + case PCI_EXP_LNKCAP: + case PCI_EXP_LNKCTL: + *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg); + return PCI_SW_BRIDGE_HANDLED; + default: + return PCI_SW_BRIDGE_NOT_HANDLED; + } + +} + +static void advk_pci_sw_bridge_pcie_write(struct pci_sw_bridge *bridge, + int reg, u32 old, u32 new, u32 mask) +{ + struct advk_pcie *pcie = bridge->data; + + switch (reg) { + case PCI_EXP_DEVCTL: + case PCI_EXP_LNKCTL: + advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg); + break; + + case PCI_EXP_RTCTL: + new = (new & PCI_EXP_RTCTL_PMEIE) << 3; + advk_writel(pcie, new, PCIE_ISR0_MASK_REG); + break; + + case PCI_EXP_RTSTA: + new = (new & PCI_EXP_RTSTA_PME) >> 9; + advk_writel(pcie, new, PCIE_ISR0_REG); + break; + + default: + break; + } +} + +struct pci_sw_bridge_ops advk_pci_sw_bridge_ops = { + .read_pcie = advk_pci_sw_bridge_pcie_read, + .write_pcie = advk_pci_sw_bridge_pcie_write, +}; + +/* + * Initialize the configuration space of the PCI-to-PCI bridge + * associated with the given PCIe interface. + */ +static void advk_sw_pci_bridge_init(struct advk_pcie *pcie) +{ + struct pci_sw_bridge *bridge = &pcie->bridge; + + bridge->conf.vendor = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff; + bridge->conf.device = advk_readl(pcie, PCIE_CORE_DEV_ID_REG) >> 16; + bridge->conf.revision = advk_readl(pcie, PCIE_CORE_DEV_REV_REG) & 0xff; + + /* Support 32 bits I/O addressing */ + bridge->conf.iobase = PCI_IO_RANGE_TYPE_32; + bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32; + + /* Support 64 bits memory pref */ + bridge->conf.pref_mem_base = PCI_PREF_RANGE_TYPE_64; + bridge->conf.pref_mem_limit = PCI_PREF_RANGE_TYPE_64; + + /* Support interrupt A for MSI feature */ + bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE; + + bridge->has_pcie = true; + bridge->data = pcie; + bridge->ops = &advk_pci_sw_bridge_ops; + + pci_sw_bridge_init(bridge); +} + static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { @@ -445,6 +550,9 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, return PCIBIOS_DEVICE_NOT_FOUND; } + if (bus->number == pcie->root_bus_nr) + return pci_sw_bridge_read(&pcie->bridge, where, size, val); + /* Start PIO */ advk_writel(pcie, 0, PIO_START); advk_writel(pcie, 1, PIO_ISR); @@ -452,7 +560,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (bus->number == pcie->root_bus_nr) + if (bus->primary == pcie->root_bus_nr) reg |= PCIE_CONFIG_RD_TYPE0; else reg |= PCIE_CONFIG_RD_TYPE1; @@ -497,6 +605,9 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) return PCIBIOS_DEVICE_NOT_FOUND; + if (bus->number == pcie->root_bus_nr) + return pci_sw_bridge_write(&pcie->bridge, where, size, val); + if (where % size) return PCIBIOS_SET_FAILED; @@ -507,7 +618,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (bus->number == pcie->root_bus_nr) + if (bus->primary == pcie->root_bus_nr) reg |= PCIE_CONFIG_WR_TYPE0; else reg |= PCIE_CONFIG_WR_TYPE1; @@ -922,6 +1033,8 @@ static int advk_pcie_probe(struct platform_device *pdev) advk_pcie_setup_hw(pcie); + advk_sw_pci_bridge_init(pcie); + ret = advk_pcie_init_irq_domain(pcie); if (ret) { dev_err(dev, "Failed to initialize irq\n");