18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * pci-j721e - PCIe controller driver for TI's J721E SoCs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com 68c2ecf20Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 138c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 148c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <linux/regmap.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "../../pci.h" 228c2ecf20Sopenharmony_ci#include "pcie-cadence.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define ENABLE_REG_SYS_2 0x108 258c2ecf20Sopenharmony_ci#define STATUS_REG_SYS_2 0x508 268c2ecf20Sopenharmony_ci#define STATUS_CLR_REG_SYS_2 0x708 278c2ecf20Sopenharmony_ci#define LINK_DOWN BIT(1) 288c2ecf20Sopenharmony_ci#define J7200_LINK_DOWN BIT(10) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define J721E_PCIE_USER_CMD_STATUS 0x4 318c2ecf20Sopenharmony_ci#define LINK_TRAINING_ENABLE BIT(0) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define J721E_PCIE_USER_LINKSTATUS 0x14 348c2ecf20Sopenharmony_ci#define LINK_STATUS GENMASK(1, 0) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cienum link_status { 378c2ecf20Sopenharmony_ci NO_RECEIVERS_DETECTED, 388c2ecf20Sopenharmony_ci LINK_TRAINING_IN_PROGRESS, 398c2ecf20Sopenharmony_ci LINK_UP_DL_IN_PROGRESS, 408c2ecf20Sopenharmony_ci LINK_UP_DL_COMPLETED, 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define J721E_MODE_RC BIT(7) 448c2ecf20Sopenharmony_ci#define LANE_COUNT_MASK BIT(8) 458c2ecf20Sopenharmony_ci#define LANE_COUNT(n) ((n) << 8) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define GENERATION_SEL_MASK GENMASK(1, 0) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define MAX_LANES 2 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct j721e_pcie { 528c2ecf20Sopenharmony_ci struct device *dev; 538c2ecf20Sopenharmony_ci u32 mode; 548c2ecf20Sopenharmony_ci u32 num_lanes; 558c2ecf20Sopenharmony_ci struct cdns_pcie *cdns_pcie; 568c2ecf20Sopenharmony_ci void __iomem *user_cfg_base; 578c2ecf20Sopenharmony_ci void __iomem *intd_cfg_base; 588c2ecf20Sopenharmony_ci u32 linkdown_irq_regfield; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cienum j721e_pcie_mode { 628c2ecf20Sopenharmony_ci PCI_MODE_RC, 638c2ecf20Sopenharmony_ci PCI_MODE_EP, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct j721e_pcie_data { 678c2ecf20Sopenharmony_ci enum j721e_pcie_mode mode; 688c2ecf20Sopenharmony_ci unsigned int quirk_retrain_flag:1; 698c2ecf20Sopenharmony_ci unsigned int quirk_detect_quiet_flag:1; 708c2ecf20Sopenharmony_ci u32 linkdown_irq_regfield; 718c2ecf20Sopenharmony_ci unsigned int byte_access_allowed:1; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return readl(pcie->user_cfg_base + offset); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset, 808c2ecf20Sopenharmony_ci u32 value) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci writel(value, pcie->user_cfg_base + offset); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return readl(pcie->intd_cfg_base + offset); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset, 918c2ecf20Sopenharmony_ci u32 value) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci writel(value, pcie->intd_cfg_base + offset); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct j721e_pcie *pcie = priv; 998c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 1008c2ecf20Sopenharmony_ci u32 reg; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2); 1038c2ecf20Sopenharmony_ci if (!(reg & pcie->linkdown_irq_regfield)) 1048c2ecf20Sopenharmony_ci return IRQ_NONE; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci dev_err(dev, "LINK DOWN!\n"); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, pcie->linkdown_irq_regfield); 1098c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void j721e_pcie_config_link_irq(struct j721e_pcie *pcie) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci u32 reg; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2); 1178c2ecf20Sopenharmony_ci reg |= pcie->linkdown_irq_regfield; 1188c2ecf20Sopenharmony_ci j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev); 1248c2ecf20Sopenharmony_ci u32 reg; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS); 1278c2ecf20Sopenharmony_ci reg |= LINK_TRAINING_ENABLE; 1288c2ecf20Sopenharmony_ci j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev); 1368c2ecf20Sopenharmony_ci u32 reg; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS); 1398c2ecf20Sopenharmony_ci reg &= ~LINK_TRAINING_ENABLE; 1408c2ecf20Sopenharmony_ci j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev); 1468c2ecf20Sopenharmony_ci u32 reg; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS); 1498c2ecf20Sopenharmony_ci reg &= LINK_STATUS; 1508c2ecf20Sopenharmony_ci if (reg == LINK_UP_DL_COMPLETED) 1518c2ecf20Sopenharmony_ci return true; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return false; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic const struct cdns_pcie_ops j721e_pcie_ops = { 1578c2ecf20Sopenharmony_ci .start_link = j721e_pcie_start_link, 1588c2ecf20Sopenharmony_ci .stop_link = j721e_pcie_stop_link, 1598c2ecf20Sopenharmony_ci .link_up = j721e_pcie_link_up, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 1658c2ecf20Sopenharmony_ci u32 mask = J721E_MODE_RC; 1668c2ecf20Sopenharmony_ci u32 mode = pcie->mode; 1678c2ecf20Sopenharmony_ci u32 val = 0; 1688c2ecf20Sopenharmony_ci int ret = 0; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (mode == PCI_MODE_RC) 1718c2ecf20Sopenharmony_ci val = J721E_MODE_RC; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ret = regmap_update_bits(syscon, 0, mask, val); 1748c2ecf20Sopenharmony_ci if (ret) 1758c2ecf20Sopenharmony_ci dev_err(dev, "failed to set pcie mode\n"); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return ret; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int j721e_pcie_set_link_speed(struct j721e_pcie *pcie, 1818c2ecf20Sopenharmony_ci struct regmap *syscon) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 1848c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 1858c2ecf20Sopenharmony_ci int link_speed; 1868c2ecf20Sopenharmony_ci u32 val = 0; 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci link_speed = of_pci_get_max_link_speed(np); 1908c2ecf20Sopenharmony_ci if (link_speed < 2) 1918c2ecf20Sopenharmony_ci link_speed = 2; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci val = link_speed - 1; 1948c2ecf20Sopenharmony_ci ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val); 1958c2ecf20Sopenharmony_ci if (ret) 1968c2ecf20Sopenharmony_ci dev_err(dev, "failed to set link speed\n"); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return ret; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int j721e_pcie_set_lane_count(struct j721e_pcie *pcie, 2028c2ecf20Sopenharmony_ci struct regmap *syscon) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 2058c2ecf20Sopenharmony_ci u32 lanes = pcie->num_lanes; 2068c2ecf20Sopenharmony_ci u32 val = 0; 2078c2ecf20Sopenharmony_ci int ret; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci val = LANE_COUNT(lanes - 1); 2108c2ecf20Sopenharmony_ci ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val); 2118c2ecf20Sopenharmony_ci if (ret) 2128c2ecf20Sopenharmony_ci dev_err(dev, "failed to set link count\n"); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return ret; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int j721e_pcie_ctrl_init(struct j721e_pcie *pcie) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct device *dev = pcie->dev; 2208c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 2218c2ecf20Sopenharmony_ci struct regmap *syscon; 2228c2ecf20Sopenharmony_ci int ret; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl"); 2258c2ecf20Sopenharmony_ci if (IS_ERR(syscon)) { 2268c2ecf20Sopenharmony_ci dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n"); 2278c2ecf20Sopenharmony_ci return PTR_ERR(syscon); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci ret = j721e_pcie_set_mode(pcie, syscon); 2318c2ecf20Sopenharmony_ci if (ret < 0) { 2328c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set pci mode\n"); 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci ret = j721e_pcie_set_link_speed(pcie, syscon); 2378c2ecf20Sopenharmony_ci if (ret < 0) { 2388c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set link speed\n"); 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = j721e_pcie_set_lane_count(pcie, syscon); 2438c2ecf20Sopenharmony_ci if (ret < 0) { 2448c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set num-lanes\n"); 2458c2ecf20Sopenharmony_ci return ret; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn, 2528c2ecf20Sopenharmony_ci int where, int size, u32 *value) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci if (pci_is_root_bus(bus)) 2558c2ecf20Sopenharmony_ci return pci_generic_config_read32(bus, devfn, where, size, 2568c2ecf20Sopenharmony_ci value); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return pci_generic_config_read(bus, devfn, where, size, value); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn, 2628c2ecf20Sopenharmony_ci int where, int size, u32 value) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci if (pci_is_root_bus(bus)) 2658c2ecf20Sopenharmony_ci return pci_generic_config_write32(bus, devfn, where, size, 2668c2ecf20Sopenharmony_ci value); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return pci_generic_config_write(bus, devfn, where, size, value); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic struct pci_ops cdns_ti_pcie_host_ops = { 2728c2ecf20Sopenharmony_ci .map_bus = cdns_pci_map_bus, 2738c2ecf20Sopenharmony_ci .read = cdns_ti_pcie_config_read, 2748c2ecf20Sopenharmony_ci .write = cdns_ti_pcie_config_write, 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic const struct j721e_pcie_data j721e_pcie_rc_data = { 2788c2ecf20Sopenharmony_ci .mode = PCI_MODE_RC, 2798c2ecf20Sopenharmony_ci .quirk_retrain_flag = true, 2808c2ecf20Sopenharmony_ci .byte_access_allowed = false, 2818c2ecf20Sopenharmony_ci .linkdown_irq_regfield = LINK_DOWN, 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const struct j721e_pcie_data j721e_pcie_ep_data = { 2858c2ecf20Sopenharmony_ci .mode = PCI_MODE_EP, 2868c2ecf20Sopenharmony_ci .linkdown_irq_regfield = LINK_DOWN, 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic const struct j721e_pcie_data j7200_pcie_rc_data = { 2908c2ecf20Sopenharmony_ci .mode = PCI_MODE_RC, 2918c2ecf20Sopenharmony_ci .quirk_detect_quiet_flag = true, 2928c2ecf20Sopenharmony_ci .linkdown_irq_regfield = J7200_LINK_DOWN, 2938c2ecf20Sopenharmony_ci .byte_access_allowed = true, 2948c2ecf20Sopenharmony_ci}; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic const struct j721e_pcie_data j7200_pcie_ep_data = { 2978c2ecf20Sopenharmony_ci .mode = PCI_MODE_EP, 2988c2ecf20Sopenharmony_ci .quirk_detect_quiet_flag = true, 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic const struct j721e_pcie_data am64_pcie_rc_data = { 3028c2ecf20Sopenharmony_ci .mode = PCI_MODE_RC, 3038c2ecf20Sopenharmony_ci .linkdown_irq_regfield = J7200_LINK_DOWN, 3048c2ecf20Sopenharmony_ci .byte_access_allowed = true, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic const struct j721e_pcie_data am64_pcie_ep_data = { 3088c2ecf20Sopenharmony_ci .mode = PCI_MODE_EP, 3098c2ecf20Sopenharmony_ci .linkdown_irq_regfield = J7200_LINK_DOWN, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic const struct of_device_id of_j721e_pcie_match[] = { 3138c2ecf20Sopenharmony_ci { 3148c2ecf20Sopenharmony_ci .compatible = "ti,j721e-pcie-host", 3158c2ecf20Sopenharmony_ci .data = &j721e_pcie_rc_data, 3168c2ecf20Sopenharmony_ci }, 3178c2ecf20Sopenharmony_ci { 3188c2ecf20Sopenharmony_ci .compatible = "ti,j721e-pcie-ep", 3198c2ecf20Sopenharmony_ci .data = &j721e_pcie_ep_data, 3208c2ecf20Sopenharmony_ci }, 3218c2ecf20Sopenharmony_ci { 3228c2ecf20Sopenharmony_ci .compatible = "ti,j7200-pcie-host", 3238c2ecf20Sopenharmony_ci .data = &j7200_pcie_rc_data, 3248c2ecf20Sopenharmony_ci }, 3258c2ecf20Sopenharmony_ci { 3268c2ecf20Sopenharmony_ci .compatible = "ti,j7200-pcie-ep", 3278c2ecf20Sopenharmony_ci .data = &j7200_pcie_ep_data, 3288c2ecf20Sopenharmony_ci }, 3298c2ecf20Sopenharmony_ci { 3308c2ecf20Sopenharmony_ci .compatible = "ti,am64-pcie-host", 3318c2ecf20Sopenharmony_ci .data = &am64_pcie_rc_data, 3328c2ecf20Sopenharmony_ci }, 3338c2ecf20Sopenharmony_ci { 3348c2ecf20Sopenharmony_ci .compatible = "ti,am64-pcie-ep", 3358c2ecf20Sopenharmony_ci .data = &am64_pcie_ep_data, 3368c2ecf20Sopenharmony_ci }, 3378c2ecf20Sopenharmony_ci {}, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int j721e_pcie_probe(struct platform_device *pdev) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3438c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 3448c2ecf20Sopenharmony_ci struct pci_host_bridge *bridge; 3458c2ecf20Sopenharmony_ci struct j721e_pcie_data *data; 3468c2ecf20Sopenharmony_ci struct cdns_pcie *cdns_pcie; 3478c2ecf20Sopenharmony_ci struct j721e_pcie *pcie; 3488c2ecf20Sopenharmony_ci struct cdns_pcie_rc *rc; 3498c2ecf20Sopenharmony_ci struct cdns_pcie_ep *ep; 3508c2ecf20Sopenharmony_ci struct gpio_desc *gpiod; 3518c2ecf20Sopenharmony_ci void __iomem *base; 3528c2ecf20Sopenharmony_ci u32 num_lanes; 3538c2ecf20Sopenharmony_ci u32 mode; 3548c2ecf20Sopenharmony_ci int ret; 3558c2ecf20Sopenharmony_ci int irq; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci data = (struct j721e_pcie_data *)of_device_get_match_data(dev); 3588c2ecf20Sopenharmony_ci if (!data) 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci mode = (u32)data->mode; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); 3648c2ecf20Sopenharmony_ci if (!pcie) 3658c2ecf20Sopenharmony_ci return -ENOMEM; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci pcie->dev = dev; 3688c2ecf20Sopenharmony_ci pcie->mode = mode; 3698c2ecf20Sopenharmony_ci pcie->linkdown_irq_regfield = data->linkdown_irq_regfield; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci base = devm_platform_ioremap_resource_byname(pdev, "intd_cfg"); 3728c2ecf20Sopenharmony_ci if (IS_ERR(base)) 3738c2ecf20Sopenharmony_ci return PTR_ERR(base); 3748c2ecf20Sopenharmony_ci pcie->intd_cfg_base = base; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci base = devm_platform_ioremap_resource_byname(pdev, "user_cfg"); 3778c2ecf20Sopenharmony_ci if (IS_ERR(base)) 3788c2ecf20Sopenharmony_ci return PTR_ERR(base); 3798c2ecf20Sopenharmony_ci pcie->user_cfg_base = base; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ret = of_property_read_u32(node, "num-lanes", &num_lanes); 3828c2ecf20Sopenharmony_ci if (ret || num_lanes > MAX_LANES) 3838c2ecf20Sopenharmony_ci num_lanes = 1; 3848c2ecf20Sopenharmony_ci pcie->num_lanes = num_lanes; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48))) 3878c2ecf20Sopenharmony_ci return -EINVAL; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "link_state"); 3908c2ecf20Sopenharmony_ci if (irq < 0) 3918c2ecf20Sopenharmony_ci return irq; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci dev_set_drvdata(dev, pcie); 3948c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 3958c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 3968c2ecf20Sopenharmony_ci if (ret < 0) { 3978c2ecf20Sopenharmony_ci dev_err(dev, "pm_runtime_get_sync failed\n"); 3988c2ecf20Sopenharmony_ci goto err_get_sync; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci ret = j721e_pcie_ctrl_init(pcie); 4028c2ecf20Sopenharmony_ci if (ret < 0) { 4038c2ecf20Sopenharmony_ci dev_err(dev, "pm_runtime_get_sync failed\n"); 4048c2ecf20Sopenharmony_ci goto err_get_sync; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler, 0, 4088c2ecf20Sopenharmony_ci "j721e-pcie-link-down-irq", pcie); 4098c2ecf20Sopenharmony_ci if (ret < 0) { 4108c2ecf20Sopenharmony_ci dev_err(dev, "failed to request link state IRQ %d\n", irq); 4118c2ecf20Sopenharmony_ci goto err_get_sync; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci j721e_pcie_config_link_irq(pcie); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci switch (mode) { 4178c2ecf20Sopenharmony_ci case PCI_MODE_RC: 4188c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) { 4198c2ecf20Sopenharmony_ci ret = -ENODEV; 4208c2ecf20Sopenharmony_ci goto err_get_sync; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); 4248c2ecf20Sopenharmony_ci if (!bridge) { 4258c2ecf20Sopenharmony_ci ret = -ENOMEM; 4268c2ecf20Sopenharmony_ci goto err_get_sync; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (!data->byte_access_allowed) 4308c2ecf20Sopenharmony_ci bridge->ops = &cdns_ti_pcie_host_ops; 4318c2ecf20Sopenharmony_ci rc = pci_host_bridge_priv(bridge); 4328c2ecf20Sopenharmony_ci rc->quirk_retrain_flag = data->quirk_retrain_flag; 4338c2ecf20Sopenharmony_ci rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci cdns_pcie = &rc->pcie; 4368c2ecf20Sopenharmony_ci cdns_pcie->dev = dev; 4378c2ecf20Sopenharmony_ci cdns_pcie->ops = &j721e_pcie_ops; 4388c2ecf20Sopenharmony_ci pcie->cdns_pcie = cdns_pcie; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 4418c2ecf20Sopenharmony_ci if (IS_ERR(gpiod)) { 4428c2ecf20Sopenharmony_ci ret = PTR_ERR(gpiod); 4438c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 4448c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get reset GPIO\n"); 4458c2ecf20Sopenharmony_ci goto err_get_sync; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = cdns_pcie_init_phy(dev, cdns_pcie); 4498c2ecf20Sopenharmony_ci if (ret) { 4508c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init phy\n"); 4518c2ecf20Sopenharmony_ci goto err_get_sync; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * "Power Sequencing and Reset Signal Timings" table in 4568c2ecf20Sopenharmony_ci * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0 4578c2ecf20Sopenharmony_ci * indicates PERST# should be deasserted after minimum of 100us 4588c2ecf20Sopenharmony_ci * once REFCLK is stable. The REFCLK to the connector in RC 4598c2ecf20Sopenharmony_ci * mode is selected while enabling the PHY. So deassert PERST# 4608c2ecf20Sopenharmony_ci * after 100 us. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci if (gpiod) { 4638c2ecf20Sopenharmony_ci usleep_range(100, 200); 4648c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(gpiod, 1); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci ret = cdns_pcie_host_setup(rc); 4688c2ecf20Sopenharmony_ci if (ret < 0) 4698c2ecf20Sopenharmony_ci goto err_pcie_setup; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci case PCI_MODE_EP: 4738c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) { 4748c2ecf20Sopenharmony_ci ret = -ENODEV; 4758c2ecf20Sopenharmony_ci goto err_get_sync; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); 4798c2ecf20Sopenharmony_ci if (!ep) { 4808c2ecf20Sopenharmony_ci ret = -ENOMEM; 4818c2ecf20Sopenharmony_ci goto err_get_sync; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci cdns_pcie = &ep->pcie; 4868c2ecf20Sopenharmony_ci cdns_pcie->dev = dev; 4878c2ecf20Sopenharmony_ci cdns_pcie->ops = &j721e_pcie_ops; 4888c2ecf20Sopenharmony_ci pcie->cdns_pcie = cdns_pcie; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci ret = cdns_pcie_init_phy(dev, cdns_pcie); 4918c2ecf20Sopenharmony_ci if (ret) { 4928c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init phy\n"); 4938c2ecf20Sopenharmony_ci goto err_get_sync; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ret = cdns_pcie_ep_setup(ep); 4978c2ecf20Sopenharmony_ci if (ret < 0) 4988c2ecf20Sopenharmony_ci goto err_pcie_setup; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci default: 5028c2ecf20Sopenharmony_ci dev_err(dev, "INVALID device type %d\n", mode); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cierr_pcie_setup: 5088c2ecf20Sopenharmony_ci cdns_pcie_disable_phy(cdns_pcie); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cierr_get_sync: 5118c2ecf20Sopenharmony_ci pm_runtime_put(dev); 5128c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return ret; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int j721e_pcie_remove(struct platform_device *pdev) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct j721e_pcie *pcie = platform_get_drvdata(pdev); 5208c2ecf20Sopenharmony_ci struct cdns_pcie *cdns_pcie = pcie->cdns_pcie; 5218c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci cdns_pcie_disable_phy(cdns_pcie); 5248c2ecf20Sopenharmony_ci pm_runtime_put(dev); 5258c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic struct platform_driver j721e_pcie_driver = { 5318c2ecf20Sopenharmony_ci .probe = j721e_pcie_probe, 5328c2ecf20Sopenharmony_ci .remove = j721e_pcie_remove, 5338c2ecf20Sopenharmony_ci .driver = { 5348c2ecf20Sopenharmony_ci .name = "j721e-pcie", 5358c2ecf20Sopenharmony_ci .of_match_table = of_j721e_pcie_match, 5368c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 5378c2ecf20Sopenharmony_ci }, 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_cibuiltin_platform_driver(j721e_pcie_driver); 540