162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCIe host controller driver for Axis ARTPEC-6 SoC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Niklas Cassel <niklas.cassel@axis.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on work done by Phil Edworthy <phil@edworthys.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/pci.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/resource.h> 1762306a36Sopenharmony_ci#include <linux/signal.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci#include <linux/interrupt.h> 2062306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2162306a36Sopenharmony_ci#include <linux/regmap.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "pcie-designware.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define to_artpec6_pcie(x) dev_get_drvdata((x)->dev) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cienum artpec_pcie_variants { 2862306a36Sopenharmony_ci ARTPEC6, 2962306a36Sopenharmony_ci ARTPEC7, 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct artpec6_pcie { 3362306a36Sopenharmony_ci struct dw_pcie *pci; 3462306a36Sopenharmony_ci struct regmap *regmap; /* DT axis,syscon-pcie */ 3562306a36Sopenharmony_ci void __iomem *phy_base; /* DT phy */ 3662306a36Sopenharmony_ci enum artpec_pcie_variants variant; 3762306a36Sopenharmony_ci enum dw_pcie_device_mode mode; 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct artpec_pcie_of_data { 4162306a36Sopenharmony_ci enum artpec_pcie_variants variant; 4262306a36Sopenharmony_ci enum dw_pcie_device_mode mode; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const struct of_device_id artpec6_pcie_of_match[]; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* ARTPEC-6 specific registers */ 4862306a36Sopenharmony_ci#define PCIECFG 0x18 4962306a36Sopenharmony_ci#define PCIECFG_DBG_OEN BIT(24) 5062306a36Sopenharmony_ci#define PCIECFG_CORE_RESET_REQ BIT(21) 5162306a36Sopenharmony_ci#define PCIECFG_LTSSM_ENABLE BIT(20) 5262306a36Sopenharmony_ci#define PCIECFG_DEVICE_TYPE_MASK GENMASK(19, 16) 5362306a36Sopenharmony_ci#define PCIECFG_CLKREQ_B BIT(11) 5462306a36Sopenharmony_ci#define PCIECFG_REFCLK_ENABLE BIT(10) 5562306a36Sopenharmony_ci#define PCIECFG_PLL_ENABLE BIT(9) 5662306a36Sopenharmony_ci#define PCIECFG_PCLK_ENABLE BIT(8) 5762306a36Sopenharmony_ci#define PCIECFG_RISRCREN BIT(4) 5862306a36Sopenharmony_ci#define PCIECFG_MODE_TX_DRV_EN BIT(3) 5962306a36Sopenharmony_ci#define PCIECFG_CISRREN BIT(2) 6062306a36Sopenharmony_ci#define PCIECFG_MACRO_ENABLE BIT(0) 6162306a36Sopenharmony_ci/* ARTPEC-7 specific fields */ 6262306a36Sopenharmony_ci#define PCIECFG_REFCLKSEL BIT(23) 6362306a36Sopenharmony_ci#define PCIECFG_NOC_RESET BIT(3) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define PCIESTAT 0x1c 6662306a36Sopenharmony_ci/* ARTPEC-7 specific fields */ 6762306a36Sopenharmony_ci#define PCIESTAT_EXTREFCLK BIT(3) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define NOCCFG 0x40 7062306a36Sopenharmony_ci#define NOCCFG_ENABLE_CLK_PCIE BIT(4) 7162306a36Sopenharmony_ci#define NOCCFG_POWER_PCIE_IDLEACK BIT(3) 7262306a36Sopenharmony_ci#define NOCCFG_POWER_PCIE_IDLE BIT(2) 7362306a36Sopenharmony_ci#define NOCCFG_POWER_PCIE_IDLEREQ BIT(1) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define PHY_STATUS 0x118 7662306a36Sopenharmony_ci#define PHY_COSPLLLOCK BIT(0) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define PHY_TX_ASIC_OUT 0x4040 7962306a36Sopenharmony_ci#define PHY_TX_ASIC_OUT_TX_ACK BIT(0) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define PHY_RX_ASIC_OUT 0x405c 8262306a36Sopenharmony_ci#define PHY_RX_ASIC_OUT_ACK BIT(0) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci u32 val; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci regmap_read(artpec6_pcie->regmap, offset, &val); 8962306a36Sopenharmony_ci return val; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void artpec6_pcie_writel(struct artpec6_pcie *artpec6_pcie, u32 offset, u32 val) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci regmap_write(artpec6_pcie->regmap, offset, val); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic u64 artpec6_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 pci_addr) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 10062306a36Sopenharmony_ci struct dw_pcie_rp *pp = &pci->pp; 10162306a36Sopenharmony_ci struct dw_pcie_ep *ep = &pci->ep; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci switch (artpec6_pcie->mode) { 10462306a36Sopenharmony_ci case DW_PCIE_RC_TYPE: 10562306a36Sopenharmony_ci return pci_addr - pp->cfg0_base; 10662306a36Sopenharmony_ci case DW_PCIE_EP_TYPE: 10762306a36Sopenharmony_ci return pci_addr - ep->phys_base; 10862306a36Sopenharmony_ci default: 10962306a36Sopenharmony_ci dev_err(pci->dev, "UNKNOWN device type\n"); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci return pci_addr; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int artpec6_pcie_establish_link(struct dw_pcie *pci) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 11762306a36Sopenharmony_ci u32 val; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 12062306a36Sopenharmony_ci val |= PCIECFG_LTSSM_ENABLE; 12162306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void artpec6_pcie_stop_link(struct dw_pcie *pci) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 12962306a36Sopenharmony_ci u32 val; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 13262306a36Sopenharmony_ci val &= ~PCIECFG_LTSSM_ENABLE; 13362306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic const struct dw_pcie_ops dw_pcie_ops = { 13762306a36Sopenharmony_ci .cpu_addr_fixup = artpec6_pcie_cpu_addr_fixup, 13862306a36Sopenharmony_ci .start_link = artpec6_pcie_establish_link, 13962306a36Sopenharmony_ci .stop_link = artpec6_pcie_stop_link, 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void artpec6_pcie_wait_for_phy_a6(struct artpec6_pcie *artpec6_pcie) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 14562306a36Sopenharmony_ci struct device *dev = pci->dev; 14662306a36Sopenharmony_ci u32 val; 14762306a36Sopenharmony_ci unsigned int retries; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci retries = 50; 15062306a36Sopenharmony_ci do { 15162306a36Sopenharmony_ci usleep_range(1000, 2000); 15262306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 15362306a36Sopenharmony_ci retries--; 15462306a36Sopenharmony_ci } while (retries && 15562306a36Sopenharmony_ci (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 15662306a36Sopenharmony_ci if (!retries) 15762306a36Sopenharmony_ci dev_err(dev, "PCIe clock manager did not leave idle state\n"); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci retries = 50; 16062306a36Sopenharmony_ci do { 16162306a36Sopenharmony_ci usleep_range(1000, 2000); 16262306a36Sopenharmony_ci val = readl(artpec6_pcie->phy_base + PHY_STATUS); 16362306a36Sopenharmony_ci retries--; 16462306a36Sopenharmony_ci } while (retries && !(val & PHY_COSPLLLOCK)); 16562306a36Sopenharmony_ci if (!retries) 16662306a36Sopenharmony_ci dev_err(dev, "PHY PLL did not lock\n"); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void artpec6_pcie_wait_for_phy_a7(struct artpec6_pcie *artpec6_pcie) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 17262306a36Sopenharmony_ci struct device *dev = pci->dev; 17362306a36Sopenharmony_ci u32 val; 17462306a36Sopenharmony_ci u16 phy_status_tx, phy_status_rx; 17562306a36Sopenharmony_ci unsigned int retries; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci retries = 50; 17862306a36Sopenharmony_ci do { 17962306a36Sopenharmony_ci usleep_range(1000, 2000); 18062306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 18162306a36Sopenharmony_ci retries--; 18262306a36Sopenharmony_ci } while (retries && 18362306a36Sopenharmony_ci (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); 18462306a36Sopenharmony_ci if (!retries) 18562306a36Sopenharmony_ci dev_err(dev, "PCIe clock manager did not leave idle state\n"); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci retries = 50; 18862306a36Sopenharmony_ci do { 18962306a36Sopenharmony_ci usleep_range(1000, 2000); 19062306a36Sopenharmony_ci phy_status_tx = readw(artpec6_pcie->phy_base + PHY_TX_ASIC_OUT); 19162306a36Sopenharmony_ci phy_status_rx = readw(artpec6_pcie->phy_base + PHY_RX_ASIC_OUT); 19262306a36Sopenharmony_ci retries--; 19362306a36Sopenharmony_ci } while (retries && ((phy_status_tx & PHY_TX_ASIC_OUT_TX_ACK) || 19462306a36Sopenharmony_ci (phy_status_rx & PHY_RX_ASIC_OUT_ACK))); 19562306a36Sopenharmony_ci if (!retries) 19662306a36Sopenharmony_ci dev_err(dev, "PHY did not enter Pn state\n"); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void artpec6_pcie_wait_for_phy(struct artpec6_pcie *artpec6_pcie) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci switch (artpec6_pcie->variant) { 20262306a36Sopenharmony_ci case ARTPEC6: 20362306a36Sopenharmony_ci artpec6_pcie_wait_for_phy_a6(artpec6_pcie); 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci case ARTPEC7: 20662306a36Sopenharmony_ci artpec6_pcie_wait_for_phy_a7(artpec6_pcie); 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void artpec6_pcie_init_phy_a6(struct artpec6_pcie *artpec6_pcie) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci u32 val; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 21662306a36Sopenharmony_ci val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 21762306a36Sopenharmony_ci PCIECFG_MODE_TX_DRV_EN | 21862306a36Sopenharmony_ci PCIECFG_CISRREN | /* Reference clock term. 100 Ohm */ 21962306a36Sopenharmony_ci PCIECFG_MACRO_ENABLE; 22062306a36Sopenharmony_ci val |= PCIECFG_REFCLK_ENABLE; 22162306a36Sopenharmony_ci val &= ~PCIECFG_DBG_OEN; 22262306a36Sopenharmony_ci val &= ~PCIECFG_CLKREQ_B; 22362306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 22462306a36Sopenharmony_ci usleep_range(5000, 6000); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 22762306a36Sopenharmony_ci val |= NOCCFG_ENABLE_CLK_PCIE; 22862306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 22962306a36Sopenharmony_ci usleep_range(20, 30); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 23262306a36Sopenharmony_ci val |= PCIECFG_PCLK_ENABLE | PCIECFG_PLL_ENABLE; 23362306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 23462306a36Sopenharmony_ci usleep_range(6000, 7000); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 23762306a36Sopenharmony_ci val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 23862306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void artpec6_pcie_init_phy_a7(struct artpec6_pcie *artpec6_pcie) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct dw_pcie *pci = artpec6_pcie->pci; 24462306a36Sopenharmony_ci u32 val; 24562306a36Sopenharmony_ci bool extrefclk; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Check if external reference clock is connected */ 24862306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIESTAT); 24962306a36Sopenharmony_ci extrefclk = !!(val & PCIESTAT_EXTREFCLK); 25062306a36Sopenharmony_ci dev_dbg(pci->dev, "Using reference clock: %s\n", 25162306a36Sopenharmony_ci extrefclk ? "external" : "internal"); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 25462306a36Sopenharmony_ci val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ 25562306a36Sopenharmony_ci PCIECFG_PCLK_ENABLE; 25662306a36Sopenharmony_ci if (extrefclk) 25762306a36Sopenharmony_ci val |= PCIECFG_REFCLKSEL; 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci val &= ~PCIECFG_REFCLKSEL; 26062306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 26162306a36Sopenharmony_ci usleep_range(10, 20); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 26462306a36Sopenharmony_ci val |= NOCCFG_ENABLE_CLK_PCIE; 26562306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 26662306a36Sopenharmony_ci usleep_range(20, 30); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); 26962306a36Sopenharmony_ci val &= ~NOCCFG_POWER_PCIE_IDLEREQ; 27062306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci switch (artpec6_pcie->variant) { 27662306a36Sopenharmony_ci case ARTPEC6: 27762306a36Sopenharmony_ci artpec6_pcie_init_phy_a6(artpec6_pcie); 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case ARTPEC7: 28062306a36Sopenharmony_ci artpec6_pcie_init_phy_a7(artpec6_pcie); 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci u32 val; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 29062306a36Sopenharmony_ci switch (artpec6_pcie->variant) { 29162306a36Sopenharmony_ci case ARTPEC6: 29262306a36Sopenharmony_ci val |= PCIECFG_CORE_RESET_REQ; 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci case ARTPEC7: 29562306a36Sopenharmony_ci val &= ~PCIECFG_NOC_RESET; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci u32 val; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 30662306a36Sopenharmony_ci switch (artpec6_pcie->variant) { 30762306a36Sopenharmony_ci case ARTPEC6: 30862306a36Sopenharmony_ci val &= ~PCIECFG_CORE_RESET_REQ; 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci case ARTPEC7: 31162306a36Sopenharmony_ci val |= PCIECFG_NOC_RESET; 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 31562306a36Sopenharmony_ci usleep_range(100, 200); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int artpec6_pcie_host_init(struct dw_pcie_rp *pp) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 32162306a36Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (artpec6_pcie->variant == ARTPEC7) { 32462306a36Sopenharmony_ci pci->n_fts[0] = 180; 32562306a36Sopenharmony_ci pci->n_fts[1] = 180; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci artpec6_pcie_assert_core_reset(artpec6_pcie); 32862306a36Sopenharmony_ci artpec6_pcie_init_phy(artpec6_pcie); 32962306a36Sopenharmony_ci artpec6_pcie_deassert_core_reset(artpec6_pcie); 33062306a36Sopenharmony_ci artpec6_pcie_wait_for_phy(artpec6_pcie); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic const struct dw_pcie_host_ops artpec6_pcie_host_ops = { 33662306a36Sopenharmony_ci .host_init = artpec6_pcie_host_init, 33762306a36Sopenharmony_ci}; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 34262306a36Sopenharmony_ci struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); 34362306a36Sopenharmony_ci enum pci_barno bar; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci artpec6_pcie_assert_core_reset(artpec6_pcie); 34662306a36Sopenharmony_ci artpec6_pcie_init_phy(artpec6_pcie); 34762306a36Sopenharmony_ci artpec6_pcie_deassert_core_reset(artpec6_pcie); 34862306a36Sopenharmony_ci artpec6_pcie_wait_for_phy(artpec6_pcie); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) 35162306a36Sopenharmony_ci dw_pcie_ep_reset_bar(pci, bar); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 35562306a36Sopenharmony_ci enum pci_epc_irq_type type, u16 interrupt_num) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci switch (type) { 36062306a36Sopenharmony_ci case PCI_EPC_IRQ_LEGACY: 36162306a36Sopenharmony_ci dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); 36262306a36Sopenharmony_ci return -EINVAL; 36362306a36Sopenharmony_ci case PCI_EPC_IRQ_MSI: 36462306a36Sopenharmony_ci return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 36562306a36Sopenharmony_ci default: 36662306a36Sopenharmony_ci dev_err(pci->dev, "UNKNOWN IRQ type\n"); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic const struct dw_pcie_ep_ops pcie_ep_ops = { 37362306a36Sopenharmony_ci .ep_init = artpec6_pcie_ep_init, 37462306a36Sopenharmony_ci .raise_irq = artpec6_pcie_raise_irq, 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int artpec6_pcie_probe(struct platform_device *pdev) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 38062306a36Sopenharmony_ci struct dw_pcie *pci; 38162306a36Sopenharmony_ci struct artpec6_pcie *artpec6_pcie; 38262306a36Sopenharmony_ci int ret; 38362306a36Sopenharmony_ci const struct artpec_pcie_of_data *data; 38462306a36Sopenharmony_ci enum artpec_pcie_variants variant; 38562306a36Sopenharmony_ci enum dw_pcie_device_mode mode; 38662306a36Sopenharmony_ci u32 val; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci data = of_device_get_match_data(dev); 38962306a36Sopenharmony_ci if (!data) 39062306a36Sopenharmony_ci return -EINVAL; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci variant = (enum artpec_pcie_variants)data->variant; 39362306a36Sopenharmony_ci mode = (enum dw_pcie_device_mode)data->mode; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci artpec6_pcie = devm_kzalloc(dev, sizeof(*artpec6_pcie), GFP_KERNEL); 39662306a36Sopenharmony_ci if (!artpec6_pcie) 39762306a36Sopenharmony_ci return -ENOMEM; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 40062306a36Sopenharmony_ci if (!pci) 40162306a36Sopenharmony_ci return -ENOMEM; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci pci->dev = dev; 40462306a36Sopenharmony_ci pci->ops = &dw_pcie_ops; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci artpec6_pcie->pci = pci; 40762306a36Sopenharmony_ci artpec6_pcie->variant = variant; 40862306a36Sopenharmony_ci artpec6_pcie->mode = mode; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci artpec6_pcie->phy_base = 41162306a36Sopenharmony_ci devm_platform_ioremap_resource_byname(pdev, "phy"); 41262306a36Sopenharmony_ci if (IS_ERR(artpec6_pcie->phy_base)) 41362306a36Sopenharmony_ci return PTR_ERR(artpec6_pcie->phy_base); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci artpec6_pcie->regmap = 41662306a36Sopenharmony_ci syscon_regmap_lookup_by_phandle(dev->of_node, 41762306a36Sopenharmony_ci "axis,syscon-pcie"); 41862306a36Sopenharmony_ci if (IS_ERR(artpec6_pcie->regmap)) 41962306a36Sopenharmony_ci return PTR_ERR(artpec6_pcie->regmap); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci platform_set_drvdata(pdev, artpec6_pcie); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci switch (artpec6_pcie->mode) { 42462306a36Sopenharmony_ci case DW_PCIE_RC_TYPE: 42562306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST)) 42662306a36Sopenharmony_ci return -ENODEV; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci pci->pp.ops = &artpec6_pcie_host_ops; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ret = dw_pcie_host_init(&pci->pp); 43162306a36Sopenharmony_ci if (ret < 0) 43262306a36Sopenharmony_ci return ret; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case DW_PCIE_EP_TYPE: 43562306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_EP)) 43662306a36Sopenharmony_ci return -ENODEV; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); 43962306a36Sopenharmony_ci val &= ~PCIECFG_DEVICE_TYPE_MASK; 44062306a36Sopenharmony_ci artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci pci->ep.ops = &pcie_ep_ops; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return dw_pcie_ep_init(&pci->ep); 44562306a36Sopenharmony_ci default: 44662306a36Sopenharmony_ci dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic const struct artpec_pcie_of_data artpec6_pcie_rc_of_data = { 45362306a36Sopenharmony_ci .variant = ARTPEC6, 45462306a36Sopenharmony_ci .mode = DW_PCIE_RC_TYPE, 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic const struct artpec_pcie_of_data artpec6_pcie_ep_of_data = { 45862306a36Sopenharmony_ci .variant = ARTPEC6, 45962306a36Sopenharmony_ci .mode = DW_PCIE_EP_TYPE, 46062306a36Sopenharmony_ci}; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic const struct artpec_pcie_of_data artpec7_pcie_rc_of_data = { 46362306a36Sopenharmony_ci .variant = ARTPEC7, 46462306a36Sopenharmony_ci .mode = DW_PCIE_RC_TYPE, 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic const struct artpec_pcie_of_data artpec7_pcie_ep_of_data = { 46862306a36Sopenharmony_ci .variant = ARTPEC7, 46962306a36Sopenharmony_ci .mode = DW_PCIE_EP_TYPE, 47062306a36Sopenharmony_ci}; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic const struct of_device_id artpec6_pcie_of_match[] = { 47362306a36Sopenharmony_ci { 47462306a36Sopenharmony_ci .compatible = "axis,artpec6-pcie", 47562306a36Sopenharmony_ci .data = &artpec6_pcie_rc_of_data, 47662306a36Sopenharmony_ci }, 47762306a36Sopenharmony_ci { 47862306a36Sopenharmony_ci .compatible = "axis,artpec6-pcie-ep", 47962306a36Sopenharmony_ci .data = &artpec6_pcie_ep_of_data, 48062306a36Sopenharmony_ci }, 48162306a36Sopenharmony_ci { 48262306a36Sopenharmony_ci .compatible = "axis,artpec7-pcie", 48362306a36Sopenharmony_ci .data = &artpec7_pcie_rc_of_data, 48462306a36Sopenharmony_ci }, 48562306a36Sopenharmony_ci { 48662306a36Sopenharmony_ci .compatible = "axis,artpec7-pcie-ep", 48762306a36Sopenharmony_ci .data = &artpec7_pcie_ep_of_data, 48862306a36Sopenharmony_ci }, 48962306a36Sopenharmony_ci {}, 49062306a36Sopenharmony_ci}; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic struct platform_driver artpec6_pcie_driver = { 49362306a36Sopenharmony_ci .probe = artpec6_pcie_probe, 49462306a36Sopenharmony_ci .driver = { 49562306a36Sopenharmony_ci .name = "artpec6-pcie", 49662306a36Sopenharmony_ci .of_match_table = artpec6_pcie_of_match, 49762306a36Sopenharmony_ci .suppress_bind_attrs = true, 49862306a36Sopenharmony_ci }, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_cibuiltin_platform_driver(artpec6_pcie_driver); 501