18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCIe host controller driver for Axis ARTPEC-6 SoC 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Niklas Cassel <niklas.cassel@axis.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on work done by Phil Edworthy <phil@edworthys.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/of_device.h> 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/resource.h> 178c2ecf20Sopenharmony_ci#include <linux/signal.h> 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 218c2ecf20Sopenharmony_ci#include <linux/regmap.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "pcie-designware.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define to_artpec6_pcie(x) dev_get_drvdata((x)->dev) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cienum artpec_pcie_variants { 288c2ecf20Sopenharmony_ci ARTPEC6, 298c2ecf20Sopenharmony_ci ARTPEC7, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct artpec6_pcie { 338c2ecf20Sopenharmony_ci struct dw_pcie *pci; 348c2ecf20Sopenharmony_ci struct regmap *regmap; /* DT axis,syscon-pcie */ 358c2ecf20Sopenharmony_ci void __iomem *phy_base; /* DT phy */ 368c2ecf20Sopenharmony_ci enum artpec_pcie_variants variant; 378c2ecf20Sopenharmony_ci enum dw_pcie_device_mode mode; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct artpec_pcie_of_data { 418c2ecf20Sopenharmony_ci enum artpec_pcie_variants variant; 428c2ecf20Sopenharmony_ci enum dw_pcie_device_mode mode; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic const struct of_device_id artpec6_pcie_of_match[]; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* ARTPEC-6 specific registers */ 488c2ecf20Sopenharmony_ci#define PCIECFG 0x18 498c2ecf20Sopenharmony_ci#define PCIECFG_DBG_OEN BIT(24) 508c2ecf20Sopenharmony_ci#define PCIECFG_CORE_RESET_REQ BIT(21) 518c2ecf20Sopenharmony_ci#define PCIECFG_LTSSM_ENABLE BIT(20) 528c2ecf20Sopenharmony_ci#define PCIECFG_DEVICE_TYPE_MASK GENMASK(19, 16) 538c2ecf20Sopenharmony_ci#define PCIECFG_CLKREQ_B BIT(11) 548c2ecf20Sopenharmony_ci#define PCIECFG_REFCLK_ENABLE BIT(10) 558c2ecf20Sopenharmony_ci#define PCIECFG_PLL_ENABLE BIT(9) 568c2ecf20Sopenharmony_ci#define PCIECFG_PCLK_ENABLE BIT(8) 578c2ecf20Sopenharmony_ci#define PCIECFG_RISRCREN BIT(4) 588c2ecf20Sopenharmony_ci#define PCIECFG_MODE_TX_DRV_EN BIT(3) 598c2ecf20Sopenharmony_ci#define PCIECFG_CISRREN BIT(2) 608c2ecf20Sopenharmony_ci#define PCIECFG_MACRO_ENABLE BIT(0) 618c2ecf20Sopenharmony_ci/* ARTPEC-7 specific fields */ 628c2ecf20Sopenharmony_ci#define PCIECFG_REFCLKSEL BIT(23) 638c2ecf20Sopenharmony_ci#define PCIECFG_NOC_RESET BIT(3) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define PCIESTAT 0x1c 668c2ecf20Sopenharmony_ci/* ARTPEC-7 specific fields */ 678c2ecf20Sopenharmony_ci#define PCIESTAT_EXTREFCLK BIT(3) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define NOCCFG 0x40 708c2ecf20Sopenharmony_ci#define NOCCFG_ENABLE_CLK_PCIE BIT(4) 718c2ecf20Sopenharmony_ci#define NOCCFG_POWER_PCIE_IDLEACK BIT(3) 728c2ecf20Sopenharmony_ci#define NOCCFG_POWER_PCIE_IDLE BIT(2) 738c2ecf20Sopenharmony_ci#define NOCCFG_POWER_PCIE_IDLEREQ BIT(1) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define PHY_STATUS 0x118 768c2ecf20Sopenharmony_ci#define PHY_COSPLLLOCK BIT(0) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define PHY_TX_ASIC_OUT 0x4040 798c2ecf20Sopenharmony_ci#define PHY_TX_ASIC_OUT_TX_ACK BIT(0) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define PHY_RX_ASIC_OUT 0x405c 828c2ecf20Sopenharmony_ci#define PHY_RX_ASIC_OUT_ACK BIT(0) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci u32 val; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci regmap_read(artpec6_pcie->regmap, offset, &val); 898c2ecf20Sopenharmony_ci return val; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void artpec6_pcie_writel(struct artpec6_pcie *artpec6_pcie, u32 offset, u32 val) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci regmap_write(artpec6_pcie->regmap, offset, val); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic u64 artpec6_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 pci_addr) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1008c2ecf20Sopenharmony_ci struct pcie_port *pp = &pci->pp; 1018c2ecf20Sopenharmony_ci struct dw_pcie_ep *ep = &pci->ep; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci switch (artpec6_pcie->mode) { 1048c2ecf20Sopenharmony_ci case DW_PCIE_RC_TYPE: 1058c2ecf20Sopenharmony_ci return pci_addr - pp->cfg0_base; 1068c2ecf20Sopenharmony_ci case DW_PCIE_EP_TYPE: 1078c2ecf20Sopenharmony_ci return pci_addr - ep->phys_base; 1088c2ecf20Sopenharmony_ci default: 1098c2ecf20Sopenharmony_ci dev_err(pci->dev, "UNKNOWN device type\n"); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci return pci_addr; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int artpec6_pcie_establish_link(struct dw_pcie *pci) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1178c2ecf20Sopenharmony_ci u32 val; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 1208c2ecf20Sopenharmony_ci val |= PCIECFG_LTSSM_ENABLE; 1218c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void artpec6_pcie_stop_link(struct dw_pcie *pci) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 1298c2ecf20Sopenharmony_ci u32 val; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 1328c2ecf20Sopenharmony_ci val &= ~PCIECFG_LTSSM_ENABLE; 1338c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic const struct dw_pcie_ops dw_pcie_ops = { 1378c2ecf20Sopenharmony_ci .cpu_addr_fixup = artpec6_pcie_cpu_addr_fixup, 1388c2ecf20Sopenharmony_ci .start_link = artpec6_pcie_establish_link, 1398c2ecf20Sopenharmony_ci .stop_link = artpec6_pcie_stop_link, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void artpec6_pcie_wait_for_phy_a6(struct artpec6_pcie *artpec6_pcie) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 1458c2ecf20Sopenharmony_ci struct device *dev = pci->dev; 1468c2ecf20Sopenharmony_ci u32 val; 1478c2ecf20Sopenharmony_ci unsigned int retries; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci retries = 50; 1508c2ecf20Sopenharmony_ci do { 1518c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 1528c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 1538c2ecf20Sopenharmony_ci retries--; 1548c2ecf20Sopenharmony_ci } while (retries && 1558c2ecf20Sopenharmony_ci (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 1568c2ecf20Sopenharmony_ci if (!retries) 1578c2ecf20Sopenharmony_ci dev_err(dev, "PCIe clock manager did not leave idle state\n"); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci retries = 50; 1608c2ecf20Sopenharmony_ci do { 1618c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 1628c2ecf20Sopenharmony_ci val = readl(artpec6_pcie->phy_base + PHY_STATUS); 1638c2ecf20Sopenharmony_ci retries--; 1648c2ecf20Sopenharmony_ci } while (retries && !(val & PHY_COSPLLLOCK)); 1658c2ecf20Sopenharmony_ci if (!retries) 1668c2ecf20Sopenharmony_ci dev_err(dev, "PHY PLL did not lock\n"); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void artpec6_pcie_wait_for_phy_a7(struct artpec6_pcie *artpec6_pcie) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 1728c2ecf20Sopenharmony_ci struct device *dev = pci->dev; 1738c2ecf20Sopenharmony_ci u32 val; 1748c2ecf20Sopenharmony_ci u16 phy_status_tx, phy_status_rx; 1758c2ecf20Sopenharmony_ci unsigned int retries; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci retries = 50; 1788c2ecf20Sopenharmony_ci do { 1798c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 1808c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 1818c2ecf20Sopenharmony_ci retries--; 1828c2ecf20Sopenharmony_ci } while (retries && 1838c2ecf20Sopenharmony_ci (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 1848c2ecf20Sopenharmony_ci if (!retries) 1858c2ecf20Sopenharmony_ci dev_err(dev, "PCIe clock manager did not leave idle state\n"); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci retries = 50; 1888c2ecf20Sopenharmony_ci do { 1898c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 1908c2ecf20Sopenharmony_ci phy_status_tx = readw(artpec6_pcie->phy_base + PHY_TX_ASIC_OUT); 1918c2ecf20Sopenharmony_ci phy_status_rx = readw(artpec6_pcie->phy_base + PHY_RX_ASIC_OUT); 1928c2ecf20Sopenharmony_ci retries--; 1938c2ecf20Sopenharmony_ci } while (retries && ((phy_status_tx & PHY_TX_ASIC_OUT_TX_ACK) || 1948c2ecf20Sopenharmony_ci (phy_status_rx & PHY_RX_ASIC_OUT_ACK))); 1958c2ecf20Sopenharmony_ci if (!retries) 1968c2ecf20Sopenharmony_ci dev_err(dev, "PHY did not enter Pn state\n"); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void artpec6_pcie_wait_for_phy(struct artpec6_pcie *artpec6_pcie) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci switch (artpec6_pcie->variant) { 2028c2ecf20Sopenharmony_ci case ARTPEC6: 2038c2ecf20Sopenharmony_ci artpec6_pcie_wait_for_phy_a6(artpec6_pcie); 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case ARTPEC7: 2068c2ecf20Sopenharmony_ci artpec6_pcie_wait_for_phy_a7(artpec6_pcie); 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void artpec6_pcie_init_phy_a6(struct artpec6_pcie *artpec6_pcie) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci u32 val; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2168c2ecf20Sopenharmony_ci val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 2178c2ecf20Sopenharmony_ci PCIECFG_MODE_TX_DRV_EN | 2188c2ecf20Sopenharmony_ci PCIECFG_CISRREN | /* Reference clock term. 100 Ohm */ 2198c2ecf20Sopenharmony_ci PCIECFG_MACRO_ENABLE; 2208c2ecf20Sopenharmony_ci val |= PCIECFG_REFCLK_ENABLE; 2218c2ecf20Sopenharmony_ci val &= ~PCIECFG_DBG_OEN; 2228c2ecf20Sopenharmony_ci val &= ~PCIECFG_CLKREQ_B; 2238c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2248c2ecf20Sopenharmony_ci usleep_range(5000, 6000); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2278c2ecf20Sopenharmony_ci val |= NOCCFG_ENABLE_CLK_PCIE; 2288c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2298c2ecf20Sopenharmony_ci usleep_range(20, 30); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2328c2ecf20Sopenharmony_ci val |= PCIECFG_PCLK_ENABLE | PCIECFG_PLL_ENABLE; 2338c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2348c2ecf20Sopenharmony_ci usleep_range(6000, 7000); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2378c2ecf20Sopenharmony_ci val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 2388c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void artpec6_pcie_init_phy_a7(struct artpec6_pcie *artpec6_pcie) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 2448c2ecf20Sopenharmony_ci u32 val; 2458c2ecf20Sopenharmony_ci bool extrefclk; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Check if external reference clock is connected */ 2488c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIESTAT); 2498c2ecf20Sopenharmony_ci extrefclk = !!(val & PCIESTAT_EXTREFCLK); 2508c2ecf20Sopenharmony_ci dev_dbg(pci->dev, "Using reference clock: %s\n", 2518c2ecf20Sopenharmony_ci extrefclk ? "external" : "internal"); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2548c2ecf20Sopenharmony_ci val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 2558c2ecf20Sopenharmony_ci PCIECFG_PCLK_ENABLE; 2568c2ecf20Sopenharmony_ci if (extrefclk) 2578c2ecf20Sopenharmony_ci val |= PCIECFG_REFCLKSEL; 2588c2ecf20Sopenharmony_ci else 2598c2ecf20Sopenharmony_ci val &= ~PCIECFG_REFCLKSEL; 2608c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2618c2ecf20Sopenharmony_ci usleep_range(10, 20); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2648c2ecf20Sopenharmony_ci val |= NOCCFG_ENABLE_CLK_PCIE; 2658c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2668c2ecf20Sopenharmony_ci usleep_range(20, 30); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 2698c2ecf20Sopenharmony_ci val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 2708c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci switch (artpec6_pcie->variant) { 2768c2ecf20Sopenharmony_ci case ARTPEC6: 2778c2ecf20Sopenharmony_ci artpec6_pcie_init_phy_a6(artpec6_pcie); 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case ARTPEC7: 2808c2ecf20Sopenharmony_ci artpec6_pcie_init_phy_a7(artpec6_pcie); 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci u32 val; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 2908c2ecf20Sopenharmony_ci switch (artpec6_pcie->variant) { 2918c2ecf20Sopenharmony_ci case ARTPEC6: 2928c2ecf20Sopenharmony_ci val |= PCIECFG_CORE_RESET_REQ; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci case ARTPEC7: 2958c2ecf20Sopenharmony_ci val &= ~PCIECFG_NOC_RESET; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci u32 val; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 3068c2ecf20Sopenharmony_ci switch (artpec6_pcie->variant) { 3078c2ecf20Sopenharmony_ci case ARTPEC6: 3088c2ecf20Sopenharmony_ci val &= ~PCIECFG_CORE_RESET_REQ; 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case ARTPEC7: 3118c2ecf20Sopenharmony_ci val |= PCIECFG_NOC_RESET; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 3158c2ecf20Sopenharmony_ci usleep_range(100, 200); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int artpec6_pcie_host_init(struct pcie_port *pp) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 3218c2ecf20Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (artpec6_pcie->variant == ARTPEC7) { 3248c2ecf20Sopenharmony_ci pci->n_fts[0] = 180; 3258c2ecf20Sopenharmony_ci pci->n_fts[1] = 180; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci artpec6_pcie_assert_core_reset(artpec6_pcie); 3288c2ecf20Sopenharmony_ci artpec6_pcie_init_phy(artpec6_pcie); 3298c2ecf20Sopenharmony_ci artpec6_pcie_deassert_core_reset(artpec6_pcie); 3308c2ecf20Sopenharmony_ci artpec6_pcie_wait_for_phy(artpec6_pcie); 3318c2ecf20Sopenharmony_ci dw_pcie_setup_rc(pp); 3328c2ecf20Sopenharmony_ci artpec6_pcie_establish_link(pci); 3338c2ecf20Sopenharmony_ci dw_pcie_wait_for_link(pci); 3348c2ecf20Sopenharmony_ci dw_pcie_msi_init(pp); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic const struct dw_pcie_host_ops artpec6_pcie_host_ops = { 3408c2ecf20Sopenharmony_ci .host_init = artpec6_pcie_host_init, 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie, 3448c2ecf20Sopenharmony_ci struct platform_device *pdev) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 3478c2ecf20Sopenharmony_ci struct pcie_port *pp = &pci->pp; 3488c2ecf20Sopenharmony_ci struct device *dev = pci->dev; 3498c2ecf20Sopenharmony_ci int ret; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI)) { 3528c2ecf20Sopenharmony_ci pp->msi_irq = platform_get_irq_byname(pdev, "msi"); 3538c2ecf20Sopenharmony_ci if (pp->msi_irq < 0) 3548c2ecf20Sopenharmony_ci return pp->msi_irq; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci pp->ops = &artpec6_pcie_host_ops; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ret = dw_pcie_host_init(pp); 3608c2ecf20Sopenharmony_ci if (ret) { 3618c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize host\n"); 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 3718c2ecf20Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 3728c2ecf20Sopenharmony_ci enum pci_barno bar; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci artpec6_pcie_assert_core_reset(artpec6_pcie); 3758c2ecf20Sopenharmony_ci artpec6_pcie_init_phy(artpec6_pcie); 3768c2ecf20Sopenharmony_ci artpec6_pcie_deassert_core_reset(artpec6_pcie); 3778c2ecf20Sopenharmony_ci artpec6_pcie_wait_for_phy(artpec6_pcie); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) 3808c2ecf20Sopenharmony_ci dw_pcie_ep_reset_bar(pci, bar); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 3848c2ecf20Sopenharmony_ci enum pci_epc_irq_type type, u16 interrupt_num) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci switch (type) { 3898c2ecf20Sopenharmony_ci case PCI_EPC_IRQ_LEGACY: 3908c2ecf20Sopenharmony_ci dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci case PCI_EPC_IRQ_MSI: 3938c2ecf20Sopenharmony_ci return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 3948c2ecf20Sopenharmony_ci default: 3958c2ecf20Sopenharmony_ci dev_err(pci->dev, "UNKNOWN IRQ type\n"); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic const struct dw_pcie_ep_ops pcie_ep_ops = { 4028c2ecf20Sopenharmony_ci .ep_init = artpec6_pcie_ep_init, 4038c2ecf20Sopenharmony_ci .raise_irq = artpec6_pcie_raise_irq, 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie, 4078c2ecf20Sopenharmony_ci struct platform_device *pdev) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci int ret; 4108c2ecf20Sopenharmony_ci struct dw_pcie_ep *ep; 4118c2ecf20Sopenharmony_ci struct resource *res; 4128c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4138c2ecf20Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci ep = &pci->ep; 4168c2ecf20Sopenharmony_ci ep->ops = &pcie_ep_ops; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2"); 4198c2ecf20Sopenharmony_ci if (IS_ERR(pci->dbi_base2)) 4208c2ecf20Sopenharmony_ci return PTR_ERR(pci->dbi_base2); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 4238c2ecf20Sopenharmony_ci if (!res) 4248c2ecf20Sopenharmony_ci return -EINVAL; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ep->phys_base = res->start; 4278c2ecf20Sopenharmony_ci ep->addr_size = resource_size(res); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ret = dw_pcie_ep_init(ep); 4308c2ecf20Sopenharmony_ci if (ret) { 4318c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize endpoint\n"); 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int artpec6_pcie_probe(struct platform_device *pdev) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4418c2ecf20Sopenharmony_ci struct dw_pcie *pci; 4428c2ecf20Sopenharmony_ci struct artpec6_pcie *artpec6_pcie; 4438c2ecf20Sopenharmony_ci int ret; 4448c2ecf20Sopenharmony_ci const struct of_device_id *match; 4458c2ecf20Sopenharmony_ci const struct artpec_pcie_of_data *data; 4468c2ecf20Sopenharmony_ci enum artpec_pcie_variants variant; 4478c2ecf20Sopenharmony_ci enum dw_pcie_device_mode mode; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci match = of_match_device(artpec6_pcie_of_match, dev); 4508c2ecf20Sopenharmony_ci if (!match) 4518c2ecf20Sopenharmony_ci return -EINVAL; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci data = (struct artpec_pcie_of_data *)match->data; 4548c2ecf20Sopenharmony_ci variant = (enum artpec_pcie_variants)data->variant; 4558c2ecf20Sopenharmony_ci mode = (enum dw_pcie_device_mode)data->mode; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci artpec6_pcie = devm_kzalloc(dev, sizeof(*artpec6_pcie), GFP_KERNEL); 4588c2ecf20Sopenharmony_ci if (!artpec6_pcie) 4598c2ecf20Sopenharmony_ci return -ENOMEM; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 4628c2ecf20Sopenharmony_ci if (!pci) 4638c2ecf20Sopenharmony_ci return -ENOMEM; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci pci->dev = dev; 4668c2ecf20Sopenharmony_ci pci->ops = &dw_pcie_ops; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci artpec6_pcie->pci = pci; 4698c2ecf20Sopenharmony_ci artpec6_pcie->variant = variant; 4708c2ecf20Sopenharmony_ci artpec6_pcie->mode = mode; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi"); 4738c2ecf20Sopenharmony_ci if (IS_ERR(pci->dbi_base)) 4748c2ecf20Sopenharmony_ci return PTR_ERR(pci->dbi_base); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci artpec6_pcie->phy_base = 4778c2ecf20Sopenharmony_ci devm_platform_ioremap_resource_byname(pdev, "phy"); 4788c2ecf20Sopenharmony_ci if (IS_ERR(artpec6_pcie->phy_base)) 4798c2ecf20Sopenharmony_ci return PTR_ERR(artpec6_pcie->phy_base); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci artpec6_pcie->regmap = 4828c2ecf20Sopenharmony_ci syscon_regmap_lookup_by_phandle(dev->of_node, 4838c2ecf20Sopenharmony_ci "axis,syscon-pcie"); 4848c2ecf20Sopenharmony_ci if (IS_ERR(artpec6_pcie->regmap)) 4858c2ecf20Sopenharmony_ci return PTR_ERR(artpec6_pcie->regmap); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, artpec6_pcie); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci switch (artpec6_pcie->mode) { 4908c2ecf20Sopenharmony_ci case DW_PCIE_RC_TYPE: 4918c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST)) 4928c2ecf20Sopenharmony_ci return -ENODEV; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci ret = artpec6_add_pcie_port(artpec6_pcie, pdev); 4958c2ecf20Sopenharmony_ci if (ret < 0) 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case DW_PCIE_EP_TYPE: { 4998c2ecf20Sopenharmony_ci u32 val; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_EP)) 5028c2ecf20Sopenharmony_ci return -ENODEV; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 5058c2ecf20Sopenharmony_ci val &= ~PCIECFG_DEVICE_TYPE_MASK; 5068c2ecf20Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 5078c2ecf20Sopenharmony_ci ret = artpec6_add_pcie_ep(artpec6_pcie, pdev); 5088c2ecf20Sopenharmony_ci if (ret < 0) 5098c2ecf20Sopenharmony_ci return ret; 5108c2ecf20Sopenharmony_ci break; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci default: 5138c2ecf20Sopenharmony_ci dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic const struct artpec_pcie_of_data artpec6_pcie_rc_of_data = { 5208c2ecf20Sopenharmony_ci .variant = ARTPEC6, 5218c2ecf20Sopenharmony_ci .mode = DW_PCIE_RC_TYPE, 5228c2ecf20Sopenharmony_ci}; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic const struct artpec_pcie_of_data artpec6_pcie_ep_of_data = { 5258c2ecf20Sopenharmony_ci .variant = ARTPEC6, 5268c2ecf20Sopenharmony_ci .mode = DW_PCIE_EP_TYPE, 5278c2ecf20Sopenharmony_ci}; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic const struct artpec_pcie_of_data artpec7_pcie_rc_of_data = { 5308c2ecf20Sopenharmony_ci .variant = ARTPEC7, 5318c2ecf20Sopenharmony_ci .mode = DW_PCIE_RC_TYPE, 5328c2ecf20Sopenharmony_ci}; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic const struct artpec_pcie_of_data artpec7_pcie_ep_of_data = { 5358c2ecf20Sopenharmony_ci .variant = ARTPEC7, 5368c2ecf20Sopenharmony_ci .mode = DW_PCIE_EP_TYPE, 5378c2ecf20Sopenharmony_ci}; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic const struct of_device_id artpec6_pcie_of_match[] = { 5408c2ecf20Sopenharmony_ci { 5418c2ecf20Sopenharmony_ci .compatible = "axis,artpec6-pcie", 5428c2ecf20Sopenharmony_ci .data = &artpec6_pcie_rc_of_data, 5438c2ecf20Sopenharmony_ci }, 5448c2ecf20Sopenharmony_ci { 5458c2ecf20Sopenharmony_ci .compatible = "axis,artpec6-pcie-ep", 5468c2ecf20Sopenharmony_ci .data = &artpec6_pcie_ep_of_data, 5478c2ecf20Sopenharmony_ci }, 5488c2ecf20Sopenharmony_ci { 5498c2ecf20Sopenharmony_ci .compatible = "axis,artpec7-pcie", 5508c2ecf20Sopenharmony_ci .data = &artpec7_pcie_rc_of_data, 5518c2ecf20Sopenharmony_ci }, 5528c2ecf20Sopenharmony_ci { 5538c2ecf20Sopenharmony_ci .compatible = "axis,artpec7-pcie-ep", 5548c2ecf20Sopenharmony_ci .data = &artpec7_pcie_ep_of_data, 5558c2ecf20Sopenharmony_ci }, 5568c2ecf20Sopenharmony_ci {}, 5578c2ecf20Sopenharmony_ci}; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic struct platform_driver artpec6_pcie_driver = { 5608c2ecf20Sopenharmony_ci .probe = artpec6_pcie_probe, 5618c2ecf20Sopenharmony_ci .driver = { 5628c2ecf20Sopenharmony_ci .name = "artpec6-pcie", 5638c2ecf20Sopenharmony_ci .of_match_table = artpec6_pcie_of_match, 5648c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 5658c2ecf20Sopenharmony_ci }, 5668c2ecf20Sopenharmony_ci}; 5678c2ecf20Sopenharmony_cibuiltin_platform_driver(artpec6_pcie_driver); 568