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 /* ARTPEC-6 specific registers */ 486e0832faSShawn Lin #define PCIECFG 0x18 496e0832faSShawn Lin #define PCIECFG_DBG_OEN BIT(24) 506e0832faSShawn Lin #define PCIECFG_CORE_RESET_REQ BIT(21) 516e0832faSShawn Lin #define PCIECFG_LTSSM_ENABLE BIT(20) 526e0832faSShawn Lin #define PCIECFG_DEVICE_TYPE_MASK GENMASK(19, 16) 536e0832faSShawn Lin #define PCIECFG_CLKREQ_B BIT(11) 546e0832faSShawn Lin #define PCIECFG_REFCLK_ENABLE BIT(10) 556e0832faSShawn Lin #define PCIECFG_PLL_ENABLE BIT(9) 566e0832faSShawn Lin #define PCIECFG_PCLK_ENABLE BIT(8) 576e0832faSShawn Lin #define PCIECFG_RISRCREN BIT(4) 586e0832faSShawn Lin #define PCIECFG_MODE_TX_DRV_EN BIT(3) 596e0832faSShawn Lin #define PCIECFG_CISRREN BIT(2) 606e0832faSShawn Lin #define PCIECFG_MACRO_ENABLE BIT(0) 616e0832faSShawn Lin /* ARTPEC-7 specific fields */ 626e0832faSShawn Lin #define PCIECFG_REFCLKSEL BIT(23) 636e0832faSShawn Lin #define PCIECFG_NOC_RESET BIT(3) 646e0832faSShawn Lin 656e0832faSShawn Lin #define PCIESTAT 0x1c 666e0832faSShawn Lin /* ARTPEC-7 specific fields */ 676e0832faSShawn Lin #define PCIESTAT_EXTREFCLK BIT(3) 686e0832faSShawn Lin 696e0832faSShawn Lin #define NOCCFG 0x40 706e0832faSShawn Lin #define NOCCFG_ENABLE_CLK_PCIE BIT(4) 716e0832faSShawn Lin #define NOCCFG_POWER_PCIE_IDLEACK BIT(3) 726e0832faSShawn Lin #define NOCCFG_POWER_PCIE_IDLE BIT(2) 736e0832faSShawn Lin #define NOCCFG_POWER_PCIE_IDLEREQ BIT(1) 746e0832faSShawn Lin 756e0832faSShawn Lin #define PHY_STATUS 0x118 766e0832faSShawn Lin #define PHY_COSPLLLOCK BIT(0) 776e0832faSShawn Lin 786e0832faSShawn Lin #define PHY_TX_ASIC_OUT 0x4040 796e0832faSShawn Lin #define PHY_TX_ASIC_OUT_TX_ACK BIT(0) 806e0832faSShawn Lin 816e0832faSShawn Lin #define PHY_RX_ASIC_OUT 0x405c 826e0832faSShawn Lin #define PHY_RX_ASIC_OUT_ACK BIT(0) 836e0832faSShawn Lin 846e0832faSShawn Lin static u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset) 856e0832faSShawn Lin { 866e0832faSShawn Lin u32 val; 876e0832faSShawn Lin 886e0832faSShawn Lin regmap_read(artpec6_pcie->regmap, offset, &val); 896e0832faSShawn Lin return val; 906e0832faSShawn Lin } 916e0832faSShawn Lin 926e0832faSShawn Lin static void artpec6_pcie_writel(struct artpec6_pcie *artpec6_pcie, u32 offset, u32 val) 936e0832faSShawn Lin { 946e0832faSShawn Lin regmap_write(artpec6_pcie->regmap, offset, val); 956e0832faSShawn Lin } 966e0832faSShawn Lin 976e0832faSShawn Lin static u64 artpec6_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 pci_addr) 986e0832faSShawn Lin { 996e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 100*60b3c27fSSerge Semin struct dw_pcie_rp *pp = &pci->pp; 1016e0832faSShawn Lin struct dw_pcie_ep *ep = &pci->ep; 1026e0832faSShawn Lin 1036e0832faSShawn Lin switch (artpec6_pcie->mode) { 1046e0832faSShawn Lin case DW_PCIE_RC_TYPE: 1056e0832faSShawn Lin return pci_addr - pp->cfg0_base; 1066e0832faSShawn Lin case DW_PCIE_EP_TYPE: 1076e0832faSShawn Lin return pci_addr - ep->phys_base; 1086e0832faSShawn Lin default: 1096e0832faSShawn Lin dev_err(pci->dev, "UNKNOWN device type\n"); 1106e0832faSShawn Lin } 1116e0832faSShawn Lin return pci_addr; 1126e0832faSShawn Lin } 1136e0832faSShawn Lin 1146e0832faSShawn Lin static int artpec6_pcie_establish_link(struct dw_pcie *pci) 1156e0832faSShawn Lin { 1166e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1176e0832faSShawn Lin u32 val; 1186e0832faSShawn Lin 1196e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 1206e0832faSShawn Lin val |= PCIECFG_LTSSM_ENABLE; 1216e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 1226e0832faSShawn Lin 1236e0832faSShawn Lin return 0; 1246e0832faSShawn Lin } 1256e0832faSShawn Lin 1266e0832faSShawn Lin static void artpec6_pcie_stop_link(struct dw_pcie *pci) 1276e0832faSShawn Lin { 1286e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1296e0832faSShawn Lin u32 val; 1306e0832faSShawn Lin 1316e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 1326e0832faSShawn Lin val &= ~PCIECFG_LTSSM_ENABLE; 1336e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 1346e0832faSShawn Lin } 1356e0832faSShawn Lin 1366e0832faSShawn Lin static const struct dw_pcie_ops dw_pcie_ops = { 1376e0832faSShawn Lin .cpu_addr_fixup = artpec6_pcie_cpu_addr_fixup, 1386e0832faSShawn Lin .start_link = artpec6_pcie_establish_link, 1396e0832faSShawn Lin .stop_link = artpec6_pcie_stop_link, 1406e0832faSShawn Lin }; 1416e0832faSShawn Lin 1426e0832faSShawn Lin static void artpec6_pcie_wait_for_phy_a6(struct artpec6_pcie *artpec6_pcie) 1436e0832faSShawn Lin { 1446e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 1456e0832faSShawn Lin struct device *dev = pci->dev; 1466e0832faSShawn Lin u32 val; 1476e0832faSShawn Lin unsigned int retries; 1486e0832faSShawn Lin 1496e0832faSShawn Lin retries = 50; 1506e0832faSShawn Lin do { 1516e0832faSShawn Lin usleep_range(1000, 2000); 1526e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 1536e0832faSShawn Lin retries--; 1546e0832faSShawn Lin } while (retries && 1556e0832faSShawn Lin (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 1566e0832faSShawn Lin if (!retries) 1576e0832faSShawn Lin dev_err(dev, "PCIe clock manager did not leave idle state\n"); 1586e0832faSShawn Lin 1596e0832faSShawn Lin retries = 50; 1606e0832faSShawn Lin do { 1616e0832faSShawn Lin usleep_range(1000, 2000); 1626e0832faSShawn Lin val = readl(artpec6_pcie->phy_base + PHY_STATUS); 1636e0832faSShawn Lin retries--; 1646e0832faSShawn Lin } while (retries && !(val & PHY_COSPLLLOCK)); 1656e0832faSShawn Lin if (!retries) 1666e0832faSShawn Lin dev_err(dev, "PHY PLL did not lock\n"); 1676e0832faSShawn Lin } 1686e0832faSShawn Lin 1696e0832faSShawn Lin static void artpec6_pcie_wait_for_phy_a7(struct artpec6_pcie *artpec6_pcie) 1706e0832faSShawn Lin { 1716e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 1726e0832faSShawn Lin struct device *dev = pci->dev; 1736e0832faSShawn Lin u32 val; 1746e0832faSShawn Lin u16 phy_status_tx, phy_status_rx; 1756e0832faSShawn Lin unsigned int retries; 1766e0832faSShawn Lin 1776e0832faSShawn Lin retries = 50; 1786e0832faSShawn Lin do { 1796e0832faSShawn Lin usleep_range(1000, 2000); 1806e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 1816e0832faSShawn Lin retries--; 1826e0832faSShawn Lin } while (retries && 1836e0832faSShawn Lin (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 1846e0832faSShawn Lin if (!retries) 1856e0832faSShawn Lin dev_err(dev, "PCIe clock manager did not leave idle state\n"); 1866e0832faSShawn Lin 1876e0832faSShawn Lin retries = 50; 1886e0832faSShawn Lin do { 1896e0832faSShawn Lin usleep_range(1000, 2000); 1906e0832faSShawn Lin phy_status_tx = readw(artpec6_pcie->phy_base + PHY_TX_ASIC_OUT); 1916e0832faSShawn Lin phy_status_rx = readw(artpec6_pcie->phy_base + PHY_RX_ASIC_OUT); 1926e0832faSShawn Lin retries--; 1936e0832faSShawn Lin } while (retries && ((phy_status_tx & PHY_TX_ASIC_OUT_TX_ACK) || 1946e0832faSShawn Lin (phy_status_rx & PHY_RX_ASIC_OUT_ACK))); 1956e0832faSShawn Lin if (!retries) 1966e0832faSShawn Lin dev_err(dev, "PHY did not enter Pn state\n"); 1976e0832faSShawn Lin } 1986e0832faSShawn Lin 1996e0832faSShawn Lin static void artpec6_pcie_wait_for_phy(struct artpec6_pcie *artpec6_pcie) 2006e0832faSShawn Lin { 2016e0832faSShawn Lin switch (artpec6_pcie->variant) { 2026e0832faSShawn Lin case ARTPEC6: 2036e0832faSShawn Lin artpec6_pcie_wait_for_phy_a6(artpec6_pcie); 2046e0832faSShawn Lin break; 2056e0832faSShawn Lin case ARTPEC7: 2066e0832faSShawn Lin artpec6_pcie_wait_for_phy_a7(artpec6_pcie); 2076e0832faSShawn Lin break; 2086e0832faSShawn Lin } 2096e0832faSShawn Lin } 2106e0832faSShawn Lin 2116e0832faSShawn Lin static void artpec6_pcie_init_phy_a6(struct artpec6_pcie *artpec6_pcie) 2126e0832faSShawn Lin { 2136e0832faSShawn Lin u32 val; 2146e0832faSShawn Lin 2156e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2166e0832faSShawn Lin val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 2176e0832faSShawn Lin PCIECFG_MODE_TX_DRV_EN | 2186e0832faSShawn Lin PCIECFG_CISRREN | /* Reference clock term. 100 Ohm */ 2196e0832faSShawn Lin PCIECFG_MACRO_ENABLE; 2206e0832faSShawn Lin val |= PCIECFG_REFCLK_ENABLE; 2216e0832faSShawn Lin val &= ~PCIECFG_DBG_OEN; 2226e0832faSShawn Lin val &= ~PCIECFG_CLKREQ_B; 2236e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2246e0832faSShawn Lin usleep_range(5000, 6000); 2256e0832faSShawn Lin 2266e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2276e0832faSShawn Lin val |= NOCCFG_ENABLE_CLK_PCIE; 2286e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2296e0832faSShawn Lin usleep_range(20, 30); 2306e0832faSShawn Lin 2316e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2326e0832faSShawn Lin val |= PCIECFG_PCLK_ENABLE | PCIECFG_PLL_ENABLE; 2336e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2346e0832faSShawn Lin usleep_range(6000, 7000); 2356e0832faSShawn Lin 2366e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2376e0832faSShawn Lin val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 2386e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2396e0832faSShawn Lin } 2406e0832faSShawn Lin 2416e0832faSShawn Lin static void artpec6_pcie_init_phy_a7(struct artpec6_pcie *artpec6_pcie) 2426e0832faSShawn Lin { 2436e0832faSShawn Lin struct dw_pcie *pci = artpec6_pcie->pci; 2446e0832faSShawn Lin u32 val; 2456e0832faSShawn Lin bool extrefclk; 2466e0832faSShawn Lin 2476e0832faSShawn Lin /* Check if external reference clock is connected */ 2486e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIESTAT); 2496e0832faSShawn Lin extrefclk = !!(val & PCIESTAT_EXTREFCLK); 2506e0832faSShawn Lin dev_dbg(pci->dev, "Using reference clock: %s\n", 2516e0832faSShawn Lin extrefclk ? "external" : "internal"); 2526e0832faSShawn Lin 2536e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2546e0832faSShawn Lin val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 2556e0832faSShawn Lin PCIECFG_PCLK_ENABLE; 2566e0832faSShawn Lin if (extrefclk) 2576e0832faSShawn Lin val |= PCIECFG_REFCLKSEL; 2586e0832faSShawn Lin else 2596e0832faSShawn Lin val &= ~PCIECFG_REFCLKSEL; 2606e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2616e0832faSShawn Lin usleep_range(10, 20); 2626e0832faSShawn Lin 2636e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2646e0832faSShawn Lin val |= NOCCFG_ENABLE_CLK_PCIE; 2656e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2666e0832faSShawn Lin usleep_range(20, 30); 2676e0832faSShawn Lin 2686e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2696e0832faSShawn Lin val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 2706e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2716e0832faSShawn Lin } 2726e0832faSShawn Lin 2736e0832faSShawn Lin static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) 2746e0832faSShawn Lin { 2756e0832faSShawn Lin switch (artpec6_pcie->variant) { 2766e0832faSShawn Lin case ARTPEC6: 2776e0832faSShawn Lin artpec6_pcie_init_phy_a6(artpec6_pcie); 2786e0832faSShawn Lin break; 2796e0832faSShawn Lin case ARTPEC7: 2806e0832faSShawn Lin artpec6_pcie_init_phy_a7(artpec6_pcie); 2816e0832faSShawn Lin break; 2826e0832faSShawn Lin } 2836e0832faSShawn Lin } 2846e0832faSShawn Lin 2856e0832faSShawn Lin static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie) 2866e0832faSShawn Lin { 2876e0832faSShawn Lin u32 val; 2886e0832faSShawn Lin 2896e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2906e0832faSShawn Lin switch (artpec6_pcie->variant) { 2916e0832faSShawn Lin case ARTPEC6: 2926e0832faSShawn Lin val |= PCIECFG_CORE_RESET_REQ; 2936e0832faSShawn Lin break; 2946e0832faSShawn Lin case ARTPEC7: 2956e0832faSShawn Lin val &= ~PCIECFG_NOC_RESET; 2966e0832faSShawn Lin break; 2976e0832faSShawn Lin } 2986e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2996e0832faSShawn Lin } 3006e0832faSShawn Lin 3016e0832faSShawn Lin static void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie) 3026e0832faSShawn Lin { 3036e0832faSShawn Lin u32 val; 3046e0832faSShawn Lin 3056e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 3066e0832faSShawn Lin switch (artpec6_pcie->variant) { 3076e0832faSShawn Lin case ARTPEC6: 3086e0832faSShawn Lin val &= ~PCIECFG_CORE_RESET_REQ; 3096e0832faSShawn Lin break; 3106e0832faSShawn Lin case ARTPEC7: 3116e0832faSShawn Lin val |= PCIECFG_NOC_RESET; 3126e0832faSShawn Lin break; 3136e0832faSShawn Lin } 3146e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 3156e0832faSShawn Lin usleep_range(100, 200); 3166e0832faSShawn Lin } 3176e0832faSShawn Lin 318*60b3c27fSSerge Semin static int artpec6_pcie_host_init(struct dw_pcie_rp *pp) 3196e0832faSShawn Lin { 3206e0832faSShawn Lin struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 3216e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 3226e0832faSShawn Lin 323aeaa0bfeSRob Herring if (artpec6_pcie->variant == ARTPEC7) { 324aeaa0bfeSRob Herring pci->n_fts[0] = 180; 325aeaa0bfeSRob Herring pci->n_fts[1] = 180; 326aeaa0bfeSRob Herring } 3276e0832faSShawn Lin artpec6_pcie_assert_core_reset(artpec6_pcie); 3286e0832faSShawn Lin artpec6_pcie_init_phy(artpec6_pcie); 3296e0832faSShawn Lin artpec6_pcie_deassert_core_reset(artpec6_pcie); 3306e0832faSShawn Lin artpec6_pcie_wait_for_phy(artpec6_pcie); 3316e0832faSShawn Lin 3326e0832faSShawn Lin return 0; 3336e0832faSShawn Lin } 3346e0832faSShawn Lin 3356e0832faSShawn Lin static const struct dw_pcie_host_ops artpec6_pcie_host_ops = { 3366e0832faSShawn Lin .host_init = artpec6_pcie_host_init, 3376e0832faSShawn Lin }; 3386e0832faSShawn Lin 3396e0832faSShawn Lin static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) 3406e0832faSShawn Lin { 3416e0832faSShawn Lin struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 3426e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 3436e0832faSShawn Lin enum pci_barno bar; 3446e0832faSShawn Lin 3456e0832faSShawn Lin artpec6_pcie_assert_core_reset(artpec6_pcie); 3466e0832faSShawn Lin artpec6_pcie_init_phy(artpec6_pcie); 3476e0832faSShawn Lin artpec6_pcie_deassert_core_reset(artpec6_pcie); 3486e0832faSShawn Lin artpec6_pcie_wait_for_phy(artpec6_pcie); 3496e0832faSShawn Lin 350c9c13ba4SDenis Efremov for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) 3516e0832faSShawn Lin dw_pcie_ep_reset_bar(pci, bar); 3526e0832faSShawn Lin } 3536e0832faSShawn Lin 3546e0832faSShawn Lin static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 355d3c70a98SGustavo Pimentel enum pci_epc_irq_type type, u16 interrupt_num) 3566e0832faSShawn Lin { 3576e0832faSShawn Lin struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 3586e0832faSShawn Lin 3596e0832faSShawn Lin switch (type) { 3606e0832faSShawn Lin case PCI_EPC_IRQ_LEGACY: 3616e0832faSShawn Lin dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); 3626e0832faSShawn Lin return -EINVAL; 3636e0832faSShawn Lin case PCI_EPC_IRQ_MSI: 3646e0832faSShawn Lin return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 3656e0832faSShawn Lin default: 3666e0832faSShawn Lin dev_err(pci->dev, "UNKNOWN IRQ type\n"); 3676e0832faSShawn Lin } 3686e0832faSShawn Lin 3696e0832faSShawn Lin return 0; 3706e0832faSShawn Lin } 3716e0832faSShawn Lin 372626961ddSKishon Vijay Abraham I static const struct dw_pcie_ep_ops pcie_ep_ops = { 3736e0832faSShawn Lin .ep_init = artpec6_pcie_ep_init, 3746e0832faSShawn Lin .raise_irq = artpec6_pcie_raise_irq, 3756e0832faSShawn Lin }; 3766e0832faSShawn Lin 3776e0832faSShawn Lin static int artpec6_pcie_probe(struct platform_device *pdev) 3786e0832faSShawn Lin { 3796e0832faSShawn Lin struct device *dev = &pdev->dev; 3806e0832faSShawn Lin struct dw_pcie *pci; 3816e0832faSShawn Lin struct artpec6_pcie *artpec6_pcie; 3826e0832faSShawn Lin int ret; 3836e0832faSShawn Lin const struct artpec_pcie_of_data *data; 3846e0832faSShawn Lin enum artpec_pcie_variants variant; 3856e0832faSShawn Lin enum dw_pcie_device_mode mode; 38630492c12SKrzysztof Wilczyński u32 val; 3876e0832faSShawn Lin 3887073f2ceSFan Fei data = of_device_get_match_data(dev); 3897073f2ceSFan Fei if (!data) 3906e0832faSShawn Lin return -EINVAL; 3916e0832faSShawn Lin 3926e0832faSShawn Lin variant = (enum artpec_pcie_variants)data->variant; 3936e0832faSShawn Lin mode = (enum dw_pcie_device_mode)data->mode; 3946e0832faSShawn Lin 3956e0832faSShawn Lin artpec6_pcie = devm_kzalloc(dev, sizeof(*artpec6_pcie), GFP_KERNEL); 3966e0832faSShawn Lin if (!artpec6_pcie) 3976e0832faSShawn Lin return -ENOMEM; 3986e0832faSShawn Lin 3996e0832faSShawn Lin pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 4006e0832faSShawn Lin if (!pci) 4016e0832faSShawn Lin return -ENOMEM; 4026e0832faSShawn Lin 4036e0832faSShawn Lin pci->dev = dev; 4046e0832faSShawn Lin pci->ops = &dw_pcie_ops; 4056e0832faSShawn Lin 4066e0832faSShawn Lin artpec6_pcie->pci = pci; 4076e0832faSShawn Lin artpec6_pcie->variant = variant; 4086e0832faSShawn Lin artpec6_pcie->mode = mode; 4096e0832faSShawn Lin 410936fa5cdSDejin Zheng artpec6_pcie->phy_base = 411936fa5cdSDejin Zheng devm_platform_ioremap_resource_byname(pdev, "phy"); 4126e0832faSShawn Lin if (IS_ERR(artpec6_pcie->phy_base)) 4136e0832faSShawn Lin return PTR_ERR(artpec6_pcie->phy_base); 4146e0832faSShawn Lin 4156e0832faSShawn Lin artpec6_pcie->regmap = 4166e0832faSShawn Lin syscon_regmap_lookup_by_phandle(dev->of_node, 4176e0832faSShawn Lin "axis,syscon-pcie"); 4186e0832faSShawn Lin if (IS_ERR(artpec6_pcie->regmap)) 4196e0832faSShawn Lin return PTR_ERR(artpec6_pcie->regmap); 4206e0832faSShawn Lin 4216e0832faSShawn Lin platform_set_drvdata(pdev, artpec6_pcie); 4226e0832faSShawn Lin 4236e0832faSShawn Lin switch (artpec6_pcie->mode) { 4246e0832faSShawn Lin case DW_PCIE_RC_TYPE: 4256e0832faSShawn Lin if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST)) 4266e0832faSShawn Lin return -ENODEV; 4276e0832faSShawn Lin 42860f5b73fSRob Herring pci->pp.ops = &artpec6_pcie_host_ops; 42960f5b73fSRob Herring 43060f5b73fSRob Herring ret = dw_pcie_host_init(&pci->pp); 4316e0832faSShawn Lin if (ret < 0) 4326e0832faSShawn Lin return ret; 4336e0832faSShawn Lin break; 43430492c12SKrzysztof Wilczyński case DW_PCIE_EP_TYPE: 4356e0832faSShawn Lin if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_EP)) 4366e0832faSShawn Lin return -ENODEV; 4376e0832faSShawn Lin 4386e0832faSShawn Lin val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 4396e0832faSShawn Lin val &= ~PCIECFG_DEVICE_TYPE_MASK; 4406e0832faSShawn Lin artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 441a0fd361dSRob Herring 442a0fd361dSRob Herring pci->ep.ops = &pcie_ep_ops; 443a0fd361dSRob Herring 444a0fd361dSRob Herring return dw_pcie_ep_init(&pci->ep); 4456e0832faSShawn Lin default: 4466e0832faSShawn Lin dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode); 4476e0832faSShawn Lin } 4486e0832faSShawn Lin 4496e0832faSShawn Lin return 0; 4506e0832faSShawn Lin } 4516e0832faSShawn Lin 4526e0832faSShawn Lin static const struct artpec_pcie_of_data artpec6_pcie_rc_of_data = { 4536e0832faSShawn Lin .variant = ARTPEC6, 4546e0832faSShawn Lin .mode = DW_PCIE_RC_TYPE, 4556e0832faSShawn Lin }; 4566e0832faSShawn Lin 4576e0832faSShawn Lin static const struct artpec_pcie_of_data artpec6_pcie_ep_of_data = { 4586e0832faSShawn Lin .variant = ARTPEC6, 4596e0832faSShawn Lin .mode = DW_PCIE_EP_TYPE, 4606e0832faSShawn Lin }; 4616e0832faSShawn Lin 4626e0832faSShawn Lin static const struct artpec_pcie_of_data artpec7_pcie_rc_of_data = { 4636e0832faSShawn Lin .variant = ARTPEC7, 4646e0832faSShawn Lin .mode = DW_PCIE_RC_TYPE, 4656e0832faSShawn Lin }; 4666e0832faSShawn Lin 4676e0832faSShawn Lin static const struct artpec_pcie_of_data artpec7_pcie_ep_of_data = { 4686e0832faSShawn Lin .variant = ARTPEC7, 4696e0832faSShawn Lin .mode = DW_PCIE_EP_TYPE, 4706e0832faSShawn Lin }; 4716e0832faSShawn Lin 4726e0832faSShawn Lin static const struct of_device_id artpec6_pcie_of_match[] = { 4736e0832faSShawn Lin { 4746e0832faSShawn Lin .compatible = "axis,artpec6-pcie", 4756e0832faSShawn Lin .data = &artpec6_pcie_rc_of_data, 4766e0832faSShawn Lin }, 4776e0832faSShawn Lin { 4786e0832faSShawn Lin .compatible = "axis,artpec6-pcie-ep", 4796e0832faSShawn Lin .data = &artpec6_pcie_ep_of_data, 4806e0832faSShawn Lin }, 4816e0832faSShawn Lin { 4826e0832faSShawn Lin .compatible = "axis,artpec7-pcie", 4836e0832faSShawn Lin .data = &artpec7_pcie_rc_of_data, 4846e0832faSShawn Lin }, 4856e0832faSShawn Lin { 4866e0832faSShawn Lin .compatible = "axis,artpec7-pcie-ep", 4876e0832faSShawn Lin .data = &artpec7_pcie_ep_of_data, 4886e0832faSShawn Lin }, 4896e0832faSShawn Lin {}, 4906e0832faSShawn Lin }; 4916e0832faSShawn Lin 4926e0832faSShawn Lin static struct platform_driver artpec6_pcie_driver = { 4936e0832faSShawn Lin .probe = artpec6_pcie_probe, 4946e0832faSShawn Lin .driver = { 4956e0832faSShawn Lin .name = "artpec6-pcie", 4966e0832faSShawn Lin .of_match_table = artpec6_pcie_of_match, 4976e0832faSShawn Lin .suppress_bind_attrs = true, 4986e0832faSShawn Lin }, 4996e0832faSShawn Lin }; 5006e0832faSShawn Lin builtin_platform_driver(artpec6_pcie_driver); 501