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