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> 963eab494SKrzysztof Wilczyński #include <linux/pci-ecam.h> 106e0832faSShawn Lin #include <linux/msi.h> 116e0832faSShawn Lin #include <linux/clk.h> 126e0832faSShawn Lin #include <linux/module.h> 136e0832faSShawn Lin #include <linux/mbus.h> 146e0832faSShawn Lin #include <linux/slab.h> 156e0832faSShawn Lin #include <linux/delay.h> 166e0832faSShawn Lin #include <linux/interrupt.h> 176e0832faSShawn Lin #include <linux/irqchip/arm-gic-v3.h> 186e0832faSShawn Lin #include <linux/platform_device.h> 196e0832faSShawn Lin #include <linux/of_address.h> 206e0832faSShawn Lin #include <linux/of_pci.h> 216e0832faSShawn Lin #include <linux/of_irq.h> 226e0832faSShawn Lin #include <linux/of_platform.h> 236e0832faSShawn Lin #include <linux/phy/phy.h> 246e0832faSShawn Lin 256e0832faSShawn Lin #include "pcie-iproc.h" 266e0832faSShawn Lin 276e0832faSShawn Lin #define EP_PERST_SOURCE_SELECT_SHIFT 2 286e0832faSShawn Lin #define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT) 296e0832faSShawn Lin #define EP_MODE_SURVIVE_PERST_SHIFT 1 306e0832faSShawn Lin #define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT) 316e0832faSShawn Lin #define RC_PCIE_RST_OUTPUT_SHIFT 0 326e0832faSShawn Lin #define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT) 336e0832faSShawn Lin #define PAXC_RESET_MASK 0x7f 346e0832faSShawn Lin 356e0832faSShawn Lin #define GIC_V3_CFG_SHIFT 0 366e0832faSShawn Lin #define GIC_V3_CFG BIT(GIC_V3_CFG_SHIFT) 376e0832faSShawn Lin 386e0832faSShawn Lin #define MSI_ENABLE_CFG_SHIFT 0 396e0832faSShawn Lin #define MSI_ENABLE_CFG BIT(MSI_ENABLE_CFG_SHIFT) 406e0832faSShawn Lin 416e0832faSShawn Lin #define CFG_IND_ADDR_MASK 0x00001ffc 426e0832faSShawn Lin 436e0832faSShawn Lin #define CFG_ADDR_REG_NUM_MASK 0x00000ffc 4463eab494SKrzysztof Wilczyński #define CFG_ADDR_CFG_TYPE_1 1 456e0832faSShawn Lin 466e0832faSShawn Lin #define SYS_RC_INTX_MASK 0xf 476e0832faSShawn Lin 486e0832faSShawn Lin #define PCIE_PHYLINKUP_SHIFT 3 496e0832faSShawn Lin #define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT) 506e0832faSShawn Lin #define PCIE_DL_ACTIVE_SHIFT 2 516e0832faSShawn Lin #define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT) 526e0832faSShawn Lin 536e0832faSShawn Lin #define APB_ERR_EN_SHIFT 0 546e0832faSShawn Lin #define APB_ERR_EN BIT(APB_ERR_EN_SHIFT) 556e0832faSShawn Lin 5673b9e4d3SSrinath Mannam #define CFG_RD_SUCCESS 0 5773b9e4d3SSrinath Mannam #define CFG_RD_UR 1 5873b9e4d3SSrinath Mannam #define CFG_RD_CRS 2 5973b9e4d3SSrinath Mannam #define CFG_RD_CA 3 606e0832faSShawn Lin #define CFG_RETRY_STATUS 0xffff0001 616e0832faSShawn Lin #define CFG_RETRY_STATUS_TIMEOUT_US 500000 /* 500 milliseconds */ 626e0832faSShawn Lin 636e0832faSShawn Lin /* derive the enum index of the outbound/inbound mapping registers */ 646e0832faSShawn Lin #define MAP_REG(base_reg, index) ((base_reg) + (index) * 2) 656e0832faSShawn Lin 666e0832faSShawn Lin /* 676e0832faSShawn Lin * Maximum number of outbound mapping window sizes that can be supported by any 686e0832faSShawn Lin * OARR/OMAP mapping pair 696e0832faSShawn Lin */ 706e0832faSShawn Lin #define MAX_NUM_OB_WINDOW_SIZES 4 716e0832faSShawn Lin 726e0832faSShawn Lin #define OARR_VALID_SHIFT 0 736e0832faSShawn Lin #define OARR_VALID BIT(OARR_VALID_SHIFT) 746e0832faSShawn Lin #define OARR_SIZE_CFG_SHIFT 1 756e0832faSShawn Lin 766e0832faSShawn Lin /* 776e0832faSShawn Lin * Maximum number of inbound mapping region sizes that can be supported by an 786e0832faSShawn Lin * IARR 796e0832faSShawn Lin */ 806e0832faSShawn Lin #define MAX_NUM_IB_REGION_SIZES 9 816e0832faSShawn Lin 826e0832faSShawn Lin #define IMAP_VALID_SHIFT 0 836e0832faSShawn Lin #define IMAP_VALID BIT(IMAP_VALID_SHIFT) 846e0832faSShawn Lin 853bc70825SRay Jui #define IPROC_PCI_PM_CAP 0x48 863bc70825SRay Jui #define IPROC_PCI_PM_CAP_MASK 0xffff 876e0832faSShawn Lin #define IPROC_PCI_EXP_CAP 0xac 886e0832faSShawn Lin 896e0832faSShawn Lin #define IPROC_PCIE_REG_INVALID 0xffff 906e0832faSShawn Lin 916e0832faSShawn Lin /** 92347269c1SKrzysztof Wilczyński * struct iproc_pcie_ob_map - iProc PCIe outbound mapping controller-specific 93347269c1SKrzysztof Wilczyński * parameters 946e0832faSShawn Lin * @window_sizes: list of supported outbound mapping window sizes in MB 956e0832faSShawn Lin * @nr_sizes: number of supported outbound mapping window sizes 966e0832faSShawn Lin */ 976e0832faSShawn Lin struct iproc_pcie_ob_map { 986e0832faSShawn Lin resource_size_t window_sizes[MAX_NUM_OB_WINDOW_SIZES]; 996e0832faSShawn Lin unsigned int nr_sizes; 1006e0832faSShawn Lin }; 1016e0832faSShawn Lin 1026e0832faSShawn Lin static const struct iproc_pcie_ob_map paxb_ob_map[] = { 1036e0832faSShawn Lin { 1046e0832faSShawn Lin /* OARR0/OMAP0 */ 1056e0832faSShawn Lin .window_sizes = { 128, 256 }, 1066e0832faSShawn Lin .nr_sizes = 2, 1076e0832faSShawn Lin }, 1086e0832faSShawn Lin { 1096e0832faSShawn Lin /* OARR1/OMAP1 */ 1106e0832faSShawn Lin .window_sizes = { 128, 256 }, 1116e0832faSShawn Lin .nr_sizes = 2, 1126e0832faSShawn Lin }, 1136e0832faSShawn Lin }; 1146e0832faSShawn Lin 1156e0832faSShawn Lin static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = { 1166e0832faSShawn Lin { 1176e0832faSShawn Lin /* OARR0/OMAP0 */ 1186e0832faSShawn Lin .window_sizes = { 128, 256 }, 1196e0832faSShawn Lin .nr_sizes = 2, 1206e0832faSShawn Lin }, 1216e0832faSShawn Lin { 1226e0832faSShawn Lin /* OARR1/OMAP1 */ 1236e0832faSShawn Lin .window_sizes = { 128, 256 }, 1246e0832faSShawn Lin .nr_sizes = 2, 1256e0832faSShawn Lin }, 1266e0832faSShawn Lin { 1276e0832faSShawn Lin /* OARR2/OMAP2 */ 1286e0832faSShawn Lin .window_sizes = { 128, 256, 512, 1024 }, 1296e0832faSShawn Lin .nr_sizes = 4, 1306e0832faSShawn Lin }, 1316e0832faSShawn Lin { 1326e0832faSShawn Lin /* OARR3/OMAP3 */ 1336e0832faSShawn Lin .window_sizes = { 128, 256, 512, 1024 }, 1346e0832faSShawn Lin .nr_sizes = 4, 1356e0832faSShawn Lin }, 1366e0832faSShawn Lin }; 1376e0832faSShawn Lin 1386e0832faSShawn Lin /** 139347269c1SKrzysztof Wilczyński * enum iproc_pcie_ib_map_type - iProc PCIe inbound mapping type 140347269c1SKrzysztof Wilczyński * @IPROC_PCIE_IB_MAP_MEM: DDR memory 141347269c1SKrzysztof Wilczyński * @IPROC_PCIE_IB_MAP_IO: device I/O memory 142347269c1SKrzysztof Wilczyński * @IPROC_PCIE_IB_MAP_INVALID: invalid or unused 1436e0832faSShawn Lin */ 1446e0832faSShawn Lin enum iproc_pcie_ib_map_type { 1456e0832faSShawn Lin IPROC_PCIE_IB_MAP_MEM = 0, 1466e0832faSShawn Lin IPROC_PCIE_IB_MAP_IO, 1476e0832faSShawn Lin IPROC_PCIE_IB_MAP_INVALID 1486e0832faSShawn Lin }; 1496e0832faSShawn Lin 1506e0832faSShawn Lin /** 151347269c1SKrzysztof Wilczyński * struct iproc_pcie_ib_map - iProc PCIe inbound mapping controller-specific 152347269c1SKrzysztof Wilczyński * parameters 1536e0832faSShawn Lin * @type: inbound mapping region type 1546e0832faSShawn Lin * @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or 1556e0832faSShawn Lin * SZ_1G 1566e0832faSShawn Lin * @region_sizes: list of supported inbound mapping region sizes in KB, MB, or 157f6b6aefeSBjorn Helgaas * GB, depending on the size unit 1586e0832faSShawn Lin * @nr_sizes: number of supported inbound mapping region sizes 1596e0832faSShawn Lin * @nr_windows: number of supported inbound mapping windows for the region 1606e0832faSShawn Lin * @imap_addr_offset: register offset between the upper and lower 32-bit 1616e0832faSShawn Lin * IMAP address registers 1626e0832faSShawn Lin * @imap_window_offset: register offset between each IMAP window 1636e0832faSShawn Lin */ 1646e0832faSShawn Lin struct iproc_pcie_ib_map { 1656e0832faSShawn Lin enum iproc_pcie_ib_map_type type; 1666e0832faSShawn Lin unsigned int size_unit; 1676e0832faSShawn Lin resource_size_t region_sizes[MAX_NUM_IB_REGION_SIZES]; 1686e0832faSShawn Lin unsigned int nr_sizes; 1696e0832faSShawn Lin unsigned int nr_windows; 1706e0832faSShawn Lin u16 imap_addr_offset; 1716e0832faSShawn Lin u16 imap_window_offset; 1726e0832faSShawn Lin }; 1736e0832faSShawn Lin 1746e0832faSShawn Lin static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = { 1756e0832faSShawn Lin { 1766e0832faSShawn Lin /* IARR0/IMAP0 */ 1776e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_IO, 1786e0832faSShawn Lin .size_unit = SZ_1K, 1796e0832faSShawn Lin .region_sizes = { 32 }, 1806e0832faSShawn Lin .nr_sizes = 1, 1816e0832faSShawn Lin .nr_windows = 8, 1826e0832faSShawn Lin .imap_addr_offset = 0x40, 1836e0832faSShawn Lin .imap_window_offset = 0x4, 1846e0832faSShawn Lin }, 1856e0832faSShawn Lin { 18689bbcaacSRoman Bacik /* IARR1/IMAP1 */ 18789bbcaacSRoman Bacik .type = IPROC_PCIE_IB_MAP_MEM, 18889bbcaacSRoman Bacik .size_unit = SZ_1M, 18989bbcaacSRoman Bacik .region_sizes = { 8 }, 19089bbcaacSRoman Bacik .nr_sizes = 1, 19189bbcaacSRoman Bacik .nr_windows = 8, 19289bbcaacSRoman Bacik .imap_addr_offset = 0x4, 19389bbcaacSRoman Bacik .imap_window_offset = 0x8, 19489bbcaacSRoman Bacik 1956e0832faSShawn Lin }, 1966e0832faSShawn Lin { 1976e0832faSShawn Lin /* IARR2/IMAP2 */ 1986e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_MEM, 1996e0832faSShawn Lin .size_unit = SZ_1M, 2006e0832faSShawn Lin .region_sizes = { 64, 128, 256, 512, 1024, 2048, 4096, 8192, 2016e0832faSShawn Lin 16384 }, 2026e0832faSShawn Lin .nr_sizes = 9, 2036e0832faSShawn Lin .nr_windows = 1, 2046e0832faSShawn Lin .imap_addr_offset = 0x4, 2056e0832faSShawn Lin .imap_window_offset = 0x8, 2066e0832faSShawn Lin }, 2076e0832faSShawn Lin { 2086e0832faSShawn Lin /* IARR3/IMAP3 */ 2096e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_MEM, 2106e0832faSShawn Lin .size_unit = SZ_1G, 2116e0832faSShawn Lin .region_sizes = { 1, 2, 4, 8, 16, 32 }, 2126e0832faSShawn Lin .nr_sizes = 6, 2136e0832faSShawn Lin .nr_windows = 8, 2146e0832faSShawn Lin .imap_addr_offset = 0x4, 2156e0832faSShawn Lin .imap_window_offset = 0x8, 2166e0832faSShawn Lin }, 2176e0832faSShawn Lin { 2186e0832faSShawn Lin /* IARR4/IMAP4 */ 2196e0832faSShawn Lin .type = IPROC_PCIE_IB_MAP_MEM, 2206e0832faSShawn Lin .size_unit = SZ_1G, 2216e0832faSShawn Lin .region_sizes = { 32, 64, 128, 256, 512 }, 2226e0832faSShawn Lin .nr_sizes = 5, 2236e0832faSShawn Lin .nr_windows = 8, 2246e0832faSShawn Lin .imap_addr_offset = 0x4, 2256e0832faSShawn Lin .imap_window_offset = 0x8, 2266e0832faSShawn Lin }, 2276e0832faSShawn Lin }; 2286e0832faSShawn Lin 2296e0832faSShawn Lin /* 2306e0832faSShawn Lin * iProc PCIe host registers 2316e0832faSShawn Lin */ 2326e0832faSShawn Lin enum iproc_pcie_reg { 2336e0832faSShawn Lin /* clock/reset signal control */ 2346e0832faSShawn Lin IPROC_PCIE_CLK_CTRL = 0, 2356e0832faSShawn Lin 2366e0832faSShawn Lin /* 2376e0832faSShawn Lin * To allow MSI to be steered to an external MSI controller (e.g., ARM 2386e0832faSShawn Lin * GICv3 ITS) 2396e0832faSShawn Lin */ 2406e0832faSShawn Lin IPROC_PCIE_MSI_GIC_MODE, 2416e0832faSShawn Lin 2426e0832faSShawn Lin /* 2436e0832faSShawn Lin * IPROC_PCIE_MSI_BASE_ADDR and IPROC_PCIE_MSI_WINDOW_SIZE define the 2446e0832faSShawn Lin * window where the MSI posted writes are written, for the writes to be 2456e0832faSShawn Lin * interpreted as MSI writes. 2466e0832faSShawn Lin */ 2476e0832faSShawn Lin IPROC_PCIE_MSI_BASE_ADDR, 2486e0832faSShawn Lin IPROC_PCIE_MSI_WINDOW_SIZE, 2496e0832faSShawn Lin 2506e0832faSShawn Lin /* 2516e0832faSShawn Lin * To hold the address of the register where the MSI writes are 252b2105b9fSKrzysztof Wilczyński * programmed. When ARM GICv3 ITS is used, this should be programmed 2536e0832faSShawn Lin * with the address of the GITS_TRANSLATER register. 2546e0832faSShawn Lin */ 2556e0832faSShawn Lin IPROC_PCIE_MSI_ADDR_LO, 2566e0832faSShawn Lin IPROC_PCIE_MSI_ADDR_HI, 2576e0832faSShawn Lin 2586e0832faSShawn Lin /* enable MSI */ 2596e0832faSShawn Lin IPROC_PCIE_MSI_EN_CFG, 2606e0832faSShawn Lin 2616e0832faSShawn Lin /* allow access to root complex configuration space */ 2626e0832faSShawn Lin IPROC_PCIE_CFG_IND_ADDR, 2636e0832faSShawn Lin IPROC_PCIE_CFG_IND_DATA, 2646e0832faSShawn Lin 2656e0832faSShawn Lin /* allow access to device configuration space */ 2666e0832faSShawn Lin IPROC_PCIE_CFG_ADDR, 2676e0832faSShawn Lin IPROC_PCIE_CFG_DATA, 2686e0832faSShawn Lin 2696e0832faSShawn Lin /* enable INTx */ 2706e0832faSShawn Lin IPROC_PCIE_INTX_EN, 2716e0832faSShawn Lin 2726e0832faSShawn Lin /* outbound address mapping */ 2736e0832faSShawn Lin IPROC_PCIE_OARR0, 2746e0832faSShawn Lin IPROC_PCIE_OMAP0, 2756e0832faSShawn Lin IPROC_PCIE_OARR1, 2766e0832faSShawn Lin IPROC_PCIE_OMAP1, 2776e0832faSShawn Lin IPROC_PCIE_OARR2, 2786e0832faSShawn Lin IPROC_PCIE_OMAP2, 2796e0832faSShawn Lin IPROC_PCIE_OARR3, 2806e0832faSShawn Lin IPROC_PCIE_OMAP3, 2816e0832faSShawn Lin 2826e0832faSShawn Lin /* inbound address mapping */ 2836e0832faSShawn Lin IPROC_PCIE_IARR0, 2846e0832faSShawn Lin IPROC_PCIE_IMAP0, 2856e0832faSShawn Lin IPROC_PCIE_IARR1, 2866e0832faSShawn Lin IPROC_PCIE_IMAP1, 2876e0832faSShawn Lin IPROC_PCIE_IARR2, 2886e0832faSShawn Lin IPROC_PCIE_IMAP2, 2896e0832faSShawn Lin IPROC_PCIE_IARR3, 2906e0832faSShawn Lin IPROC_PCIE_IMAP3, 2916e0832faSShawn Lin IPROC_PCIE_IARR4, 2926e0832faSShawn Lin IPROC_PCIE_IMAP4, 2936e0832faSShawn Lin 29473b9e4d3SSrinath Mannam /* config read status */ 29573b9e4d3SSrinath Mannam IPROC_PCIE_CFG_RD_STATUS, 29673b9e4d3SSrinath Mannam 2976e0832faSShawn Lin /* link status */ 2986e0832faSShawn Lin IPROC_PCIE_LINK_STATUS, 2996e0832faSShawn Lin 3006e0832faSShawn Lin /* enable APB error for unsupported requests */ 3016e0832faSShawn Lin IPROC_PCIE_APB_ERR_EN, 3026e0832faSShawn Lin 3036e0832faSShawn Lin /* total number of core registers */ 3046e0832faSShawn Lin IPROC_PCIE_MAX_NUM_REG, 3056e0832faSShawn Lin }; 3066e0832faSShawn Lin 3076e0832faSShawn Lin /* iProc PCIe PAXB BCMA registers */ 308a3ff529fSBharat Gooty static const u16 iproc_pcie_reg_paxb_bcma[IPROC_PCIE_MAX_NUM_REG] = { 3096e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3106e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x120, 3116e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x124, 3126e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3136e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3146e0832faSShawn Lin [IPROC_PCIE_INTX_EN] = 0x330, 3156e0832faSShawn Lin [IPROC_PCIE_LINK_STATUS] = 0xf0c, 3166e0832faSShawn Lin }; 3176e0832faSShawn Lin 3186e0832faSShawn Lin /* iProc PCIe PAXB registers */ 319a3ff529fSBharat Gooty static const u16 iproc_pcie_reg_paxb[IPROC_PCIE_MAX_NUM_REG] = { 3206e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3216e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x120, 3226e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x124, 3236e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3246e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3256e0832faSShawn Lin [IPROC_PCIE_INTX_EN] = 0x330, 3266e0832faSShawn Lin [IPROC_PCIE_OARR0] = 0xd20, 3276e0832faSShawn Lin [IPROC_PCIE_OMAP0] = 0xd40, 3286e0832faSShawn Lin [IPROC_PCIE_OARR1] = 0xd28, 3296e0832faSShawn Lin [IPROC_PCIE_OMAP1] = 0xd48, 3306e0832faSShawn Lin [IPROC_PCIE_LINK_STATUS] = 0xf0c, 3316e0832faSShawn Lin [IPROC_PCIE_APB_ERR_EN] = 0xf40, 3326e0832faSShawn Lin }; 3336e0832faSShawn Lin 3346e0832faSShawn Lin /* iProc PCIe PAXB v2 registers */ 335a3ff529fSBharat Gooty static const u16 iproc_pcie_reg_paxb_v2[IPROC_PCIE_MAX_NUM_REG] = { 3366e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3376e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x120, 3386e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x124, 3396e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3406e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3416e0832faSShawn Lin [IPROC_PCIE_INTX_EN] = 0x330, 3426e0832faSShawn Lin [IPROC_PCIE_OARR0] = 0xd20, 3436e0832faSShawn Lin [IPROC_PCIE_OMAP0] = 0xd40, 3446e0832faSShawn Lin [IPROC_PCIE_OARR1] = 0xd28, 3456e0832faSShawn Lin [IPROC_PCIE_OMAP1] = 0xd48, 3466e0832faSShawn Lin [IPROC_PCIE_OARR2] = 0xd60, 3476e0832faSShawn Lin [IPROC_PCIE_OMAP2] = 0xd68, 3486e0832faSShawn Lin [IPROC_PCIE_OARR3] = 0xdf0, 3496e0832faSShawn Lin [IPROC_PCIE_OMAP3] = 0xdf8, 3506e0832faSShawn Lin [IPROC_PCIE_IARR0] = 0xd00, 3516e0832faSShawn Lin [IPROC_PCIE_IMAP0] = 0xc00, 35289bbcaacSRoman Bacik [IPROC_PCIE_IARR1] = 0xd08, 35389bbcaacSRoman Bacik [IPROC_PCIE_IMAP1] = 0xd70, 3546e0832faSShawn Lin [IPROC_PCIE_IARR2] = 0xd10, 3556e0832faSShawn Lin [IPROC_PCIE_IMAP2] = 0xcc0, 3566e0832faSShawn Lin [IPROC_PCIE_IARR3] = 0xe00, 3576e0832faSShawn Lin [IPROC_PCIE_IMAP3] = 0xe08, 3586e0832faSShawn Lin [IPROC_PCIE_IARR4] = 0xe68, 3596e0832faSShawn Lin [IPROC_PCIE_IMAP4] = 0xe70, 36073b9e4d3SSrinath Mannam [IPROC_PCIE_CFG_RD_STATUS] = 0xee0, 3616e0832faSShawn Lin [IPROC_PCIE_LINK_STATUS] = 0xf0c, 3626e0832faSShawn Lin [IPROC_PCIE_APB_ERR_EN] = 0xf40, 3636e0832faSShawn Lin }; 3646e0832faSShawn Lin 3656e0832faSShawn Lin /* iProc PCIe PAXC v1 registers */ 366a3ff529fSBharat Gooty static const u16 iproc_pcie_reg_paxc[IPROC_PCIE_MAX_NUM_REG] = { 3676e0832faSShawn Lin [IPROC_PCIE_CLK_CTRL] = 0x000, 3686e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, 3696e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, 3706e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3716e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3726e0832faSShawn Lin }; 3736e0832faSShawn Lin 3746e0832faSShawn Lin /* iProc PCIe PAXC v2 registers */ 375a3ff529fSBharat Gooty static const u16 iproc_pcie_reg_paxc_v2[IPROC_PCIE_MAX_NUM_REG] = { 3766e0832faSShawn Lin [IPROC_PCIE_MSI_GIC_MODE] = 0x050, 3776e0832faSShawn Lin [IPROC_PCIE_MSI_BASE_ADDR] = 0x074, 3786e0832faSShawn Lin [IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078, 3796e0832faSShawn Lin [IPROC_PCIE_MSI_ADDR_LO] = 0x07c, 3806e0832faSShawn Lin [IPROC_PCIE_MSI_ADDR_HI] = 0x080, 3816e0832faSShawn Lin [IPROC_PCIE_MSI_EN_CFG] = 0x09c, 3826e0832faSShawn Lin [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, 3836e0832faSShawn Lin [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, 3846e0832faSShawn Lin [IPROC_PCIE_CFG_ADDR] = 0x1f8, 3856e0832faSShawn Lin [IPROC_PCIE_CFG_DATA] = 0x1fc, 3866e0832faSShawn Lin }; 3876e0832faSShawn Lin 3883bc70825SRay Jui /* 3893bc70825SRay Jui * List of device IDs of controllers that have corrupted capability list that 3903bc70825SRay Jui * require SW fixup 3913bc70825SRay Jui */ 3923bc70825SRay Jui static const u16 iproc_pcie_corrupt_cap_did[] = { 3933bc70825SRay Jui 0x16cd, 3943bc70825SRay Jui 0x16f0, 3953bc70825SRay Jui 0xd802, 3963bc70825SRay Jui 0xd804 3973bc70825SRay Jui }; 3983bc70825SRay Jui 3996e0832faSShawn Lin static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) 4006e0832faSShawn Lin { 4016e0832faSShawn Lin struct iproc_pcie *pcie = bus->sysdata; 4026e0832faSShawn Lin return pcie; 4036e0832faSShawn Lin } 4046e0832faSShawn Lin 4056e0832faSShawn Lin static inline bool iproc_pcie_reg_is_invalid(u16 reg_offset) 4066e0832faSShawn Lin { 4076e0832faSShawn Lin return !!(reg_offset == IPROC_PCIE_REG_INVALID); 4086e0832faSShawn Lin } 4096e0832faSShawn Lin 4106e0832faSShawn Lin static inline u16 iproc_pcie_reg_offset(struct iproc_pcie *pcie, 4116e0832faSShawn Lin enum iproc_pcie_reg reg) 4126e0832faSShawn Lin { 4136e0832faSShawn Lin return pcie->reg_offsets[reg]; 4146e0832faSShawn Lin } 4156e0832faSShawn Lin 4166e0832faSShawn Lin static inline u32 iproc_pcie_read_reg(struct iproc_pcie *pcie, 4176e0832faSShawn Lin enum iproc_pcie_reg reg) 4186e0832faSShawn Lin { 4196e0832faSShawn Lin u16 offset = iproc_pcie_reg_offset(pcie, reg); 4206e0832faSShawn Lin 4216e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 4226e0832faSShawn Lin return 0; 4236e0832faSShawn Lin 4246e0832faSShawn Lin return readl(pcie->base + offset); 4256e0832faSShawn Lin } 4266e0832faSShawn Lin 4276e0832faSShawn Lin static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie, 4286e0832faSShawn Lin enum iproc_pcie_reg reg, u32 val) 4296e0832faSShawn Lin { 4306e0832faSShawn Lin u16 offset = iproc_pcie_reg_offset(pcie, reg); 4316e0832faSShawn Lin 4326e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 4336e0832faSShawn Lin return; 4346e0832faSShawn Lin 4356e0832faSShawn Lin writel(val, pcie->base + offset); 4366e0832faSShawn Lin } 4376e0832faSShawn Lin 438347269c1SKrzysztof Wilczyński /* 4396e0832faSShawn Lin * APB error forwarding can be disabled during access of configuration 4406e0832faSShawn Lin * registers of the endpoint device, to prevent unsupported requests 4416e0832faSShawn Lin * (typically seen during enumeration with multi-function devices) from 4426e0832faSShawn Lin * triggering a system exception. 4436e0832faSShawn Lin */ 4446e0832faSShawn Lin static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus, 4456e0832faSShawn Lin bool disable) 4466e0832faSShawn Lin { 4476e0832faSShawn Lin struct iproc_pcie *pcie = iproc_data(bus); 4486e0832faSShawn Lin u32 val; 4496e0832faSShawn Lin 4506e0832faSShawn Lin if (bus->number && pcie->has_apb_err_disable) { 4516e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_APB_ERR_EN); 4526e0832faSShawn Lin if (disable) 4536e0832faSShawn Lin val &= ~APB_ERR_EN; 4546e0832faSShawn Lin else 4556e0832faSShawn Lin val |= APB_ERR_EN; 4566e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_APB_ERR_EN, val); 4576e0832faSShawn Lin } 4586e0832faSShawn Lin } 4596e0832faSShawn Lin 4606e0832faSShawn Lin static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie, 4616e0832faSShawn Lin unsigned int busno, 46263eab494SKrzysztof Wilczyński unsigned int devfn, 4636e0832faSShawn Lin int where) 4646e0832faSShawn Lin { 4656e0832faSShawn Lin u16 offset; 4666e0832faSShawn Lin u32 val; 4676e0832faSShawn Lin 4686e0832faSShawn Lin /* EP device access */ 46963eab494SKrzysztof Wilczyński val = ALIGN_DOWN(PCIE_ECAM_OFFSET(busno, devfn, where), 4) | 47063eab494SKrzysztof Wilczyński CFG_ADDR_CFG_TYPE_1; 4716e0832faSShawn Lin 4726e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val); 4736e0832faSShawn Lin offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA); 4746e0832faSShawn Lin 4756e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 4766e0832faSShawn Lin return NULL; 4776e0832faSShawn Lin 4786e0832faSShawn Lin return (pcie->base + offset); 4796e0832faSShawn Lin } 4806e0832faSShawn Lin 48173b9e4d3SSrinath Mannam static unsigned int iproc_pcie_cfg_retry(struct iproc_pcie *pcie, 48273b9e4d3SSrinath Mannam void __iomem *cfg_data_p) 4836e0832faSShawn Lin { 4846e0832faSShawn Lin int timeout = CFG_RETRY_STATUS_TIMEOUT_US; 4856e0832faSShawn Lin unsigned int data; 48673b9e4d3SSrinath Mannam u32 status; 4876e0832faSShawn Lin 4886e0832faSShawn Lin /* 4896e0832faSShawn Lin * As per PCIe spec r3.1, sec 2.3.2, CRS Software Visibility only 4906e0832faSShawn Lin * affects config reads of the Vendor ID. For config writes or any 4916e0832faSShawn Lin * other config reads, the Root may automatically reissue the 4926e0832faSShawn Lin * configuration request again as a new request. 4936e0832faSShawn Lin * 4946e0832faSShawn Lin * For config reads, this hardware returns CFG_RETRY_STATUS data 4956e0832faSShawn Lin * when it receives a CRS completion, regardless of the address of 4966e0832faSShawn Lin * the read or the CRS Software Visibility Enable bit. As a 4976e0832faSShawn Lin * partial workaround for this, we retry in software any read that 4986e0832faSShawn Lin * returns CFG_RETRY_STATUS. 4996e0832faSShawn Lin * 5006e0832faSShawn Lin * Note that a non-Vendor ID config register may have a value of 5016e0832faSShawn Lin * CFG_RETRY_STATUS. If we read that, we can't distinguish it from 5026e0832faSShawn Lin * a CRS completion, so we will incorrectly retry the read and 5036e0832faSShawn Lin * eventually return the wrong data (0xffffffff). 5046e0832faSShawn Lin */ 5056e0832faSShawn Lin data = readl(cfg_data_p); 5066e0832faSShawn Lin while (data == CFG_RETRY_STATUS && timeout--) { 50773b9e4d3SSrinath Mannam /* 50873b9e4d3SSrinath Mannam * CRS state is set in CFG_RD status register 50973b9e4d3SSrinath Mannam * This will handle the case where CFG_RETRY_STATUS is 51073b9e4d3SSrinath Mannam * valid config data. 51173b9e4d3SSrinath Mannam */ 51273b9e4d3SSrinath Mannam status = iproc_pcie_read_reg(pcie, IPROC_PCIE_CFG_RD_STATUS); 51373b9e4d3SSrinath Mannam if (status != CFG_RD_CRS) 51473b9e4d3SSrinath Mannam return data; 51573b9e4d3SSrinath Mannam 5166e0832faSShawn Lin udelay(1); 5176e0832faSShawn Lin data = readl(cfg_data_p); 5186e0832faSShawn Lin } 5196e0832faSShawn Lin 5206e0832faSShawn Lin if (data == CFG_RETRY_STATUS) 5216e0832faSShawn Lin data = 0xffffffff; 5226e0832faSShawn Lin 5236e0832faSShawn Lin return data; 5246e0832faSShawn Lin } 5256e0832faSShawn Lin 5263bc70825SRay Jui static void iproc_pcie_fix_cap(struct iproc_pcie *pcie, int where, u32 *val) 5273bc70825SRay Jui { 5283bc70825SRay Jui u32 i, dev_id; 5293bc70825SRay Jui 5303bc70825SRay Jui switch (where & ~0x3) { 5313bc70825SRay Jui case PCI_VENDOR_ID: 5323bc70825SRay Jui dev_id = *val >> 16; 5333bc70825SRay Jui 5343bc70825SRay Jui /* 5353bc70825SRay Jui * Activate fixup for those controllers that have corrupted 5363bc70825SRay Jui * capability list registers 5373bc70825SRay Jui */ 5383bc70825SRay Jui for (i = 0; i < ARRAY_SIZE(iproc_pcie_corrupt_cap_did); i++) 5393bc70825SRay Jui if (dev_id == iproc_pcie_corrupt_cap_did[i]) 5403bc70825SRay Jui pcie->fix_paxc_cap = true; 5413bc70825SRay Jui break; 5423bc70825SRay Jui 5433bc70825SRay Jui case IPROC_PCI_PM_CAP: 5443bc70825SRay Jui if (pcie->fix_paxc_cap) { 5453bc70825SRay Jui /* advertise PM, force next capability to PCIe */ 5463bc70825SRay Jui *val &= ~IPROC_PCI_PM_CAP_MASK; 5473bc70825SRay Jui *val |= IPROC_PCI_EXP_CAP << 8 | PCI_CAP_ID_PM; 5483bc70825SRay Jui } 5493bc70825SRay Jui break; 5503bc70825SRay Jui 5513bc70825SRay Jui case IPROC_PCI_EXP_CAP: 5523bc70825SRay Jui if (pcie->fix_paxc_cap) { 5533bc70825SRay Jui /* advertise root port, version 2, terminate here */ 5543bc70825SRay Jui *val = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2) << 16 | 5553bc70825SRay Jui PCI_CAP_ID_EXP; 5563bc70825SRay Jui } 5573bc70825SRay Jui break; 5583bc70825SRay Jui 5593bc70825SRay Jui case IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL: 5603bc70825SRay Jui /* Don't advertise CRS SV support */ 5613bc70825SRay Jui *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16); 5623bc70825SRay Jui break; 5633bc70825SRay Jui 5643bc70825SRay Jui default: 5653bc70825SRay Jui break; 5663bc70825SRay Jui } 5673bc70825SRay Jui } 5683bc70825SRay Jui 5696e0832faSShawn Lin static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, 5706e0832faSShawn Lin int where, int size, u32 *val) 5716e0832faSShawn Lin { 5726e0832faSShawn Lin struct iproc_pcie *pcie = iproc_data(bus); 5736e0832faSShawn Lin unsigned int busno = bus->number; 5746e0832faSShawn Lin void __iomem *cfg_data_p; 5756e0832faSShawn Lin unsigned int data; 5766e0832faSShawn Lin int ret; 5776e0832faSShawn Lin 5786e0832faSShawn Lin /* root complex access */ 5796e0832faSShawn Lin if (busno == 0) { 5806e0832faSShawn Lin ret = pci_generic_config_read32(bus, devfn, where, size, val); 5813bc70825SRay Jui if (ret == PCIBIOS_SUCCESSFUL) 5823bc70825SRay Jui iproc_pcie_fix_cap(pcie, where, val); 5836e0832faSShawn Lin 5843bc70825SRay Jui return ret; 5856e0832faSShawn Lin } 5866e0832faSShawn Lin 58763eab494SKrzysztof Wilczyński cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where); 5886e0832faSShawn Lin 5896e0832faSShawn Lin if (!cfg_data_p) 5906e0832faSShawn Lin return PCIBIOS_DEVICE_NOT_FOUND; 5916e0832faSShawn Lin 59273b9e4d3SSrinath Mannam data = iproc_pcie_cfg_retry(pcie, cfg_data_p); 5936e0832faSShawn Lin 5946e0832faSShawn Lin *val = data; 5956e0832faSShawn Lin if (size <= 2) 5966e0832faSShawn Lin *val = (data >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); 5976e0832faSShawn Lin 598f78e60a2SRay Jui /* 599f78e60a2SRay Jui * For PAXC and PAXCv2, the total number of PFs that one can enumerate 600f78e60a2SRay Jui * depends on the firmware configuration. Unfortunately, due to an ASIC 601f78e60a2SRay Jui * bug, unconfigured PFs cannot be properly hidden from the root 602f78e60a2SRay Jui * complex. As a result, write access to these PFs will cause bus lock 603f78e60a2SRay Jui * up on the embedded processor 604f78e60a2SRay Jui * 605f78e60a2SRay Jui * Since all unconfigured PFs are left with an incorrect, staled device 606f78e60a2SRay Jui * ID of 0x168e (PCI_DEVICE_ID_NX2_57810), we try to catch those access 607f78e60a2SRay Jui * early here and reject them all 608f78e60a2SRay Jui */ 609f78e60a2SRay Jui #define DEVICE_ID_MASK 0xffff0000 610f78e60a2SRay Jui #define DEVICE_ID_SHIFT 16 611f78e60a2SRay Jui if (pcie->rej_unconfig_pf && 612f78e60a2SRay Jui (where & CFG_ADDR_REG_NUM_MASK) == PCI_VENDOR_ID) 613f78e60a2SRay Jui if ((*val & DEVICE_ID_MASK) == 614f78e60a2SRay Jui (PCI_DEVICE_ID_NX2_57810 << DEVICE_ID_SHIFT)) 615f78e60a2SRay Jui return PCIBIOS_FUNC_NOT_SUPPORTED; 616f78e60a2SRay Jui 6176e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6186e0832faSShawn Lin } 6196e0832faSShawn Lin 620347269c1SKrzysztof Wilczyński /* 6216e0832faSShawn Lin * Note access to the configuration registers are protected at the higher layer 6226e0832faSShawn Lin * by 'pci_lock' in drivers/pci/access.c 6236e0832faSShawn Lin */ 6246e0832faSShawn Lin static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, 6256e0832faSShawn Lin int busno, unsigned int devfn, 6266e0832faSShawn Lin int where) 6276e0832faSShawn Lin { 6286e0832faSShawn Lin u16 offset; 6296e0832faSShawn Lin 6306e0832faSShawn Lin /* root complex access */ 6316e0832faSShawn Lin if (busno == 0) { 63263eab494SKrzysztof Wilczyński if (PCIE_ECAM_DEVFN(devfn) > 0) 6336e0832faSShawn Lin return NULL; 6346e0832faSShawn Lin 6356e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR, 6366e0832faSShawn Lin where & CFG_IND_ADDR_MASK); 6376e0832faSShawn Lin offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_IND_DATA); 6386e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(offset)) 6396e0832faSShawn Lin return NULL; 6406e0832faSShawn Lin else 6416e0832faSShawn Lin return (pcie->base + offset); 6426e0832faSShawn Lin } 6436e0832faSShawn Lin 64463eab494SKrzysztof Wilczyński return iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where); 6456e0832faSShawn Lin } 6466e0832faSShawn Lin 6476e0832faSShawn Lin static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus, 6486e0832faSShawn Lin unsigned int devfn, 6496e0832faSShawn Lin int where) 6506e0832faSShawn Lin { 6516e0832faSShawn Lin return iproc_pcie_map_cfg_bus(iproc_data(bus), bus->number, devfn, 6526e0832faSShawn Lin where); 6536e0832faSShawn Lin } 6546e0832faSShawn Lin 6556e0832faSShawn Lin static int iproc_pci_raw_config_read32(struct iproc_pcie *pcie, 6566e0832faSShawn Lin unsigned int devfn, int where, 6576e0832faSShawn Lin int size, u32 *val) 6586e0832faSShawn Lin { 6596e0832faSShawn Lin void __iomem *addr; 6606e0832faSShawn Lin 6616e0832faSShawn Lin addr = iproc_pcie_map_cfg_bus(pcie, 0, devfn, where & ~0x3); 662814dccecSNaveen Naidu if (!addr) 6636e0832faSShawn Lin return PCIBIOS_DEVICE_NOT_FOUND; 6646e0832faSShawn Lin 6656e0832faSShawn Lin *val = readl(addr); 6666e0832faSShawn Lin 6676e0832faSShawn Lin if (size <= 2) 6686e0832faSShawn Lin *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); 6696e0832faSShawn Lin 6706e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6716e0832faSShawn Lin } 6726e0832faSShawn Lin 6736e0832faSShawn Lin static int iproc_pci_raw_config_write32(struct iproc_pcie *pcie, 6746e0832faSShawn Lin unsigned int devfn, int where, 6756e0832faSShawn Lin int size, u32 val) 6766e0832faSShawn Lin { 6776e0832faSShawn Lin void __iomem *addr; 6786e0832faSShawn Lin u32 mask, tmp; 6796e0832faSShawn Lin 6806e0832faSShawn Lin addr = iproc_pcie_map_cfg_bus(pcie, 0, devfn, where & ~0x3); 6816e0832faSShawn Lin if (!addr) 6826e0832faSShawn Lin return PCIBIOS_DEVICE_NOT_FOUND; 6836e0832faSShawn Lin 6846e0832faSShawn Lin if (size == 4) { 6856e0832faSShawn Lin writel(val, addr); 6866e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6876e0832faSShawn Lin } 6886e0832faSShawn Lin 6896e0832faSShawn Lin mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); 6906e0832faSShawn Lin tmp = readl(addr) & mask; 6916e0832faSShawn Lin tmp |= val << ((where & 0x3) * 8); 6926e0832faSShawn Lin writel(tmp, addr); 6936e0832faSShawn Lin 6946e0832faSShawn Lin return PCIBIOS_SUCCESSFUL; 6956e0832faSShawn Lin } 6966e0832faSShawn Lin 6976e0832faSShawn Lin static int iproc_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, 6986e0832faSShawn Lin int where, int size, u32 *val) 6996e0832faSShawn Lin { 7006e0832faSShawn Lin int ret; 7016e0832faSShawn Lin struct iproc_pcie *pcie = iproc_data(bus); 7026e0832faSShawn Lin 7036e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, true); 704f78e60a2SRay Jui if (pcie->iproc_cfg_read) 7056e0832faSShawn Lin ret = iproc_pcie_config_read(bus, devfn, where, size, val); 7066e0832faSShawn Lin else 7076e0832faSShawn Lin ret = pci_generic_config_read32(bus, devfn, where, size, val); 7086e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, false); 7096e0832faSShawn Lin 7106e0832faSShawn Lin return ret; 7116e0832faSShawn Lin } 7126e0832faSShawn Lin 7136e0832faSShawn Lin static int iproc_pcie_config_write32(struct pci_bus *bus, unsigned int devfn, 7146e0832faSShawn Lin int where, int size, u32 val) 7156e0832faSShawn Lin { 7166e0832faSShawn Lin int ret; 7176e0832faSShawn Lin 7186e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, true); 7196e0832faSShawn Lin ret = pci_generic_config_write32(bus, devfn, where, size, val); 7206e0832faSShawn Lin iproc_pcie_apb_err_disable(bus, false); 7216e0832faSShawn Lin 7226e0832faSShawn Lin return ret; 7236e0832faSShawn Lin } 7246e0832faSShawn Lin 7256e0832faSShawn Lin static struct pci_ops iproc_pcie_ops = { 7266e0832faSShawn Lin .map_bus = iproc_pcie_bus_map_cfg_bus, 7276e0832faSShawn Lin .read = iproc_pcie_config_read32, 7286e0832faSShawn Lin .write = iproc_pcie_config_write32, 7296e0832faSShawn Lin }; 7306e0832faSShawn Lin 7316e0832faSShawn Lin static void iproc_pcie_perst_ctrl(struct iproc_pcie *pcie, bool assert) 7326e0832faSShawn Lin { 7336e0832faSShawn Lin u32 val; 7346e0832faSShawn Lin 7356e0832faSShawn Lin /* 7366e0832faSShawn Lin * PAXC and the internal emulated endpoint device downstream should not 7376e0832faSShawn Lin * be reset. If firmware has been loaded on the endpoint device at an 7386e0832faSShawn Lin * earlier boot stage, reset here causes issues. 7396e0832faSShawn Lin */ 7406e0832faSShawn Lin if (pcie->ep_is_internal) 7416e0832faSShawn Lin return; 7426e0832faSShawn Lin 7436e0832faSShawn Lin if (assert) { 7446e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); 7456e0832faSShawn Lin val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST & 7466e0832faSShawn Lin ~RC_PCIE_RST_OUTPUT; 7476e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); 7486e0832faSShawn Lin udelay(250); 7496e0832faSShawn Lin } else { 7506e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); 7516e0832faSShawn Lin val |= RC_PCIE_RST_OUTPUT; 7526e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); 7536e0832faSShawn Lin msleep(100); 7546e0832faSShawn Lin } 7556e0832faSShawn Lin } 7566e0832faSShawn Lin 7576e0832faSShawn Lin int iproc_pcie_shutdown(struct iproc_pcie *pcie) 7586e0832faSShawn Lin { 7596e0832faSShawn Lin iproc_pcie_perst_ctrl(pcie, true); 7606e0832faSShawn Lin msleep(500); 7616e0832faSShawn Lin 7626e0832faSShawn Lin return 0; 7636e0832faSShawn Lin } 7646e0832faSShawn Lin EXPORT_SYMBOL_GPL(iproc_pcie_shutdown); 7656e0832faSShawn Lin 7666e0832faSShawn Lin static int iproc_pcie_check_link(struct iproc_pcie *pcie) 7676e0832faSShawn Lin { 7686e0832faSShawn Lin struct device *dev = pcie->dev; 7696e0832faSShawn Lin u32 hdr_type, link_ctrl, link_status, class, val; 7706e0832faSShawn Lin bool link_is_active = false; 7716e0832faSShawn Lin 7726e0832faSShawn Lin /* 7736e0832faSShawn Lin * PAXC connects to emulated endpoint devices directly and does not 7746e0832faSShawn Lin * have a Serdes. Therefore skip the link detection logic here. 7756e0832faSShawn Lin */ 7766e0832faSShawn Lin if (pcie->ep_is_internal) 7776e0832faSShawn Lin return 0; 7786e0832faSShawn Lin 7796e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS); 7806e0832faSShawn Lin if (!(val & PCIE_PHYLINKUP) || !(val & PCIE_DL_ACTIVE)) { 7816e0832faSShawn Lin dev_err(dev, "PHY or data link is INACTIVE!\n"); 7826e0832faSShawn Lin return -ENODEV; 7836e0832faSShawn Lin } 7846e0832faSShawn Lin 7856e0832faSShawn Lin /* make sure we are not in EP mode */ 7866e0832faSShawn Lin iproc_pci_raw_config_read32(pcie, 0, PCI_HEADER_TYPE, 1, &hdr_type); 7876e0832faSShawn Lin if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) { 7886e0832faSShawn Lin dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type); 7896e0832faSShawn Lin return -EFAULT; 7906e0832faSShawn Lin } 7916e0832faSShawn Lin 792*fe665816SPali Rohár /* force class to PCI_CLASS_BRIDGE_PCI_NORMAL (0x060400) */ 7936e0832faSShawn Lin #define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c 794*fe665816SPali Rohár #define PCI_BRIDGE_CTRL_REG_CLASS_MASK 0xffffff 7956e0832faSShawn Lin iproc_pci_raw_config_read32(pcie, 0, PCI_BRIDGE_CTRL_REG_OFFSET, 7966e0832faSShawn Lin 4, &class); 797*fe665816SPali Rohár class &= ~PCI_BRIDGE_CTRL_REG_CLASS_MASK; 798*fe665816SPali Rohár class |= PCI_CLASS_BRIDGE_PCI_NORMAL; 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 895347269c1SKrzysztof Wilczyński /* 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 947ea2df11fSSrinath Mannam /* 948ea2df11fSSrinath Mannam * Keep iterating until we reach the last window and 949ea2df11fSSrinath Mannam * with the minimal window size at index zero. In this 950ea2df11fSSrinath Mannam * case, we take a compromise by mapping it using the 951ea2df11fSSrinath Mannam * minimum window size that can be supported 952ea2df11fSSrinath Mannam */ 953ea2df11fSSrinath Mannam if (size < window_size) { 954ea2df11fSSrinath Mannam if (size_idx > 0 || window_idx > 0) 9556e0832faSShawn Lin continue; 9566e0832faSShawn Lin 957ea2df11fSSrinath Mannam /* 958ea2df11fSSrinath Mannam * For the corner case of reaching the minimal 959ea2df11fSSrinath Mannam * window size that can be supported on the 960ea2df11fSSrinath Mannam * last window 961ea2df11fSSrinath Mannam */ 962ea2df11fSSrinath Mannam axi_addr = ALIGN_DOWN(axi_addr, window_size); 963ea2df11fSSrinath Mannam pci_addr = ALIGN_DOWN(pci_addr, window_size); 964ea2df11fSSrinath Mannam size = window_size; 965ea2df11fSSrinath Mannam } 966ea2df11fSSrinath Mannam 9676e0832faSShawn Lin if (!IS_ALIGNED(axi_addr, window_size) || 9686e0832faSShawn Lin !IS_ALIGNED(pci_addr, window_size)) { 9696e0832faSShawn Lin dev_err(dev, 9706e0832faSShawn Lin "axi %pap or pci %pap not aligned\n", 9716e0832faSShawn Lin &axi_addr, &pci_addr); 9726e0832faSShawn Lin return -EINVAL; 9736e0832faSShawn Lin } 9746e0832faSShawn Lin 9756e0832faSShawn Lin /* 9766e0832faSShawn Lin * Match found! Program both OARR and OMAP and mark 9776e0832faSShawn Lin * them as a valid entry. 9786e0832faSShawn Lin */ 9796e0832faSShawn Lin ret = iproc_pcie_ob_write(pcie, window_idx, size_idx, 9806e0832faSShawn Lin axi_addr, pci_addr); 9816e0832faSShawn Lin if (ret) 9826e0832faSShawn Lin goto err_ob; 9836e0832faSShawn Lin 9846e0832faSShawn Lin size -= window_size; 9856e0832faSShawn Lin if (size == 0) 9866e0832faSShawn Lin return 0; 9876e0832faSShawn Lin 9886e0832faSShawn Lin /* 9896e0832faSShawn Lin * If we are here, we are done with the current window, 9906e0832faSShawn Lin * but not yet finished all mappings. Need to move on 9916e0832faSShawn Lin * to the next window. 9926e0832faSShawn Lin */ 9936e0832faSShawn Lin axi_addr += window_size; 9946e0832faSShawn Lin pci_addr += window_size; 9956e0832faSShawn Lin break; 9966e0832faSShawn Lin } 9976e0832faSShawn Lin } 9986e0832faSShawn Lin 9996e0832faSShawn Lin err_ob: 10006e0832faSShawn Lin dev_err(dev, "unable to configure outbound mapping\n"); 10016e0832faSShawn Lin dev_err(dev, 10026e0832faSShawn Lin "axi %pap, axi offset %pap, pci %pap, res size %pap\n", 10036e0832faSShawn Lin &axi_addr, &ob->axi_offset, &pci_addr, &size); 10046e0832faSShawn Lin 10056e0832faSShawn Lin return ret; 10066e0832faSShawn Lin } 10076e0832faSShawn Lin 10086e0832faSShawn Lin static int iproc_pcie_map_ranges(struct iproc_pcie *pcie, 10096e0832faSShawn Lin struct list_head *resources) 10106e0832faSShawn Lin { 10116e0832faSShawn Lin struct device *dev = pcie->dev; 10126e0832faSShawn Lin struct resource_entry *window; 10136e0832faSShawn Lin int ret; 10146e0832faSShawn Lin 10156e0832faSShawn Lin resource_list_for_each_entry(window, resources) { 10166e0832faSShawn Lin struct resource *res = window->res; 10176e0832faSShawn Lin u64 res_type = resource_type(res); 10186e0832faSShawn Lin 10196e0832faSShawn Lin switch (res_type) { 10206e0832faSShawn Lin case IORESOURCE_IO: 10216e0832faSShawn Lin case IORESOURCE_BUS: 10226e0832faSShawn Lin break; 10236e0832faSShawn Lin case IORESOURCE_MEM: 10246e0832faSShawn Lin ret = iproc_pcie_setup_ob(pcie, res->start, 10256e0832faSShawn Lin res->start - window->offset, 10266e0832faSShawn Lin resource_size(res)); 10276e0832faSShawn Lin if (ret) 10286e0832faSShawn Lin return ret; 10296e0832faSShawn Lin break; 10306e0832faSShawn Lin default: 10316e0832faSShawn Lin dev_err(dev, "invalid resource %pR\n", res); 10326e0832faSShawn Lin return -EINVAL; 10336e0832faSShawn Lin } 10346e0832faSShawn Lin } 10356e0832faSShawn Lin 10366e0832faSShawn Lin return 0; 10376e0832faSShawn Lin } 10386e0832faSShawn Lin 10396e0832faSShawn Lin static inline bool iproc_pcie_ib_is_in_use(struct iproc_pcie *pcie, 10406e0832faSShawn Lin int region_idx) 10416e0832faSShawn Lin { 10426e0832faSShawn Lin const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx]; 10436e0832faSShawn Lin u32 val; 10446e0832faSShawn Lin 10456e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, MAP_REG(IPROC_PCIE_IARR0, region_idx)); 10466e0832faSShawn Lin 10476e0832faSShawn Lin return !!(val & (BIT(ib_map->nr_sizes) - 1)); 10486e0832faSShawn Lin } 10496e0832faSShawn Lin 10506e0832faSShawn Lin static inline bool iproc_pcie_ib_check_type(const struct iproc_pcie_ib_map *ib_map, 10516e0832faSShawn Lin enum iproc_pcie_ib_map_type type) 10526e0832faSShawn Lin { 10536e0832faSShawn Lin return !!(ib_map->type == type); 10546e0832faSShawn Lin } 10556e0832faSShawn Lin 10566e0832faSShawn Lin static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx, 10576e0832faSShawn Lin int size_idx, int nr_windows, u64 axi_addr, 10586e0832faSShawn Lin u64 pci_addr, resource_size_t size) 10596e0832faSShawn Lin { 10606e0832faSShawn Lin struct device *dev = pcie->dev; 10616e0832faSShawn Lin const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx]; 10626e0832faSShawn Lin u16 iarr_offset, imap_offset; 10636e0832faSShawn Lin u32 val; 10646e0832faSShawn Lin int window_idx; 10656e0832faSShawn Lin 10666e0832faSShawn Lin iarr_offset = iproc_pcie_reg_offset(pcie, 10676e0832faSShawn Lin MAP_REG(IPROC_PCIE_IARR0, region_idx)); 10686e0832faSShawn Lin imap_offset = iproc_pcie_reg_offset(pcie, 10696e0832faSShawn Lin MAP_REG(IPROC_PCIE_IMAP0, region_idx)); 10706e0832faSShawn Lin if (iproc_pcie_reg_is_invalid(iarr_offset) || 10716e0832faSShawn Lin iproc_pcie_reg_is_invalid(imap_offset)) 10726e0832faSShawn Lin return -EINVAL; 10736e0832faSShawn Lin 10740043d4aeSRay Jui dev_dbg(dev, "ib region [%d]: offset 0x%x axi %pap pci %pap\n", 10756e0832faSShawn Lin region_idx, iarr_offset, &axi_addr, &pci_addr); 10766e0832faSShawn Lin 10776e0832faSShawn Lin /* 10786e0832faSShawn Lin * Program the IARR registers. The upper 32-bit IARR register is 10796e0832faSShawn Lin * always right after the lower 32-bit IARR register. 10806e0832faSShawn Lin */ 10816e0832faSShawn Lin writel(lower_32_bits(pci_addr) | BIT(size_idx), 10826e0832faSShawn Lin pcie->base + iarr_offset); 10836e0832faSShawn Lin writel(upper_32_bits(pci_addr), pcie->base + iarr_offset + 4); 10846e0832faSShawn Lin 10850043d4aeSRay Jui dev_dbg(dev, "iarr lo 0x%x iarr hi 0x%x\n", 10866e0832faSShawn Lin readl(pcie->base + iarr_offset), 10876e0832faSShawn Lin readl(pcie->base + iarr_offset + 4)); 10886e0832faSShawn Lin 10896e0832faSShawn Lin /* 10906e0832faSShawn Lin * Now program the IMAP registers. Each IARR region may have one or 10916e0832faSShawn Lin * more IMAP windows. 10926e0832faSShawn Lin */ 10936e0832faSShawn Lin size >>= ilog2(nr_windows); 10946e0832faSShawn Lin for (window_idx = 0; window_idx < nr_windows; window_idx++) { 10956e0832faSShawn Lin val = readl(pcie->base + imap_offset); 10966e0832faSShawn Lin val |= lower_32_bits(axi_addr) | IMAP_VALID; 10976e0832faSShawn Lin writel(val, pcie->base + imap_offset); 10986e0832faSShawn Lin writel(upper_32_bits(axi_addr), 10996e0832faSShawn Lin pcie->base + imap_offset + ib_map->imap_addr_offset); 11006e0832faSShawn Lin 11010043d4aeSRay Jui dev_dbg(dev, "imap window [%d] lo 0x%x hi 0x%x\n", 11026e0832faSShawn Lin window_idx, readl(pcie->base + imap_offset), 11036e0832faSShawn Lin readl(pcie->base + imap_offset + 11046e0832faSShawn Lin ib_map->imap_addr_offset)); 11056e0832faSShawn Lin 11066e0832faSShawn Lin imap_offset += ib_map->imap_window_offset; 11076e0832faSShawn Lin axi_addr += size; 11086e0832faSShawn Lin } 11096e0832faSShawn Lin 11106e0832faSShawn Lin return 0; 11116e0832faSShawn Lin } 11126e0832faSShawn Lin 11136e0832faSShawn Lin static int iproc_pcie_setup_ib(struct iproc_pcie *pcie, 1114b9ae59b3SRob Herring struct resource_entry *entry, 11156e0832faSShawn Lin enum iproc_pcie_ib_map_type type) 11166e0832faSShawn Lin { 11176e0832faSShawn Lin struct device *dev = pcie->dev; 11186e0832faSShawn Lin struct iproc_pcie_ib *ib = &pcie->ib; 11196e0832faSShawn Lin int ret; 11206e0832faSShawn Lin unsigned int region_idx, size_idx; 1121b9ae59b3SRob Herring u64 axi_addr = entry->res->start; 1122b9ae59b3SRob Herring u64 pci_addr = entry->res->start - entry->offset; 1123b9ae59b3SRob Herring resource_size_t size = resource_size(entry->res); 11246e0832faSShawn Lin 11256e0832faSShawn Lin /* iterate through all IARR mapping regions */ 11266e0832faSShawn Lin for (region_idx = 0; region_idx < ib->nr_regions; region_idx++) { 11276e0832faSShawn Lin const struct iproc_pcie_ib_map *ib_map = 11286e0832faSShawn Lin &pcie->ib_map[region_idx]; 11296e0832faSShawn Lin 11306e0832faSShawn Lin /* 11316e0832faSShawn Lin * If current inbound region is already in use or not a 11326e0832faSShawn Lin * compatible type, move on to the next. 11336e0832faSShawn Lin */ 11346e0832faSShawn Lin if (iproc_pcie_ib_is_in_use(pcie, region_idx) || 11356e0832faSShawn Lin !iproc_pcie_ib_check_type(ib_map, type)) 11366e0832faSShawn Lin continue; 11376e0832faSShawn Lin 11386e0832faSShawn Lin /* iterate through all supported region sizes to find a match */ 11396e0832faSShawn Lin for (size_idx = 0; size_idx < ib_map->nr_sizes; size_idx++) { 11406e0832faSShawn Lin resource_size_t region_size = 11416e0832faSShawn Lin ib_map->region_sizes[size_idx] * ib_map->size_unit; 11426e0832faSShawn Lin 11436e0832faSShawn Lin if (size != region_size) 11446e0832faSShawn Lin continue; 11456e0832faSShawn Lin 11466e0832faSShawn Lin if (!IS_ALIGNED(axi_addr, region_size) || 11476e0832faSShawn Lin !IS_ALIGNED(pci_addr, region_size)) { 11486e0832faSShawn Lin dev_err(dev, 11496e0832faSShawn Lin "axi %pap or pci %pap not aligned\n", 11506e0832faSShawn Lin &axi_addr, &pci_addr); 11516e0832faSShawn Lin return -EINVAL; 11526e0832faSShawn Lin } 11536e0832faSShawn Lin 11546e0832faSShawn Lin /* Match found! Program IARR and all IMAP windows. */ 11556e0832faSShawn Lin ret = iproc_pcie_ib_write(pcie, region_idx, size_idx, 11566e0832faSShawn Lin ib_map->nr_windows, axi_addr, 11576e0832faSShawn Lin pci_addr, size); 11586e0832faSShawn Lin if (ret) 11596e0832faSShawn Lin goto err_ib; 11606e0832faSShawn Lin else 11616e0832faSShawn Lin return 0; 11626e0832faSShawn Lin 11636e0832faSShawn Lin } 11646e0832faSShawn Lin } 11656e0832faSShawn Lin ret = -EINVAL; 11666e0832faSShawn Lin 11676e0832faSShawn Lin err_ib: 11686e0832faSShawn Lin dev_err(dev, "unable to configure inbound mapping\n"); 11696e0832faSShawn Lin dev_err(dev, "axi %pap, pci %pap, res size %pap\n", 11706e0832faSShawn Lin &axi_addr, &pci_addr, &size); 11716e0832faSShawn Lin 11726e0832faSShawn Lin return ret; 11736e0832faSShawn Lin } 11746e0832faSShawn Lin 11756e0832faSShawn Lin static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) 11766e0832faSShawn Lin { 117790199c95SSrinath Mannam struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); 1178b9ae59b3SRob Herring struct resource_entry *entry; 1179b9ae59b3SRob Herring int ret = 0; 11806e0832faSShawn Lin 1181b9ae59b3SRob Herring resource_list_for_each_entry(entry, &host->dma_ranges) { 11826e0832faSShawn Lin /* Each range entry corresponds to an inbound mapping region */ 1183b9ae59b3SRob Herring ret = iproc_pcie_setup_ib(pcie, entry, IPROC_PCIE_IB_MAP_MEM); 11846e0832faSShawn Lin if (ret) 1185b9ae59b3SRob Herring break; 11866e0832faSShawn Lin } 11876e0832faSShawn Lin 118890199c95SSrinath Mannam return ret; 11896e0832faSShawn Lin } 11906e0832faSShawn Lin 11919415743eSAbhishek Shah static void iproc_pcie_invalidate_mapping(struct iproc_pcie *pcie) 11929415743eSAbhishek Shah { 11939415743eSAbhishek Shah struct iproc_pcie_ib *ib = &pcie->ib; 11949415743eSAbhishek Shah struct iproc_pcie_ob *ob = &pcie->ob; 11959415743eSAbhishek Shah int idx; 11969415743eSAbhishek Shah 11979415743eSAbhishek Shah if (pcie->ep_is_internal) 11989415743eSAbhishek Shah return; 11999415743eSAbhishek Shah 12009415743eSAbhishek Shah if (pcie->need_ob_cfg) { 12019415743eSAbhishek Shah /* iterate through all OARR mapping regions */ 12029415743eSAbhishek Shah for (idx = ob->nr_windows - 1; idx >= 0; idx--) { 12039415743eSAbhishek Shah iproc_pcie_write_reg(pcie, 12049415743eSAbhishek Shah MAP_REG(IPROC_PCIE_OARR0, idx), 0); 12059415743eSAbhishek Shah } 12069415743eSAbhishek Shah } 12079415743eSAbhishek Shah 12089415743eSAbhishek Shah if (pcie->need_ib_cfg) { 12099415743eSAbhishek Shah /* iterate through all IARR mapping regions */ 12109415743eSAbhishek Shah for (idx = 0; idx < ib->nr_regions; idx++) { 12119415743eSAbhishek Shah iproc_pcie_write_reg(pcie, 12129415743eSAbhishek Shah MAP_REG(IPROC_PCIE_IARR0, idx), 0); 12139415743eSAbhishek Shah } 12149415743eSAbhishek Shah } 12159415743eSAbhishek Shah } 12169415743eSAbhishek Shah 12176e0832faSShawn Lin static int iproce_pcie_get_msi(struct iproc_pcie *pcie, 12186e0832faSShawn Lin struct device_node *msi_node, 12196e0832faSShawn Lin u64 *msi_addr) 12206e0832faSShawn Lin { 12216e0832faSShawn Lin struct device *dev = pcie->dev; 12226e0832faSShawn Lin int ret; 12236e0832faSShawn Lin struct resource res; 12246e0832faSShawn Lin 12256e0832faSShawn Lin /* 12266e0832faSShawn Lin * Check if 'msi-map' points to ARM GICv3 ITS, which is the only 12276e0832faSShawn Lin * supported external MSI controller that requires steering. 12286e0832faSShawn Lin */ 12296e0832faSShawn Lin if (!of_device_is_compatible(msi_node, "arm,gic-v3-its")) { 12306e0832faSShawn Lin dev_err(dev, "unable to find compatible MSI controller\n"); 12316e0832faSShawn Lin return -ENODEV; 12326e0832faSShawn Lin } 12336e0832faSShawn Lin 12346e0832faSShawn Lin /* derive GITS_TRANSLATER address from GICv3 */ 12356e0832faSShawn Lin ret = of_address_to_resource(msi_node, 0, &res); 12366e0832faSShawn Lin if (ret < 0) { 12376e0832faSShawn Lin dev_err(dev, "unable to obtain MSI controller resources\n"); 12386e0832faSShawn Lin return ret; 12396e0832faSShawn Lin } 12406e0832faSShawn Lin 12416e0832faSShawn Lin *msi_addr = res.start + GITS_TRANSLATER; 12426e0832faSShawn Lin return 0; 12436e0832faSShawn Lin } 12446e0832faSShawn Lin 12456e0832faSShawn Lin static int iproc_pcie_paxb_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) 12466e0832faSShawn Lin { 12476e0832faSShawn Lin int ret; 1248b9ae59b3SRob Herring struct resource_entry entry; 12496e0832faSShawn Lin 1250b9ae59b3SRob Herring memset(&entry, 0, sizeof(entry)); 1251b9ae59b3SRob Herring entry.res = &entry.__res; 12526e0832faSShawn Lin 1253b9ae59b3SRob Herring msi_addr &= ~(SZ_32K - 1); 1254b9ae59b3SRob Herring entry.res->start = msi_addr; 1255b9ae59b3SRob Herring entry.res->end = msi_addr + SZ_32K - 1; 1256b9ae59b3SRob Herring 1257b9ae59b3SRob Herring ret = iproc_pcie_setup_ib(pcie, &entry, IPROC_PCIE_IB_MAP_IO); 12586e0832faSShawn Lin return ret; 12596e0832faSShawn Lin } 12606e0832faSShawn Lin 12611e5748c2SRay Jui static void iproc_pcie_paxc_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr, 12621e5748c2SRay Jui bool enable) 12636e0832faSShawn Lin { 12646e0832faSShawn Lin u32 val; 12656e0832faSShawn Lin 12661e5748c2SRay Jui if (!enable) { 12671e5748c2SRay Jui /* 12681e5748c2SRay Jui * Disable PAXC MSI steering. All write transfers will be 12691e5748c2SRay Jui * treated as non-MSI transfers 12701e5748c2SRay Jui */ 12711e5748c2SRay Jui val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_EN_CFG); 12721e5748c2SRay Jui val &= ~MSI_ENABLE_CFG; 12731e5748c2SRay Jui iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_EN_CFG, val); 12741e5748c2SRay Jui return; 12751e5748c2SRay Jui } 12761e5748c2SRay Jui 12776e0832faSShawn Lin /* 12786e0832faSShawn Lin * Program bits [43:13] of address of GITS_TRANSLATER register into 12796e0832faSShawn Lin * bits [30:0] of the MSI base address register. In fact, in all iProc 12806e0832faSShawn Lin * based SoCs, all I/O register bases are well below the 32-bit 12816e0832faSShawn Lin * boundary, so we can safely assume bits [43:32] are always zeros. 12826e0832faSShawn Lin */ 12836e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_BASE_ADDR, 12846e0832faSShawn Lin (u32)(msi_addr >> 13)); 12856e0832faSShawn Lin 12866e0832faSShawn Lin /* use a default 8K window size */ 12876e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_WINDOW_SIZE, 0); 12886e0832faSShawn Lin 12896e0832faSShawn Lin /* steering MSI to GICv3 ITS */ 12906e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_GIC_MODE); 12916e0832faSShawn Lin val |= GIC_V3_CFG; 12926e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_GIC_MODE, val); 12936e0832faSShawn Lin 12946e0832faSShawn Lin /* 12956e0832faSShawn Lin * Program bits [43:2] of address of GITS_TRANSLATER register into the 12966e0832faSShawn Lin * iProc MSI address registers. 12976e0832faSShawn Lin */ 12986e0832faSShawn Lin msi_addr >>= 2; 12996e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_ADDR_HI, 13006e0832faSShawn Lin upper_32_bits(msi_addr)); 13016e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_ADDR_LO, 13026e0832faSShawn Lin lower_32_bits(msi_addr)); 13036e0832faSShawn Lin 13046e0832faSShawn Lin /* enable MSI */ 13056e0832faSShawn Lin val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_EN_CFG); 13066e0832faSShawn Lin val |= MSI_ENABLE_CFG; 13076e0832faSShawn Lin iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_EN_CFG, val); 13086e0832faSShawn Lin } 13096e0832faSShawn Lin 13106e0832faSShawn Lin static int iproc_pcie_msi_steer(struct iproc_pcie *pcie, 13116e0832faSShawn Lin struct device_node *msi_node) 13126e0832faSShawn Lin { 13136e0832faSShawn Lin struct device *dev = pcie->dev; 13146e0832faSShawn Lin int ret; 13156e0832faSShawn Lin u64 msi_addr; 13166e0832faSShawn Lin 13176e0832faSShawn Lin ret = iproce_pcie_get_msi(pcie, msi_node, &msi_addr); 13186e0832faSShawn Lin if (ret < 0) { 13196e0832faSShawn Lin dev_err(dev, "msi steering failed\n"); 13206e0832faSShawn Lin return ret; 13216e0832faSShawn Lin } 13226e0832faSShawn Lin 13236e0832faSShawn Lin switch (pcie->type) { 13246e0832faSShawn Lin case IPROC_PCIE_PAXB_V2: 13256e0832faSShawn Lin ret = iproc_pcie_paxb_v2_msi_steer(pcie, msi_addr); 13266e0832faSShawn Lin if (ret) 13276e0832faSShawn Lin return ret; 13286e0832faSShawn Lin break; 13296e0832faSShawn Lin case IPROC_PCIE_PAXC_V2: 13301e5748c2SRay Jui iproc_pcie_paxc_v2_msi_steer(pcie, msi_addr, true); 13316e0832faSShawn Lin break; 13326e0832faSShawn Lin default: 13336e0832faSShawn Lin return -EINVAL; 13346e0832faSShawn Lin } 13356e0832faSShawn Lin 13366e0832faSShawn Lin return 0; 13376e0832faSShawn Lin } 13386e0832faSShawn Lin 13396e0832faSShawn Lin static int iproc_pcie_msi_enable(struct iproc_pcie *pcie) 13406e0832faSShawn Lin { 13416e0832faSShawn Lin struct device_node *msi_node; 13426e0832faSShawn Lin int ret; 13436e0832faSShawn Lin 13446e0832faSShawn Lin /* 13456e0832faSShawn Lin * Either the "msi-parent" or the "msi-map" phandle needs to exist 13466e0832faSShawn Lin * for us to obtain the MSI node. 13476e0832faSShawn Lin */ 13486e0832faSShawn Lin 13496e0832faSShawn Lin msi_node = of_parse_phandle(pcie->dev->of_node, "msi-parent", 0); 13506e0832faSShawn Lin if (!msi_node) { 13516e0832faSShawn Lin const __be32 *msi_map = NULL; 13526e0832faSShawn Lin int len; 13536e0832faSShawn Lin u32 phandle; 13546e0832faSShawn Lin 13556e0832faSShawn Lin msi_map = of_get_property(pcie->dev->of_node, "msi-map", &len); 13566e0832faSShawn Lin if (!msi_map) 13576e0832faSShawn Lin return -ENODEV; 13586e0832faSShawn Lin 13596e0832faSShawn Lin phandle = be32_to_cpup(msi_map + 1); 13606e0832faSShawn Lin msi_node = of_find_node_by_phandle(phandle); 13616e0832faSShawn Lin if (!msi_node) 13626e0832faSShawn Lin return -ENODEV; 13636e0832faSShawn Lin } 13646e0832faSShawn Lin 13656e0832faSShawn Lin /* 13666e0832faSShawn Lin * Certain revisions of the iProc PCIe controller require additional 13676e0832faSShawn Lin * configurations to steer the MSI writes towards an external MSI 13686e0832faSShawn Lin * controller. 13696e0832faSShawn Lin */ 13706e0832faSShawn Lin if (pcie->need_msi_steer) { 13716e0832faSShawn Lin ret = iproc_pcie_msi_steer(pcie, msi_node); 13726e0832faSShawn Lin if (ret) 13738956388dSWen Yang goto out_put_node; 13746e0832faSShawn Lin } 13756e0832faSShawn Lin 13766e0832faSShawn Lin /* 13776e0832faSShawn Lin * If another MSI controller is being used, the call below should fail 13786e0832faSShawn Lin * but that is okay 13796e0832faSShawn Lin */ 13808956388dSWen Yang ret = iproc_msi_init(pcie, msi_node); 13818956388dSWen Yang 13828956388dSWen Yang out_put_node: 13838956388dSWen Yang of_node_put(msi_node); 13848956388dSWen Yang return ret; 13856e0832faSShawn Lin } 13866e0832faSShawn Lin 13876e0832faSShawn Lin static void iproc_pcie_msi_disable(struct iproc_pcie *pcie) 13886e0832faSShawn Lin { 13896e0832faSShawn Lin iproc_msi_exit(pcie); 13906e0832faSShawn Lin } 13916e0832faSShawn Lin 13926e0832faSShawn Lin static int iproc_pcie_rev_init(struct iproc_pcie *pcie) 13936e0832faSShawn Lin { 13946e0832faSShawn Lin struct device *dev = pcie->dev; 13956e0832faSShawn Lin unsigned int reg_idx; 13966e0832faSShawn Lin const u16 *regs; 13976e0832faSShawn Lin 13986e0832faSShawn Lin switch (pcie->type) { 13996e0832faSShawn Lin case IPROC_PCIE_PAXB_BCMA: 14006e0832faSShawn Lin regs = iproc_pcie_reg_paxb_bcma; 14016e0832faSShawn Lin break; 14026e0832faSShawn Lin case IPROC_PCIE_PAXB: 14036e0832faSShawn Lin regs = iproc_pcie_reg_paxb; 14046e0832faSShawn Lin pcie->has_apb_err_disable = true; 14056e0832faSShawn Lin if (pcie->need_ob_cfg) { 14066e0832faSShawn Lin pcie->ob_map = paxb_ob_map; 14076e0832faSShawn Lin pcie->ob.nr_windows = ARRAY_SIZE(paxb_ob_map); 14086e0832faSShawn Lin } 14096e0832faSShawn Lin break; 14106e0832faSShawn Lin case IPROC_PCIE_PAXB_V2: 14116e0832faSShawn Lin regs = iproc_pcie_reg_paxb_v2; 14128cff9954SSrinath Mannam pcie->iproc_cfg_read = true; 14136e0832faSShawn Lin pcie->has_apb_err_disable = true; 14146e0832faSShawn Lin if (pcie->need_ob_cfg) { 14156e0832faSShawn Lin pcie->ob_map = paxb_v2_ob_map; 14166e0832faSShawn Lin pcie->ob.nr_windows = ARRAY_SIZE(paxb_v2_ob_map); 14176e0832faSShawn Lin } 14186e0832faSShawn Lin pcie->ib.nr_regions = ARRAY_SIZE(paxb_v2_ib_map); 14196e0832faSShawn Lin pcie->ib_map = paxb_v2_ib_map; 14206e0832faSShawn Lin pcie->need_msi_steer = true; 14216e0832faSShawn Lin dev_warn(dev, "reads of config registers that contain %#x return incorrect data\n", 14226e0832faSShawn Lin CFG_RETRY_STATUS); 14236e0832faSShawn Lin break; 14246e0832faSShawn Lin case IPROC_PCIE_PAXC: 14256e0832faSShawn Lin regs = iproc_pcie_reg_paxc; 14266e0832faSShawn Lin pcie->ep_is_internal = true; 1427f78e60a2SRay Jui pcie->iproc_cfg_read = true; 1428f78e60a2SRay Jui pcie->rej_unconfig_pf = true; 14296e0832faSShawn Lin break; 14306e0832faSShawn Lin case IPROC_PCIE_PAXC_V2: 14316e0832faSShawn Lin regs = iproc_pcie_reg_paxc_v2; 14326e0832faSShawn Lin pcie->ep_is_internal = true; 1433f78e60a2SRay Jui pcie->iproc_cfg_read = true; 1434f78e60a2SRay Jui pcie->rej_unconfig_pf = true; 14356e0832faSShawn Lin pcie->need_msi_steer = true; 14366e0832faSShawn Lin break; 14376e0832faSShawn Lin default: 14386e0832faSShawn Lin dev_err(dev, "incompatible iProc PCIe interface\n"); 14396e0832faSShawn Lin return -EINVAL; 14406e0832faSShawn Lin } 14416e0832faSShawn Lin 14426e0832faSShawn Lin pcie->reg_offsets = devm_kcalloc(dev, IPROC_PCIE_MAX_NUM_REG, 14436e0832faSShawn Lin sizeof(*pcie->reg_offsets), 14446e0832faSShawn Lin GFP_KERNEL); 14456e0832faSShawn Lin if (!pcie->reg_offsets) 14466e0832faSShawn Lin return -ENOMEM; 14476e0832faSShawn Lin 14486e0832faSShawn Lin /* go through the register table and populate all valid registers */ 14496e0832faSShawn Lin pcie->reg_offsets[0] = (pcie->type == IPROC_PCIE_PAXC_V2) ? 14506e0832faSShawn Lin IPROC_PCIE_REG_INVALID : regs[0]; 14516e0832faSShawn Lin for (reg_idx = 1; reg_idx < IPROC_PCIE_MAX_NUM_REG; reg_idx++) 14526e0832faSShawn Lin pcie->reg_offsets[reg_idx] = regs[reg_idx] ? 14536e0832faSShawn Lin regs[reg_idx] : IPROC_PCIE_REG_INVALID; 14546e0832faSShawn Lin 14556e0832faSShawn Lin return 0; 14566e0832faSShawn Lin } 14576e0832faSShawn Lin 14586e0832faSShawn Lin int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) 14596e0832faSShawn Lin { 14606e0832faSShawn Lin struct device *dev; 14616e0832faSShawn Lin int ret; 14627698c0f1SSrinath Mannam struct pci_dev *pdev; 14636e0832faSShawn Lin struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); 14646e0832faSShawn Lin 14656e0832faSShawn Lin dev = pcie->dev; 14666e0832faSShawn Lin 14676e0832faSShawn Lin ret = iproc_pcie_rev_init(pcie); 14686e0832faSShawn Lin if (ret) { 14696e0832faSShawn Lin dev_err(dev, "unable to initialize controller parameters\n"); 14706e0832faSShawn Lin return ret; 14716e0832faSShawn Lin } 14726e0832faSShawn Lin 14736e0832faSShawn Lin ret = phy_init(pcie->phy); 14746e0832faSShawn Lin if (ret) { 14756e0832faSShawn Lin dev_err(dev, "unable to initialize PCIe PHY\n"); 14766e0832faSShawn Lin return ret; 14776e0832faSShawn Lin } 14786e0832faSShawn Lin 14796e0832faSShawn Lin ret = phy_power_on(pcie->phy); 14806e0832faSShawn Lin if (ret) { 14816e0832faSShawn Lin dev_err(dev, "unable to power on PCIe PHY\n"); 14826e0832faSShawn Lin goto err_exit_phy; 14836e0832faSShawn Lin } 14846e0832faSShawn Lin 14856e0832faSShawn Lin iproc_pcie_perst_ctrl(pcie, true); 14866e0832faSShawn Lin iproc_pcie_perst_ctrl(pcie, false); 14876e0832faSShawn Lin 14889415743eSAbhishek Shah iproc_pcie_invalidate_mapping(pcie); 14899415743eSAbhishek Shah 14906e0832faSShawn Lin if (pcie->need_ob_cfg) { 14916e0832faSShawn Lin ret = iproc_pcie_map_ranges(pcie, res); 14926e0832faSShawn Lin if (ret) { 14936e0832faSShawn Lin dev_err(dev, "map failed\n"); 14946e0832faSShawn Lin goto err_power_off_phy; 14956e0832faSShawn Lin } 14966e0832faSShawn Lin } 14976e0832faSShawn Lin 14986e0832faSShawn Lin if (pcie->need_ib_cfg) { 14996e0832faSShawn Lin ret = iproc_pcie_map_dma_ranges(pcie); 15006e0832faSShawn Lin if (ret && ret != -ENOENT) 15016e0832faSShawn Lin goto err_power_off_phy; 15026e0832faSShawn Lin } 15036e0832faSShawn Lin 15046e0832faSShawn Lin ret = iproc_pcie_check_link(pcie); 15056e0832faSShawn Lin if (ret) { 15066e0832faSShawn Lin dev_err(dev, "no PCIe EP device detected\n"); 15076e0832faSShawn Lin goto err_power_off_phy; 15086e0832faSShawn Lin } 15096e0832faSShawn Lin 15106e0832faSShawn Lin iproc_pcie_enable(pcie); 15116e0832faSShawn Lin 15126e0832faSShawn Lin if (IS_ENABLED(CONFIG_PCI_MSI)) 15136e0832faSShawn Lin if (iproc_pcie_msi_enable(pcie)) 15146e0832faSShawn Lin dev_info(dev, "not using iProc MSI\n"); 15156e0832faSShawn Lin 15166e0832faSShawn Lin host->ops = &iproc_pcie_ops; 15176e0832faSShawn Lin host->sysdata = pcie; 15186e0832faSShawn Lin host->map_irq = pcie->map_irq; 15196e0832faSShawn Lin 152081ce3cf4SRob Herring ret = pci_host_probe(host); 15216e0832faSShawn Lin if (ret < 0) { 15226e0832faSShawn Lin dev_err(dev, "failed to scan host: %d\n", ret); 15236e0832faSShawn Lin goto err_power_off_phy; 15246e0832faSShawn Lin } 15256e0832faSShawn Lin 15267698c0f1SSrinath Mannam for_each_pci_bridge(pdev, host->bus) { 15277698c0f1SSrinath Mannam if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) 15287698c0f1SSrinath Mannam pcie_print_link_status(pdev); 15297698c0f1SSrinath Mannam } 15307698c0f1SSrinath Mannam 15316e0832faSShawn Lin return 0; 15326e0832faSShawn Lin 15336e0832faSShawn Lin err_power_off_phy: 15346e0832faSShawn Lin phy_power_off(pcie->phy); 15356e0832faSShawn Lin err_exit_phy: 15366e0832faSShawn Lin phy_exit(pcie->phy); 15376e0832faSShawn Lin return ret; 15386e0832faSShawn Lin } 15396e0832faSShawn Lin EXPORT_SYMBOL(iproc_pcie_setup); 15406e0832faSShawn Lin 15416e0832faSShawn Lin int iproc_pcie_remove(struct iproc_pcie *pcie) 15426e0832faSShawn Lin { 154381ce3cf4SRob Herring struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); 154481ce3cf4SRob Herring 154581ce3cf4SRob Herring pci_stop_root_bus(host->bus); 154681ce3cf4SRob Herring pci_remove_root_bus(host->bus); 15476e0832faSShawn Lin 15486e0832faSShawn Lin iproc_pcie_msi_disable(pcie); 15496e0832faSShawn Lin 15506e0832faSShawn Lin phy_power_off(pcie->phy); 15516e0832faSShawn Lin phy_exit(pcie->phy); 15526e0832faSShawn Lin 15536e0832faSShawn Lin return 0; 15546e0832faSShawn Lin } 15556e0832faSShawn Lin EXPORT_SYMBOL(iproc_pcie_remove); 15566e0832faSShawn Lin 15571e5748c2SRay Jui /* 15581e5748c2SRay Jui * The MSI parsing logic in certain revisions of Broadcom PAXC based root 15591e5748c2SRay Jui * complex does not work and needs to be disabled 15601e5748c2SRay Jui */ 15611e5748c2SRay Jui static void quirk_paxc_disable_msi_parsing(struct pci_dev *pdev) 15621e5748c2SRay Jui { 15631e5748c2SRay Jui struct iproc_pcie *pcie = iproc_data(pdev->bus); 15641e5748c2SRay Jui 15651e5748c2SRay Jui if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 15661e5748c2SRay Jui iproc_pcie_paxc_v2_msi_steer(pcie, 0, false); 15671e5748c2SRay Jui } 15681e5748c2SRay Jui DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16f0, 15691e5748c2SRay Jui quirk_paxc_disable_msi_parsing); 15701e5748c2SRay Jui DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd802, 15711e5748c2SRay Jui quirk_paxc_disable_msi_parsing); 15721e5748c2SRay Jui DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd804, 15731e5748c2SRay Jui quirk_paxc_disable_msi_parsing); 15741e5748c2SRay Jui 1575574f2903SWei Liu static void quirk_paxc_bridge(struct pci_dev *pdev) 1576574f2903SWei Liu { 1577574f2903SWei Liu /* 1578574f2903SWei Liu * The PCI config space is shared with the PAXC root port and the first 1579574f2903SWei Liu * Ethernet device. So, we need to workaround this by telling the PCI 1580574f2903SWei Liu * code that the bridge is not an Ethernet device. 1581574f2903SWei Liu */ 1582574f2903SWei Liu if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 1583904b10fbSPali Rohár pdev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; 1584574f2903SWei Liu 1585574f2903SWei Liu /* 1586574f2903SWei Liu * MPSS is not being set properly (as it is currently 0). This is 1587574f2903SWei Liu * because that area of the PCI config space is hard coded to zero, and 1588574f2903SWei Liu * is not modifiable by firmware. Set this to 2 (e.g., 512 byte MPS) 1589574f2903SWei Liu * so that the MPS can be set to the real max value. 1590574f2903SWei Liu */ 1591574f2903SWei Liu pdev->pcie_mpss = 2; 1592574f2903SWei Liu } 1593574f2903SWei Liu DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16cd, quirk_paxc_bridge); 1594574f2903SWei Liu DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16f0, quirk_paxc_bridge); 1595574f2903SWei Liu DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd750, quirk_paxc_bridge); 1596574f2903SWei Liu DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd802, quirk_paxc_bridge); 1597574f2903SWei Liu DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd804, quirk_paxc_bridge); 1598574f2903SWei Liu 15996e0832faSShawn Lin MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>"); 16006e0832faSShawn Lin MODULE_DESCRIPTION("Broadcom iPROC PCIe common driver"); 16016e0832faSShawn Lin MODULE_LICENSE("GPL v2"); 1602