16e0832faSShawn Lin // SPDX-License-Identifier: GPL-2.0 26e0832faSShawn Lin /* 36e0832faSShawn Lin * PCIe host controller driver for Axis ARTPEC-6 SoC 46e0832faSShawn Lin * 56e0832faSShawn Lin * Author: Niklas Cassel <niklas.cassel@axis.com> 66e0832faSShawn Lin * 76e0832faSShawn Lin * Based on work done by Phil Edworthy <phil@edworthys.org> 86e0832faSShawn Lin */ 96e0832faSShawn Lin 106e0832faSShawn Lin #include <linux/delay.h> 116e0832faSShawn Lin #include <linux/kernel.h> 126e0832faSShawn Lin #include <linux/init.h> 136e0832faSShawn Lin #include <linux/of_device.h> 146e0832faSShawn Lin #include <linux/pci.h> 156e0832faSShawn Lin #include <linux/platform_device.h> 166e0832faSShawn Lin #include <linux/resource.h> 176e0832faSShawn Lin #include <linux/signal.h> 186e0832faSShawn Lin #include <linux/types.h> 196e0832faSShawn Lin #include <linux/interrupt.h> 206e0832faSShawn Lin #include <linux/mfd/syscon.h> 216e0832faSShawn Lin #include <linux/regmap.h> 226e0832faSShawn Lin 236e0832faSShawn Lin #include "pcie-designware.h" 246e0832faSShawn Lin 256e0832faSShawn Lin #define to_artpec6_pcie(x) dev_get_drvdata((x)->dev) 266e0832faSShawn Lin 276e0832faSShawn Lin enum artpec_pcie_variants { 286e0832faSShawn Lin ARTPEC6, 296e0832faSShawn Lin ARTPEC7, 306e0832faSShawn Lin }; 316e0832faSShawn Lin 326e0832faSShawn Lin struct artpec6_pcie { 336e0832faSShawn Lin struct dw_pcie *pci; 346e0832faSShawn Lin struct regmap *regmap; /* DT axis,syscon-pcie */ 356e0832faSShawn Lin void __iomem *phy_base; /* DT phy */ 366e0832faSShawn Lin enum artpec_pcie_variants variant; 376e0832faSShawn Lin enum dw_pcie_device_mode mode; 386e0832faSShawn Lin }; 396e0832faSShawn Lin 406e0832faSShawn Lin struct artpec_pcie_of_data { 416e0832faSShawn Lin enum artpec_pcie_variants variant; 426e0832faSShawn Lin enum dw_pcie_device_mode mode; 436e0832faSShawn Lin }; 446e0832faSShawn Lin 456e0832faSShawn Lin static const struct of_device_id artpec6_pcie_of_match[]; 466e0832faSShawn Lin 476e0832faSShawn Lin /* PCIe Port Logic registers (memory-mapped) */ 486e0832faSShawn Lin #define PL_OFFSET 0x700 496e0832faSShawn Lin 506e0832faSShawn Lin #define ACK_F_ASPM_CTRL_OFF (PL_OFFSET + 0xc) 516e0832faSShawn Lin #define ACK_N_FTS_MASK GENMASK(15, 8) 526e0832faSShawn Lin #define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK) 536e0832faSShawn Lin 546e0832faSShawn Lin #define FAST_TRAINING_SEQ_MASK GENMASK(7, 0) 556e0832faSShawn Lin #define FAST_TRAINING_SEQ(x) (((x) << 0) & FAST_TRAINING_SEQ_MASK) 566e0832faSShawn Lin 576e0832faSShawn Lin /* ARTPEC-6 specific registers */ 586e0832faSShawn Lin #define PCIECFG 0x18 596e0832faSShawn Lin #define PCIECFG_DBG_OEN BIT(24) 606e0832faSShawn Lin #define PCIECFG_CORE_RESET_REQ BIT(21) 616e0832faSShawn Lin #define PCIECFG_LTSSM_ENABLE BIT(20) 626e0832faSShawn Lin #define PCIECFG_DEVICE_TYPE_MASK GENMASK(19, 16) 636e0832faSShawn Lin #define PCIECFG_CLKREQ_B BIT(11) 646e0832faSShawn Lin #define PCIECFG_REFCLK_ENABLE BIT(10) 656e0832faSShawn Lin #define PCIECFG_PLL_ENABLE BIT(9) 666e0832faSShawn Lin #define PCIECFG_PCLK_ENABLE BIT(8) 676e0832faSShawn Lin #define PCIECFG_RISRCREN BIT(4) 686e0832faSShawn Lin #define PCIECFG_MODE_TX_DRV_EN BIT(3) 696e0832faSShawn Lin #define PCIECFG_CISRREN BIT(2) 706e0832faSShawn Lin #define PCIECFG_MACRO_ENABLE BIT(0) 716e0832faSShawn Lin /* ARTPEC-7 specific fields */ 726e0832faSShawn Lin #define PCIECFG_REFCLKSEL BIT(23) 736e0832faSShawn Lin #define PCIECFG_NOC_RESET BIT(3) 746e0832faSShawn Lin 756e0832faSShawn Lin #define PCIESTAT 0x1c 766e0832faSShawn Lin /* ARTPEC-7 specific fields */ 776e0832faSShawn Lin #define PCIESTAT_EXTREFCLK BIT(3) 786e0832faSShawn Lin 796e0832faSShawn Lin #define NOCCFG 0x40 806e0832faSShawn Lin #define NOCCFG_ENABLE_CLK_PCIE BIT(4) 816e0832faSShawn Lin #define NOCCFG_POWER_PCIE_IDLEACK BIT(3) 826e0832faSShawn Lin #define NOCCFG_POWER_PCIE_IDLE BIT(2) 836e0832faSShawn Lin #define NOCCFG_POWER_PCIE_IDLEREQ BIT(1) 846e0832faSShawn Lin 856e0832faSShawn Lin #define PHY_STATUS 0x118 866e0832faSShawn Lin #define PHY_COSPLLLOCK BIT(0) 876e0832faSShawn Lin 886e0832faSShawn Lin #define PHY_TX_ASIC_OUT 0x4040 896e0832faSShawn Lin #define PHY_TX_ASIC_OUT_TX_ACK BIT(0) 906e0832faSShawn Lin 916e0832faSShawn Lin #define PHY_RX_ASIC_OUT 0x405c 926e0832faSShawn Lin #define PHY_RX_ASIC_OUT_ACK BIT(0) 936e0832faSShawn Lin 946e0832faSShawn Lin static u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset) 956e0832faSShawn Lin { 966e0832faSShawn Lin u32 val; 976e0832faSShawn Lin 986e0832faSShawn Lin regmap_read(artpec6_pcie->regmap, offset, &val); 996e0832faSShawn Lin return val; 1006e0832faSShawn Lin } 1016e0832faSShawn Lin 1026e0832faSShawn Lin static void artpec6_pcie_writel(struct artpec6_pcie *artpec6_pcie, u32 offset, u32 val) 1036e0832faSShawn Lin { 1046e0832faSShawn Lin regmap_write(artpec6_pcie->regmap, offset, val); 1056e0832faSShawn Lin } 1066e0832faSShawn Lin 1076e0832faSShawn Lin static u64 artpec6_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 pci_addr) 1086e0832faSShawn Lin { 1096e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1106e0832faSShawn Lin struct pcie_port *pp = &pci->pp; 1116e0832faSShawn Lin struct dw_pcie_ep *ep = &pci->ep; 1126e0832faSShawn Lin 1136e0832faSShawn Lin switch (artpec6_pcie->mode) { 1146e0832faSShawn Lin case DW_PCIE_RC_TYPE: 1156e0832faSShawn Lin return pci_addr - pp->cfg0_base; 1166e0832faSShawn Lin case DW_PCIE_EP_TYPE: 1176e0832faSShawn Lin return pci_addr - ep->phys_base; 1186e0832faSShawn Lin default: 1196e0832faSShawn Lin dev_err(pci->dev, "UNKNOWN device type\n"); 1206e0832faSShawn Lin } 1216e0832faSShawn Lin return pci_addr; 1226e0832faSShawn Lin } 1236e0832faSShawn Lin 1246e0832faSShawn Lin static int artpec6_pcie_establish_link(struct dw_pcie *pci) 1256e0832faSShawn Lin { 1266e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1276e0832faSShawn Lin u32 val; 1286e0832faSShawn Lin 1296e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 1306e0832faSShawn Lin val |= PCIECFG_LTSSM_ENABLE; 1316e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 1326e0832faSShawn Lin 1336e0832faSShawn Lin return 0; 1346e0832faSShawn Lin } 1356e0832faSShawn Lin 1366e0832faSShawn Lin static void artpec6_pcie_stop_link(struct dw_pcie *pci) 1376e0832faSShawn Lin { 1386e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1396e0832faSShawn Lin u32 val; 1406e0832faSShawn Lin 1416e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 1426e0832faSShawn Lin val &= ~PCIECFG_LTSSM_ENABLE; 1436e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 1446e0832faSShawn Lin } 1456e0832faSShawn Lin 1466e0832faSShawn Lin static const struct dw_pcie_ops dw_pcie_ops = { 1476e0832faSShawn Lin .cpu_addr_fixup = artpec6_pcie_cpu_addr_fixup, 1486e0832faSShawn Lin .start_link = artpec6_pcie_establish_link, 1496e0832faSShawn Lin .stop_link = artpec6_pcie_stop_link, 1506e0832faSShawn Lin }; 1516e0832faSShawn Lin 1526e0832faSShawn Lin static void artpec6_pcie_wait_for_phy_a6(struct artpec6_pcie *artpec6_pcie) 1536e0832faSShawn Lin { 1546e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 1556e0832faSShawn Lin struct device *dev = pci->dev; 1566e0832faSShawn Lin u32 val; 1576e0832faSShawn Lin unsigned int retries; 1586e0832faSShawn Lin 1596e0832faSShawn Lin retries = 50; 1606e0832faSShawn Lin do { 1616e0832faSShawn Lin usleep_range(1000, 2000); 1626e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 1636e0832faSShawn Lin retries--; 1646e0832faSShawn Lin } while (retries && 1656e0832faSShawn Lin (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 1666e0832faSShawn Lin if (!retries) 1676e0832faSShawn Lin dev_err(dev, "PCIe clock manager did not leave idle state\n"); 1686e0832faSShawn Lin 1696e0832faSShawn Lin retries = 50; 1706e0832faSShawn Lin do { 1716e0832faSShawn Lin usleep_range(1000, 2000); 1726e0832faSShawn Lin val = readl(artpec6_pcie->phy_base + PHY_STATUS); 1736e0832faSShawn Lin retries--; 1746e0832faSShawn Lin } while (retries && !(val & PHY_COSPLLLOCK)); 1756e0832faSShawn Lin if (!retries) 1766e0832faSShawn Lin dev_err(dev, "PHY PLL did not lock\n"); 1776e0832faSShawn Lin } 1786e0832faSShawn Lin 1796e0832faSShawn Lin static void artpec6_pcie_wait_for_phy_a7(struct artpec6_pcie *artpec6_pcie) 1806e0832faSShawn Lin { 1816e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 1826e0832faSShawn Lin struct device *dev = pci->dev; 1836e0832faSShawn Lin u32 val; 1846e0832faSShawn Lin u16 phy_status_tx, phy_status_rx; 1856e0832faSShawn Lin unsigned int retries; 1866e0832faSShawn Lin 1876e0832faSShawn Lin retries = 50; 1886e0832faSShawn Lin do { 1896e0832faSShawn Lin usleep_range(1000, 2000); 1906e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 1916e0832faSShawn Lin retries--; 1926e0832faSShawn Lin } while (retries && 1936e0832faSShawn Lin (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 1946e0832faSShawn Lin if (!retries) 1956e0832faSShawn Lin dev_err(dev, "PCIe clock manager did not leave idle state\n"); 1966e0832faSShawn Lin 1976e0832faSShawn Lin retries = 50; 1986e0832faSShawn Lin do { 1996e0832faSShawn Lin usleep_range(1000, 2000); 2006e0832faSShawn Lin phy_status_tx = readw(artpec6_pcie->phy_base + PHY_TX_ASIC_OUT); 2016e0832faSShawn Lin phy_status_rx = readw(artpec6_pcie->phy_base + PHY_RX_ASIC_OUT); 2026e0832faSShawn Lin retries--; 2036e0832faSShawn Lin } while (retries && ((phy_status_tx & PHY_TX_ASIC_OUT_TX_ACK) || 2046e0832faSShawn Lin (phy_status_rx & PHY_RX_ASIC_OUT_ACK))); 2056e0832faSShawn Lin if (!retries) 2066e0832faSShawn Lin dev_err(dev, "PHY did not enter Pn state\n"); 2076e0832faSShawn Lin } 2086e0832faSShawn Lin 2096e0832faSShawn Lin static void artpec6_pcie_wait_for_phy(struct artpec6_pcie *artpec6_pcie) 2106e0832faSShawn Lin { 2116e0832faSShawn Lin switch (artpec6_pcie->variant) { 2126e0832faSShawn Lin case ARTPEC6: 2136e0832faSShawn Lin artpec6_pcie_wait_for_phy_a6(artpec6_pcie); 2146e0832faSShawn Lin break; 2156e0832faSShawn Lin case ARTPEC7: 2166e0832faSShawn Lin artpec6_pcie_wait_for_phy_a7(artpec6_pcie); 2176e0832faSShawn Lin break; 2186e0832faSShawn Lin } 2196e0832faSShawn Lin } 2206e0832faSShawn Lin 2216e0832faSShawn Lin static void artpec6_pcie_init_phy_a6(struct artpec6_pcie *artpec6_pcie) 2226e0832faSShawn Lin { 2236e0832faSShawn Lin u32 val; 2246e0832faSShawn Lin 2256e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2266e0832faSShawn Lin val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 2276e0832faSShawn Lin PCIECFG_MODE_TX_DRV_EN | 2286e0832faSShawn Lin PCIECFG_CISRREN | /* Reference clock term. 100 Ohm */ 2296e0832faSShawn Lin PCIECFG_MACRO_ENABLE; 2306e0832faSShawn Lin val |= PCIECFG_REFCLK_ENABLE; 2316e0832faSShawn Lin val &= ~PCIECFG_DBG_OEN; 2326e0832faSShawn Lin val &= ~PCIECFG_CLKREQ_B; 2336e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2346e0832faSShawn Lin usleep_range(5000, 6000); 2356e0832faSShawn Lin 2366e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2376e0832faSShawn Lin val |= NOCCFG_ENABLE_CLK_PCIE; 2386e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2396e0832faSShawn Lin usleep_range(20, 30); 2406e0832faSShawn Lin 2416e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2426e0832faSShawn Lin val |= PCIECFG_PCLK_ENABLE | PCIECFG_PLL_ENABLE; 2436e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2446e0832faSShawn Lin usleep_range(6000, 7000); 2456e0832faSShawn Lin 2466e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2476e0832faSShawn Lin val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 2486e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2496e0832faSShawn Lin } 2506e0832faSShawn Lin 2516e0832faSShawn Lin static void artpec6_pcie_init_phy_a7(struct artpec6_pcie *artpec6_pcie) 2526e0832faSShawn Lin { 2536e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 2546e0832faSShawn Lin u32 val; 2556e0832faSShawn Lin bool extrefclk; 2566e0832faSShawn Lin 2576e0832faSShawn Lin /* Check if external reference clock is connected */ 2586e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIESTAT); 2596e0832faSShawn Lin extrefclk = !!(val & PCIESTAT_EXTREFCLK); 2606e0832faSShawn Lin dev_dbg(pci->dev, "Using reference clock: %s\n", 2616e0832faSShawn Lin extrefclk ? "external" : "internal"); 2626e0832faSShawn Lin 2636e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2646e0832faSShawn Lin val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 2656e0832faSShawn Lin PCIECFG_PCLK_ENABLE; 2666e0832faSShawn Lin if (extrefclk) 2676e0832faSShawn Lin val |= PCIECFG_REFCLKSEL; 2686e0832faSShawn Lin else 2696e0832faSShawn Lin val &= ~PCIECFG_REFCLKSEL; 2706e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2716e0832faSShawn Lin usleep_range(10, 20); 2726e0832faSShawn Lin 2736e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2746e0832faSShawn Lin val |= NOCCFG_ENABLE_CLK_PCIE; 2756e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2766e0832faSShawn Lin usleep_range(20, 30); 2776e0832faSShawn Lin 2786e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2796e0832faSShawn Lin val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 2806e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2816e0832faSShawn Lin } 2826e0832faSShawn Lin 2836e0832faSShawn Lin static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) 2846e0832faSShawn Lin { 2856e0832faSShawn Lin switch (artpec6_pcie->variant) { 2866e0832faSShawn Lin case ARTPEC6: 2876e0832faSShawn Lin artpec6_pcie_init_phy_a6(artpec6_pcie); 2886e0832faSShawn Lin break; 2896e0832faSShawn Lin case ARTPEC7: 2906e0832faSShawn Lin artpec6_pcie_init_phy_a7(artpec6_pcie); 2916e0832faSShawn Lin break; 2926e0832faSShawn Lin } 2936e0832faSShawn Lin } 2946e0832faSShawn Lin 2956e0832faSShawn Lin static void artpec6_pcie_set_nfts(struct artpec6_pcie *artpec6_pcie) 2966e0832faSShawn Lin { 2976e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 2986e0832faSShawn Lin u32 val; 2996e0832faSShawn Lin 3006e0832faSShawn Lin if (artpec6_pcie->variant != ARTPEC7) 3016e0832faSShawn Lin return; 3026e0832faSShawn Lin 3036e0832faSShawn Lin /* 3046e0832faSShawn Lin * Increase the N_FTS (Number of Fast Training Sequences) 3056e0832faSShawn Lin * to be transmitted when transitioning from L0s to L0. 3066e0832faSShawn Lin */ 3076e0832faSShawn Lin val = dw_pcie_readl_dbi(pci, ACK_F_ASPM_CTRL_OFF); 3086e0832faSShawn Lin val &= ~ACK_N_FTS_MASK; 3096e0832faSShawn Lin val |= ACK_N_FTS(180); 3106e0832faSShawn Lin dw_pcie_writel_dbi(pci, ACK_F_ASPM_CTRL_OFF, val); 3116e0832faSShawn Lin 3126e0832faSShawn Lin /* 3136e0832faSShawn Lin * Set the Number of Fast Training Sequences that the core 3146e0832faSShawn Lin * advertises as its N_FTS during Gen2 or Gen3 link training. 3156e0832faSShawn Lin */ 3166e0832faSShawn Lin val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); 3176e0832faSShawn Lin val &= ~FAST_TRAINING_SEQ_MASK; 3186e0832faSShawn Lin val |= FAST_TRAINING_SEQ(180); 3196e0832faSShawn Lin dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); 3206e0832faSShawn Lin } 3216e0832faSShawn Lin 3226e0832faSShawn Lin static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie) 3236e0832faSShawn Lin { 3246e0832faSShawn Lin u32 val; 3256e0832faSShawn Lin 3266e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 3276e0832faSShawn Lin switch (artpec6_pcie->variant) { 3286e0832faSShawn Lin case ARTPEC6: 3296e0832faSShawn Lin val |= PCIECFG_CORE_RESET_REQ; 3306e0832faSShawn Lin break; 3316e0832faSShawn Lin case ARTPEC7: 3326e0832faSShawn Lin val &= ~PCIECFG_NOC_RESET; 3336e0832faSShawn Lin break; 3346e0832faSShawn Lin } 3356e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 3366e0832faSShawn Lin } 3376e0832faSShawn Lin 3386e0832faSShawn Lin static void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie) 3396e0832faSShawn Lin { 3406e0832faSShawn Lin u32 val; 3416e0832faSShawn Lin 3426e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 3436e0832faSShawn Lin switch (artpec6_pcie->variant) { 3446e0832faSShawn Lin case ARTPEC6: 3456e0832faSShawn Lin val &= ~PCIECFG_CORE_RESET_REQ; 3466e0832faSShawn Lin break; 3476e0832faSShawn Lin case ARTPEC7: 3486e0832faSShawn Lin val |= PCIECFG_NOC_RESET; 3496e0832faSShawn Lin break; 3506e0832faSShawn Lin } 3516e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 3526e0832faSShawn Lin usleep_range(100, 200); 3536e0832faSShawn Lin } 3546e0832faSShawn Lin 3556e0832faSShawn Lin static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie) 3566e0832faSShawn Lin { 3576e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 3586e0832faSShawn Lin struct pcie_port *pp = &pci->pp; 3596e0832faSShawn Lin 3606e0832faSShawn Lin if (IS_ENABLED(CONFIG_PCI_MSI)) 3616e0832faSShawn Lin dw_pcie_msi_init(pp); 3626e0832faSShawn Lin } 3636e0832faSShawn Lin 3646e0832faSShawn Lin static int artpec6_pcie_host_init(struct pcie_port *pp) 3656e0832faSShawn Lin { 3666e0832faSShawn Lin struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 3676e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 3686e0832faSShawn Lin 3696e0832faSShawn Lin artpec6_pcie_assert_core_reset(artpec6_pcie); 3706e0832faSShawn Lin artpec6_pcie_init_phy(artpec6_pcie); 3716e0832faSShawn Lin artpec6_pcie_deassert_core_reset(artpec6_pcie); 3726e0832faSShawn Lin artpec6_pcie_wait_for_phy(artpec6_pcie); 3736e0832faSShawn Lin artpec6_pcie_set_nfts(artpec6_pcie); 3746e0832faSShawn Lin dw_pcie_setup_rc(pp); 3756e0832faSShawn Lin artpec6_pcie_establish_link(pci); 3766e0832faSShawn Lin dw_pcie_wait_for_link(pci); 3776e0832faSShawn Lin artpec6_pcie_enable_interrupts(artpec6_pcie); 3786e0832faSShawn Lin 3796e0832faSShawn Lin return 0; 3806e0832faSShawn Lin } 3816e0832faSShawn Lin 3826e0832faSShawn Lin static const struct dw_pcie_host_ops artpec6_pcie_host_ops = { 3836e0832faSShawn Lin .host_init = artpec6_pcie_host_init, 3846e0832faSShawn Lin }; 3856e0832faSShawn Lin 3866e0832faSShawn Lin static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, 3876e0832faSShawn Lin struct platform_device *pdev) 3886e0832faSShawn Lin { 3896e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 3906e0832faSShawn Lin struct pcie_port *pp = &pci->pp; 3916e0832faSShawn Lin struct device *dev = pci->dev; 3926e0832faSShawn Lin int ret; 3936e0832faSShawn Lin 3946e0832faSShawn Lin if (IS_ENABLED(CONFIG_PCI_MSI)) { 3956e0832faSShawn Lin pp->msi_irq = platform_get_irq_byname(pdev, "msi"); 3966e0832faSShawn Lin if (pp->msi_irq < 0) { 3976e0832faSShawn Lin dev_err(dev, "failed to get MSI irq\n"); 3986e0832faSShawn Lin return pp->msi_irq; 3996e0832faSShawn Lin } 4006e0832faSShawn Lin } 4016e0832faSShawn Lin 4026e0832faSShawn Lin pp->ops = &artpec6_pcie_host_ops; 4036e0832faSShawn Lin 4046e0832faSShawn Lin ret = dw_pcie_host_init(pp); 4056e0832faSShawn Lin if (ret) { 4066e0832faSShawn Lin dev_err(dev, "failed to initialize host\n"); 4076e0832faSShawn Lin return ret; 4086e0832faSShawn Lin } 4096e0832faSShawn Lin 4106e0832faSShawn Lin return 0; 4116e0832faSShawn Lin } 4126e0832faSShawn Lin 4136e0832faSShawn Lin static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) 4146e0832faSShawn Lin { 4156e0832faSShawn Lin struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 4166e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 4176e0832faSShawn Lin enum pci_barno bar; 4186e0832faSShawn Lin 4196e0832faSShawn Lin artpec6_pcie_assert_core_reset(artpec6_pcie); 4206e0832faSShawn Lin artpec6_pcie_init_phy(artpec6_pcie); 4216e0832faSShawn Lin artpec6_pcie_deassert_core_reset(artpec6_pcie); 4226e0832faSShawn Lin artpec6_pcie_wait_for_phy(artpec6_pcie); 4236e0832faSShawn Lin artpec6_pcie_set_nfts(artpec6_pcie); 4246e0832faSShawn Lin 4256e0832faSShawn Lin for (bar = BAR_0; bar <= BAR_5; bar++) 4266e0832faSShawn Lin dw_pcie_ep_reset_bar(pci, bar); 4276e0832faSShawn Lin } 4286e0832faSShawn Lin 4296e0832faSShawn Lin static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 430d3c70a98SGustavo Pimentel enum pci_epc_irq_type type, u16 interrupt_num) 4316e0832faSShawn Lin { 4326e0832faSShawn Lin struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 4336e0832faSShawn Lin 4346e0832faSShawn Lin switch (type) { 4356e0832faSShawn Lin case PCI_EPC_IRQ_LEGACY: 4366e0832faSShawn Lin dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); 4376e0832faSShawn Lin return -EINVAL; 4386e0832faSShawn Lin case PCI_EPC_IRQ_MSI: 4396e0832faSShawn Lin return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 4406e0832faSShawn Lin default: 4416e0832faSShawn Lin dev_err(pci->dev, "UNKNOWN IRQ type\n"); 4426e0832faSShawn Lin } 4436e0832faSShawn Lin 4446e0832faSShawn Lin return 0; 4456e0832faSShawn Lin } 4466e0832faSShawn Lin 4476e0832faSShawn Lin static struct dw_pcie_ep_ops pcie_ep_ops = { 4486e0832faSShawn Lin .ep_init = artpec6_pcie_ep_init, 4496e0832faSShawn Lin .raise_irq = artpec6_pcie_raise_irq, 4506e0832faSShawn Lin }; 4516e0832faSShawn Lin 4526e0832faSShawn Lin static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie, 4536e0832faSShawn Lin struct platform_device *pdev) 4546e0832faSShawn Lin { 4556e0832faSShawn Lin int ret; 4566e0832faSShawn Lin struct dw_pcie_ep *ep; 4576e0832faSShawn Lin struct resource *res; 4586e0832faSShawn Lin struct device *dev = &pdev->dev; 4596e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 4606e0832faSShawn Lin 4616e0832faSShawn Lin ep = &pci->ep; 4626e0832faSShawn Lin ep->ops = &pcie_ep_ops; 4636e0832faSShawn Lin 4646e0832faSShawn Lin res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2"); 4656e0832faSShawn Lin pci->dbi_base2 = devm_ioremap_resource(dev, res); 4666e0832faSShawn Lin if (IS_ERR(pci->dbi_base2)) 4676e0832faSShawn Lin return PTR_ERR(pci->dbi_base2); 4686e0832faSShawn Lin 4696e0832faSShawn Lin res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 4706e0832faSShawn Lin if (!res) 4716e0832faSShawn Lin return -EINVAL; 4726e0832faSShawn Lin 4736e0832faSShawn Lin ep->phys_base = res->start; 4746e0832faSShawn Lin ep->addr_size = resource_size(res); 4756e0832faSShawn Lin 4766e0832faSShawn Lin ret = dw_pcie_ep_init(ep); 4776e0832faSShawn Lin if (ret) { 4786e0832faSShawn Lin dev_err(dev, "failed to initialize endpoint\n"); 4796e0832faSShawn Lin return ret; 4806e0832faSShawn Lin } 4816e0832faSShawn Lin 4826e0832faSShawn Lin return 0; 4836e0832faSShawn Lin } 4846e0832faSShawn Lin 4856e0832faSShawn Lin static int artpec6_pcie_probe(struct platform_device *pdev) 4866e0832faSShawn Lin { 4876e0832faSShawn Lin struct device *dev = &pdev->dev; 4886e0832faSShawn Lin struct dw_pcie *pci; 4896e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie; 4906e0832faSShawn Lin struct resource *dbi_base; 4916e0832faSShawn Lin struct resource *phy_base; 4926e0832faSShawn Lin int ret; 4936e0832faSShawn Lin const struct of_device_id *match; 4946e0832faSShawn Lin const struct artpec_pcie_of_data *data; 4956e0832faSShawn Lin enum artpec_pcie_variants variant; 4966e0832faSShawn Lin enum dw_pcie_device_mode mode; 4976e0832faSShawn Lin 4986e0832faSShawn Lin match = of_match_device(artpec6_pcie_of_match, dev); 4996e0832faSShawn Lin if (!match) 5006e0832faSShawn Lin return -EINVAL; 5016e0832faSShawn Lin 5026e0832faSShawn Lin data = (struct artpec_pcie_of_data *)match->data; 5036e0832faSShawn Lin variant = (enum artpec_pcie_variants)data->variant; 5046e0832faSShawn Lin mode = (enum dw_pcie_device_mode)data->mode; 5056e0832faSShawn Lin 5066e0832faSShawn Lin artpec6_pcie = devm_kzalloc(dev, sizeof(*artpec6_pcie), GFP_KERNEL); 5076e0832faSShawn Lin if (!artpec6_pcie) 5086e0832faSShawn Lin return -ENOMEM; 5096e0832faSShawn Lin 5106e0832faSShawn Lin pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 5116e0832faSShawn Lin if (!pci) 5126e0832faSShawn Lin return -ENOMEM; 5136e0832faSShawn Lin 5146e0832faSShawn Lin pci->dev = dev; 5156e0832faSShawn Lin pci->ops = &dw_pcie_ops; 5166e0832faSShawn Lin 5176e0832faSShawn Lin artpec6_pcie->pci = pci; 5186e0832faSShawn Lin artpec6_pcie->variant = variant; 5196e0832faSShawn Lin artpec6_pcie->mode = mode; 5206e0832faSShawn Lin 5216e0832faSShawn Lin dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); 5226e0832faSShawn Lin pci->dbi_base = devm_ioremap_resource(dev, dbi_base); 5236e0832faSShawn Lin if (IS_ERR(pci->dbi_base)) 5246e0832faSShawn Lin return PTR_ERR(pci->dbi_base); 5256e0832faSShawn Lin 5266e0832faSShawn Lin phy_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); 5276e0832faSShawn Lin artpec6_pcie->phy_base = devm_ioremap_resource(dev, phy_base); 5286e0832faSShawn Lin if (IS_ERR(artpec6_pcie->phy_base)) 5296e0832faSShawn Lin return PTR_ERR(artpec6_pcie->phy_base); 5306e0832faSShawn Lin 5316e0832faSShawn Lin artpec6_pcie->regmap = 5326e0832faSShawn Lin syscon_regmap_lookup_by_phandle(dev->of_node, 5336e0832faSShawn Lin "axis,syscon-pcie"); 5346e0832faSShawn Lin if (IS_ERR(artpec6_pcie->regmap)) 5356e0832faSShawn Lin return PTR_ERR(artpec6_pcie->regmap); 5366e0832faSShawn Lin 5376e0832faSShawn Lin platform_set_drvdata(pdev, artpec6_pcie); 5386e0832faSShawn Lin 5396e0832faSShawn Lin switch (artpec6_pcie->mode) { 5406e0832faSShawn Lin case DW_PCIE_RC_TYPE: 5416e0832faSShawn Lin if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST)) 5426e0832faSShawn Lin return -ENODEV; 5436e0832faSShawn Lin 5446e0832faSShawn Lin ret = artpec6_add_pcie_port(artpec6_pcie, pdev); 5456e0832faSShawn Lin if (ret < 0) 5466e0832faSShawn Lin return ret; 5476e0832faSShawn Lin break; 5486e0832faSShawn Lin case DW_PCIE_EP_TYPE: { 5496e0832faSShawn Lin u32 val; 5506e0832faSShawn Lin 5516e0832faSShawn Lin if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_EP)) 5526e0832faSShawn Lin return -ENODEV; 5536e0832faSShawn Lin 5546e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 5556e0832faSShawn Lin val &= ~PCIECFG_DEVICE_TYPE_MASK; 5566e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 5576e0832faSShawn Lin ret = artpec6_add_pcie_ep(artpec6_pcie, pdev); 5586e0832faSShawn Lin if (ret < 0) 5596e0832faSShawn Lin return ret; 5606e0832faSShawn Lin break; 5616e0832faSShawn Lin } 5626e0832faSShawn Lin default: 5636e0832faSShawn Lin dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode); 5646e0832faSShawn Lin } 5656e0832faSShawn Lin 5666e0832faSShawn Lin return 0; 5676e0832faSShawn Lin } 5686e0832faSShawn Lin 5696e0832faSShawn Lin static const struct artpec_pcie_of_data artpec6_pcie_rc_of_data = { 5706e0832faSShawn Lin .variant = ARTPEC6, 5716e0832faSShawn Lin .mode = DW_PCIE_RC_TYPE, 5726e0832faSShawn Lin }; 5736e0832faSShawn Lin 5746e0832faSShawn Lin static const struct artpec_pcie_of_data artpec6_pcie_ep_of_data = { 5756e0832faSShawn Lin .variant = ARTPEC6, 5766e0832faSShawn Lin .mode = DW_PCIE_EP_TYPE, 5776e0832faSShawn Lin }; 5786e0832faSShawn Lin 5796e0832faSShawn Lin static const struct artpec_pcie_of_data artpec7_pcie_rc_of_data = { 5806e0832faSShawn Lin .variant = ARTPEC7, 5816e0832faSShawn Lin .mode = DW_PCIE_RC_TYPE, 5826e0832faSShawn Lin }; 5836e0832faSShawn Lin 5846e0832faSShawn Lin static const struct artpec_pcie_of_data artpec7_pcie_ep_of_data = { 5856e0832faSShawn Lin .variant = ARTPEC7, 5866e0832faSShawn Lin .mode = DW_PCIE_EP_TYPE, 5876e0832faSShawn Lin }; 5886e0832faSShawn Lin 5896e0832faSShawn Lin static const struct of_device_id artpec6_pcie_of_match[] = { 5906e0832faSShawn Lin { 5916e0832faSShawn Lin .compatible = "axis,artpec6-pcie", 5926e0832faSShawn Lin .data = &artpec6_pcie_rc_of_data, 5936e0832faSShawn Lin }, 5946e0832faSShawn Lin { 5956e0832faSShawn Lin .compatible = "axis,artpec6-pcie-ep", 5966e0832faSShawn Lin .data = &artpec6_pcie_ep_of_data, 5976e0832faSShawn Lin }, 5986e0832faSShawn Lin { 5996e0832faSShawn Lin .compatible = "axis,artpec7-pcie", 6006e0832faSShawn Lin .data = &artpec7_pcie_rc_of_data, 6016e0832faSShawn Lin }, 6026e0832faSShawn Lin { 6036e0832faSShawn Lin .compatible = "axis,artpec7-pcie-ep", 6046e0832faSShawn Lin .data = &artpec7_pcie_ep_of_data, 6056e0832faSShawn Lin }, 6066e0832faSShawn Lin {}, 6076e0832faSShawn Lin }; 6086e0832faSShawn Lin 6096e0832faSShawn Lin static struct platform_driver artpec6_pcie_driver = { 6106e0832faSShawn Lin .probe = artpec6_pcie_probe, 6116e0832faSShawn Lin .driver = { 6126e0832faSShawn Lin .name = "artpec6-pcie", 6136e0832faSShawn Lin .of_match_table = artpec6_pcie_of_match, 6146e0832faSShawn Lin .suppress_bind_attrs = true, 6156e0832faSShawn Lin }, 6166e0832faSShawn Lin }; 6176e0832faSShawn Lin builtin_platform_driver(artpec6_pcie_driver); 618