Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: mobiveil: Modularize the Mobiveil PCIe Host Bridge IP driver

Modularize the Mobiveil PCIe host driver according to the abstraction of
Root Complex and Endpoint and move it into a new directory in order to
make it easier to reuse the driver functions to add new host drivers for
systems integrating the Mobiveil PCIe GPEX IP.

Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
[lorenzo.pieralisi@arm.com: updated commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Andrew Murray <andrew.murray@arm.com>

authored by

Hou Zhiqiang and committed by
Lorenzo Pieralisi
03bdc388 39e3a03e

+499 -411
+1 -1
MAINTAINERS
··· 12794 12794 L: linux-pci@vger.kernel.org 12795 12795 S: Supported 12796 12796 F: Documentation/devicetree/bindings/pci/mobiveil-pcie.txt 12797 - F: drivers/pci/controller/pcie-mobiveil.c 12797 + F: drivers/pci/controller/mobiveil/pcie-mobiveil* 12798 12798 12799 12799 PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support) 12800 12800 M: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+1 -10
drivers/pci/controller/Kconfig
··· 213 213 Say Y here if you want to enable PCIe controller support on 214 214 MediaTek SoCs. 215 215 216 - config PCIE_MOBIVEIL 217 - bool "Mobiveil AXI PCIe controller" 218 - depends on ARCH_ZYNQMP || COMPILE_TEST 219 - depends on OF 220 - depends on PCI_MSI_IRQ_DOMAIN 221 - help 222 - Say Y here if you want to enable support for the Mobiveil AXI PCIe 223 - Soft IP. It has up to 8 outbound and inbound windows 224 - for address translation and it is a PCIe Gen4 IP. 225 - 226 216 config PCIE_TANGO_SMP8759 227 217 bool "Tango SMP8759 PCIe controller (DANGEROUS)" 228 218 depends on ARCH_TANGO && PCI_MSI && OF ··· 259 269 have a common interface with the Hyper-V PCI frontend driver. 260 270 261 271 source "drivers/pci/controller/dwc/Kconfig" 272 + source "drivers/pci/controller/mobiveil/Kconfig" 262 273 source "drivers/pci/controller/cadence/Kconfig" 263 274 endmenu
+1 -1
drivers/pci/controller/Makefile
··· 25 25 obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o 26 26 obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o 27 27 obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o 28 - obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o 29 28 obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o 30 29 obj-$(CONFIG_VMD) += vmd.o 31 30 obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o 32 31 # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW 33 32 obj-y += dwc/ 33 + obj-y += mobiveil/ 34 34 35 35 36 36 # The following drivers are for devices that use the generic ACPI
+24
drivers/pci/controller/mobiveil/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + menu "Mobiveil PCIe Core Support" 4 + depends on PCI 5 + 6 + config PCIE_MOBIVEIL 7 + bool 8 + 9 + config PCIE_MOBIVEIL_HOST 10 + bool 11 + depends on PCI_MSI_IRQ_DOMAIN 12 + select PCIE_MOBIVEIL 13 + 14 + config PCIE_MOBIVEIL_PLAT 15 + bool "Mobiveil AXI PCIe controller" 16 + depends on ARCH_ZYNQMP || COMPILE_TEST 17 + depends on OF 18 + select PCIE_MOBIVEIL_HOST 19 + help 20 + Say Y here if you want to enable support for the Mobiveil AXI PCIe 21 + Soft IP. It has up to 8 outbound and inbound windows 22 + for address translation and it is a PCIe Gen4 IP. 23 + 24 + endmenu
+4
drivers/pci/controller/mobiveil/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o 3 + obj-$(CONFIG_PCIE_MOBIVEIL_HOST) += pcie-mobiveil-host.o 4 + obj-$(CONFIG_PCIE_MOBIVEIL_PLAT) += pcie-mobiveil-plat.o
+61
drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * PCIe host controller driver for Mobiveil PCIe Host controller 4 + * 5 + * Copyright (c) 2018 Mobiveil Inc. 6 + * Copyright 2019 NXP 7 + * 8 + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in> 9 + * Hou Zhiqiang <Zhiqiang.Hou@nxp.com> 10 + */ 11 + 12 + #include <linux/init.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/of_pci.h> 16 + #include <linux/pci.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/slab.h> 19 + 20 + #include "pcie-mobiveil.h" 21 + 22 + static int mobiveil_pcie_probe(struct platform_device *pdev) 23 + { 24 + struct mobiveil_pcie *pcie; 25 + struct pci_host_bridge *bridge; 26 + struct device *dev = &pdev->dev; 27 + 28 + /* allocate the PCIe port */ 29 + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); 30 + if (!bridge) 31 + return -ENOMEM; 32 + 33 + pcie = pci_host_bridge_priv(bridge); 34 + pcie->rp.bridge = bridge; 35 + 36 + pcie->pdev = pdev; 37 + 38 + return mobiveil_pcie_host_probe(pcie); 39 + } 40 + 41 + static const struct of_device_id mobiveil_pcie_of_match[] = { 42 + {.compatible = "mbvl,gpex40-pcie",}, 43 + {}, 44 + }; 45 + 46 + MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match); 47 + 48 + static struct platform_driver mobiveil_pcie_driver = { 49 + .probe = mobiveil_pcie_probe, 50 + .driver = { 51 + .name = "mobiveil-pcie", 52 + .of_match_table = mobiveil_pcie_of_match, 53 + .suppress_bind_attrs = true, 54 + }, 55 + }; 56 + 57 + builtin_platform_driver(mobiveil_pcie_driver); 58 + 59 + MODULE_LICENSE("GPL v2"); 60 + MODULE_DESCRIPTION("Mobiveil PCIe host controller driver"); 61 + MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
+227
drivers/pci/controller/mobiveil/pcie-mobiveil.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * PCIe host controller driver for Mobiveil PCIe Host controller 4 + * 5 + * Copyright (c) 2018 Mobiveil Inc. 6 + * Copyright 2019 NXP 7 + * 8 + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in> 9 + * Hou Zhiqiang <Zhiqiang.Hou@nxp.com> 10 + */ 11 + 12 + #include <linux/delay.h> 13 + #include <linux/init.h> 14 + #include <linux/kernel.h> 15 + #include <linux/pci.h> 16 + #include <linux/platform_device.h> 17 + 18 + #include "pcie-mobiveil.h" 19 + 20 + /* 21 + * mobiveil_pcie_sel_page - routine to access paged register 22 + * 23 + * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged, 24 + * for this scheme to work extracted higher 6 bits of the offset will be 25 + * written to pg_sel field of PAB_CTRL register and rest of the lower 10 26 + * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register. 27 + */ 28 + static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx) 29 + { 30 + u32 val; 31 + 32 + val = readl(pcie->csr_axi_slave_base + PAB_CTRL); 33 + val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT); 34 + val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT; 35 + 36 + writel(val, pcie->csr_axi_slave_base + PAB_CTRL); 37 + } 38 + 39 + static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off) 40 + { 41 + if (off < PAGED_ADDR_BNDRY) { 42 + /* For directly accessed registers, clear the pg_sel field */ 43 + mobiveil_pcie_sel_page(pcie, 0); 44 + return pcie->csr_axi_slave_base + off; 45 + } 46 + 47 + mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off)); 48 + return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off); 49 + } 50 + 51 + static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val) 52 + { 53 + if ((uintptr_t)addr & (size - 1)) { 54 + *val = 0; 55 + return PCIBIOS_BAD_REGISTER_NUMBER; 56 + } 57 + 58 + switch (size) { 59 + case 4: 60 + *val = readl(addr); 61 + break; 62 + case 2: 63 + *val = readw(addr); 64 + break; 65 + case 1: 66 + *val = readb(addr); 67 + break; 68 + default: 69 + *val = 0; 70 + return PCIBIOS_BAD_REGISTER_NUMBER; 71 + } 72 + 73 + return PCIBIOS_SUCCESSFUL; 74 + } 75 + 76 + static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val) 77 + { 78 + if ((uintptr_t)addr & (size - 1)) 79 + return PCIBIOS_BAD_REGISTER_NUMBER; 80 + 81 + switch (size) { 82 + case 4: 83 + writel(val, addr); 84 + break; 85 + case 2: 86 + writew(val, addr); 87 + break; 88 + case 1: 89 + writeb(val, addr); 90 + break; 91 + default: 92 + return PCIBIOS_BAD_REGISTER_NUMBER; 93 + } 94 + 95 + return PCIBIOS_SUCCESSFUL; 96 + } 97 + 98 + u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size) 99 + { 100 + void *addr; 101 + u32 val; 102 + int ret; 103 + 104 + addr = mobiveil_pcie_comp_addr(pcie, off); 105 + 106 + ret = mobiveil_pcie_read(addr, size, &val); 107 + if (ret) 108 + dev_err(&pcie->pdev->dev, "read CSR address failed\n"); 109 + 110 + return val; 111 + } 112 + 113 + void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, 114 + size_t size) 115 + { 116 + void *addr; 117 + int ret; 118 + 119 + addr = mobiveil_pcie_comp_addr(pcie, off); 120 + 121 + ret = mobiveil_pcie_write(addr, size, val); 122 + if (ret) 123 + dev_err(&pcie->pdev->dev, "write CSR address failed\n"); 124 + } 125 + 126 + bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie) 127 + { 128 + return (mobiveil_csr_readl(pcie, LTSSM_STATUS) & 129 + LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0; 130 + } 131 + 132 + void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, 133 + u64 cpu_addr, u64 pci_addr, u32 type, u64 size) 134 + { 135 + u32 value; 136 + u64 size64 = ~(size - 1); 137 + 138 + if (win_num >= pcie->ppio_wins) { 139 + dev_err(&pcie->pdev->dev, 140 + "ERROR: max inbound windows reached !\n"); 141 + return; 142 + } 143 + 144 + value = mobiveil_csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num)); 145 + value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK); 146 + value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT | 147 + (lower_32_bits(size64) & WIN_SIZE_MASK); 148 + mobiveil_csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num)); 149 + 150 + mobiveil_csr_writel(pcie, upper_32_bits(size64), 151 + PAB_EXT_PEX_AMAP_SIZEN(win_num)); 152 + 153 + mobiveil_csr_writel(pcie, lower_32_bits(cpu_addr), 154 + PAB_PEX_AMAP_AXI_WIN(win_num)); 155 + mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr), 156 + PAB_EXT_PEX_AMAP_AXI_WIN(win_num)); 157 + 158 + mobiveil_csr_writel(pcie, lower_32_bits(pci_addr), 159 + PAB_PEX_AMAP_PEX_WIN_L(win_num)); 160 + mobiveil_csr_writel(pcie, upper_32_bits(pci_addr), 161 + PAB_PEX_AMAP_PEX_WIN_H(win_num)); 162 + 163 + pcie->ib_wins_configured++; 164 + } 165 + 166 + /* 167 + * routine to program the outbound windows 168 + */ 169 + void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, 170 + u64 cpu_addr, u64 pci_addr, u32 type, u64 size) 171 + { 172 + u32 value; 173 + u64 size64 = ~(size - 1); 174 + 175 + if (win_num >= pcie->apio_wins) { 176 + dev_err(&pcie->pdev->dev, 177 + "ERROR: max outbound windows reached !\n"); 178 + return; 179 + } 180 + 181 + /* 182 + * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit 183 + * to 4 KB in PAB_AXI_AMAP_CTRL register 184 + */ 185 + value = mobiveil_csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num)); 186 + value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK); 187 + value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT | 188 + (lower_32_bits(size64) & WIN_SIZE_MASK); 189 + mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num)); 190 + 191 + mobiveil_csr_writel(pcie, upper_32_bits(size64), 192 + PAB_EXT_AXI_AMAP_SIZE(win_num)); 193 + 194 + /* 195 + * program AXI window base with appropriate value in 196 + * PAB_AXI_AMAP_AXI_WIN0 register 197 + */ 198 + mobiveil_csr_writel(pcie, 199 + lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK), 200 + PAB_AXI_AMAP_AXI_WIN(win_num)); 201 + mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr), 202 + PAB_EXT_AXI_AMAP_AXI_WIN(win_num)); 203 + 204 + mobiveil_csr_writel(pcie, lower_32_bits(pci_addr), 205 + PAB_AXI_AMAP_PEX_WIN_L(win_num)); 206 + mobiveil_csr_writel(pcie, upper_32_bits(pci_addr), 207 + PAB_AXI_AMAP_PEX_WIN_H(win_num)); 208 + 209 + pcie->ob_wins_configured++; 210 + } 211 + 212 + int mobiveil_bringup_link(struct mobiveil_pcie *pcie) 213 + { 214 + int retries; 215 + 216 + /* check if the link is up or not */ 217 + for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { 218 + if (mobiveil_pcie_link_up(pcie)) 219 + return 0; 220 + 221 + usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX); 222 + } 223 + 224 + dev_err(&pcie->pdev->dev, "link never came up\n"); 225 + 226 + return -ETIMEDOUT; 227 + }
+178
drivers/pci/controller/mobiveil/pcie-mobiveil.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * PCIe host controller driver for Mobiveil PCIe Host controller 4 + * 5 + * Copyright (c) 2018 Mobiveil Inc. 6 + * Copyright 2019 NXP 7 + * 8 + * Author: Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in> 9 + * Hou Zhiqiang <Zhiqiang.Hou@nxp.com> 10 + */ 11 + 12 + #ifndef _PCIE_MOBIVEIL_H 13 + #define _PCIE_MOBIVEIL_H 14 + 15 + #include <linux/pci.h> 16 + #include <linux/irq.h> 17 + #include <linux/msi.h> 18 + #include "../../pci.h" 19 + 20 + /* register offsets and bit positions */ 21 + 22 + /* 23 + * translation tables are grouped into windows, each window registers are 24 + * grouped into blocks of 4 or 16 registers each 25 + */ 26 + #define PAB_REG_BLOCK_SIZE 16 27 + #define PAB_EXT_REG_BLOCK_SIZE 4 28 + 29 + #define PAB_REG_ADDR(offset, win) \ 30 + (offset + (win * PAB_REG_BLOCK_SIZE)) 31 + #define PAB_EXT_REG_ADDR(offset, win) \ 32 + (offset + (win * PAB_EXT_REG_BLOCK_SIZE)) 33 + 34 + #define LTSSM_STATUS 0x0404 35 + #define LTSSM_STATUS_L0_MASK 0x3f 36 + #define LTSSM_STATUS_L0 0x2d 37 + 38 + #define PAB_CTRL 0x0808 39 + #define AMBA_PIO_ENABLE_SHIFT 0 40 + #define PEX_PIO_ENABLE_SHIFT 1 41 + #define PAGE_SEL_SHIFT 13 42 + #define PAGE_SEL_MASK 0x3f 43 + #define PAGE_LO_MASK 0x3ff 44 + #define PAGE_SEL_OFFSET_SHIFT 10 45 + 46 + #define PAB_AXI_PIO_CTRL 0x0840 47 + #define APIO_EN_MASK 0xf 48 + 49 + #define PAB_PEX_PIO_CTRL 0x08c0 50 + #define PIO_ENABLE_SHIFT 0 51 + 52 + #define PAB_INTP_AMBA_MISC_ENB 0x0b0c 53 + #define PAB_INTP_AMBA_MISC_STAT 0x0b1c 54 + #define PAB_INTP_INTX_MASK 0x01e0 55 + #define PAB_INTP_MSI_MASK 0x8 56 + 57 + #define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win) 58 + #define WIN_ENABLE_SHIFT 0 59 + #define WIN_TYPE_SHIFT 1 60 + #define WIN_TYPE_MASK 0x3 61 + #define WIN_SIZE_MASK 0xfffffc00 62 + 63 + #define PAB_EXT_AXI_AMAP_SIZE(win) PAB_EXT_REG_ADDR(0xbaf0, win) 64 + 65 + #define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win) 66 + #define PAB_AXI_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x0ba4, win) 67 + #define AXI_WINDOW_ALIGN_MASK 3 68 + 69 + #define PAB_AXI_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x0ba8, win) 70 + #define PAB_BUS_SHIFT 24 71 + #define PAB_DEVICE_SHIFT 19 72 + #define PAB_FUNCTION_SHIFT 16 73 + 74 + #define PAB_AXI_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x0bac, win) 75 + #define PAB_INTP_AXI_PIO_CLASS 0x474 76 + 77 + #define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win) 78 + #define AMAP_CTRL_EN_SHIFT 0 79 + #define AMAP_CTRL_TYPE_SHIFT 1 80 + #define AMAP_CTRL_TYPE_MASK 3 81 + 82 + #define PAB_EXT_PEX_AMAP_SIZEN(win) PAB_EXT_REG_ADDR(0xbef0, win) 83 + #define PAB_EXT_PEX_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0xb4a0, win) 84 + #define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win) 85 + #define PAB_PEX_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x4ba8, win) 86 + #define PAB_PEX_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x4bac, win) 87 + 88 + /* starting offset of INTX bits in status register */ 89 + #define PAB_INTX_START 5 90 + 91 + /* supported number of MSI interrupts */ 92 + #define PCI_NUM_MSI 16 93 + 94 + /* MSI registers */ 95 + #define MSI_BASE_LO_OFFSET 0x04 96 + #define MSI_BASE_HI_OFFSET 0x08 97 + #define MSI_SIZE_OFFSET 0x0c 98 + #define MSI_ENABLE_OFFSET 0x14 99 + #define MSI_STATUS_OFFSET 0x18 100 + #define MSI_DATA_OFFSET 0x20 101 + #define MSI_ADDR_L_OFFSET 0x24 102 + #define MSI_ADDR_H_OFFSET 0x28 103 + 104 + /* outbound and inbound window definitions */ 105 + #define WIN_NUM_0 0 106 + #define WIN_NUM_1 1 107 + #define CFG_WINDOW_TYPE 0 108 + #define IO_WINDOW_TYPE 1 109 + #define MEM_WINDOW_TYPE 2 110 + #define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024) 111 + #define MAX_PIO_WINDOWS 8 112 + 113 + /* Parameters for the waiting for link up routine */ 114 + #define LINK_WAIT_MAX_RETRIES 10 115 + #define LINK_WAIT_MIN 90000 116 + #define LINK_WAIT_MAX 100000 117 + 118 + #define PAGED_ADDR_BNDRY 0xc00 119 + #define OFFSET_TO_PAGE_ADDR(off) \ 120 + ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY) 121 + #define OFFSET_TO_PAGE_IDX(off) \ 122 + ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK) 123 + 124 + struct mobiveil_msi { /* MSI information */ 125 + struct mutex lock; /* protect bitmap variable */ 126 + struct irq_domain *msi_domain; 127 + struct irq_domain *dev_domain; 128 + phys_addr_t msi_pages_phys; 129 + int num_of_vectors; 130 + DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI); 131 + }; 132 + 133 + struct mobiveil_root_port { 134 + char root_bus_nr; 135 + void __iomem *config_axi_slave_base; /* endpoint config base */ 136 + struct resource *ob_io_res; 137 + int irq; 138 + raw_spinlock_t intx_mask_lock; 139 + struct irq_domain *intx_domain; 140 + struct mobiveil_msi msi; 141 + struct pci_host_bridge *bridge; 142 + }; 143 + 144 + struct mobiveil_pcie { 145 + struct platform_device *pdev; 146 + void __iomem *csr_axi_slave_base; /* root port config base */ 147 + void __iomem *apb_csr_base; /* MSI register base */ 148 + phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base */ 149 + int apio_wins; 150 + int ppio_wins; 151 + int ob_wins_configured; /* configured outbound windows */ 152 + int ib_wins_configured; /* configured inbound windows */ 153 + struct mobiveil_root_port rp; 154 + }; 155 + 156 + int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie); 157 + bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie); 158 + int mobiveil_bringup_link(struct mobiveil_pcie *pcie); 159 + void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr, 160 + u64 pci_addr, u32 type, u64 size); 161 + void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, u64 cpu_addr, 162 + u64 pci_addr, u32 type, u64 size); 163 + u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size); 164 + void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, 165 + size_t size); 166 + 167 + static inline u32 mobiveil_csr_readl(struct mobiveil_pcie *pcie, u32 off) 168 + { 169 + return mobiveil_csr_read(pcie, off, 0x4); 170 + } 171 + 172 + static inline void mobiveil_csr_writel(struct mobiveil_pcie *pcie, u32 val, 173 + u32 off) 174 + { 175 + mobiveil_csr_write(pcie, val, off, 0x4); 176 + } 177 + 178 + #endif /* _PCIE_MOBIVEIL_H */
+2 -399
drivers/pci/controller/pcie-mobiveil.c drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
··· 9 9 * Hou Zhiqiang <Zhiqiang.Hou@nxp.com> 10 10 */ 11 11 12 - #include <linux/delay.h> 13 12 #include <linux/init.h> 14 13 #include <linux/interrupt.h> 15 14 #include <linux/irq.h> ··· 25 26 #include <linux/platform_device.h> 26 27 #include <linux/slab.h> 27 28 28 - #include "../pci.h" 29 - 30 - /* register offsets and bit positions */ 31 - 32 - /* 33 - * translation tables are grouped into windows, each window registers are 34 - * grouped into blocks of 4 or 16 registers each 35 - */ 36 - #define PAB_REG_BLOCK_SIZE 16 37 - #define PAB_EXT_REG_BLOCK_SIZE 4 38 - 39 - #define PAB_REG_ADDR(offset, win) \ 40 - (offset + (win * PAB_REG_BLOCK_SIZE)) 41 - #define PAB_EXT_REG_ADDR(offset, win) \ 42 - (offset + (win * PAB_EXT_REG_BLOCK_SIZE)) 43 - 44 - #define LTSSM_STATUS 0x0404 45 - #define LTSSM_STATUS_L0_MASK 0x3f 46 - #define LTSSM_STATUS_L0 0x2d 47 - 48 - #define PAB_CTRL 0x0808 49 - #define AMBA_PIO_ENABLE_SHIFT 0 50 - #define PEX_PIO_ENABLE_SHIFT 1 51 - #define PAGE_SEL_SHIFT 13 52 - #define PAGE_SEL_MASK 0x3f 53 - #define PAGE_LO_MASK 0x3ff 54 - #define PAGE_SEL_OFFSET_SHIFT 10 55 - 56 - #define PAB_AXI_PIO_CTRL 0x0840 57 - #define APIO_EN_MASK 0xf 58 - 59 - #define PAB_PEX_PIO_CTRL 0x08c0 60 - #define PIO_ENABLE_SHIFT 0 61 - 62 - #define PAB_INTP_AMBA_MISC_ENB 0x0b0c 63 - #define PAB_INTP_AMBA_MISC_STAT 0x0b1c 64 - #define PAB_INTP_INTX_MASK 0x01e0 65 - #define PAB_INTP_MSI_MASK 0x8 66 - 67 - #define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win) 68 - #define WIN_ENABLE_SHIFT 0 69 - #define WIN_TYPE_SHIFT 1 70 - #define WIN_TYPE_MASK 0x3 71 - #define WIN_SIZE_MASK 0xfffffc00 72 - 73 - #define PAB_EXT_AXI_AMAP_SIZE(win) PAB_EXT_REG_ADDR(0xbaf0, win) 74 - 75 - #define PAB_EXT_AXI_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0x80a0, win) 76 - #define PAB_AXI_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x0ba4, win) 77 - #define AXI_WINDOW_ALIGN_MASK 3 78 - 79 - #define PAB_AXI_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x0ba8, win) 80 - #define PAB_BUS_SHIFT 24 81 - #define PAB_DEVICE_SHIFT 19 82 - #define PAB_FUNCTION_SHIFT 16 83 - 84 - #define PAB_AXI_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x0bac, win) 85 - #define PAB_INTP_AXI_PIO_CLASS 0x474 86 - 87 - #define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win) 88 - #define AMAP_CTRL_EN_SHIFT 0 89 - #define AMAP_CTRL_TYPE_SHIFT 1 90 - #define AMAP_CTRL_TYPE_MASK 3 91 - 92 - #define PAB_EXT_PEX_AMAP_SIZEN(win) PAB_EXT_REG_ADDR(0xbef0, win) 93 - #define PAB_EXT_PEX_AMAP_AXI_WIN(win) PAB_EXT_REG_ADDR(0xb4a0, win) 94 - #define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win) 95 - #define PAB_PEX_AMAP_PEX_WIN_L(win) PAB_REG_ADDR(0x4ba8, win) 96 - #define PAB_PEX_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x4bac, win) 97 - 98 - /* starting offset of INTX bits in status register */ 99 - #define PAB_INTX_START 5 100 - 101 - /* supported number of MSI interrupts */ 102 - #define PCI_NUM_MSI 16 103 - 104 - /* MSI registers */ 105 - #define MSI_BASE_LO_OFFSET 0x04 106 - #define MSI_BASE_HI_OFFSET 0x08 107 - #define MSI_SIZE_OFFSET 0x0c 108 - #define MSI_ENABLE_OFFSET 0x14 109 - #define MSI_STATUS_OFFSET 0x18 110 - #define MSI_DATA_OFFSET 0x20 111 - #define MSI_ADDR_L_OFFSET 0x24 112 - #define MSI_ADDR_H_OFFSET 0x28 113 - 114 - /* outbound and inbound window definitions */ 115 - #define WIN_NUM_0 0 116 - #define WIN_NUM_1 1 117 - #define CFG_WINDOW_TYPE 0 118 - #define IO_WINDOW_TYPE 1 119 - #define MEM_WINDOW_TYPE 2 120 - #define IB_WIN_SIZE ((u64)256 * 1024 * 1024 * 1024) 121 - #define MAX_PIO_WINDOWS 8 122 - 123 - /* Parameters for the waiting for link up routine */ 124 - #define LINK_WAIT_MAX_RETRIES 10 125 - #define LINK_WAIT_MIN 90000 126 - #define LINK_WAIT_MAX 100000 127 - 128 - #define PAGED_ADDR_BNDRY 0xc00 129 - #define OFFSET_TO_PAGE_ADDR(off) \ 130 - ((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY) 131 - #define OFFSET_TO_PAGE_IDX(off) \ 132 - ((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK) 133 - 134 - struct mobiveil_msi { /* MSI information */ 135 - struct mutex lock; /* protect bitmap variable */ 136 - struct irq_domain *msi_domain; 137 - struct irq_domain *dev_domain; 138 - phys_addr_t msi_pages_phys; 139 - int num_of_vectors; 140 - DECLARE_BITMAP(msi_irq_in_use, PCI_NUM_MSI); 141 - }; 142 - 143 - struct mobiveil_root_port { 144 - char root_bus_nr; 145 - void __iomem *config_axi_slave_base; /* endpoint config base */ 146 - struct resource *ob_io_res; 147 - int irq; 148 - raw_spinlock_t intx_mask_lock; 149 - struct irq_domain *intx_domain; 150 - struct mobiveil_msi msi; 151 - struct pci_host_bridge *bridge; 152 - }; 153 - 154 - struct mobiveil_pcie { 155 - struct platform_device *pdev; 156 - void __iomem *csr_axi_slave_base; /* root port config base */ 157 - void __iomem *apb_csr_base; /* MSI register base */ 158 - phys_addr_t pcie_reg_base; /* Physical PCIe Controller Base */ 159 - int apio_wins; 160 - int ppio_wins; 161 - int ob_wins_configured; /* configured outbound windows */ 162 - int ib_wins_configured; /* configured inbound windows */ 163 - struct mobiveil_root_port rp; 164 - }; 165 - 166 - /* 167 - * mobiveil_pcie_sel_page - routine to access paged register 168 - * 169 - * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged, 170 - * for this scheme to work extracted higher 6 bits of the offset will be 171 - * written to pg_sel field of PAB_CTRL register and rest of the lower 10 172 - * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register. 173 - */ 174 - static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx) 175 - { 176 - u32 val; 177 - 178 - val = readl(pcie->csr_axi_slave_base + PAB_CTRL); 179 - val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT); 180 - val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT; 181 - 182 - writel(val, pcie->csr_axi_slave_base + PAB_CTRL); 183 - } 184 - 185 - static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off) 186 - { 187 - if (off < PAGED_ADDR_BNDRY) { 188 - /* For directly accessed registers, clear the pg_sel field */ 189 - mobiveil_pcie_sel_page(pcie, 0); 190 - return pcie->csr_axi_slave_base + off; 191 - } 192 - 193 - mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off)); 194 - return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off); 195 - } 196 - 197 - static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val) 198 - { 199 - if ((uintptr_t)addr & (size - 1)) { 200 - *val = 0; 201 - return PCIBIOS_BAD_REGISTER_NUMBER; 202 - } 203 - 204 - switch (size) { 205 - case 4: 206 - *val = readl(addr); 207 - break; 208 - case 2: 209 - *val = readw(addr); 210 - break; 211 - case 1: 212 - *val = readb(addr); 213 - break; 214 - default: 215 - *val = 0; 216 - return PCIBIOS_BAD_REGISTER_NUMBER; 217 - } 218 - 219 - return PCIBIOS_SUCCESSFUL; 220 - } 221 - 222 - static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val) 223 - { 224 - if ((uintptr_t)addr & (size - 1)) 225 - return PCIBIOS_BAD_REGISTER_NUMBER; 226 - 227 - switch (size) { 228 - case 4: 229 - writel(val, addr); 230 - break; 231 - case 2: 232 - writew(val, addr); 233 - break; 234 - case 1: 235 - writeb(val, addr); 236 - break; 237 - default: 238 - return PCIBIOS_BAD_REGISTER_NUMBER; 239 - } 240 - 241 - return PCIBIOS_SUCCESSFUL; 242 - } 243 - 244 - static u32 mobiveil_csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size) 245 - { 246 - void *addr; 247 - u32 val; 248 - int ret; 249 - 250 - addr = mobiveil_pcie_comp_addr(pcie, off); 251 - 252 - ret = mobiveil_pcie_read(addr, size, &val); 253 - if (ret) 254 - dev_err(&pcie->pdev->dev, "read CSR address failed\n"); 255 - 256 - return val; 257 - } 258 - 259 - static void mobiveil_csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, 260 - size_t size) 261 - { 262 - void *addr; 263 - int ret; 264 - 265 - addr = mobiveil_pcie_comp_addr(pcie, off); 266 - 267 - ret = mobiveil_pcie_write(addr, size, val); 268 - if (ret) 269 - dev_err(&pcie->pdev->dev, "write CSR address failed\n"); 270 - } 271 - 272 - static u32 mobiveil_csr_readl(struct mobiveil_pcie *pcie, u32 off) 273 - { 274 - return mobiveil_csr_read(pcie, off, 0x4); 275 - } 276 - 277 - static void mobiveil_csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off) 278 - { 279 - mobiveil_csr_write(pcie, val, off, 0x4); 280 - } 281 - 282 - static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie) 283 - { 284 - return (mobiveil_csr_readl(pcie, LTSSM_STATUS) & 285 - LTSSM_STATUS_L0_MASK) == LTSSM_STATUS_L0; 286 - } 29 + #include "pcie-mobiveil.h" 287 30 288 31 static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) 289 32 { ··· 203 462 pcie->ppio_wins = MAX_PIO_WINDOWS; 204 463 205 464 return 0; 206 - } 207 - 208 - static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num, 209 - u64 cpu_addr, u64 pci_addr, u32 type, u64 size) 210 - { 211 - u32 value; 212 - u64 size64 = ~(size - 1); 213 - 214 - if (win_num >= pcie->ppio_wins) { 215 - dev_err(&pcie->pdev->dev, 216 - "ERROR: max inbound windows reached !\n"); 217 - return; 218 - } 219 - 220 - value = mobiveil_csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num)); 221 - value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK); 222 - value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT | 223 - (lower_32_bits(size64) & WIN_SIZE_MASK); 224 - mobiveil_csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num)); 225 - 226 - mobiveil_csr_writel(pcie, upper_32_bits(size64), 227 - PAB_EXT_PEX_AMAP_SIZEN(win_num)); 228 - 229 - mobiveil_csr_writel(pcie, lower_32_bits(cpu_addr), 230 - PAB_PEX_AMAP_AXI_WIN(win_num)); 231 - mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr), 232 - PAB_EXT_PEX_AMAP_AXI_WIN(win_num)); 233 - 234 - mobiveil_csr_writel(pcie, lower_32_bits(pci_addr), 235 - PAB_PEX_AMAP_PEX_WIN_L(win_num)); 236 - mobiveil_csr_writel(pcie, upper_32_bits(pci_addr), 237 - PAB_PEX_AMAP_PEX_WIN_H(win_num)); 238 - 239 - pcie->ib_wins_configured++; 240 - } 241 - 242 - /* 243 - * routine to program the outbound windows 244 - */ 245 - static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, 246 - u64 cpu_addr, u64 pci_addr, u32 type, u64 size) 247 - { 248 - u32 value; 249 - u64 size64 = ~(size - 1); 250 - 251 - if (win_num >= pcie->apio_wins) { 252 - dev_err(&pcie->pdev->dev, 253 - "ERROR: max outbound windows reached !\n"); 254 - return; 255 - } 256 - 257 - /* 258 - * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit 259 - * to 4 KB in PAB_AXI_AMAP_CTRL register 260 - */ 261 - value = mobiveil_csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num)); 262 - value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK); 263 - value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT | 264 - (lower_32_bits(size64) & WIN_SIZE_MASK); 265 - mobiveil_csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num)); 266 - 267 - mobiveil_csr_writel(pcie, upper_32_bits(size64), 268 - PAB_EXT_AXI_AMAP_SIZE(win_num)); 269 - 270 - /* 271 - * program AXI window base with appropriate value in 272 - * PAB_AXI_AMAP_AXI_WIN0 register 273 - */ 274 - mobiveil_csr_writel(pcie, 275 - lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK), 276 - PAB_AXI_AMAP_AXI_WIN(win_num)); 277 - mobiveil_csr_writel(pcie, upper_32_bits(cpu_addr), 278 - PAB_EXT_AXI_AMAP_AXI_WIN(win_num)); 279 - 280 - mobiveil_csr_writel(pcie, lower_32_bits(pci_addr), 281 - PAB_AXI_AMAP_PEX_WIN_L(win_num)); 282 - mobiveil_csr_writel(pcie, upper_32_bits(pci_addr), 283 - PAB_AXI_AMAP_PEX_WIN_H(win_num)); 284 - 285 - pcie->ob_wins_configured++; 286 - } 287 - 288 - static int mobiveil_bringup_link(struct mobiveil_pcie *pcie) 289 - { 290 - int retries; 291 - 292 - /* check if the link is up or not */ 293 - for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { 294 - if (mobiveil_pcie_link_up(pcie)) 295 - return 0; 296 - 297 - usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX); 298 - } 299 - 300 - dev_err(&pcie->pdev->dev, "link never came up\n"); 301 - 302 - return -ETIMEDOUT; 303 465 } 304 466 305 467 static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie) ··· 539 895 return 0; 540 896 } 541 897 542 - static int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie) 898 + int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie) 543 899 { 544 900 struct mobiveil_root_port *rp = &pcie->rp; 545 901 struct pci_host_bridge *bridge = rp->bridge; ··· 606 962 607 963 return 0; 608 964 } 609 - 610 - static int mobiveil_pcie_probe(struct platform_device *pdev) 611 - { 612 - struct mobiveil_pcie *pcie; 613 - struct pci_host_bridge *bridge; 614 - struct device *dev = &pdev->dev; 615 - 616 - /* allocate the PCIe port */ 617 - bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); 618 - if (!bridge) 619 - return -ENOMEM; 620 - 621 - pcie = pci_host_bridge_priv(bridge); 622 - pcie->rp.bridge = bridge; 623 - 624 - pcie->pdev = pdev; 625 - 626 - return mobiveil_pcie_host_probe(pcie); 627 - } 628 - 629 - static const struct of_device_id mobiveil_pcie_of_match[] = { 630 - {.compatible = "mbvl,gpex40-pcie",}, 631 - {}, 632 - }; 633 - 634 - MODULE_DEVICE_TABLE(of, mobiveil_pcie_of_match); 635 - 636 - static struct platform_driver mobiveil_pcie_driver = { 637 - .probe = mobiveil_pcie_probe, 638 - .driver = { 639 - .name = "mobiveil-pcie", 640 - .of_match_table = mobiveil_pcie_of_match, 641 - .suppress_bind_attrs = true, 642 - }, 643 - }; 644 - 645 - builtin_platform_driver(mobiveil_pcie_driver); 646 - 647 - MODULE_LICENSE("GPL v2"); 648 - MODULE_DESCRIPTION("Mobiveil PCIe host controller driver"); 649 - MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");