16e0832faSShawn Lin // SPDX-License-Identifier: GPL-2.0 26e0832faSShawn Lin /* 36e0832faSShawn Lin * Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de> 46e0832faSShawn Lin * Copyright (C) 2015 Broadcom Corporation 56e0832faSShawn Lin */ 66e0832faSShawn Lin 76e0832faSShawn Lin #include <linux/kernel.h> 86e0832faSShawn Lin #include <linux/pci.h> 96e0832faSShawn Lin #include <linux/msi.h> 106e0832faSShawn Lin #include <linux/clk.h> 116e0832faSShawn Lin #include <linux/module.h> 126e0832faSShawn Lin #include <linux/mbus.h> 136e0832faSShawn Lin #include <linux/slab.h> 146e0832faSShawn Lin #include <linux/delay.h> 156e0832faSShawn Lin #include <linux/interrupt.h> 166e0832faSShawn Lin #include <linux/irqchip/arm-gic-v3.h> 176e0832faSShawn Lin #include <linux/platform_device.h> 186e0832faSShawn Lin #include <linux/of_address.h> 196e0832faSShawn Lin #include <linux/of_pci.h> 206e0832faSShawn Lin #include <linux/of_irq.h> 216e0832faSShawn Lin #include <linux/of_platform.h> 226e0832faSShawn Lin #include <linux/phy/phy.h> 236e0832faSShawn Lin 246e0832faSShawn Lin #include "pcie-iproc.h" 256e0832faSShawn Lin 266e0832faSShawn Lin #define EP_PERST_SOURCE_SELECT_SHIFT 2 276e0832faSShawn Lin #define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT) 286e0832faSShawn Lin #define EP_MODE_SURVIVE_PERST_SHIFT 1 296e0832faSShawn Lin #define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT) 306e0832faSShawn Lin #define RC_PCIE_RST_OUTPUT_SHIFT 0 316e0832faSShawn Lin #define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT) 326e0832faSShawn Lin #define PAXC_RESET_MASK 0x7f 336e0832faSShawn Lin 346e0832faSShawn Lin #define GIC_V3_CFG_SHIFT 0 356e0832faSShawn Lin #define GIC_V3_CFG BIT(GIC_V3_CFG_SHIFT) 366e0832faSShawn Lin 376e0832faSShawn Lin #define MSI_ENABLE_CFG_SHIFT 0 386e0832faSShawn Lin #define MSI_ENABLE_CFG BIT(MSI_ENABLE_CFG_SHIFT) 396e0832faSShawn Lin 406e0832faSShawn Lin #define CFG_IND_ADDR_MASK 0x00001ffc 416e0832faSShawn Lin 426e0832faSShawn Lin #define CFG_ADDR_BUS_NUM_SHIFT 20 436e0832faSShawn Lin #define CFG_ADDR_BUS_NUM_MASK 0x0ff00000 446e0832faSShawn Lin #define CFG_ADDR_DEV_NUM_SHIFT 15 456e0832faSShawn Lin #define CFG_ADDR_DEV_NUM_MASK 0x000f8000 466e0832faSShawn Lin #define CFG_ADDR_FUNC_NUM_SHIFT 12 476e0832faSShawn Lin #define CFG_ADDR_FUNC_NUM_MASK 0x00007000 486e0832faSShawn Lin #define CFG_ADDR_REG_NUM_SHIFT 2 496e0832faSShawn Lin #define CFG_ADDR_REG_NUM_MASK 0x00000ffc 506e0832faSShawn Lin #define CFG_ADDR_CFG_TYPE_SHIFT 0 516e0832faSShawn Lin #define CFG_ADDR_CFG_TYPE_MASK 0x00000003 526e0832faSShawn Lin 536e0832faSShawn Lin #define SYS_RC_INTX_MASK 0xf 546e0832faSShawn Lin 556e0832faSShawn Lin #define PCIE_PHYLINKUP_SHIFT 3 566e0832faSShawn Lin #define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT) 576e0832faSShawn Lin #define PCIE_DL_ACTIVE_SHIFT 2 586e0832faSShawn Lin #define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT) 596e0832faSShawn Lin 606e0832faSShawn Lin #define APB_ERR_EN_SHIFT 0 616e0832faSShawn Lin #define APB_ERR_EN BIT(APB_ERR_EN_SHIFT) 626e0832faSShawn Lin 636e0832faSShawn Lin #define CFG_RETRY_STATUS 0xffff0001 646e0832faSShawn Lin #define CFG_RETRY_STATUS_TIMEOUT_US 500000 /* 500 milliseconds */ 656e0832faSShawn Lin 666e0832faSShawn Lin /* derive the enum index of the outbound/inbound mapping registers */ 676e0832faSShawn Lin #define MAP_REG(base_reg, index) ((base_reg) + (index) * 2) 686e0832faSShawn Lin 696e0832faSShawn Lin /* 706e0832faSShawn Lin * Maximum number of outbound mapping window sizes that can be supported by any 716e0832faSShawn Lin * OARR/OMAP mapping pair 726e0832faSShawn Lin */ 736e0832faSShawn Lin #define MAX_NUM_OB_WINDOW_SIZES 4 746e0832faSShawn Lin 756e0832faSShawn Lin #define OARR_VALID_SHIFT 0 766e0832faSShawn Lin #define OARR_VALID BIT(OARR_VALID_SHIFT) 776e0832faSShawn Lin #define OARR_SIZE_CFG_SHIFT 1 786e0832faSShawn Lin 796e0832faSShawn Lin /* 806e0832faSShawn Lin * Maximum number of inbound mapping region sizes that can be supported by an 816e0832faSShawn Lin * IARR 826e0832faSShawn Lin */ 836e0832faSShawn Lin #define MAX_NUM_IB_REGION_SIZES 9 846e0832faSShawn Lin 856e0832faSShawn Lin #define IMAP_VALID_SHIFT 0 866e0832faSShawn Lin #define IMAP_VALID BIT(IMAP_VALID_SHIFT) 876e0832faSShawn Lin 883bc70825SRay Jui #define IPROC_PCI_PM_CAP 0x48 893bc70825SRay Jui #define IPROC_PCI_PM_CAP_MASK 0xffff 906e0832faSShawn Lin #define IPROC_PCI_EXP_CAP 0xac 916e0832faSShawn Lin 926e0832faSShawn Lin #define IPROC_PCIE_REG_INVALID 0xffff 936e0832faSShawn Lin 946e0832faSShawn Lin /** 956e0832faSShawn Lin * iProc PCIe outbound mapping controller specific parameters 966e0832faSShawn Lin * 976e0832faSShawn Lin * @window_sizes: list of supported outbound mapping window sizes in MB 986e0832faSShawn Lin * @nr_sizes: number of supported outbound mapping window sizes 996e0832faSShawn Lin */ 1006e0832faSShawn Lin struct iproc_pcie_ob_map { 1016e0832faSShawn Lin resource_size_t window_sizes[MAX_NUM_OB_WINDOW_SIZES]; 1026e0832faSShawn Lin unsigned int nr_sizes; 1036e0832faSShawn Lin }; 1046e0832faSShawn Lin 1056e0832faSShawn Lin static const struct iproc_pcie_ob_map paxb_ob_map[] = { 1066e0832faSShawn Lin { 1076e0832faSShawn Lin /* OARR0/OMAP0 */ 1086e0832faSShawn Lin .window_sizes = { 128, 256 }, 1096e0832faSShawn Lin .nr_sizes = 2, 1106e0832faSShawn Lin }, 1116e0832faSShawn Lin { 1126e0832faSShawn Lin /* OARR1/OMAP1 */ 1136e0832faSShawn Lin .window_sizes = { 128, 256 }, 1146e0832faSShawn Lin .nr_sizes = 2, 1156e0832faSShawn Lin }, 1166e0832faSShawn Lin }; 1176e0832faSShawn Lin 1186e0832faSShawn Lin static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = { 1196e0832faSShawn Lin { 1206e0832faSShawn Lin /* OARR0/OMAP0 */ 1216e0832faSShawn Lin .window_sizes = { 128, 256 }, 1226e0832faSShawn Lin .nr_sizes = 2, 1236e0832faSShawn Lin }, 1246e0832faSShawn Lin { 1256e0832faSShawn Lin /* OARR1/OMAP1 */ 1266e0832faSShawn Lin .window_sizes = { 128, 256 }, 1276e0832faSShawn Lin .nr_sizes = 2, 1286e0832faSShawn Lin }, 1296e0832faSShawn Lin { 1306e0832faSShawn Lin /* OARR2/OMAP2 */ 1316e0832faSShawn Lin .window_sizes = { 128, 256, 512, 1024 }, 1326e0832faSShawn Lin .nr_sizes = 4, 1336e0832faSShawn Lin }, 1346e0832faSShawn Lin { 1356e0832faSShawn Lin /* OARR3/OMAP3 */ 1366e0832faSShawn Lin .window_sizes = { 128, 256, 512, 1024 }, 1376e0832faSShawn Lin .nr_sizes = 4, 1386e0832faSShawn Lin }, 1396e0832faSShawn Lin }; 1406e0832faSShawn Lin 1416e0832faSShawn Lin /** 1426e0832faSShawn Lin * iProc PCIe inbound mapping type 1436e0832faSShawn Lin */ 1446e0832faSShawn Lin enum iproc_pcie_ib_map_type { 1456e0832faSShawn Lin /* for DDR memory */ 1466e0832faSShawn Lin IPROC_PCIE_IB_MAP_MEM = 0, 1476e0832faSShawn Lin 1486e0832faSShawn Lin /* for device I/O memory */ 1496e0832faSShawn Lin IPROC_PCIE_IB_MAP_IO, 1506e0832faSShawn Lin 1516e0832faSShawn Lin /* invalid or unused */ 1526e0832faSShawn Lin IPROC_PCIE_IB_MAP_INVALID 1536e0832faSShawn Lin }; 1546e0832faSShawn Lin 1556e0832faSShawn Lin /** 1566e0832faSShawn Lin * iProc PCIe inbound mapping controller specific parameters 1576e0832faSShawn Lin * 1586e0832faSShawn Lin * @type: inbound mapping region type 1596e0832faSShawn Lin * @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or 1606e0832faSShawn Lin * SZ_1G 1616e0832faSShawn Lin * @region_sizes: list of supported inbound mapping region sizes in KB, MB, or 1626e0832faSShawn Lin * GB, depedning on the size unit 1636e0832faSShawn Lin * @nr_sizes: number of supported inbound mapping region sizes 1646e0832faSShawn Lin * @nr_windows: number of supported inbound mapping windows for the region 1656e0832faSShawn Lin * @imap_addr_offset: register offset between the upper and lower 32-bit 1666e0832faSShawn Lin * IMAP address registers 1676e0832faSShawn Lin * @imap_window_offset: register offset between each IMAP window 1686e0832faSShawn Lin */ 1696e0832faSShawn Lin struct iproc_pcie_ib_map { 1706e0832faSShawn Lin enum iproc_pcie_ib_map_type type; 1716e0832faSShawn Lin unsigned int size_unit; 1726e0832faSShawn Lin resource_size_t region_sizes[MAX_NUM_IB_REGION_SIZES]; 1736e0832faSShawn Lin unsigned int nr_sizes; 1746e0832faSShawn Lin unsigned int nr_windows; 1756e0832faSShawn Lin u16 imap_addr_offset; 1766e0832faSShawn Lin u16 imap_window_offset; 1776e0832faSShawn Lin }; 1786e0832faSShawn Lin 1796e0832faSShawn Lin static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = { 1806e0832faSShawn Lin { 1816e0832faSShawn Lin /* IARR0/IMAP0 */ 1826e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_IO, 1836e0832faSShawn Lin .size_unit = SZ_1K, 1846e0832faSShawn Lin .region_sizes = { 32 }, 1856e0832faSShawn Lin .nr_sizes = 1, 1866e0832faSShawn Lin .nr_windows = 8, 1876e0832faSShawn Lin .imap_addr_offset = 0x40, 1886e0832faSShawn Lin .imap_window_offset = 0x4, 1896e0832faSShawn Lin }, 1906e0832faSShawn Lin { 1916e0832faSShawn Lin /* IARR1/IMAP1 (currently unused) */ 1926e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_INVALID, 1936e0832faSShawn Lin }, 1946e0832faSShawn Lin { 1956e0832faSShawn Lin /* IARR2/IMAP2 */ 1966e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_MEM, 1976e0832faSShawn Lin .size_unit = SZ_1M, 1986e0832faSShawn Lin .region_sizes = { 64, 128, 256, 512, 1024, 2048, 4096, 8192, 1996e0832faSShawn Lin 16384 }, 2006e0832faSShawn Lin .nr_sizes = 9, 2016e0832faSShawn Lin .nr_windows = 1, 2026e0832faSShawn Lin .imap_addr_offset = 0x4, 2036e0832faSShawn Lin .imap_window_offset = 0x8, 2046e0832faSShawn Lin }, 2056e0832faSShawn Lin { 2066e0832faSShawn Lin /* IARR3/IMAP3 */ 2076e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_MEM, 2086e0832faSShawn Lin .size_unit = SZ_1G, 2096e0832faSShawn Lin .region_sizes = { 1, 2, 4, 8, 16, 32 }, 2106e0832faSShawn Lin .nr_sizes = 6, 2116e0832faSShawn Lin .nr_windows = 8, 2126e0832faSShawn Lin .imap_addr_offset = 0x4, 2136e0832faSShawn Lin .imap_window_offset = 0x8, 2146e0832faSShawn Lin }, 2156e0832faSShawn Lin { 2166e0832faSShawn Lin /* IARR4/IMAP4 */ 2176e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_MEM, 2186e0832faSShawn Lin .size_unit = SZ_1G, 2196e0832faSShawn Lin .region_sizes = { 32, 64, 128, 256, 512 }, 2206e0832faSShawn Lin .nr_sizes = 5, 2216e0832faSShawn Lin .nr_windows = 8, 2226e0832faSShawn Lin .imap_addr_offset = 0x4, 2236e0832faSShawn Lin .imap_window_offset = 0x8, 2246e0832faSShawn Lin }, 2256e0832faSShawn Lin }; 2266e0832faSShawn Lin 2276e0832faSShawn Lin /* 2286e0832faSShawn Lin * iProc PCIe host registers 2296e0832faSShawn Lin */ 2306e0832faSShawn Lin enum iproc_pcie_reg { 2316e0832faSShawn Lin /* clock/reset signal control */ 2326e0832faSShawn Lin IPROC_PCIE_CLK_CTRL = 0, 2336e0832faSShawn Lin 2346e0832faSShawn Lin /* 2356e0832faSShawn Lin * To allow MSI to be steered to an external MSI controller (e.g., ARM 2366e0832faSShawn Lin * GICv3 ITS) 2376e0832faSShawn Lin */ 2386e0832faSShawn Lin IPROC_PCIE_MSI_GIC_MODE, 2396e0832faSShawn Lin 2406e0832faSShawn Lin /* 2416e0832faSShawn Lin * IPROC_PCIE_MSI_BASE_ADDR and IPROC_PCIE_MSI_WINDOW_SIZE define the 2426e0832faSShawn Lin * window where the MSI posted writes are written, for the writes to be 2436e0832faSShawn Lin * interpreted as MSI writes. 2446e0832faSShawn Lin */ 2456e0832faSShawn Lin IPROC_PCIE_MSI_BASE_ADDR, 2466e0832faSShawn Lin IPROC_PCIE_MSI_WINDOW_SIZE, 2476e0832faSShawn Lin 2486e0832faSShawn Lin /* 2496e0832faSShawn Lin * To hold the address of the register where the MSI writes are 2506e0832faSShawn Lin * programed. When ARM GICv3 ITS is used, this should be programmed 2516e0832faSShawn Lin * with the address of the GITS_TRANSLATER register. 2526e0832faSShawn Lin */ 2536e0832faSShawn Lin IPROC_PCIE_MSI_ADDR_LO, 2546e0832faSShawn Lin IPROC_PCIE_MSI_ADDR_HI, 2556e0832faSShawn Lin 2566e0832faSShawn Lin /* enable MSI */ 2576e0832faSShawn Lin IPROC_PCIE_MSI_EN_CFG, 2586e0832faSShawn Lin 2596e0832faSShawn Lin /* allow access to root complex configuration space */ 2606e0832faSShawn Lin IPROC_PCIE_CFG_IND_ADDR, 2616e0832faSShawn Lin IPROC_PCIE_CFG_IND_DATA, 2626e0832faSShawn Lin 2636e0832faSShawn Lin /* allow access to device configuration space */ 2646e0832faSShawn Lin IPROC_PCIE_CFG_ADDR, 2656e0832faSShawn Lin IPROC_PCIE_CFG_DATA, 2666e0832faSShawn Lin 2676e0832faSShawn Lin /* enable INTx */ 2686e0832faSShawn Lin IPROC_PCIE_INTX_EN, 2696e0832faSShawn Lin 2706e0832faSShawn Lin /* outbound address mapping */ 2716e0832faSShawn Lin IPROC_PCIE_OARR0, 2726e0832faSShawn Lin IPROC_PCIE_OMAP0, 2736e0832faSShawn Lin IPROC_PCIE_OARR1, 2746e0832faSShawn Lin IPROC_PCIE_OMAP1, 2756e0832faSShawn Lin IPROC_PCIE_OARR2, 2766e0832faSShawn Lin IPROC_PCIE_OMAP2, 2776e0832faSShawn Lin IPROC_PCIE_OARR3, 2786e0832faSShawn Lin IPROC_PCIE_OMAP3, 2796e0832faSShawn Lin 2806e0832faSShawn Lin /* inbound address mapping */ 2816e0832faSShawn Lin IPROC_PCIE_IARR0, 2826e0832faSShawn Lin IPROC_PCIE_IMAP0, 2836e0832faSShawn Lin IPROC_PCIE_IARR1, 2846e0832faSShawn Lin IPROC_PCIE_IMAP1, 2856e0832faSShawn Lin IPROC_PCIE_IARR2, 2866e0832faSShawn Lin IPROC_PCIE_IMAP2, 2876e0832faSShawn Lin IPROC_PCIE_IARR3, 2886e0832faSShawn Lin IPROC_PCIE_IMAP3, 2896e0832faSShawn Lin IPROC_PCIE_IARR4, 2906e0832faSShawn Lin IPROC_PCIE_IMAP4, 2916e0832faSShawn Lin 2926e0832faSShawn Lin /* link status */ 2936e0832faSShawn Lin IPROC_PCIE_LINK_STATUS, 2946e0832faSShawn Lin 2956e0832faSShawn Lin /* enable APB error for unsupported requests */ 2966e0832faSShawn Lin IPROC_PCIE_APB_ERR_EN, 2976e0832faSShawn Lin 2986e0832faSShawn Lin /* total number of core registers */ 2996e0832faSShawn Lin IPROC_PCIE_MAX_NUM_REG, 3006e0832faSShawn Lin }; 3016e0832faSShawn Lin 3026e0832faSShawn Lin /* iProc PCIe PAXB BCMA registers */ 3036e0832faSShawn Lin static const u16 iproc_pcie_reg_paxb_bcma[] = { 3046e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3056e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x120, 3066e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x124, 3076e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3086e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3096e0832faSShawn Lin [IPROC_PCIE_INTX_EN] = 0x330, 3106e0832faSShawn Lin [IPROC_PCIE_LINK_STATUS] = 0xf0c, 3116e0832faSShawn Lin }; 3126e0832faSShawn Lin 3136e0832faSShawn Lin /* iProc PCIe PAXB registers */ 3146e0832faSShawn Lin static const u16 iproc_pcie_reg_paxb[] = { 3156e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3166e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x120, 3176e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x124, 3186e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3196e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3206e0832faSShawn Lin [IPROC_PCIE_INTX_EN] = 0x330, 3216e0832faSShawn Lin [IPROC_PCIE_OARR0] = 0xd20, 3226e0832faSShawn Lin [IPROC_PCIE_OMAP0] = 0xd40, 3236e0832faSShawn Lin [IPROC_PCIE_OARR1] = 0xd28, 3246e0832faSShawn Lin [IPROC_PCIE_OMAP1] = 0xd48, 3256e0832faSShawn Lin [IPROC_PCIE_LINK_STATUS] = 0xf0c, 3266e0832faSShawn Lin [IPROC_PCIE_APB_ERR_EN] = 0xf40, 3276e0832faSShawn Lin }; 3286e0832faSShawn Lin 3296e0832faSShawn Lin /* iProc PCIe PAXB v2 registers */ 3306e0832faSShawn Lin static const u16 iproc_pcie_reg_paxb_v2[] = { 3316e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3326e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x120, 3336e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x124, 3346e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3356e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3366e0832faSShawn Lin [IPROC_PCIE_INTX_EN] = 0x330, 3376e0832faSShawn Lin [IPROC_PCIE_OARR0] = 0xd20, 3386e0832faSShawn Lin [IPROC_PCIE_OMAP0] = 0xd40, 3396e0832faSShawn Lin [IPROC_PCIE_OARR1] = 0xd28, 3406e0832faSShawn Lin [IPROC_PCIE_OMAP1] = 0xd48, 3416e0832faSShawn Lin [IPROC_PCIE_OARR2] = 0xd60, 3426e0832faSShawn Lin [IPROC_PCIE_OMAP2] = 0xd68, 3436e0832faSShawn Lin [IPROC_PCIE_OARR3] = 0xdf0, 3446e0832faSShawn Lin [IPROC_PCIE_OMAP3] = 0xdf8, 3456e0832faSShawn Lin [IPROC_PCIE_IARR0] = 0xd00, 3466e0832faSShawn Lin [IPROC_PCIE_IMAP0] = 0xc00, 3476e0832faSShawn Lin [IPROC_PCIE_IARR2] = 0xd10, 3486e0832faSShawn Lin [IPROC_PCIE_IMAP2] = 0xcc0, 3496e0832faSShawn Lin [IPROC_PCIE_IARR3] = 0xe00, 3506e0832faSShawn Lin [IPROC_PCIE_IMAP3] = 0xe08, 3516e0832faSShawn Lin [IPROC_PCIE_IARR4] = 0xe68, 3526e0832faSShawn Lin [IPROC_PCIE_IMAP4] = 0xe70, 3536e0832faSShawn Lin [IPROC_PCIE_LINK_STATUS] = 0xf0c, 3546e0832faSShawn Lin [IPROC_PCIE_APB_ERR_EN] = 0xf40, 3556e0832faSShawn Lin }; 3566e0832faSShawn Lin 3576e0832faSShawn Lin /* iProc PCIe PAXC v1 registers */ 3586e0832faSShawn Lin static const u16 iproc_pcie_reg_paxc[] = { 3596e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3606e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, 3616e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, 3626e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3636e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3646e0832faSShawn Lin }; 3656e0832faSShawn Lin 3666e0832faSShawn Lin /* iProc PCIe PAXC v2 registers */ 3676e0832faSShawn Lin static const u16 iproc_pcie_reg_paxc_v2[] = { 3686e0832faSShawn Lin [IPROC_PCIE_MSI_GIC_MODE] = 0x050, 3696e0832faSShawn Lin [IPROC_PCIE_MSI_BASE_ADDR] = 0x074, 3706e0832faSShawn Lin [IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078, 3716e0832faSShawn Lin [IPROC_PCIE_MSI_ADDR_LO] = 0x07c, 3726e0832faSShawn Lin [IPROC_PCIE_MSI_ADDR_HI] = 0x080, 3736e0832faSShawn Lin [IPROC_PCIE_MSI_EN_CFG] = 0x09c, 3746e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, 3756e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, 3766e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3776e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3786e0832faSShawn Lin }; 3796e0832faSShawn Lin 3803bc70825SRay Jui /* 3813bc70825SRay Jui * List of device IDs of controllers that have corrupted capability list that 3823bc70825SRay Jui * require SW fixup 3833bc70825SRay Jui */ 3843bc70825SRay Jui static const u16 iproc_pcie_corrupt_cap_did[] = { 3853bc70825SRay Jui 0x16cd, 3863bc70825SRay Jui 0x16f0, 3873bc70825SRay Jui 0xd802, 3883bc70825SRay Jui 0xd804 3893bc70825SRay Jui }; 3903bc70825SRay Jui 3916e0832faSShawn Lin static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) 3926e0832faSShawn Lin { 3936e0832faSShawn Lin struct iproc_pcie *pcie = bus->sysdata; 3946e0832faSShawn Lin return pcie; 3956e0832faSShawn Lin } 3966e0832faSShawn Lin 3976e0832faSShawn Lin static inline bool iproc_pcie_reg_is_invalid(u16 reg_offset) 3986e0832faSShawn Lin { 3996e0832faSShawn Lin return !!(reg_offset == IPROC_PCIE_REG_INVALID); 4006e0832faSShawn Lin } 4016e0832faSShawn Lin 4026e0832faSShawn Lin static inline u16 iproc_pcie_reg_offset(struct iproc_pcie *pcie, 4036e0832faSShawn Lin enum iproc_pcie_reg reg) 4046e0832faSShawn Lin { 4056e0832faSShawn Lin return pcie->reg_offsets[reg]; 4066e0832faSShawn Lin } 4076e0832faSShawn Lin 4086e0832faSShawn Lin static inline u32 iproc_pcie_read_reg(struct iproc_pcie *pcie, 4096e0832faSShawn Lin enum iproc_pcie_reg reg) 4106e0832faSShawn Lin { 4116e0832faSShawn Lin u16 offset = iproc_pcie_reg_offset(pcie, reg); 4126e0832faSShawn Lin 4136e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 4146e0832faSShawn Lin return 0; 4156e0832faSShawn Lin 4166e0832faSShawn Lin return readl(pcie->base + offset); 4176e0832faSShawn Lin } 4186e0832faSShawn Lin 4196e0832faSShawn Lin static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie, 4206e0832faSShawn Lin enum iproc_pcie_reg reg, u32 val) 4216e0832faSShawn Lin { 4226e0832faSShawn Lin u16 offset = iproc_pcie_reg_offset(pcie, reg); 4236e0832faSShawn Lin 4246e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 4256e0832faSShawn Lin return; 4266e0832faSShawn Lin 4276e0832faSShawn Lin writel(val, pcie->base + offset); 4286e0832faSShawn Lin } 4296e0832faSShawn Lin 4306e0832faSShawn Lin /** 4316e0832faSShawn Lin * APB error forwarding can be disabled during access of configuration 4326e0832faSShawn Lin * registers of the endpoint device, to prevent unsupported requests 4336e0832faSShawn Lin * (typically seen during enumeration with multi-function devices) from 4346e0832faSShawn Lin * triggering a system exception. 4356e0832faSShawn Lin */ 4366e0832faSShawn Lin static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus, 4376e0832faSShawn Lin bool disable) 4386e0832faSShawn Lin { 4396e0832faSShawn Lin struct iproc_pcie *pcie = iproc_data(bus); 4406e0832faSShawn Lin u32 val; 4416e0832faSShawn Lin 4426e0832faSShawn Lin if (bus->number && pcie->has_apb_err_disable) { 4436e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_APB_ERR_EN); 4446e0832faSShawn Lin if (disable) 4456e0832faSShawn Lin val &= ~APB_ERR_EN; 4466e0832faSShawn Lin else 4476e0832faSShawn Lin val |= APB_ERR_EN; 4486e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_APB_ERR_EN, val); 4496e0832faSShawn Lin } 4506e0832faSShawn Lin } 4516e0832faSShawn Lin 4526e0832faSShawn Lin static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie, 4536e0832faSShawn Lin unsigned int busno, 4546e0832faSShawn Lin unsigned int slot, 4556e0832faSShawn Lin unsigned int fn, 4566e0832faSShawn Lin int where) 4576e0832faSShawn Lin { 4586e0832faSShawn Lin u16 offset; 4596e0832faSShawn Lin u32 val; 4606e0832faSShawn Lin 4616e0832faSShawn Lin /* EP device access */ 4626e0832faSShawn Lin val = (busno << CFG_ADDR_BUS_NUM_SHIFT) | 4636e0832faSShawn Lin (slot << CFG_ADDR_DEV_NUM_SHIFT) | 4646e0832faSShawn Lin (fn << CFG_ADDR_FUNC_NUM_SHIFT) | 4656e0832faSShawn Lin (where & CFG_ADDR_REG_NUM_MASK) | 4666e0832faSShawn Lin (1 & CFG_ADDR_CFG_TYPE_MASK); 4676e0832faSShawn Lin 4686e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val); 4696e0832faSShawn Lin offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA); 4706e0832faSShawn Lin 4716e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 4726e0832faSShawn Lin return NULL; 4736e0832faSShawn Lin 4746e0832faSShawn Lin return (pcie->base + offset); 4756e0832faSShawn Lin } 4766e0832faSShawn Lin 4776e0832faSShawn Lin static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p) 4786e0832faSShawn Lin { 4796e0832faSShawn Lin int timeout = CFG_RETRY_STATUS_TIMEOUT_US; 4806e0832faSShawn Lin unsigned int data; 4816e0832faSShawn Lin 4826e0832faSShawn Lin /* 4836e0832faSShawn Lin * As per PCIe spec r3.1, sec 2.3.2, CRS Software Visibility only 4846e0832faSShawn Lin * affects config reads of the Vendor ID. For config writes or any 4856e0832faSShawn Lin * other config reads, the Root may automatically reissue the 4866e0832faSShawn Lin * configuration request again as a new request. 4876e0832faSShawn Lin * 4886e0832faSShawn Lin * For config reads, this hardware returns CFG_RETRY_STATUS data 4896e0832faSShawn Lin * when it receives a CRS completion, regardless of the address of 4906e0832faSShawn Lin * the read or the CRS Software Visibility Enable bit. As a 4916e0832faSShawn Lin * partial workaround for this, we retry in software any read that 4926e0832faSShawn Lin * returns CFG_RETRY_STATUS. 4936e0832faSShawn Lin * 4946e0832faSShawn Lin * Note that a non-Vendor ID config register may have a value of 4956e0832faSShawn Lin * CFG_RETRY_STATUS. If we read that, we can't distinguish it from 4966e0832faSShawn Lin * a CRS completion, so we will incorrectly retry the read and 4976e0832faSShawn Lin * eventually return the wrong data (0xffffffff). 4986e0832faSShawn Lin */ 4996e0832faSShawn Lin data = readl(cfg_data_p); 5006e0832faSShawn Lin while (data == CFG_RETRY_STATUS && timeout--) { 5016e0832faSShawn Lin udelay(1); 5026e0832faSShawn Lin data = readl(cfg_data_p); 5036e0832faSShawn Lin } 5046e0832faSShawn Lin 5056e0832faSShawn Lin if (data == CFG_RETRY_STATUS) 5066e0832faSShawn Lin data = 0xffffffff; 5076e0832faSShawn Lin 5086e0832faSShawn Lin return data; 5096e0832faSShawn Lin } 5106e0832faSShawn Lin 5113bc70825SRay Jui static void iproc_pcie_fix_cap(struct iproc_pcie *pcie, int where, u32 *val) 5123bc70825SRay Jui { 5133bc70825SRay Jui u32 i, dev_id; 5143bc70825SRay Jui 5153bc70825SRay Jui switch (where & ~0x3) { 5163bc70825SRay Jui case PCI_VENDOR_ID: 5173bc70825SRay Jui dev_id = *val >> 16; 5183bc70825SRay Jui 5193bc70825SRay Jui /* 5203bc70825SRay Jui * Activate fixup for those controllers that have corrupted 5213bc70825SRay Jui * capability list registers 5223bc70825SRay Jui */ 5233bc70825SRay Jui for (i = 0; i < ARRAY_SIZE(iproc_pcie_corrupt_cap_did); i++) 5243bc70825SRay Jui if (dev_id == iproc_pcie_corrupt_cap_did[i]) 5253bc70825SRay Jui pcie->fix_paxc_cap = true; 5263bc70825SRay Jui break; 5273bc70825SRay Jui 5283bc70825SRay Jui case IPROC_PCI_PM_CAP: 5293bc70825SRay Jui if (pcie->fix_paxc_cap) { 5303bc70825SRay Jui /* advertise PM, force next capability to PCIe */ 5313bc70825SRay Jui *val &= ~IPROC_PCI_PM_CAP_MASK; 5323bc70825SRay Jui *val |= IPROC_PCI_EXP_CAP << 8 | PCI_CAP_ID_PM; 5333bc70825SRay Jui } 5343bc70825SRay Jui break; 5353bc70825SRay Jui 5363bc70825SRay Jui case IPROC_PCI_EXP_CAP: 5373bc70825SRay Jui if (pcie->fix_paxc_cap) { 5383bc70825SRay Jui /* advertise root port, version 2, terminate here */ 5393bc70825SRay Jui *val = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2) << 16 | 5403bc70825SRay Jui PCI_CAP_ID_EXP; 5413bc70825SRay Jui } 5423bc70825SRay Jui break; 5433bc70825SRay Jui 5443bc70825SRay Jui case IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL: 5453bc70825SRay Jui /* Don't advertise CRS SV support */ 5463bc70825SRay Jui *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16); 5473bc70825SRay Jui break; 5483bc70825SRay Jui 5493bc70825SRay Jui default: 5503bc70825SRay Jui break; 5513bc70825SRay Jui } 5523bc70825SRay Jui } 5533bc70825SRay Jui 5546e0832faSShawn Lin static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, 5556e0832faSShawn Lin int where, int size, u32 *val) 5566e0832faSShawn Lin { 5576e0832faSShawn Lin struct iproc_pcie *pcie = iproc_data(bus); 5586e0832faSShawn Lin unsigned int slot = PCI_SLOT(devfn); 5596e0832faSShawn Lin unsigned int fn = PCI_FUNC(devfn); 5606e0832faSShawn Lin unsigned int busno = bus->number; 5616e0832faSShawn Lin void __iomem *cfg_data_p; 5626e0832faSShawn Lin unsigned int data; 5636e0832faSShawn Lin int ret; 5646e0832faSShawn Lin 5656e0832faSShawn Lin /* root complex access */ 5666e0832faSShawn Lin if (busno == 0) { 5676e0832faSShawn Lin ret = pci_generic_config_read32(bus, devfn, where, size, val); 5683bc70825SRay Jui if (ret == PCIBIOS_SUCCESSFUL) 5693bc70825SRay Jui iproc_pcie_fix_cap(pcie, where, val); 5706e0832faSShawn Lin 5713bc70825SRay Jui return ret; 5726e0832faSShawn Lin } 5736e0832faSShawn Lin 5746e0832faSShawn Lin cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); 5756e0832faSShawn Lin 5766e0832faSShawn Lin if (!cfg_data_p) 5776e0832faSShawn Lin return PCIBIOS_DEVICE_NOT_FOUND; 5786e0832faSShawn Lin 5796e0832faSShawn Lin data = iproc_pcie_cfg_retry(cfg_data_p); 5806e0832faSShawn Lin 5816e0832faSShawn Lin *val = data; 5826e0832faSShawn Lin if (size <= 2) 5836e0832faSShawn Lin *val = (data >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); 5846e0832faSShawn Lin 585f78e60a2SRay Jui /* 586f78e60a2SRay Jui * For PAXC and PAXCv2, the total number of PFs that one can enumerate 587f78e60a2SRay Jui * depends on the firmware configuration. Unfortunately, due to an ASIC 588f78e60a2SRay Jui * bug, unconfigured PFs cannot be properly hidden from the root 589f78e60a2SRay Jui * complex. As a result, write access to these PFs will cause bus lock 590f78e60a2SRay Jui * up on the embedded processor 591f78e60a2SRay Jui * 592f78e60a2SRay Jui * Since all unconfigured PFs are left with an incorrect, staled device 593f78e60a2SRay Jui * ID of 0x168e (PCI_DEVICE_ID_NX2_57810), we try to catch those access 594f78e60a2SRay Jui * early here and reject them all 595f78e60a2SRay Jui */ 596f78e60a2SRay Jui #define DEVICE_ID_MASK 0xffff0000 597f78e60a2SRay Jui #define DEVICE_ID_SHIFT 16 598f78e60a2SRay Jui if (pcie->rej_unconfig_pf && 599f78e60a2SRay Jui (where & CFG_ADDR_REG_NUM_MASK) == PCI_VENDOR_ID) 600f78e60a2SRay Jui if ((*val & DEVICE_ID_MASK) == 601f78e60a2SRay Jui (PCI_DEVICE_ID_NX2_57810 << DEVICE_ID_SHIFT)) 602f78e60a2SRay Jui return PCIBIOS_FUNC_NOT_SUPPORTED; 603f78e60a2SRay Jui 6046e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6056e0832faSShawn Lin } 6066e0832faSShawn Lin 6076e0832faSShawn Lin /** 6086e0832faSShawn Lin * Note access to the configuration registers are protected at the higher layer 6096e0832faSShawn Lin * by 'pci_lock' in drivers/pci/access.c 6106e0832faSShawn Lin */ 6116e0832faSShawn Lin static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, 6126e0832faSShawn Lin int busno, unsigned int devfn, 6136e0832faSShawn Lin int where) 6146e0832faSShawn Lin { 6156e0832faSShawn Lin unsigned slot = PCI_SLOT(devfn); 6166e0832faSShawn Lin unsigned fn = PCI_FUNC(devfn); 6176e0832faSShawn Lin u16 offset; 6186e0832faSShawn Lin 6196e0832faSShawn Lin /* root complex access */ 6206e0832faSShawn Lin if (busno == 0) { 6216e0832faSShawn Lin if (slot > 0 || fn > 0) 6226e0832faSShawn Lin return NULL; 6236e0832faSShawn Lin 6246e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR, 6256e0832faSShawn Lin where & CFG_IND_ADDR_MASK); 6266e0832faSShawn Lin offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_IND_DATA); 6276e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 6286e0832faSShawn Lin return NULL; 6296e0832faSShawn Lin else 6306e0832faSShawn Lin return (pcie->base + offset); 6316e0832faSShawn Lin } 6326e0832faSShawn Lin 6336e0832faSShawn Lin /* 6346e0832faSShawn Lin * PAXC is connected to an internally emulated EP within the SoC. It 6356e0832faSShawn Lin * allows only one device. 6366e0832faSShawn Lin */ 6376e0832faSShawn Lin if (pcie->ep_is_internal) 6386e0832faSShawn Lin if (slot > 0) 6396e0832faSShawn Lin return NULL; 6406e0832faSShawn Lin 6416e0832faSShawn Lin return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); 6426e0832faSShawn Lin } 6436e0832faSShawn Lin 6446e0832faSShawn Lin static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus, 6456e0832faSShawn Lin unsigned int devfn, 6466e0832faSShawn Lin int where) 6476e0832faSShawn Lin { 6486e0832faSShawn Lin return iproc_pcie_map_cfg_bus(iproc_data(bus), bus->number, devfn, 6496e0832faSShawn Lin where); 6506e0832faSShawn Lin } 6516e0832faSShawn Lin 6526e0832faSShawn Lin static int iproc_pci_raw_config_read32(struct iproc_pcie *pcie, 6536e0832faSShawn Lin unsigned int devfn, int where, 6546e0832faSShawn Lin int size, u32 *val) 6556e0832faSShawn Lin { 6566e0832faSShawn Lin void __iomem *addr; 6576e0832faSShawn Lin 6586e0832faSShawn Lin addr = iproc_pcie_map_cfg_bus(pcie, 0, devfn, where & ~0x3); 6596e0832faSShawn Lin if (!addr) { 6606e0832faSShawn Lin *val = ~0; 6616e0832faSShawn Lin return PCIBIOS_DEVICE_NOT_FOUND; 6626e0832faSShawn Lin } 6636e0832faSShawn Lin 6646e0832faSShawn Lin *val = readl(addr); 6656e0832faSShawn Lin 6666e0832faSShawn Lin if (size <= 2) 6676e0832faSShawn Lin *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); 6686e0832faSShawn Lin 6696e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6706e0832faSShawn Lin } 6716e0832faSShawn Lin 6726e0832faSShawn Lin static int iproc_pci_raw_config_write32(struct iproc_pcie *pcie, 6736e0832faSShawn Lin unsigned int devfn, int where, 6746e0832faSShawn Lin int size, u32 val) 6756e0832faSShawn Lin { 6766e0832faSShawn Lin void __iomem *addr; 6776e0832faSShawn Lin u32 mask, tmp; 6786e0832faSShawn Lin 6796e0832faSShawn Lin addr = iproc_pcie_map_cfg_bus(pcie, 0, devfn, where & ~0x3); 6806e0832faSShawn Lin if (!addr) 6816e0832faSShawn Lin return PCIBIOS_DEVICE_NOT_FOUND; 6826e0832faSShawn Lin 6836e0832faSShawn Lin if (size == 4) { 6846e0832faSShawn Lin writel(val, addr); 6856e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6866e0832faSShawn Lin } 6876e0832faSShawn Lin 6886e0832faSShawn Lin mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); 6896e0832faSShawn Lin tmp = readl(addr) & mask; 6906e0832faSShawn Lin tmp |= val << ((where & 0x3) * 8); 6916e0832faSShawn Lin writel(tmp, addr); 6926e0832faSShawn Lin 6936e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6946e0832faSShawn Lin } 6956e0832faSShawn Lin 6966e0832faSShawn Lin static int iproc_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, 6976e0832faSShawn Lin int where, int size, u32 *val) 6986e0832faSShawn Lin { 6996e0832faSShawn Lin int ret; 7006e0832faSShawn Lin struct iproc_pcie *pcie = iproc_data(bus); 7016e0832faSShawn Lin 7026e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, true); 703f78e60a2SRay Jui if (pcie->iproc_cfg_read) 7046e0832faSShawn Lin ret = iproc_pcie_config_read(bus, devfn, where, size, val); 7056e0832faSShawn Lin else 7066e0832faSShawn Lin ret = pci_generic_config_read32(bus, devfn, where, size, val); 7076e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, false); 7086e0832faSShawn Lin 7096e0832faSShawn Lin return ret; 7106e0832faSShawn Lin } 7116e0832faSShawn Lin 7126e0832faSShawn Lin static int iproc_pcie_config_write32(struct pci_bus *bus, unsigned int devfn, 7136e0832faSShawn Lin int where, int size, u32 val) 7146e0832faSShawn Lin { 7156e0832faSShawn Lin int ret; 7166e0832faSShawn Lin 7176e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, true); 7186e0832faSShawn Lin ret = pci_generic_config_write32(bus, devfn, where, size, val); 7196e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, false); 7206e0832faSShawn Lin 7216e0832faSShawn Lin return ret; 7226e0832faSShawn Lin } 7236e0832faSShawn Lin 7246e0832faSShawn Lin static struct pci_ops iproc_pcie_ops = { 7256e0832faSShawn Lin .map_bus = iproc_pcie_bus_map_cfg_bus, 7266e0832faSShawn Lin .read = iproc_pcie_config_read32, 7276e0832faSShawn Lin .write = iproc_pcie_config_write32, 7286e0832faSShawn Lin }; 7296e0832faSShawn Lin 7306e0832faSShawn Lin static void iproc_pcie_perst_ctrl(struct iproc_pcie *pcie, bool assert) 7316e0832faSShawn Lin { 7326e0832faSShawn Lin u32 val; 7336e0832faSShawn Lin 7346e0832faSShawn Lin /* 7356e0832faSShawn Lin * PAXC and the internal emulated endpoint device downstream should not 7366e0832faSShawn Lin * be reset. If firmware has been loaded on the endpoint device at an 7376e0832faSShawn Lin * earlier boot stage, reset here causes issues. 7386e0832faSShawn Lin */ 7396e0832faSShawn Lin if (pcie->ep_is_internal) 7406e0832faSShawn Lin return; 7416e0832faSShawn Lin 7426e0832faSShawn Lin if (assert) { 7436e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); 7446e0832faSShawn Lin val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST & 7456e0832faSShawn Lin ~RC_PCIE_RST_OUTPUT; 7466e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); 7476e0832faSShawn Lin udelay(250); 7486e0832faSShawn Lin } else { 7496e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); 7506e0832faSShawn Lin val |= RC_PCIE_RST_OUTPUT; 7516e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); 7526e0832faSShawn Lin msleep(100); 7536e0832faSShawn Lin } 7546e0832faSShawn Lin } 7556e0832faSShawn Lin 7566e0832faSShawn Lin int iproc_pcie_shutdown(struct iproc_pcie *pcie) 7576e0832faSShawn Lin { 7586e0832faSShawn Lin iproc_pcie_perst_ctrl(pcie, true); 7596e0832faSShawn Lin msleep(500); 7606e0832faSShawn Lin 7616e0832faSShawn Lin return 0; 7626e0832faSShawn Lin } 7636e0832faSShawn Lin EXPORT_SYMBOL_GPL(iproc_pcie_shutdown); 7646e0832faSShawn Lin 7656e0832faSShawn Lin static int iproc_pcie_check_link(struct iproc_pcie *pcie) 7666e0832faSShawn Lin { 7676e0832faSShawn Lin struct device *dev = pcie->dev; 7686e0832faSShawn Lin u32 hdr_type, link_ctrl, link_status, class, val; 7696e0832faSShawn Lin bool link_is_active = false; 7706e0832faSShawn Lin 7716e0832faSShawn Lin /* 7726e0832faSShawn Lin * PAXC connects to emulated endpoint devices directly and does not 7736e0832faSShawn Lin * have a Serdes. Therefore skip the link detection logic here. 7746e0832faSShawn Lin */ 7756e0832faSShawn Lin if (pcie->ep_is_internal) 7766e0832faSShawn Lin return 0; 7776e0832faSShawn Lin 7786e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS); 7796e0832faSShawn Lin if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) { 7806e0832faSShawn Lin dev_err(dev, "PHY or data link is INACTIVE!\n"); 7816e0832faSShawn Lin return -ENODEV; 7826e0832faSShawn Lin } 7836e0832faSShawn Lin 7846e0832faSShawn Lin /* make sure we are not in EP mode */ 7856e0832faSShawn Lin iproc_pci_raw_config_read32(pcie, 0, PCI_HEADER_TYPE, 1, &hdr_type); 7866e0832faSShawn Lin if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) { 7876e0832faSShawn Lin dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type); 7886e0832faSShawn Lin return -EFAULT; 7896e0832faSShawn Lin } 7906e0832faSShawn Lin 7916e0832faSShawn Lin /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */ 7926e0832faSShawn Lin #define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c 7936e0832faSShawn Lin #define PCI_CLASS_BRIDGE_MASK 0xffff00 7946e0832faSShawn Lin #define PCI_CLASS_BRIDGE_SHIFT 8 7956e0832faSShawn Lin iproc_pci_raw_config_read32(pcie, 0, PCI_BRIDGE_CTRL_REG_OFFSET, 7966e0832faSShawn Lin 4, &class); 7976e0832faSShawn Lin class &= ~PCI_CLASS_BRIDGE_MASK; 7986e0832faSShawn Lin class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT); 7996e0832faSShawn Lin iproc_pci_raw_config_write32(pcie, 0, PCI_BRIDGE_CTRL_REG_OFFSET, 8006e0832faSShawn Lin 4, class); 8016e0832faSShawn Lin 8026e0832faSShawn Lin /* check link status to see if link is active */ 8036e0832faSShawn Lin iproc_pci_raw_config_read32(pcie, 0, IPROC_PCI_EXP_CAP + PCI_EXP_LNKSTA, 8046e0832faSShawn Lin 2, &link_status); 8056e0832faSShawn Lin if (link_status & PCI_EXP_LNKSTA_NLW) 8066e0832faSShawn Lin link_is_active = true; 8076e0832faSShawn Lin 8086e0832faSShawn Lin if (!link_is_active) { 8096e0832faSShawn Lin /* try GEN 1 link speed */ 8106e0832faSShawn Lin #define PCI_TARGET_LINK_SPEED_MASK 0xf 8116e0832faSShawn Lin #define PCI_TARGET_LINK_SPEED_GEN2 0x2 8126e0832faSShawn Lin #define PCI_TARGET_LINK_SPEED_GEN1 0x1 8136e0832faSShawn Lin iproc_pci_raw_config_read32(pcie, 0, 8146e0832faSShawn Lin IPROC_PCI_EXP_CAP + PCI_EXP_LNKCTL2, 8156e0832faSShawn Lin 4, &link_ctrl); 8166e0832faSShawn Lin if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) == 8176e0832faSShawn Lin PCI_TARGET_LINK_SPEED_GEN2) { 8186e0832faSShawn Lin link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK; 8196e0832faSShawn Lin link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1; 8206e0832faSShawn Lin iproc_pci_raw_config_write32(pcie, 0, 8216e0832faSShawn Lin IPROC_PCI_EXP_CAP + PCI_EXP_LNKCTL2, 8226e0832faSShawn Lin 4, link_ctrl); 8236e0832faSShawn Lin msleep(100); 8246e0832faSShawn Lin 8256e0832faSShawn Lin iproc_pci_raw_config_read32(pcie, 0, 8266e0832faSShawn Lin IPROC_PCI_EXP_CAP + PCI_EXP_LNKSTA, 8276e0832faSShawn Lin 2, &link_status); 8286e0832faSShawn Lin if (link_status & PCI_EXP_LNKSTA_NLW) 8296e0832faSShawn Lin link_is_active = true; 8306e0832faSShawn Lin } 8316e0832faSShawn Lin } 8326e0832faSShawn Lin 8336e0832faSShawn Lin dev_info(dev, "link: %s\n", link_is_active ? "UP" : "DOWN"); 8346e0832faSShawn Lin 8356e0832faSShawn Lin return link_is_active ? 0 : -ENODEV; 8366e0832faSShawn Lin } 8376e0832faSShawn Lin 8386e0832faSShawn Lin static void iproc_pcie_enable(struct iproc_pcie *pcie) 8396e0832faSShawn Lin { 8406e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_INTX_EN, SYS_RC_INTX_MASK); 8416e0832faSShawn Lin } 8426e0832faSShawn Lin 8436e0832faSShawn Lin static inline bool iproc_pcie_ob_is_valid(struct iproc_pcie *pcie, 8446e0832faSShawn Lin int window_idx) 8456e0832faSShawn Lin { 8466e0832faSShawn Lin u32 val; 8476e0832faSShawn Lin 8486e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, MAP_REG(IPROC_PCIE_OARR0, window_idx)); 8496e0832faSShawn Lin 8506e0832faSShawn Lin return !!(val & OARR_VALID); 8516e0832faSShawn Lin } 8526e0832faSShawn Lin 8536e0832faSShawn Lin static inline int iproc_pcie_ob_write(struct iproc_pcie *pcie, int window_idx, 8546e0832faSShawn Lin int size_idx, u64 axi_addr, u64 pci_addr) 8556e0832faSShawn Lin { 8566e0832faSShawn Lin struct device *dev = pcie->dev; 8576e0832faSShawn Lin u16 oarr_offset, omap_offset; 8586e0832faSShawn Lin 8596e0832faSShawn Lin /* 8606e0832faSShawn Lin * Derive the OARR/OMAP offset from the first pair (OARR0/OMAP0) based 8616e0832faSShawn Lin * on window index. 8626e0832faSShawn Lin */ 8636e0832faSShawn Lin oarr_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_OARR0, 8646e0832faSShawn Lin window_idx)); 8656e0832faSShawn Lin omap_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_OMAP0, 8666e0832faSShawn Lin window_idx)); 8676e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(oarr_offset) || 8686e0832faSShawn Lin iproc_pcie_reg_is_invalid(omap_offset)) 8696e0832faSShawn Lin return -EINVAL; 8706e0832faSShawn Lin 8716e0832faSShawn Lin /* 8726e0832faSShawn Lin * Program the OARR registers. The upper 32-bit OARR register is 8736e0832faSShawn Lin * always right after the lower 32-bit OARR register. 8746e0832faSShawn Lin */ 8756e0832faSShawn Lin writel(lower_32_bits(axi_addr) | (size_idx << OARR_SIZE_CFG_SHIFT) | 8766e0832faSShawn Lin OARR_VALID, pcie->base + oarr_offset); 8776e0832faSShawn Lin writel(upper_32_bits(axi_addr), pcie->base + oarr_offset + 4); 8786e0832faSShawn Lin 8796e0832faSShawn Lin /* now program the OMAP registers */ 8806e0832faSShawn Lin writel(lower_32_bits(pci_addr), pcie->base + omap_offset); 8816e0832faSShawn Lin writel(upper_32_bits(pci_addr), pcie->base + omap_offset + 4); 8826e0832faSShawn Lin 8830043d4aeSRay Jui dev_dbg(dev, "ob window [%d]: offset 0x%x axi %pap pci %pap\n", 8846e0832faSShawn Lin window_idx, oarr_offset, &axi_addr, &pci_addr); 8850043d4aeSRay Jui dev_dbg(dev, "oarr lo 0x%x oarr hi 0x%x\n", 8866e0832faSShawn Lin readl(pcie->base + oarr_offset), 8876e0832faSShawn Lin readl(pcie->base + oarr_offset + 4)); 8880043d4aeSRay Jui dev_dbg(dev, "omap lo 0x%x omap hi 0x%x\n", 8896e0832faSShawn Lin readl(pcie->base + omap_offset), 8906e0832faSShawn Lin readl(pcie->base + omap_offset + 4)); 8916e0832faSShawn Lin 8926e0832faSShawn Lin return 0; 8936e0832faSShawn Lin } 8946e0832faSShawn Lin 8956e0832faSShawn Lin /** 8966e0832faSShawn Lin * Some iProc SoCs require the SW to configure the outbound address mapping 8976e0832faSShawn Lin * 8986e0832faSShawn Lin * Outbound address translation: 8996e0832faSShawn Lin * 9006e0832faSShawn Lin * iproc_pcie_address = axi_address - axi_offset 9016e0832faSShawn Lin * OARR = iproc_pcie_address 9026e0832faSShawn Lin * OMAP = pci_addr 9036e0832faSShawn Lin * 9046e0832faSShawn Lin * axi_addr -> iproc_pcie_address -> OARR -> OMAP -> pci_address 9056e0832faSShawn Lin */ 9066e0832faSShawn Lin static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, 9076e0832faSShawn Lin u64 pci_addr, resource_size_t size) 9086e0832faSShawn Lin { 9096e0832faSShawn Lin struct iproc_pcie_ob *ob = &pcie->ob; 9106e0832faSShawn Lin struct device *dev = pcie->dev; 9116e0832faSShawn Lin int ret = -EINVAL, window_idx, size_idx; 9126e0832faSShawn Lin 9136e0832faSShawn Lin if (axi_addr < ob->axi_offset) { 9146e0832faSShawn Lin dev_err(dev, "axi address %pap less than offset %pap\n", 9156e0832faSShawn Lin &axi_addr, &ob->axi_offset); 9166e0832faSShawn Lin return -EINVAL; 9176e0832faSShawn Lin } 9186e0832faSShawn Lin 9196e0832faSShawn Lin /* 9206e0832faSShawn Lin * Translate the AXI address to the internal address used by the iProc 9216e0832faSShawn Lin * PCIe core before programming the OARR 9226e0832faSShawn Lin */ 9236e0832faSShawn Lin axi_addr -= ob->axi_offset; 9246e0832faSShawn Lin 9256e0832faSShawn Lin /* iterate through all OARR/OMAP mapping windows */ 9266e0832faSShawn Lin for (window_idx = ob->nr_windows - 1; window_idx >= 0; window_idx--) { 9276e0832faSShawn Lin const struct iproc_pcie_ob_map *ob_map = 9286e0832faSShawn Lin &pcie->ob_map[window_idx]; 9296e0832faSShawn Lin 9306e0832faSShawn Lin /* 9316e0832faSShawn Lin * If current outbound window is already in use, move on to the 9326e0832faSShawn Lin * next one. 9336e0832faSShawn Lin */ 9346e0832faSShawn Lin if (iproc_pcie_ob_is_valid(pcie, window_idx)) 9356e0832faSShawn Lin continue; 9366e0832faSShawn Lin 9376e0832faSShawn Lin /* 9386e0832faSShawn Lin * Iterate through all supported window sizes within the 9396e0832faSShawn Lin * OARR/OMAP pair to find a match. Go through the window sizes 9406e0832faSShawn Lin * in a descending order. 9416e0832faSShawn Lin */ 9426e0832faSShawn Lin for (size_idx = ob_map->nr_sizes - 1; size_idx >= 0; 9436e0832faSShawn Lin size_idx--) { 9446e0832faSShawn Lin resource_size_t window_size = 9456e0832faSShawn Lin ob_map->window_sizes[size_idx] * SZ_1M; 9466e0832faSShawn Lin 9476e0832faSShawn Lin if (size < window_size) 9486e0832faSShawn Lin continue; 9496e0832faSShawn Lin 9506e0832faSShawn Lin if (!IS_ALIGNED(axi_addr, window_size) || 9516e0832faSShawn Lin !IS_ALIGNED(pci_addr, window_size)) { 9526e0832faSShawn Lin dev_err(dev, 9536e0832faSShawn Lin "axi %pap or pci %pap not aligned\n", 9546e0832faSShawn Lin &axi_addr, &pci_addr); 9556e0832faSShawn Lin return -EINVAL; 9566e0832faSShawn Lin } 9576e0832faSShawn Lin 9586e0832faSShawn Lin /* 9596e0832faSShawn Lin * Match found! Program both OARR and OMAP and mark 9606e0832faSShawn Lin * them as a valid entry. 9616e0832faSShawn Lin */ 9626e0832faSShawn Lin ret = iproc_pcie_ob_write(pcie, window_idx, size_idx, 9636e0832faSShawn Lin axi_addr, pci_addr); 9646e0832faSShawn Lin if (ret) 9656e0832faSShawn Lin goto err_ob; 9666e0832faSShawn Lin 9676e0832faSShawn Lin size -= window_size; 9686e0832faSShawn Lin if (size == 0) 9696e0832faSShawn Lin return 0; 9706e0832faSShawn Lin 9716e0832faSShawn Lin /* 9726e0832faSShawn Lin * If we are here, we are done with the current window, 9736e0832faSShawn Lin * but not yet finished all mappings. Need to move on 9746e0832faSShawn Lin * to the next window. 9756e0832faSShawn Lin */ 9766e0832faSShawn Lin axi_addr += window_size; 9776e0832faSShawn Lin pci_addr += window_size; 9786e0832faSShawn Lin break; 9796e0832faSShawn Lin } 9806e0832faSShawn Lin } 9816e0832faSShawn Lin 9826e0832faSShawn Lin err_ob: 9836e0832faSShawn Lin dev_err(dev, "unable to configure outbound mapping\n"); 9846e0832faSShawn Lin dev_err(dev, 9856e0832faSShawn Lin "axi %pap, axi offset %pap, pci %pap, res size %pap\n", 9866e0832faSShawn Lin &axi_addr, &ob->axi_offset, &pci_addr, &size); 9876e0832faSShawn Lin 9886e0832faSShawn Lin return ret; 9896e0832faSShawn Lin } 9906e0832faSShawn Lin 9916e0832faSShawn Lin static int iproc_pcie_map_ranges(struct iproc_pcie *pcie, 9926e0832faSShawn Lin struct list_head *resources) 9936e0832faSShawn Lin { 9946e0832faSShawn Lin struct device *dev = pcie->dev; 9956e0832faSShawn Lin struct resource_entry *window; 9966e0832faSShawn Lin int ret; 9976e0832faSShawn Lin 9986e0832faSShawn Lin resource_list_for_each_entry(window, resources) { 9996e0832faSShawn Lin struct resource *res = window->res; 10006e0832faSShawn Lin u64 res_type = resource_type(res); 10016e0832faSShawn Lin 10026e0832faSShawn Lin switch (res_type) { 10036e0832faSShawn Lin case IORESOURCE_IO: 10046e0832faSShawn Lin case IORESOURCE_BUS: 10056e0832faSShawn Lin break; 10066e0832faSShawn Lin case IORESOURCE_MEM: 10076e0832faSShawn Lin ret = iproc_pcie_setup_ob(pcie, res->start, 10086e0832faSShawn Lin res->start - window->offset, 10096e0832faSShawn Lin resource_size(res)); 10106e0832faSShawn Lin if (ret) 10116e0832faSShawn Lin return ret; 10126e0832faSShawn Lin break; 10136e0832faSShawn Lin default: 10146e0832faSShawn Lin dev_err(dev, "invalid resource %pR\n", res); 10156e0832faSShawn Lin return -EINVAL; 10166e0832faSShawn Lin } 10176e0832faSShawn Lin } 10186e0832faSShawn Lin 10196e0832faSShawn Lin return 0; 10206e0832faSShawn Lin } 10216e0832faSShawn Lin 10226e0832faSShawn Lin static inline bool iproc_pcie_ib_is_in_use(struct iproc_pcie *pcie, 10236e0832faSShawn Lin int region_idx) 10246e0832faSShawn Lin { 10256e0832faSShawn Lin const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx]; 10266e0832faSShawn Lin u32 val; 10276e0832faSShawn Lin 10286e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, MAP_REG(IPROC_PCIE_IARR0, region_idx)); 10296e0832faSShawn Lin 10306e0832faSShawn Lin return !!(val & (BIT(ib_map->nr_sizes) - 1)); 10316e0832faSShawn Lin } 10326e0832faSShawn Lin 10336e0832faSShawn Lin static inline bool iproc_pcie_ib_check_type(const struct iproc_pcie_ib_map *ib_map, 10346e0832faSShawn Lin enum iproc_pcie_ib_map_type type) 10356e0832faSShawn Lin { 10366e0832faSShawn Lin return !!(ib_map->type == type); 10376e0832faSShawn Lin } 10386e0832faSShawn Lin 10396e0832faSShawn Lin static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx, 10406e0832faSShawn Lin int size_idx, int nr_windows, u64 axi_addr, 10416e0832faSShawn Lin u64 pci_addr, resource_size_t size) 10426e0832faSShawn Lin { 10436e0832faSShawn Lin struct device *dev = pcie->dev; 10446e0832faSShawn Lin const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx]; 10456e0832faSShawn Lin u16 iarr_offset, imap_offset; 10466e0832faSShawn Lin u32 val; 10476e0832faSShawn Lin int window_idx; 10486e0832faSShawn Lin 10496e0832faSShawn Lin iarr_offset = iproc_pcie_reg_offset(pcie, 10506e0832faSShawn Lin MAP_REG(IPROC_PCIE_IARR0, region_idx)); 10516e0832faSShawn Lin imap_offset = iproc_pcie_reg_offset(pcie, 10526e0832faSShawn Lin MAP_REG(IPROC_PCIE_IMAP0, region_idx)); 10536e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(iarr_offset) || 10546e0832faSShawn Lin iproc_pcie_reg_is_invalid(imap_offset)) 10556e0832faSShawn Lin return -EINVAL; 10566e0832faSShawn Lin 10570043d4aeSRay Jui dev_dbg(dev, "ib region [%d]: offset 0x%x axi %pap pci %pap\n", 10586e0832faSShawn Lin region_idx, iarr_offset, &axi_addr, &pci_addr); 10596e0832faSShawn Lin 10606e0832faSShawn Lin /* 10616e0832faSShawn Lin * Program the IARR registers. The upper 32-bit IARR register is 10626e0832faSShawn Lin * always right after the lower 32-bit IARR register. 10636e0832faSShawn Lin */ 10646e0832faSShawn Lin writel(lower_32_bits(pci_addr) | BIT(size_idx), 10656e0832faSShawn Lin pcie->base + iarr_offset); 10666e0832faSShawn Lin writel(upper_32_bits(pci_addr), pcie->base + iarr_offset + 4); 10676e0832faSShawn Lin 10680043d4aeSRay Jui dev_dbg(dev, "iarr lo 0x%x iarr hi 0x%x\n", 10696e0832faSShawn Lin readl(pcie->base + iarr_offset), 10706e0832faSShawn Lin readl(pcie->base + iarr_offset + 4)); 10716e0832faSShawn Lin 10726e0832faSShawn Lin /* 10736e0832faSShawn Lin * Now program the IMAP registers. Each IARR region may have one or 10746e0832faSShawn Lin * more IMAP windows. 10756e0832faSShawn Lin */ 10766e0832faSShawn Lin size >>= ilog2(nr_windows); 10776e0832faSShawn Lin for (window_idx = 0; window_idx < nr_windows; window_idx++) { 10786e0832faSShawn Lin val = readl(pcie->base + imap_offset); 10796e0832faSShawn Lin val |= lower_32_bits(axi_addr) | IMAP_VALID; 10806e0832faSShawn Lin writel(val, pcie->base + imap_offset); 10816e0832faSShawn Lin writel(upper_32_bits(axi_addr), 10826e0832faSShawn Lin pcie->base + imap_offset + ib_map->imap_addr_offset); 10836e0832faSShawn Lin 10840043d4aeSRay Jui dev_dbg(dev, "imap window [%d] lo 0x%x hi 0x%x\n", 10856e0832faSShawn Lin window_idx, readl(pcie->base + imap_offset), 10866e0832faSShawn Lin readl(pcie->base + imap_offset + 10876e0832faSShawn Lin ib_map->imap_addr_offset)); 10886e0832faSShawn Lin 10896e0832faSShawn Lin imap_offset += ib_map->imap_window_offset; 10906e0832faSShawn Lin axi_addr += size; 10916e0832faSShawn Lin } 10926e0832faSShawn Lin 10936e0832faSShawn Lin return 0; 10946e0832faSShawn Lin } 10956e0832faSShawn Lin 10966e0832faSShawn Lin static int iproc_pcie_setup_ib(struct iproc_pcie *pcie, 10976e0832faSShawn Lin struct of_pci_range *range, 10986e0832faSShawn Lin enum iproc_pcie_ib_map_type type) 10996e0832faSShawn Lin { 11006e0832faSShawn Lin struct device *dev = pcie->dev; 11016e0832faSShawn Lin struct iproc_pcie_ib *ib = &pcie->ib; 11026e0832faSShawn Lin int ret; 11036e0832faSShawn Lin unsigned int region_idx, size_idx; 11046e0832faSShawn Lin u64 axi_addr = range->cpu_addr, pci_addr = range->pci_addr; 11056e0832faSShawn Lin resource_size_t size = range->size; 11066e0832faSShawn Lin 11076e0832faSShawn Lin /* iterate through all IARR mapping regions */ 11086e0832faSShawn Lin for (region_idx = 0; region_idx < ib->nr_regions; region_idx++) { 11096e0832faSShawn Lin const struct iproc_pcie_ib_map *ib_map = 11106e0832faSShawn Lin &pcie->ib_map[region_idx]; 11116e0832faSShawn Lin 11126e0832faSShawn Lin /* 11136e0832faSShawn Lin * If current inbound region is already in use or not a 11146e0832faSShawn Lin * compatible type, move on to the next. 11156e0832faSShawn Lin */ 11166e0832faSShawn Lin if (iproc_pcie_ib_is_in_use(pcie, region_idx) || 11176e0832faSShawn Lin !iproc_pcie_ib_check_type(ib_map, type)) 11186e0832faSShawn Lin continue; 11196e0832faSShawn Lin 11206e0832faSShawn Lin /* iterate through all supported region sizes to find a match */ 11216e0832faSShawn Lin for (size_idx = 0; size_idx < ib_map->nr_sizes; size_idx++) { 11226e0832faSShawn Lin resource_size_t region_size = 11236e0832faSShawn Lin ib_map->region_sizes[size_idx] * ib_map->size_unit; 11246e0832faSShawn Lin 11256e0832faSShawn Lin if (size != region_size) 11266e0832faSShawn Lin continue; 11276e0832faSShawn Lin 11286e0832faSShawn Lin if (!IS_ALIGNED(axi_addr, region_size) || 11296e0832faSShawn Lin !IS_ALIGNED(pci_addr, region_size)) { 11306e0832faSShawn Lin dev_err(dev, 11316e0832faSShawn Lin "axi %pap or pci %pap not aligned\n", 11326e0832faSShawn Lin &axi_addr, &pci_addr); 11336e0832faSShawn Lin return -EINVAL; 11346e0832faSShawn Lin } 11356e0832faSShawn Lin 11366e0832faSShawn Lin /* Match found! Program IARR and all IMAP windows. */ 11376e0832faSShawn Lin ret = iproc_pcie_ib_write(pcie, region_idx, size_idx, 11386e0832faSShawn Lin ib_map->nr_windows, axi_addr, 11396e0832faSShawn Lin pci_addr, size); 11406e0832faSShawn Lin if (ret) 11416e0832faSShawn Lin goto err_ib; 11426e0832faSShawn Lin else 11436e0832faSShawn Lin return 0; 11446e0832faSShawn Lin 11456e0832faSShawn Lin } 11466e0832faSShawn Lin } 11476e0832faSShawn Lin ret = -EINVAL; 11486e0832faSShawn Lin 11496e0832faSShawn Lin err_ib: 11506e0832faSShawn Lin dev_err(dev, "unable to configure inbound mapping\n"); 11516e0832faSShawn Lin dev_err(dev, "axi %pap, pci %pap, res size %pap\n", 11526e0832faSShawn Lin &axi_addr, &pci_addr, &size); 11536e0832faSShawn Lin 11546e0832faSShawn Lin return ret; 11556e0832faSShawn Lin } 11566e0832faSShawn Lin 11576e0832faSShawn Lin static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) 11586e0832faSShawn Lin { 11596e0832faSShawn Lin struct of_pci_range range; 11606e0832faSShawn Lin struct of_pci_range_parser parser; 11616e0832faSShawn Lin int ret; 11626e0832faSShawn Lin 11636e0832faSShawn Lin /* Get the dma-ranges from DT */ 11646e0832faSShawn Lin ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node); 11656e0832faSShawn Lin if (ret) 11666e0832faSShawn Lin return ret; 11676e0832faSShawn Lin 11686e0832faSShawn Lin for_each_of_pci_range(&parser, &range) { 11696e0832faSShawn Lin /* Each range entry corresponds to an inbound mapping region */ 11706e0832faSShawn Lin ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM); 11716e0832faSShawn Lin if (ret) 11726e0832faSShawn Lin return ret; 11736e0832faSShawn Lin } 11746e0832faSShawn Lin 11756e0832faSShawn Lin return 0; 11766e0832faSShawn Lin } 11776e0832faSShawn Lin 11786e0832faSShawn Lin static int iproce_pcie_get_msi(struct iproc_pcie *pcie, 11796e0832faSShawn Lin struct device_node *msi_node, 11806e0832faSShawn Lin u64 *msi_addr) 11816e0832faSShawn Lin { 11826e0832faSShawn Lin struct device *dev = pcie->dev; 11836e0832faSShawn Lin int ret; 11846e0832faSShawn Lin struct resource res; 11856e0832faSShawn Lin 11866e0832faSShawn Lin /* 11876e0832faSShawn Lin * Check if 'msi-map' points to ARM GICv3 ITS, which is the only 11886e0832faSShawn Lin * supported external MSI controller that requires steering. 11896e0832faSShawn Lin */ 11906e0832faSShawn Lin if (!of_device_is_compatible(msi_node, "arm,gic-v3-its")) { 11916e0832faSShawn Lin dev_err(dev, "unable to find compatible MSI controller\n"); 11926e0832faSShawn Lin return -ENODEV; 11936e0832faSShawn Lin } 11946e0832faSShawn Lin 11956e0832faSShawn Lin /* derive GITS_TRANSLATER address from GICv3 */ 11966e0832faSShawn Lin ret = of_address_to_resource(msi_node, 0, &res); 11976e0832faSShawn Lin if (ret < 0) { 11986e0832faSShawn Lin dev_err(dev, "unable to obtain MSI controller resources\n"); 11996e0832faSShawn Lin return ret; 12006e0832faSShawn Lin } 12016e0832faSShawn Lin 12026e0832faSShawn Lin *msi_addr = res.start + GITS_TRANSLATER; 12036e0832faSShawn Lin return 0; 12046e0832faSShawn Lin } 12056e0832faSShawn Lin 12066e0832faSShawn Lin static int iproc_pcie_paxb_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) 12076e0832faSShawn Lin { 12086e0832faSShawn Lin int ret; 12096e0832faSShawn Lin struct of_pci_range range; 12106e0832faSShawn Lin 12116e0832faSShawn Lin memset(&range, 0, sizeof(range)); 12126e0832faSShawn Lin range.size = SZ_32K; 12136e0832faSShawn Lin range.pci_addr = range.cpu_addr = msi_addr & ~(range.size - 1); 12146e0832faSShawn Lin 12156e0832faSShawn Lin ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_IO); 12166e0832faSShawn Lin return ret; 12176e0832faSShawn Lin } 12186e0832faSShawn Lin 12191e5748c2SRay Jui static void iproc_pcie_paxc_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr, 12201e5748c2SRay Jui bool enable) 12216e0832faSShawn Lin { 12226e0832faSShawn Lin u32 val; 12236e0832faSShawn Lin 12241e5748c2SRay Jui if (!enable) { 12251e5748c2SRay Jui /* 12261e5748c2SRay Jui * Disable PAXC MSI steering. All write transfers will be 12271e5748c2SRay Jui * treated as non-MSI transfers 12281e5748c2SRay Jui */ 12291e5748c2SRay Jui val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_EN_CFG); 12301e5748c2SRay Jui val &= ~MSI_ENABLE_CFG; 12311e5748c2SRay Jui iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_EN_CFG, val); 12321e5748c2SRay Jui return; 12331e5748c2SRay Jui } 12341e5748c2SRay Jui 12356e0832faSShawn Lin /* 12366e0832faSShawn Lin * Program bits [43:13] of address of GITS_TRANSLATER register into 12376e0832faSShawn Lin * bits [30:0] of the MSI base address register. In fact, in all iProc 12386e0832faSShawn Lin * based SoCs, all I/O register bases are well below the 32-bit 12396e0832faSShawn Lin * boundary, so we can safely assume bits [43:32] are always zeros. 12406e0832faSShawn Lin */ 12416e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_BASE_ADDR, 12426e0832faSShawn Lin (u32)(msi_addr >> 13)); 12436e0832faSShawn Lin 12446e0832faSShawn Lin /* use a default 8K window size */ 12456e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_WINDOW_SIZE, 0); 12466e0832faSShawn Lin 12476e0832faSShawn Lin /* steering MSI to GICv3 ITS */ 12486e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_GIC_MODE); 12496e0832faSShawn Lin val |= GIC_V3_CFG; 12506e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_GIC_MODE, val); 12516e0832faSShawn Lin 12526e0832faSShawn Lin /* 12536e0832faSShawn Lin * Program bits [43:2] of address of GITS_TRANSLATER register into the 12546e0832faSShawn Lin * iProc MSI address registers. 12556e0832faSShawn Lin */ 12566e0832faSShawn Lin msi_addr >>= 2; 12576e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_ADDR_HI, 12586e0832faSShawn Lin upper_32_bits(msi_addr)); 12596e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_ADDR_LO, 12606e0832faSShawn Lin lower_32_bits(msi_addr)); 12616e0832faSShawn Lin 12626e0832faSShawn Lin /* enable MSI */ 12636e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_EN_CFG); 12646e0832faSShawn Lin val |= MSI_ENABLE_CFG; 12656e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_EN_CFG, val); 12666e0832faSShawn Lin } 12676e0832faSShawn Lin 12686e0832faSShawn Lin static int iproc_pcie_msi_steer(struct iproc_pcie *pcie, 12696e0832faSShawn Lin struct device_node *msi_node) 12706e0832faSShawn Lin { 12716e0832faSShawn Lin struct device *dev = pcie->dev; 12726e0832faSShawn Lin int ret; 12736e0832faSShawn Lin u64 msi_addr; 12746e0832faSShawn Lin 12756e0832faSShawn Lin ret = iproce_pcie_get_msi(pcie, msi_node, &msi_addr); 12766e0832faSShawn Lin if (ret < 0) { 12776e0832faSShawn Lin dev_err(dev, "msi steering failed\n"); 12786e0832faSShawn Lin return ret; 12796e0832faSShawn Lin } 12806e0832faSShawn Lin 12816e0832faSShawn Lin switch (pcie->type) { 12826e0832faSShawn Lin case IPROC_PCIE_PAXB_V2: 12836e0832faSShawn Lin ret = iproc_pcie_paxb_v2_msi_steer(pcie, msi_addr); 12846e0832faSShawn Lin if (ret) 12856e0832faSShawn Lin return ret; 12866e0832faSShawn Lin break; 12876e0832faSShawn Lin case IPROC_PCIE_PAXC_V2: 12881e5748c2SRay Jui iproc_pcie_paxc_v2_msi_steer(pcie, msi_addr, true); 12896e0832faSShawn Lin break; 12906e0832faSShawn Lin default: 12916e0832faSShawn Lin return -EINVAL; 12926e0832faSShawn Lin } 12936e0832faSShawn Lin 12946e0832faSShawn Lin return 0; 12956e0832faSShawn Lin } 12966e0832faSShawn Lin 12976e0832faSShawn Lin static int iproc_pcie_msi_enable(struct iproc_pcie *pcie) 12986e0832faSShawn Lin { 12996e0832faSShawn Lin struct device_node *msi_node; 13006e0832faSShawn Lin int ret; 13016e0832faSShawn Lin 13026e0832faSShawn Lin /* 13036e0832faSShawn Lin * Either the "msi-parent" or the "msi-map" phandle needs to exist 13046e0832faSShawn Lin * for us to obtain the MSI node. 13056e0832faSShawn Lin */ 13066e0832faSShawn Lin 13076e0832faSShawn Lin msi_node = of_parse_phandle(pcie->dev->of_node, "msi-parent", 0); 13086e0832faSShawn Lin if (!msi_node) { 13096e0832faSShawn Lin const __be32 *msi_map = NULL; 13106e0832faSShawn Lin int len; 13116e0832faSShawn Lin u32 phandle; 13126e0832faSShawn Lin 13136e0832faSShawn Lin msi_map = of_get_property(pcie->dev->of_node, "msi-map", &len); 13146e0832faSShawn Lin if (!msi_map) 13156e0832faSShawn Lin return -ENODEV; 13166e0832faSShawn Lin 13176e0832faSShawn Lin phandle = be32_to_cpup(msi_map + 1); 13186e0832faSShawn Lin msi_node = of_find_node_by_phandle(phandle); 13196e0832faSShawn Lin if (!msi_node) 13206e0832faSShawn Lin return -ENODEV; 13216e0832faSShawn Lin } 13226e0832faSShawn Lin 13236e0832faSShawn Lin /* 13246e0832faSShawn Lin * Certain revisions of the iProc PCIe controller require additional 13256e0832faSShawn Lin * configurations to steer the MSI writes towards an external MSI 13266e0832faSShawn Lin * controller. 13276e0832faSShawn Lin */ 13286e0832faSShawn Lin if (pcie->need_msi_steer) { 13296e0832faSShawn Lin ret = iproc_pcie_msi_steer(pcie, msi_node); 13306e0832faSShawn Lin if (ret) 13316e0832faSShawn Lin return ret; 13326e0832faSShawn Lin } 13336e0832faSShawn Lin 13346e0832faSShawn Lin /* 13356e0832faSShawn Lin * If another MSI controller is being used, the call below should fail 13366e0832faSShawn Lin * but that is okay 13376e0832faSShawn Lin */ 13386e0832faSShawn Lin return iproc_msi_init(pcie, msi_node); 13396e0832faSShawn Lin } 13406e0832faSShawn Lin 13416e0832faSShawn Lin static void iproc_pcie_msi_disable(struct iproc_pcie *pcie) 13426e0832faSShawn Lin { 13436e0832faSShawn Lin iproc_msi_exit(pcie); 13446e0832faSShawn Lin } 13456e0832faSShawn Lin 13466e0832faSShawn Lin static int iproc_pcie_rev_init(struct iproc_pcie *pcie) 13476e0832faSShawn Lin { 13486e0832faSShawn Lin struct device *dev = pcie->dev; 13496e0832faSShawn Lin unsigned int reg_idx; 13506e0832faSShawn Lin const u16 *regs; 13516e0832faSShawn Lin 13526e0832faSShawn Lin switch (pcie->type) { 13536e0832faSShawn Lin case IPROC_PCIE_PAXB_BCMA: 13546e0832faSShawn Lin regs = iproc_pcie_reg_paxb_bcma; 13556e0832faSShawn Lin break; 13566e0832faSShawn Lin case IPROC_PCIE_PAXB: 13576e0832faSShawn Lin regs = iproc_pcie_reg_paxb; 1358f78e60a2SRay Jui pcie->iproc_cfg_read = true; 13596e0832faSShawn Lin pcie->has_apb_err_disable = true; 13606e0832faSShawn Lin if (pcie->need_ob_cfg) { 13616e0832faSShawn Lin pcie->ob_map = paxb_ob_map; 13626e0832faSShawn Lin pcie->ob.nr_windows = ARRAY_SIZE(paxb_ob_map); 13636e0832faSShawn Lin } 13646e0832faSShawn Lin break; 13656e0832faSShawn Lin case IPROC_PCIE_PAXB_V2: 13666e0832faSShawn Lin regs = iproc_pcie_reg_paxb_v2; 13676e0832faSShawn Lin pcie->has_apb_err_disable = true; 13686e0832faSShawn Lin if (pcie->need_ob_cfg) { 13696e0832faSShawn Lin pcie->ob_map = paxb_v2_ob_map; 13706e0832faSShawn Lin pcie->ob.nr_windows = ARRAY_SIZE(paxb_v2_ob_map); 13716e0832faSShawn Lin } 13726e0832faSShawn Lin pcie->ib.nr_regions = ARRAY_SIZE(paxb_v2_ib_map); 13736e0832faSShawn Lin pcie->ib_map = paxb_v2_ib_map; 13746e0832faSShawn Lin pcie->need_msi_steer = true; 13756e0832faSShawn Lin dev_warn(dev, "reads of config registers that contain %#x return incorrect data\n", 13766e0832faSShawn Lin CFG_RETRY_STATUS); 13776e0832faSShawn Lin break; 13786e0832faSShawn Lin case IPROC_PCIE_PAXC: 13796e0832faSShawn Lin regs = iproc_pcie_reg_paxc; 13806e0832faSShawn Lin pcie->ep_is_internal = true; 1381f78e60a2SRay Jui pcie->iproc_cfg_read = true; 1382f78e60a2SRay Jui pcie->rej_unconfig_pf = true; 13836e0832faSShawn Lin break; 13846e0832faSShawn Lin case IPROC_PCIE_PAXC_V2: 13856e0832faSShawn Lin regs = iproc_pcie_reg_paxc_v2; 13866e0832faSShawn Lin pcie->ep_is_internal = true; 1387f78e60a2SRay Jui pcie->iproc_cfg_read = true; 1388f78e60a2SRay Jui pcie->rej_unconfig_pf = true; 13896e0832faSShawn Lin pcie->need_msi_steer = true; 13906e0832faSShawn Lin break; 13916e0832faSShawn Lin default: 13926e0832faSShawn Lin dev_err(dev, "incompatible iProc PCIe interface\n"); 13936e0832faSShawn Lin return -EINVAL; 13946e0832faSShawn Lin } 13956e0832faSShawn Lin 13966e0832faSShawn Lin pcie->reg_offsets = devm_kcalloc(dev, IPROC_PCIE_MAX_NUM_REG, 13976e0832faSShawn Lin sizeof(*pcie->reg_offsets), 13986e0832faSShawn Lin GFP_KERNEL); 13996e0832faSShawn Lin if (!pcie->reg_offsets) 14006e0832faSShawn Lin return -ENOMEM; 14016e0832faSShawn Lin 14026e0832faSShawn Lin /* go through the register table and populate all valid registers */ 14036e0832faSShawn Lin pcie->reg_offsets[0] = (pcie->type == IPROC_PCIE_PAXC_V2) ? 14046e0832faSShawn Lin IPROC_PCIE_REG_INVALID : regs[0]; 14056e0832faSShawn Lin for (reg_idx = 1; reg_idx < IPROC_PCIE_MAX_NUM_REG; reg_idx++) 14066e0832faSShawn Lin pcie->reg_offsets[reg_idx] = regs[reg_idx] ? 14076e0832faSShawn Lin regs[reg_idx] : IPROC_PCIE_REG_INVALID; 14086e0832faSShawn Lin 14096e0832faSShawn Lin return 0; 14106e0832faSShawn Lin } 14116e0832faSShawn Lin 14126e0832faSShawn Lin int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) 14136e0832faSShawn Lin { 14146e0832faSShawn Lin struct device *dev; 14156e0832faSShawn Lin int ret; 14166e0832faSShawn Lin struct pci_bus *child; 14176e0832faSShawn Lin struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); 14186e0832faSShawn Lin 14196e0832faSShawn Lin dev = pcie->dev; 14206e0832faSShawn Lin 14216e0832faSShawn Lin ret = iproc_pcie_rev_init(pcie); 14226e0832faSShawn Lin if (ret) { 14236e0832faSShawn Lin dev_err(dev, "unable to initialize controller parameters\n"); 14246e0832faSShawn Lin return ret; 14256e0832faSShawn Lin } 14266e0832faSShawn Lin 14276e0832faSShawn Lin ret = devm_request_pci_bus_resources(dev, res); 14286e0832faSShawn Lin if (ret) 14296e0832faSShawn Lin return ret; 14306e0832faSShawn Lin 14316e0832faSShawn Lin ret = phy_init(pcie->phy); 14326e0832faSShawn Lin if (ret) { 14336e0832faSShawn Lin dev_err(dev, "unable to initialize PCIe PHY\n"); 14346e0832faSShawn Lin return ret; 14356e0832faSShawn Lin } 14366e0832faSShawn Lin 14376e0832faSShawn Lin ret = phy_power_on(pcie->phy); 14386e0832faSShawn Lin if (ret) { 14396e0832faSShawn Lin dev_err(dev, "unable to power on PCIe PHY\n"); 14406e0832faSShawn Lin goto err_exit_phy; 14416e0832faSShawn Lin } 14426e0832faSShawn Lin 14436e0832faSShawn Lin iproc_pcie_perst_ctrl(pcie, true); 14446e0832faSShawn Lin iproc_pcie_perst_ctrl(pcie, false); 14456e0832faSShawn Lin 14466e0832faSShawn Lin if (pcie->need_ob_cfg) { 14476e0832faSShawn Lin ret = iproc_pcie_map_ranges(pcie, res); 14486e0832faSShawn Lin if (ret) { 14496e0832faSShawn Lin dev_err(dev, "map failed\n"); 14506e0832faSShawn Lin goto err_power_off_phy; 14516e0832faSShawn Lin } 14526e0832faSShawn Lin } 14536e0832faSShawn Lin 14546e0832faSShawn Lin if (pcie->need_ib_cfg) { 14556e0832faSShawn Lin ret = iproc_pcie_map_dma_ranges(pcie); 14566e0832faSShawn Lin if (ret && ret != -ENOENT) 14576e0832faSShawn Lin goto err_power_off_phy; 14586e0832faSShawn Lin } 14596e0832faSShawn Lin 14606e0832faSShawn Lin ret = iproc_pcie_check_link(pcie); 14616e0832faSShawn Lin if (ret) { 14626e0832faSShawn Lin dev_err(dev, "no PCIe EP device detected\n"); 14636e0832faSShawn Lin goto err_power_off_phy; 14646e0832faSShawn Lin } 14656e0832faSShawn Lin 14666e0832faSShawn Lin iproc_pcie_enable(pcie); 14676e0832faSShawn Lin 14686e0832faSShawn Lin if (IS_ENABLED(CONFIG_PCI_MSI)) 14696e0832faSShawn Lin if (iproc_pcie_msi_enable(pcie)) 14706e0832faSShawn Lin dev_info(dev, "not using iProc MSI\n"); 14716e0832faSShawn Lin 14726e0832faSShawn Lin list_splice_init(res, &host->windows); 14736e0832faSShawn Lin host->busnr = 0; 14746e0832faSShawn Lin host->dev.parent = dev; 14756e0832faSShawn Lin host->ops = &iproc_pcie_ops; 14766e0832faSShawn Lin host->sysdata = pcie; 14776e0832faSShawn Lin host->map_irq = pcie->map_irq; 14786e0832faSShawn Lin host->swizzle_irq = pci_common_swizzle; 14796e0832faSShawn Lin 14806e0832faSShawn Lin ret = pci_scan_root_bus_bridge(host); 14816e0832faSShawn Lin if (ret < 0) { 14826e0832faSShawn Lin dev_err(dev, "failed to scan host: %d\n", ret); 14836e0832faSShawn Lin goto err_power_off_phy; 14846e0832faSShawn Lin } 14856e0832faSShawn Lin 14866e0832faSShawn Lin pci_assign_unassigned_bus_resources(host->bus); 14876e0832faSShawn Lin 14886e0832faSShawn Lin pcie->root_bus = host->bus; 14896e0832faSShawn Lin 14906e0832faSShawn Lin list_for_each_entry(child, &host->bus->children, node) 14916e0832faSShawn Lin pcie_bus_configure_settings(child); 14926e0832faSShawn Lin 14936e0832faSShawn Lin pci_bus_add_devices(host->bus); 14946e0832faSShawn Lin 14956e0832faSShawn Lin return 0; 14966e0832faSShawn Lin 14976e0832faSShawn Lin err_power_off_phy: 14986e0832faSShawn Lin phy_power_off(pcie->phy); 14996e0832faSShawn Lin err_exit_phy: 15006e0832faSShawn Lin phy_exit(pcie->phy); 15016e0832faSShawn Lin return ret; 15026e0832faSShawn Lin } 15036e0832faSShawn Lin EXPORT_SYMBOL(iproc_pcie_setup); 15046e0832faSShawn Lin 15056e0832faSShawn Lin int iproc_pcie_remove(struct iproc_pcie *pcie) 15066e0832faSShawn Lin { 15076e0832faSShawn Lin pci_stop_root_bus(pcie->root_bus); 15086e0832faSShawn Lin pci_remove_root_bus(pcie->root_bus); 15096e0832faSShawn Lin 15106e0832faSShawn Lin iproc_pcie_msi_disable(pcie); 15116e0832faSShawn Lin 15126e0832faSShawn Lin phy_power_off(pcie->phy); 15136e0832faSShawn Lin phy_exit(pcie->phy); 15146e0832faSShawn Lin 15156e0832faSShawn Lin return 0; 15166e0832faSShawn Lin } 15176e0832faSShawn Lin EXPORT_SYMBOL(iproc_pcie_remove); 15186e0832faSShawn Lin 15191e5748c2SRay Jui /* 15201e5748c2SRay Jui * The MSI parsing logic in certain revisions of Broadcom PAXC based root 15211e5748c2SRay Jui * complex does not work and needs to be disabled 15221e5748c2SRay Jui */ 15231e5748c2SRay Jui static void quirk_paxc_disable_msi_parsing(struct pci_dev *pdev) 15241e5748c2SRay Jui { 15251e5748c2SRay Jui struct iproc_pcie *pcie = iproc_data(pdev->bus); 15261e5748c2SRay Jui 15271e5748c2SRay Jui if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 15281e5748c2SRay Jui iproc_pcie_paxc_v2_msi_steer(pcie, 0, false); 15291e5748c2SRay Jui } 15301e5748c2SRay Jui DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16f0, 15311e5748c2SRay Jui quirk_paxc_disable_msi_parsing); 15321e5748c2SRay Jui DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd802, 15331e5748c2SRay Jui quirk_paxc_disable_msi_parsing); 15341e5748c2SRay Jui DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd804, 15351e5748c2SRay Jui quirk_paxc_disable_msi_parsing); 15361e5748c2SRay Jui 15376e0832faSShawn Lin MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>"); 15386e0832faSShawn Lin MODULE_DESCRIPTION("Broadcom iPROC PCIe common driver"); 15396e0832faSShawn Lin MODULE_LICENSE("GPL v2"); 1540