RE: [PATCHv4 16/28] PCI: mobiveil: refactor Mobiveil PCIe Host Bridge IP driver
From: "Z.q. Hou" <zhiqiang.hou@nxp.com>
Date: 2019-03-29 06:07:35
Also in:
linux-devicetree, linux-pci, lkml
Hi Lorenzo, Thanks a lot for your comments!
-----Original Message----- From: Lorenzo Pieralisi <redacted> Sent: 2019年3月29日 0:09 To: Z.q. Hou <zhiqiang.hou@nxp.com> Cc: linux-pci@vger.kernel.org; linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; bhelgaas@google.com; robh+dt@kernel.org; mark.rutland@arm.com; l.subrahmanya@mobiveil.co.in; shawnguo@kernel.org; Leo Li [off-list ref]; catalin.marinas@arm.com; will.deacon@arm.com; Mingkai Hu [off-list ref]; M.h. Lian [off-list ref]; Xiaowei Bao [off-list ref] Subject: Re: [PATCHv4 16/28] PCI: mobiveil: refactor Mobiveil PCIe Host Bridge IP driver On Thu, Mar 28, 2019 at 02:09:55AM +0000, Z.q. Hou wrote: [...]quoted
quoted
quoted
quoted
On Mon, Mar 11, 2019 at 09:32:04AM +0000, Z.q. Hou wrote:quoted
From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com> As the Mobiveil PCIe controller support RC&EP DAUL mode, and tomakequoted
quoted
quoted
quoted
quoted
platforms which integrated the Mobiveil PCIe IP more easy to addtheirquoted
quoted
quoted
quoted
quoted
drivers, this patch moved the Mobiveil driver to a new directory 'drivers/pci/controller/mobiveil' and refactored it according to the abstraction of RC&EP (EP driver will be added later).I do not want to create a subdirectory for every controller that canwork inquoted
quoted
quoted
quoted
RC&EP so drop this patch, more so given that it will be required "later",wequoted
quoted
quoted
quoted
will create a directory when and if we actually have to.Please don't drop this patch, Xiaowei Bao has sent v1 of the EP mode driver, which is depends on this patch.I understand but he will have to rebase that code anyway, I do not want to create a directory for mobiveil before I see other IPs built on it, we did not do it for the cadence and rockchip controllers either. So you will have to drop this patch and rework it.It's different from cadence and rockchip cases, they only have 1 driver, so do not need to create a directory, while we have NXP's LX2160 platform and Mobiveil's FPGA platform both use Mobiveil's GPEX IP, so we already have 2 drivers, so I think it is reasonable to collect into an new directory.Wrap your messages to 80 characters per line. OK, please follow Bjorn's guidelines when reposting and split the series as discussed.
OK, I will. Thanks, Zhiqiang
Thanks, Lorenzoquoted
Thanks, Zhiqiangquoted
Thanks, Lorenzoquoted
quoted
Thanks, Lorenzoquoted
Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com> Reviewed-by: Minghuan Lian <Minghuan.Lian@nxp.com> Reviewed-by: Subrahmanya Lingappa[off-list ref]quoted
quoted
quoted
quoted
quoted
--- V4: - no change MAINTAINERS | 2 +- drivers/pci/controller/Kconfig | 11 +- drivers/pci/controller/Makefile | 2 +- drivers/pci/controller/mobiveil/Kconfig | 24 + drivers/pci/controller/mobiveil/Makefile | 4 + .../pcie-mobiveil-host.c} | 528+++---------------quoted
quoted
quoted
.../controller/mobiveil/pcie-mobiveil-plat.c | 54 ++ .../pci/controller/mobiveil/pcie-mobiveil.c | 228 ++++++++ .../pci/controller/mobiveil/pcie-mobiveil.h | 187 +++++++ 9 files changed, 587 insertions(+), 453 deletions(-) create mode 100644 drivers/pci/controller/mobiveil/Kconfig create mode 100644 drivers/pci/controller/mobiveil/Makefile rename drivers/pci/controller/{pcie-mobiveil.c => mobiveil/pcie-mobiveil-host.c} (55%) create mode 100644 drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c create mode 100644drivers/pci/controller/mobiveil/pcie-mobiveil.cquoted
quoted
quoted
quoted
quoted
create mode 100644drivers/pci/controller/mobiveil/pcie-mobiveil.hquoted
quoted
quoted
quoted
quoted
diff --git a/MAINTAINERS b/MAINTAINERS index1e64279f338a..1013e74b14f2 100644--- a/MAINTAINERS +++ b/MAINTAINERS@@ -11877,7 +11877,7 @@ M: Subrahmanya Lingappa[off-list ref]quoted
L: linux-pci@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/pci/mobiveil-pcie.txt -F: drivers/pci/controller/pcie-mobiveil.c +F: drivers/pci/controller/mobiveil/pcie-mobiveil* PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOCsupport)quoted
M: Thomas Petazzoni [off-list ref]diff --git a/drivers/pci/controller/Kconfigb/drivers/pci/controller/Kconfig index 6671946dbf66..0e981ed00a75 100644--- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig@@ -241,16 +241,6 @@ config PCIE_MEDIATEK Say Y here if you want to enable PCIe controller support on MediaTek SoCs. -config PCIE_MOBIVEIL - bool "Mobiveil AXI PCIe controller" - depends on ARCH_ZYNQMP || COMPILE_TEST - depends on OF - depends on PCI_MSI_IRQ_DOMAIN - help - Say Y here if you want to enable support for the Mobiveil AXIPCIequoted
quoted
quoted
quoted
quoted
- Soft IP. It has up to 8 outbound and inbound windows - for address translation and it is a PCIe Gen4 IP. - config PCIE_TANGO_SMP8759 bool "Tango SMP8759 PCIe controller (DANGEROUS)" depends on ARCH_TANGO && PCI_MSI && OF @@ -281,4+271,5quoted
quoted
@@quoted
quoted
configquoted
VMD module will be called vmd. source "drivers/pci/controller/dwc/Kconfig" +source "drivers/pci/controller/mobiveil/Kconfig" endmenudiff --git a/drivers/pci/controller/Makefileb/drivers/pci/controller/Makefile indexd56a507495c5..b79a615041a0quoted
quoted
quoted
quoted
quoted
100644--- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile@@ -26,11 +26,11 @@ obj-$(CONFIG_PCIE_ROCKCHIP) +=pcie-rockchip.oquoted
quoted
quoted
obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o -obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o obj-$(CONFIG_VMD) += vmd.o # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW obj-y += dwc/ +obj-y += mobiveil/ # The following drivers are for devices that use the generic ACPIdiff --git a/drivers/pci/controller/mobiveil/Kconfigb/drivers/pci/controller/mobiveil/Kconfig new file mode 100644 index 000000000000..64343c07bfed--- /dev/null +++ b/drivers/pci/controller/mobiveil/Kconfig@@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0 + +menu "Mobiveil PCIe Core Support" + depends on PCI + +config PCIE_MOBIVEIL + bool + +config PCIE_MOBIVEIL_HOST + bool + depends on PCI_MSI_IRQ_DOMAIN + select PCIE_MOBIVEIL + +config PCIE_MOBIVEIL_PLAT + bool "Mobiveil AXI PCIe controller" + depends on ARCH_ZYNQMP || COMPILE_TEST + depends on OF + select PCIE_MOBIVEIL_HOST + help + Say Y here if you want to enable support for the Mobiveil AXIPCIequoted
quoted
quoted
quoted
quoted
+ Soft IP. It has up to 8 outbound and inbound windows + for address translation and it is a PCIe Gen4 IP. + +endmenudiff --git a/drivers/pci/controller/mobiveil/Makefileb/drivers/pci/controller/mobiveil/Makefile new file mode 100644 index 000000000000..9fb6d1c6504d--- /dev/null +++ b/drivers/pci/controller/mobiveil/Makefile@@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o +obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o +obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.odiff --git a/drivers/pci/controller/pcie-mobiveil.cb/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c similarity index 55% rename from drivers/pci/controller/pcie-mobiveil.c rename to drivers/pci/controller/mobiveil/pcie-mobiveil-host.c index 9210165fe8c0..dc5324d94466 100644--- a/drivers/pci/controller/pcie-mobiveil.c +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c@@ -4,9 +4,9 @@ * * Copyright (c) 2018 Mobiveil Inc. * Author: Subrahmanya Lingappa[off-list ref]quoted
quoted
quoted
quoted
quoted
+ * Refactor: Zhiqiang Hou [off-list ref] */ -#include <linux/delay.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h>@@ -23,275 +23,21 @@ #include <linux/platform_device.h> #include <linux/slab.h> -#include "../pci.h" - -/* register offsets and bit positions */ - -/* - * translation tables are grouped into windows, each windowregistersquoted
quoted
quoted
quoted
quoted
are - * grouped into blocks of 4 or 16 registers each - */ -#define PAB_REG_BLOCK_SIZE 16 -#define PAB_EXT_REG_BLOCK_SIZE 4 - -#define PAB_REG_ADDR(offset, win) \ - (offset + (win * PAB_REG_BLOCK_SIZE)) -#define PAB_EXT_REG_ADDR(offset, win) \ - (offset + (win * PAB_EXT_REG_BLOCK_SIZE)) - -#define LTSSM_STATUS 0x0404 -#define LTSSM_STATUS_L0_MASK 0x3f -#define LTSSM_STATUS_L0 0x2d - -#define PAB_CTRL 0x0808 -#define AMBA_PIO_ENABLE_SHIFT 0 -#define PEX_PIO_ENABLE_SHIFT 1 -#define PAGE_SEL_SHIFT 13 -#define PAGE_SEL_MASK 0x3f -#define PAGE_LO_MASK 0x3ff -#define PAGE_SEL_OFFSET_SHIFT 10 - -#define PAB_AXI_PIO_CTRL 0x0840 -#define APIO_EN_MASK 0xf - -#define PAB_PEX_PIO_CTRL 0x08c0 -#define PIO_ENABLE_SHIFT 0 - -#define PAB_INTP_AMBA_MISC_ENB 0x0b0c -#define PAB_INTP_AMBA_MISC_STAT 0x0b1c -#define PAB_INTP_INTX_MASK 0x01e0 -#define PAB_INTP_MSI_MASK 0x8 - -#define PAB_AXI_AMAP_CTRL(win)PAB_REG_ADDR(0x0ba0,quoted
quoted
win)quoted
quoted
quoted
-#define WIN_ENABLE_SHIFT 0 -#define WIN_TYPE_SHIFT 1 -#define WIN_TYPE_MASK 0x3 -#define WIN_SIZE_SHIFT 10 -#define WIN_SIZE_MASK 0x3fffff - -#define PAB_EXT_AXI_AMAP_SIZE(win)PAB_EXT_REG_ADDR(0xbaf0,quoted
quoted
win)quoted
- -#define PAB_EXT_AXI_AMAP_AXI_WIN(win)PAB_EXT_REG_ADDR(0x80a0, win)quoted
-#define PAB_AXI_AMAP_AXI_WIN(win)PAB_REG_ADDR(0x0ba4,quoted
quoted
win)quoted
quoted
quoted
-#define AXI_WINDOW_ALIGN_MASK 3 - -#define PAB_AXI_AMAP_PEX_WIN_L(win)PAB_REG_ADDR(0x0ba8,quoted
quoted
quoted
quoted
win)quoted
-#define PAB_BUS_SHIFT 24 -#define PAB_DEVICE_SHIFT 19 -#define PAB_FUNCTION_SHIFT 16 - -#define PAB_AXI_AMAP_PEX_WIN_H(win)PAB_REG_ADDR(0x0bac,quoted
quoted
win)quoted
-#define PAB_INTP_AXI_PIO_CLASS 0x474 - -#define PAB_PEX_AMAP_CTRL(win)PAB_REG_ADDR(0x4ba0,quoted
quoted
win)quoted
quoted
quoted
-#define AMAP_CTRL_EN_SHIFT 0 -#define AMAP_CTRL_TYPE_SHIFT 1 -#define AMAP_CTRL_TYPE_MASK 3 - -#define PAB_EXT_PEX_AMAP_SIZEN(win)PAB_EXT_REG_ADDR(0xbef0,quoted
quoted
win)quoted
-#define PAB_EXT_PEX_AMAP_AXI_WIN(win)PAB_EXT_REG_ADDR(0xb4a0, win)quoted
-#define PAB_PEX_AMAP_AXI_WIN(win)PAB_REG_ADDR(0x4ba4,quoted
quoted
win)quoted
quoted
quoted
-#define PAB_PEX_AMAP_PEX_WIN_L(win)PAB_REG_ADDR(0x4ba8,quoted
quoted
win)quoted
-#define PAB_PEX_AMAP_PEX_WIN_H(win)PAB_REG_ADDR(0x4bac,quoted
quoted
win)quoted
- -/* starting offset of INTX bits in status register */ -#define PAB_INTX_START 5 - -/* supported number of MSI interrupts */ -#define PCI_NUM_MSI 16 - -/* MSI registers */ -#define MSI_BASE_LO_OFFSET 0x04 -#define MSI_BASE_HI_OFFSET 0x08 -#define MSI_SIZE_OFFSET 0x0c -#define MSI_ENABLE_OFFSET 0x14 -#define MSI_STATUS_OFFSET 0x18 -#define MSI_DATA_OFFSET 0x20 -#define MSI_ADDR_L_OFFSET 0x24 -#define MSI_ADDR_H_OFFSET 0x28 - -/* outbound and inbound window definitions */ -#define WIN_NUM_0 0 -#define WIN_NUM_1 1 -#define CFG_WINDOW_TYPE 0 -#define IO_WINDOW_TYPE 1 -#define MEM_WINDOW_TYPE 2 -#define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024) -#define MAX_PIO_WINDOWS 8 - -/* Parameters for the waiting for link up routine */ -#define LINK_WAIT_MAX_RETRIES 10 -#define LINK_WAIT_MIN 90000 -#define LINK_WAIT_MAX 100000 - -#define PAGED_ADDR_BNDRY 0xc00 -#define OFFSET_TO_PAGE_ADDR(off) \ - ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY) -#define OFFSET_TO_PAGE_IDX(off) \ - ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK) - -struct mobiveil_msi { /* MSI information */ - struct mutex lock; /* protect bitmap variable */ - struct irq_domain *msi_domain; - struct irq_domain *dev_domain; - phys_addr_t msi_pages_phys; - int num_of_vectors; - DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI); -}; - -struct mobiveil_pcie { - struct platform_device *pdev; - struct list_head resources; - void __iomem *config_axi_slave_base; /* endpoint configbasequoted
quoted
*/quoted
quoted
quoted
- void __iomem *csr_axi_slave_base; /* root port config base*/quoted
quoted
quoted
quoted
quoted
- void __iomem *apb_csr_base; /* MSI register base */ - phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base*/quoted
quoted
quoted
quoted
quoted
- struct irq_domain *intx_domain; - raw_spinlock_t intx_mask_lock; - int irq; - int apio_wins; - int ppio_wins; - int ob_wins_configured; /* configured outbound windows*/quoted
quoted
quoted
quoted
quoted
- int ib_wins_configured; /* configured inbound windows */ - struct resource *ob_io_res; - char root_bus_nr; - struct mobiveil_msi msi; -}; - -/* - * mobiveil_pcie_sel_page - routine to access paged register - * - * Registers whose address greater than PAGED_ADDR_BNDRY(0xc00)quoted
quoted
arequoted
quoted
quoted
paged, - * for this scheme to work extracted higher 6 bits of the offset will be - * written to pg_sel field of PAB_CTRL register and rest of the lower 10 - * bits enabled with PAGED_ADDR_BNDRY are used as offset of theregister.quoted
- */ -static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx) -{ - u32 val; - - val = readl(pcie->csr_axi_slave_base + PAB_CTRL); - val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT); - val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT; - - writel(val, pcie->csr_axi_slave_base + PAB_CTRL); -} - -static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie,u32quoted
quoted
quoted
quoted
quoted
off) -{ - if (off < PAGED_ADDR_BNDRY) { - /* For directly accessed registers, clear the pg_sel field */ - mobiveil_pcie_sel_page(pcie, 0); - return pcie->csr_axi_slave_base + off; - } - - mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off)); - return pcie->csr_axi_slave_base +OFFSET_TO_PAGE_ADDR(off);quoted
quoted
quoted
quoted
quoted
-} - -static int mobiveil_pcie_read(void __iomem *addr, int size, u32*val)quoted
quoted
quoted
quoted
quoted
-{ - if ((uintptr_t)addr & (size - 1)) { - *val = 0; - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - switch (size) { - case 4: - *val = readl(addr); - break; - case 2: - *val = readw(addr); - break; - case 1: - *val = readb(addr); - break; - default: - *val = 0; - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val) -{ - if ((uintptr_t)addr & (size - 1)) - return PCIBIOS_BAD_REGISTER_NUMBER; - - switch (size) { - case 4: - writel(val, addr); - break; - case 2: - writew(val, addr); - break; - case 1: - writeb(val, addr); - break; - default: - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - return PCIBIOS_SUCCESSFUL; -} - -static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size) -{ - void *addr; - u32 val; - int ret; - - addr = mobiveil_pcie_comp_addr(pcie, off); - - ret = mobiveil_pcie_read(addr, size, &val); - if (ret) - dev_err(&pcie->pdev->dev, "read CSR address failed\n"); - - return val; -} - -static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size) -{ - void *addr; - int ret; - - addr = mobiveil_pcie_comp_addr(pcie, off); - - ret = mobiveil_pcie_write(addr, size, val); - if (ret) - dev_err(&pcie->pdev->dev, "write CSR address failed\n"); -} - -static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off) -{ - return csr_read(pcie, off, 0x4); -} - -static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off) -{ - csr_write(pcie, val, off, 0x4); -} - -static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie) -{ - return (csr_readl(pcie, LTSSM_STATUS) & - LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0; -} +#include "pcie-mobiveil.h" static bool mobiveil_pcie_valid_device(struct pci_bus *bus,unsignedquoted
quoted
quoted
quoted
quoted
int devfn) { struct mobiveil_pcie *pcie = bus->sysdata; /* Only one device down on each root port */ - if ((bus->number == pcie->root_bus_nr) && (devfn > 0)) + if ((bus->number == pcie->rp.root_bus_nr) && (devfn > 0)) return false; /* * Do not read more than one device on the bus directly * attached to RC */ - if ((bus->primary == pcie->root_bus_nr) && (devfn > 0)) + if ((bus->primary == pcie->rp.root_bus_nr) && (devfn > 0)) return false; return true;@@ -311,7 +57,7 @@ static void __iomem*mobiveil_pcie_map_bus(structquoted
quoted
pci_bus *bus,quoted
return NULL; /* RC config access */ - if (bus->number == pcie->root_bus_nr) + if (bus->number == pcie->rp.root_bus_nr) return pcie->csr_axi_slave_base + where; /*@@ -326,7 +72,7 @@ static void __iomem*mobiveil_pcie_map_bus(structquoted
quoted
quoted
pci_bus *bus, csr_writel(pcie, value,PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));quoted
quoted
quoted
quoted
quoted
- return pcie->config_axi_slave_base + where; + return pcie->rp.config_axi_slave_base + where; } static struct pci_ops mobiveil_pcie_ops = { @@ -340,7 +86,7 @@staticquoted
quoted
quoted
void mobiveil_pcie_isr(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); struct mobiveil_pcie *pcie = irq_desc_get_handler_data(desc); struct device *dev = &pcie->pdev->dev; - struct mobiveil_msi *msi = &pcie->msi; + struct mobiveil_msi *msi = &pcie->rp.msi; u32 msi_data, msi_addr_lo, msi_addr_hi; u32 intr_status, msi_status; unsigned long shifted_status;@@ -365,7 +111,7 @@ static void mobiveil_pcie_isr(struct irq_desc*desc)quoted
quoted
quoted
shifted_status >>= PAB_INTX_START; do { for_each_set_bit(bit, &shifted_status,PCI_NUM_INTX) {quoted
quoted
quoted
quoted
quoted
- virq = irq_find_mapping(pcie->intx_domain, + virq = irq_find_mapping(pcie->rp.intx_domain, bit + 1); if (virq) generic_handle_irq(virq);@@ -428,10 +174,10 @@ static int mobiveil_pcie_parse_dt(structmobiveil_pcie *pcie)quoted
/* map config resource */ res = platform_get_resource_byname(pdev,IORESOURCE_MEM,quoted
quoted
quoted
quoted
quoted
"config_axi_slave"); - pcie->config_axi_slave_base =devm_pci_remap_cfg_resource(dev,quoted
quoted
res);quoted
quoted
quoted
- if (IS_ERR(pcie->config_axi_slave_base)) - return PTR_ERR(pcie->config_axi_slave_base); - pcie->ob_io_res = res; + pcie->rp.config_axi_slave_base =devm_pci_remap_cfg_resource(dev,quoted
quoted
res);quoted
+ if (IS_ERR(pcie->rp.config_axi_slave_base)) + return PTR_ERR(pcie->rp.config_axi_slave_base); + pcie->rp.ob_io_res = res; /* map csr resource */ res = platform_get_resource_byname(pdev,IORESOURCE_MEM,quoted
quoted
@@quoted
quoted
-441,12quoted
+187,6 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie*pcie)quoted
quoted
quoted
return PTR_ERR(pcie->csr_axi_slave_base); pcie->pcie_reg_base = res->start; - /* map MSI config resource */ - res = platform_get_resource_byname(pdev,IORESOURCE_MEM,quoted
quoted
quoted
quoted
"apb_csr");quoted
- pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev,res);quoted
quoted
quoted
quoted
quoted
- if (IS_ERR(pcie->apb_csr_base)) - return PTR_ERR(pcie->apb_csr_base); - /* read the number of windows requested */ if (of_property_read_u32(node, "apio-wins",&pcie->apio_wins))quoted
quoted
quoted
quoted
quoted
pcie->apio_wins = MAX_PIO_WINDOWS;@@ -454,119 +194,15 @@ static int mobiveil_pcie_parse_dt(structmobiveil_pcie *pcie)quoted
if (of_property_read_u32(node, "ppio-wins",&pcie->ppio_wins))quoted
quoted
quoted
quoted
quoted
pcie->ppio_wins = MAX_PIO_WINDOWS; - pcie->irq = platform_get_irq(pdev, 0); - if (pcie->irq <= 0) { - dev_err(dev, "failed to map IRQ: %d\n", pcie->irq); - return -ENODEV; - } - return 0; } -static void program_ib_windows(struct mobiveil_pcie *pcie, intwin_num,quoted
quoted
quoted
- u64 cpu_addr, u64 pci_addr, u32 type, u64size)quoted
quoted
quoted
quoted
quoted
-{ - u32 value; - u64 size64 = ~(size - 1); - - if (win_num >= pcie->ppio_wins) { - dev_err(&pcie->pdev->dev, - "ERROR: max inbound windows reached !\n"); - return; - } - - value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num)); - value &= ~(AMAP_CTRL_TYPE_MASK <<AMAP_CTRL_TYPE_SHIFT |quoted
quoted
quoted
quoted
quoted
- WIN_SIZE_MASK << WIN_SIZE_SHIFT); - value |= (type << AMAP_CTRL_TYPE_SHIFT) | (1 <<AMAP_CTRL_EN_SHIFT) |quoted
- (lower_32_bits(size64) & WIN_SIZE_MASK <<WIN_SIZE_SHIFT);quoted
quoted
quoted
- csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num)); - - csr_writel(pcie, upper_32_bits(size64), - PAB_EXT_PEX_AMAP_SIZEN(win_num)); - - csr_writel(pcie, lower_32_bits(cpu_addr), - PAB_PEX_AMAP_AXI_WIN(win_num)); - csr_writel(pcie, upper_32_bits(cpu_addr), - PAB_EXT_PEX_AMAP_AXI_WIN(win_num)); - - csr_writel(pcie, lower_32_bits(pci_addr), - PAB_PEX_AMAP_PEX_WIN_L(win_num)); - csr_writel(pcie, upper_32_bits(pci_addr), - PAB_PEX_AMAP_PEX_WIN_H(win_num)); - - pcie->ib_wins_configured++; -} - -/* - * routine to program the outbound windows - */ -static void program_ob_windows(struct mobiveil_pcie *pcie, intwin_num,quoted
quoted
quoted
- u64 cpu_addr, u64 pci_addr, u32 type, u64size)quoted
quoted
quoted
quoted
quoted
-{ - - u32 value; - u64 size64 = ~(size - 1); - - if (win_num >= pcie->apio_wins) { - dev_err(&pcie->pdev->dev, - "ERROR: max outbound windows reached !\n"); - return; - } - - /* - * program Enable Bit to 1, Type Bit to (00) base 2, AXI WindowSizequoted
quoted
Bitquoted
quoted
quoted
- * to 4 KB in PAB_AXI_AMAP_CTRL register - */ - value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num)); - value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | - WIN_SIZE_MASK << WIN_SIZE_SHIFT); - value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT|quoted
quoted
quoted
quoted
quoted
- (lower_32_bits(size64) & WIN_SIZE_MASK <<WIN_SIZE_SHIFT);quoted
quoted
quoted
- csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num)); - - csr_writel(pcie, upper_32_bits(size64),PAB_EXT_AXI_AMAP_SIZE(win_num));quoted
- - /* - * program AXI window base with appropriate value in - * PAB_AXI_AMAP_AXI_WIN0 register - */ - csr_writel(pcie, lower_32_bits(cpu_addr) &(~AXI_WINDOW_ALIGN_MASK),quoted
- PAB_AXI_AMAP_AXI_WIN(win_num)); - csr_writel(pcie, upper_32_bits(cpu_addr), - PAB_EXT_AXI_AMAP_AXI_WIN(win_num)); - - csr_writel(pcie, lower_32_bits(pci_addr), - PAB_AXI_AMAP_PEX_WIN_L(win_num)); - csr_writel(pcie, upper_32_bits(pci_addr), - PAB_AXI_AMAP_PEX_WIN_H(win_num)); - - pcie->ob_wins_configured++; -} - -static int mobiveil_bringup_link(struct mobiveil_pcie *pcie) -{ - int retries; - - /* check if the link is up or not */ - for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++){quoted
quoted
quoted
quoted
quoted
- if (mobiveil_pcie_link_up(pcie)) - return 0; - - usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX); - } - - dev_err(&pcie->pdev->dev, "link never came up\n"); - - return -ETIMEDOUT; -} - static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie){quoted
quoted
quoted
quoted
quoted
phys_addr_t msg_addr = pcie->pcie_reg_base; - struct mobiveil_msi *msi = &pcie->msi; + struct mobiveil_msi *msi = &pcie->rp.msi; - pcie->msi.num_of_vectors = PCI_NUM_MSI; + msi->num_of_vectors = PCI_NUM_MSI; msi->msi_pages_phys = (phys_addr_t)msg_addr; writel_relaxed(lower_32_bits(msg_addr),@@ -604,9 +240,6 @@ static int mobiveil_host_init(structmobiveil_pciequoted
quoted
*pcie)quoted
pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 <<PEX_PIO_ENABLE_SHIFT);quoted
csr_writel(pcie, pab_ctrl, PAB_CTRL); - csr_writel(pcie, (PAB_INTP_INTX_MASK |PAB_INTP_MSI_MASK),quoted
quoted
quoted
quoted
quoted
- PAB_INTP_AMBA_MISC_ENB); - /* * program PIO Enable Bit to 1 and Config Window Enable Bitto 1quoted
quoted
inquoted
quoted
quoted
* PAB_AXI_PIO_CTRL Register@@ -628,20 +261,24 @@ static int mobiveil_host_init(structmobiveil_pciequoted
quoted
*pcie)quoted
*/ /* config outbound translation window */ - program_ob_windows(pcie, WIN_NUM_0,pcie->ob_io_res->start,quoted
quoted
0,quoted
quoted
quoted
- CFG_WINDOW_TYPE,resource_size(pcie->ob_io_res));quoted
quoted
quoted
+ program_ob_windows(pcie, WIN_NUM_0,pcie->rp.ob_io_res->start, 0,quoted
quoted
quoted
+ CFG_WINDOW_TYPE,resource_size(pcie->rp.ob_io_res));quoted
quoted
quoted
/* memory inbound translation window */ program_ib_windows(pcie, WIN_NUM_0, 0, 0,MEM_WINDOW_TYPE,quoted
quoted
IB_WIN_SIZE);quoted
/* Get the I/O and memory ranges from DT */ resource_list_for_each_entry(win, &pcie->resources) { - if (resource_type(win->res) == IORESOURCE_MEM) + if (resource_type(win->res) == IORESOURCE_MEM) { type = MEM_WINDOW_TYPE; - else if (resource_type(win->res) == IORESOURCE_IO) + } else if (resource_type(win->res) == IORESOURCE_IO) { type = IO_WINDOW_TYPE; - else + } else if (resource_type(win->res) == IORESOURCE_BUS) { + pcie->rp.root_bus_nr = win->res->start; + continue; + } else { continue; + } /* configure outbound translation window */ program_ob_windows(pcie, pcie->ob_wins_configured,@@ -656,9 +293,6 @@ static int mobiveil_host_init(structmobiveil_pciequoted
quoted
*pcie)quoted
value |= (PCI_CLASS_BRIDGE_PCI << 16); csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS); - /* setup MSI hardware registers */ - mobiveil_pcie_enable_msi(pcie); - return 0; }@@ -671,11 +305,11 @@ static void mobiveil_mask_intx_irq(structirq_data *data)quoted
pcie = irq_desc_get_chip_data(desc); mask = 1 << ((data->hwirq + PAB_INTX_START) - 1); - raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags); + raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags); shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB); shifted_val &= ~mask; csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB); - raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags); + raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags); } static void mobiveil_unmask_intx_irq(struct irq_data *data)@@ -687,11 +321,11 @@ static voidmobiveil_unmask_intx_irq(structquoted
quoted
quoted
quoted
irq_data *data)quoted
pcie = irq_desc_get_chip_data(desc); mask = 1 << ((data->hwirq + PAB_INTX_START) - 1); - raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags); + raw_spin_lock_irqsave(&pcie->rp.intx_mask_lock, flags); shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB); shifted_val |= mask; csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB); - raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags); + raw_spin_unlock_irqrestore(&pcie->rp.intx_mask_lock, flags); } static struct irq_chip intx_irq_chip = {@@ -759,7 +393,7 @@ static intmobiveil_irq_msi_domain_alloc(structquoted
quoted
quoted
quoted
irq_domain *domain,quoted
unsigned int nr_irqs, void *args) { struct mobiveil_pcie *pcie = domain->host_data; - struct mobiveil_msi *msi = &pcie->msi; + struct mobiveil_msi *msi = &pcie->rp.msi; unsigned long bit; WARN_ON(nr_irqs != 1);@@ -786,7 +420,7 @@ static voidmobiveil_irq_msi_domain_free(structquoted
quoted
irq_domain *domain,quoted
{ struct irq_data *d = irq_domain_get_irq_data(domain, virq); struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d); - struct mobiveil_msi *msi = &pcie->msi; + struct mobiveil_msi *msi = &pcie->rp.msi; mutex_lock(&msi->lock);@@ -807,9 +441,9 @@ static intmobiveil_allocate_msi_domains(structquoted
quoted
quoted
quoted
mobiveil_pcie *pcie)quoted
{ struct device *dev = &pcie->pdev->dev; struct fwnode_handle *fwnode =of_node_to_fwnode(dev->of_node);quoted
quoted
quoted
- struct mobiveil_msi *msi = &pcie->msi; + struct mobiveil_msi *msi = &pcie->rp.msi; - mutex_init(&pcie->msi.lock); + mutex_init(&msi->lock); msi->dev_domain = irq_domain_add_linear(NULL,msi->num_of_vectors,quoted
&msi_domain_ops, pcie); if (!msi->dev_domain) {@@ -836,15 +470,15 @@ static intmobiveil_pcie_init_irq_domain(structquoted
quoted
mobiveil_pcie *pcie)quoted
int ret; /* setup INTx */ - pcie->intx_domain = irq_domain_add_linear(node,PCI_NUM_INTX,quoted
quoted
quoted
quoted
quoted
- &intx_domain_ops, pcie); + pcie->rp.intx_domain = irq_domain_add_linear(node,PCI_NUM_INTX,quoted
quoted
quoted
+ &intx_domain_ops, pcie); - if (!pcie->intx_domain) { + if (!pcie->rp.intx_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); return -ENOMEM; } - raw_spin_lock_init(&pcie->intx_mask_lock); + raw_spin_lock_init(&pcie->rp.intx_mask_lock); /* setup MSI */ ret = mobiveil_allocate_msi_domains(pcie);@@ -854,24 +488,58 @@ static intmobiveil_pcie_init_irq_domain(structquoted
quoted
mobiveil_pcie *pcie)quoted
return 0; } -static int mobiveil_pcie_probe(struct platform_device *pdev) +static int mobiveil_pcie_interrupt_init(struct mobiveil_pcie *pcie) +{ + struct device *dev = &pcie->pdev->dev; + struct resource *res; + int ret; + + if (pcie->rp.ops->interrupt_init) + return pcie->rp.ops->interrupt_init(pcie); + + /* map MSI config resource */ + res = platform_get_resource_byname(pcie->pdev,IORESOURCE_MEM,quoted
quoted
quoted
+ "apb_csr"); + pcie->apb_csr_base = devm_pci_remap_cfg_resource(dev,res);quoted
quoted
quoted
quoted
quoted
+ if (IS_ERR(pcie->apb_csr_base)) + return PTR_ERR(pcie->apb_csr_base); + + /* setup MSI hardware registers */ + mobiveil_pcie_enable_msi(pcie); + + pcie->rp.irq = platform_get_irq(pcie->pdev, 0); + if (pcie->rp.irq <= 0) { + dev_err(dev, "failed to map IRQ: %d\n", pcie->rp.irq); + return -ENODEV; + } + + /* initialize the IRQ domains */ + ret = mobiveil_pcie_init_irq_domain(pcie); + if (ret) { + dev_err(dev, "Failed creating IRQ Domain\n"); + return ret; + } + + irq_set_chained_handler_and_data(pcie->rp.irq, + mobiveil_pcie_isr, pcie); + + /* Enable interrupts */ + csr_writel(pcie, (PAB_INTP_INTX_MASK |PAB_INTP_MSI_MASK),quoted
quoted
quoted
quoted
quoted
+ PAB_INTP_AMBA_MISC_ENB); + + return 0; +} + +int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie) { - struct mobiveil_pcie *pcie; struct pci_bus *bus; struct pci_bus *child; struct pci_host_bridge *bridge; - struct device *dev = &pdev->dev; + struct device *dev = &pcie->pdev->dev; resource_size_t iobase; int ret; - /* allocate the PCIe port */ - bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); - if (!bridge) - return -ENOMEM; - - pcie = pci_host_bridge_priv(bridge); - - pcie->pdev = pdev; + INIT_LIST_HEAD(&pcie->resources); ret = mobiveil_pcie_parse_dt(pcie); if (ret) {@@ -879,7 +547,10 @@ static int mobiveil_pcie_probe(structplatform_device *pdev)quoted
return ret; } - INIT_LIST_HEAD(&pcie->resources); + /* allocate the PCIe port */ + bridge = devm_pci_alloc_host_bridge(dev, 0); + if (!bridge) + return -ENOMEM; /* parse the host bridge base addresses from the device treefile */quoted
quoted
quoted
quoted
quoted
ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,@@ -899,15 +570,12 @@ static int mobiveil_pcie_probe(structplatform_device *pdev)quoted
goto error; } - /* initialize the IRQ domains */ - ret = mobiveil_pcie_init_irq_domain(pcie); + ret = mobiveil_pcie_interrupt_init(pcie); if (ret) { - dev_err(dev, "Failed creating IRQ Domain\n"); + dev_err(dev, "Interrupt init failed\n"); goto error; } - irq_set_chained_handler_and_data(pcie->irq,mobiveil_pcie_isr,quoted
quoted
pcie);quoted
quoted
quoted
- ret = devm_request_pci_bus_resources(dev,&pcie->resources);quoted
quoted
quoted
quoted
quoted
if (ret) goto error;@@ -916,7 +584,7 @@ static int mobiveil_pcie_probe(structplatform_device *pdev)quoted
list_splice_init(&pcie->resources, &bridge->windows); bridge->dev.parent = dev; bridge->sysdata = pcie; - bridge->busnr = pcie->root_bus_nr; + bridge->busnr = pcie->rp.root_bus_nr; bridge->ops = &mobiveil_pcie_ops; bridge->map_irq = of_irq_parse_and_map_pci; bridge->swizzle_irq = pci_common_swizzle;@@ -944,25 +612,3 @@ static int mobiveil_pcie_probe(structplatform_device *pdev)quoted
pci_free_resource_list(&pcie->resources); return ret; } - -static const struct of_device_id mobiveil_pcie_of_match[] = { - {.compatible = "mbvl,gpex40-pcie",}, - {}, -}; - -MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match); - -static struct platform_driver mobiveil_pcie_driver = { - .probe = mobiveil_pcie_probe, - .driver = { - .name = "mobiveil-pcie", - .of_match_table = mobiveil_pcie_of_match, - .suppress_bind_attrs = true, - }, -}; - -builtin_platform_driver(mobiveil_pcie_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Mobiveil PCIe host controller driver"); -MODULE_AUTHOR("Subrahmanya Lingappa[off-list ref]");quoted
diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.cb/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.cquoted
new file mode 100644 index 000000000000..216c62f35568--- /dev/null +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c@@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe host controller driver for Mobiveil PCIe Host controller + * + * Copyright (c) 2018 Mobiveil Inc. + * Author: Subrahmanya Lingappa[off-list ref]quoted
quoted
quoted
quoted
quoted
+ * Refactor: Zhiqiang Hou [off-list ref] + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_pci.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "pcie-mobiveil.h" + +static int mobiveil_pcie_probe(struct platform_device *pdev) +{ + struct mobiveil_pcie *pcie; + struct device *dev = &pdev->dev; + + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->pdev = pdev; + + return mobiveil_pcie_host_probe(pcie); +} + +static const struct of_device_id mobiveil_pcie_of_match[] = { + {.compatible = "mbvl,gpex40-pcie",}, + {}, +}; + +MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match); + +static struct platform_driver mobiveil_pcie_driver = { + .probe = mobiveil_pcie_probe, + .driver = { + .name = "mobiveil-pcie", + .of_match_table = mobiveil_pcie_of_match, + .suppress_bind_attrs = true, + }, +}; + +builtin_platform_driver(mobiveil_pcie_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Mobiveil PCIe host controller driver"); +MODULE_AUTHOR("Subrahmanya Lingappa[off-list ref]");quoted
diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.cb/drivers/pci/controller/mobiveil/pcie-mobiveil.cquoted
new file mode 100644 index 000000000000..ee678a60825d--- /dev/null +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.c@@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe host controller driver for Mobiveil PCIe Host controller + * + * Copyright (c) 2018 Mobiveil Inc. + * Author: Subrahmanya Lingappa[off-list ref]quoted
quoted
quoted
quoted
quoted
+ * Refactor: Zhiqiang Hou [off-list ref] + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/platform_device.h> + +#include "pcie-mobiveil.h" + +/* + * mobiveil_pcie_sel_page - routine to access paged register + * + * Registers whose address greater than PAGED_ADDR_BNDRY(0xc00)quoted
quoted
arequoted
quoted
paged,quoted
+ * for this scheme to work extracted higher 6 bits of the offset willbequoted
quoted
quoted
quoted
quoted
+ * written to pg_sel field of PAB_CTRL register and rest of the lower10quoted
quoted
quoted
quoted
quoted
+ * bits enabled with PAGED_ADDR_BNDRY are used as offset of theregister.quoted
+ */ +static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8pg_idx)quoted
quoted
quoted
+{ + u32 val; + + val = readl(pcie->csr_axi_slave_base + PAB_CTRL); + val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT); + val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT; + + writel(val, pcie->csr_axi_slave_base + PAB_CTRL); +} + +static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie,u32quoted
quoted
off)quoted
quoted
quoted
+{ + if (off < PAGED_ADDR_BNDRY) { + /* For directly accessed registers, clear the pg_sel field */ + mobiveil_pcie_sel_page(pcie, 0); + return pcie->csr_axi_slave_base + off; + } + + mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off)); + return pcie->csr_axi_slave_base +OFFSET_TO_PAGE_ADDR(off);quoted
quoted
quoted
quoted
quoted
+} + +static int mobiveil_pcie_read(void __iomem *addr, int size, u32*val)quoted
quoted
quoted
quoted
quoted
+{ + if ((uintptr_t)addr & (size - 1)) { + *val = 0; + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + switch (size) { + case 4: + *val = readl(addr); + break; + case 2: + *val = readw(addr); + break; + case 1: + *val = readb(addr); + break; + default: + *val = 0; + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int mobiveil_pcie_write(void __iomem *addr, int size, u32val)quoted
quoted
quoted
quoted
quoted
+{ + if ((uintptr_t)addr & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + switch (size) { + case 4: + writel(val, addr); + break; + case 2: + writew(val, addr); + break; + case 1: + writeb(val, addr); + break; + default: + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + return PCIBIOS_SUCCESSFUL; +} + +u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size) +{ + void *addr; + u32 val; + int ret; + + addr = mobiveil_pcie_comp_addr(pcie, off); + + ret = mobiveil_pcie_read(addr, size, &val); + if (ret) + dev_err(&pcie->pdev->dev, "read CSR address failed\n"); + + return val; +} + +void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_tsize)quoted
quoted
quoted
quoted
quoted
+{ + void *addr; + int ret; + + addr = mobiveil_pcie_comp_addr(pcie, off); + + ret = mobiveil_pcie_write(addr, size, val); + if (ret) + dev_err(&pcie->pdev->dev, "write CSR address failed\n"); +} + +bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie) +{ + if (pcie->ops->link_up) + return pcie->ops->link_up(pcie); + + return (csr_readl(pcie, LTSSM_STATUS) & + LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0; +} + +void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,u64quoted
quoted
cpu_addr,quoted
+ u64 pci_addr, u32 type, u64 size) +{ + u32 value; + u64 size64 = ~(size - 1); + + if (win_num >= pcie->ppio_wins) { + dev_err(&pcie->pdev->dev, + "ERROR: max inbound windows reached !\n"); + return; + } + + value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num)); + value &= ~(AMAP_CTRL_TYPE_MASK <<AMAP_CTRL_TYPE_SHIFT |quoted
quoted
quoted
quoted
quoted
+ WIN_SIZE_MASK << WIN_SIZE_SHIFT); + value |= (type << AMAP_CTRL_TYPE_SHIFT) | (1 <<AMAP_CTRL_EN_SHIFT) |quoted
+ (lower_32_bits(size64) & WIN_SIZE_MASK <<WIN_SIZE_SHIFT);quoted
quoted
quoted
+ csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num)); + + csr_writel(pcie, upper_32_bits(size64), + PAB_EXT_PEX_AMAP_SIZEN(win_num)); + + csr_writel(pcie, lower_32_bits(cpu_addr), + PAB_PEX_AMAP_AXI_WIN(win_num)); + csr_writel(pcie, upper_32_bits(cpu_addr), + PAB_EXT_PEX_AMAP_AXI_WIN(win_num)); + + csr_writel(pcie, lower_32_bits(pci_addr), + PAB_PEX_AMAP_PEX_WIN_L(win_num)); + csr_writel(pcie, upper_32_bits(pci_addr), + PAB_PEX_AMAP_PEX_WIN_H(win_num)); + + pcie->ib_wins_configured++; +} + +/* + * routine to program the outbound windows + */ +void program_ob_windows(struct mobiveil_pcie *pcie, intwin_num,quoted
quoted
u64quoted
quoted
cpu_addr,quoted
+ u64 pci_addr, u32 type, u64 size) +{ + + u32 value; + u64 size64 = ~(size - 1); + + if (win_num >= pcie->apio_wins) { + dev_err(&pcie->pdev->dev, + "ERROR: max outbound windows reached !\n"); + return; + } + + /* + * program Enable Bit to 1, Type Bit to (00) base 2, AXI WindowSizequoted
quoted
Bitquoted
quoted
quoted
+ * to 4 KB in PAB_AXI_AMAP_CTRL register + */ + value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num)); + value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | + WIN_SIZE_MASK << WIN_SIZE_SHIFT); + value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT|quoted
quoted
quoted
quoted
quoted
+ (lower_32_bits(size64) & WIN_SIZE_MASK <<WIN_SIZE_SHIFT);quoted
quoted
quoted
+ csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num)); + + csr_writel(pcie, upper_32_bits(size64),PAB_EXT_AXI_AMAP_SIZE(win_num));quoted
+ + /* + * program AXI window base with appropriate value in + * PAB_AXI_AMAP_AXI_WIN0 register + */ + csr_writel(pcie, lower_32_bits(cpu_addr) &(~AXI_WINDOW_ALIGN_MASK),quoted
+ PAB_AXI_AMAP_AXI_WIN(win_num)); + csr_writel(pcie, upper_32_bits(cpu_addr), + PAB_EXT_AXI_AMAP_AXI_WIN(win_num)); + + csr_writel(pcie, lower_32_bits(pci_addr), + PAB_AXI_AMAP_PEX_WIN_L(win_num)); + csr_writel(pcie, upper_32_bits(pci_addr), + PAB_AXI_AMAP_PEX_WIN_H(win_num)); + + pcie->ob_wins_configured++; +} + +int mobiveil_bringup_link(struct mobiveil_pcie *pcie) +{ + int retries; + + /* check if the link is up or not */ + for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++){quoted
quoted
quoted
quoted
quoted
+ if (mobiveil_pcie_link_up(pcie)) + return 0; + + usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX); + } + + dev_err(&pcie->pdev->dev, "link never came up\n"); + + return -ETIMEDOUT; +}diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.hb/drivers/pci/controller/mobiveil/pcie-mobiveil.hquoted
new file mode 100644 index 000000000000..eb4cb61291a8--- /dev/null +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h@@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PCIe host controller driver for Mobiveil PCIe Host controller + * + * Copyright (c) 2018 Mobiveil Inc. + * Author: Subrahmanya Lingappa[off-list ref]quoted
quoted
quoted
quoted
quoted
+ * Refactor: Zhiqiang Hou [off-list ref] + */ + +#ifndef _PCIE_MOBIVEIL_H +#define _PCIE_MOBIVEIL_H + +#include <linux/pci.h> +#include <linux/irq.h> +#include <linux/msi.h> +#include "../../pci.h" + +/* register offsets and bit positions */ + +/* + * translation tables are grouped into windows, each windowregistersquoted
quoted
arequoted
quoted
quoted
+ * grouped into blocks of 4 or 16 registers each + */ +#define PAB_REG_BLOCK_SIZE 16 +#define PAB_EXT_REG_BLOCK_SIZE 4 + +#define PAB_REG_ADDR(offset, win) \ + (offset + (win * PAB_REG_BLOCK_SIZE)) +#define PAB_EXT_REG_ADDR(offset, win) \ + (offset + (win * PAB_EXT_REG_BLOCK_SIZE)) + +#define LTSSM_STATUS 0x0404 +#define LTSSM_STATUS_L0_MASK 0x3f +#define LTSSM_STATUS_L0 0x2d + +#define PAB_CTRL 0x0808 +#define AMBA_PIO_ENABLE_SHIFT 0 +#define PEX_PIO_ENABLE_SHIFT 1 +#define PAGE_SEL_SHIFT 13 +#define PAGE_SEL_MASK 0x3f +#define PAGE_LO_MASK 0x3ff +#define PAGE_SEL_OFFSET_SHIFT 10 + +#define PAB_AXI_PIO_CTRL 0x0840 +#define APIO_EN_MASK 0xf + +#define PAB_PEX_PIO_CTRL 0x08c0 +#define PIO_ENABLE_SHIFT 0 + +#define PAB_INTP_AMBA_MISC_ENB 0x0b0c +#define PAB_INTP_AMBA_MISC_STAT 0x0b1c +#define PAB_INTP_INTX_MASK 0x01e0 +#define PAB_INTP_MSI_MASK 0x8 + +#define PAB_AXI_AMAP_CTRL(win)PAB_REG_ADDR(0x0ba0,quoted
quoted
win)quoted
quoted
quoted
+#define WIN_ENABLE_SHIFT 0 +#define WIN_TYPE_SHIFT 1 +#define WIN_TYPE_MASK 0x3 +#define WIN_SIZE_SHIFT 10 +#define WIN_SIZE_MASK 0x3fffff + +#define PAB_EXT_AXI_AMAP_SIZE(win)PAB_EXT_REG_ADDR(0xbaf0,quoted
quoted
win)quoted
+ +#define PAB_EXT_AXI_AMAP_AXI_WIN(win)PAB_EXT_REG_ADDR(0x80a0, win)quoted
+#define PAB_AXI_AMAP_AXI_WIN(win)PAB_REG_ADDR(0x0ba4,quoted
quoted
win)quoted
quoted
quoted
+#define AXI_WINDOW_ALIGN_MASK 3 + +#define PAB_AXI_AMAP_PEX_WIN_L(win)PAB_REG_ADDR(0x0ba8,quoted
quoted
win)quoted
+#define PAB_BUS_SHIFT 24 +#define PAB_DEVICE_SHIFT 19 +#define PAB_FUNCTION_SHIFT 16 + +#define PAB_AXI_AMAP_PEX_WIN_H(win)PAB_REG_ADDR(0x0bac,quoted
quoted
win)quoted
+#define PAB_INTP_AXI_PIO_CLASS 0x474 + +#define PAB_PEX_AMAP_CTRL(win)PAB_REG_ADDR(0x4ba0,quoted
quoted
quoted
quoted
win)quoted
+#define AMAP_CTRL_EN_SHIFT 0 +#define AMAP_CTRL_TYPE_SHIFT 1 +#define AMAP_CTRL_TYPE_MASK 3 + +#define PAB_EXT_PEX_AMAP_SIZEN(win)PAB_EXT_REG_ADDR(0xbef0,quoted
quoted
win)quoted
+#define PAB_EXT_PEX_AMAP_AXI_WIN(win)PAB_EXT_REG_ADDR(0xb4a0, win)quoted
+#define PAB_PEX_AMAP_AXI_WIN(win)PAB_REG_ADDR(0x4ba4,quoted
quoted
win)quoted
quoted
quoted
+#define PAB_PEX_AMAP_PEX_WIN_L(win)PAB_REG_ADDR(0x4ba8,quoted
quoted
win)quoted
+#define PAB_PEX_AMAP_PEX_WIN_H(win)PAB_REG_ADDR(0x4bac,quoted
quoted
win)quoted
+ +/* starting offset of INTX bits in status register */ +#define PAB_INTX_START 5 + +/* supported number of MSI interrupts */ +#define PCI_NUM_MSI 16 + +/* MSI registers */ +#define MSI_BASE_LO_OFFSET 0x04 +#define MSI_BASE_HI_OFFSET 0x08 +#define MSI_SIZE_OFFSET 0x0c +#define MSI_ENABLE_OFFSET 0x14 +#define MSI_STATUS_OFFSET 0x18 +#define MSI_DATA_OFFSET 0x20 +#define MSI_ADDR_L_OFFSET 0x24 +#define MSI_ADDR_H_OFFSET 0x28 + +/* outbound and inbound window definitions */ +#define WIN_NUM_0 0 +#define WIN_NUM_1 1 +#define CFG_WINDOW_TYPE 0 +#define IO_WINDOW_TYPE 1 +#define MEM_WINDOW_TYPE 2 +#define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024) +#define MAX_PIO_WINDOWS 8 + +/* Parameters for the waiting for link up routine */ +#define LINK_WAIT_MAX_RETRIES 10 +#define LINK_WAIT_MIN 90000 +#define LINK_WAIT_MAX 100000 + +#define PAGED_ADDR_BNDRY 0xc00 +#define OFFSET_TO_PAGE_ADDR(off) \ + ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY) +#define OFFSET_TO_PAGE_IDX(off) \ + ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK) + +struct mobiveil_pcie; + +struct mobiveil_msi { /* MSI information */ + struct mutex lock; /* protect bitmap variable */ + struct irq_domain *msi_domain; + struct irq_domain *dev_domain; + phys_addr_t msi_pages_phys; + int num_of_vectors; + DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI); +}; + +struct mobiveil_rp_ops { + int (*interrupt_init)(struct mobiveil_pcie *pcie); +}; + +struct root_port { + u8 root_bus_nr; + void __iomem *config_axi_slave_base; /* endpoint configbasequoted
quoted
*/quoted
quoted
quoted
+ struct resource *ob_io_res; + struct mobiveil_rp_ops *ops; + int irq; + raw_spinlock_t intx_mask_lock; + struct irq_domain *intx_domain; + struct mobiveil_msi msi; +}; + +struct mobiveil_pab_ops { + int (*link_up)(struct mobiveil_pcie *pcie); +}; + +struct mobiveil_pcie { + struct platform_device *pdev; + struct list_head resources; + void __iomem *csr_axi_slave_base; /* PAB registers base */ + phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base*/quoted
quoted
quoted
quoted
quoted
+ void __iomem *apb_csr_base; /* MSI register base */ + u32 apio_wins; + u32 ppio_wins; + u32 ob_wins_configured; /* configured outboundwindowsquoted
quoted
*/quoted
quoted
quoted
+ u32 ib_wins_configured; /* configured inboundwindows */quoted
quoted
quoted
quoted
quoted
+ const struct mobiveil_pab_ops *ops; + struct root_port rp; +}; + +int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie); +bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie); +int mobiveil_bringup_link(struct mobiveil_pcie *pcie); +void program_ob_windows(struct mobiveil_pcie *pcie, intwin_num,quoted
quoted
u64quoted
quoted
cpu_addr,quoted
+ u64 pci_addr, u32 type, u64 size); +void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,u64quoted
quoted
cpu_addr,quoted
+ u64 pci_addr, u32 type, u64 size); +u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size); +void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_tsize);quoted
quoted
quoted
quoted
quoted
+ +static inline u32 csr_readl(struct mobiveil_pcie *pcie, u32 off) +{ + return csr_read(pcie, off, 0x4); +} + +static inline void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32off)quoted
quoted
quoted
quoted
quoted
+{ + csr_write(pcie, val, off, 0x4); +} + +#endif /* _PCIE_MOBIVEIL_H */ -- 2.17.1Thanks, Zhiqiang
_______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel