18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCIe host controller driver for Amazon's Annapurna Labs IP (used in chips
48c2ecf20Sopenharmony_ci * such as Graviton and Alpine)
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Author: Jonathan Chocron <jonnyc@amazon.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/pci.h>
128c2ecf20Sopenharmony_ci#include <linux/pci-ecam.h>
138c2ecf20Sopenharmony_ci#include <linux/pci-acpi.h>
148c2ecf20Sopenharmony_ci#include "../../pci.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct al_pcie_acpi  {
198c2ecf20Sopenharmony_ci	void __iomem *dbi_base;
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void __iomem *al_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
238c2ecf20Sopenharmony_ci				     int where)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct pci_config_window *cfg = bus->sysdata;
268c2ecf20Sopenharmony_ci	struct al_pcie_acpi *pcie = cfg->priv;
278c2ecf20Sopenharmony_ci	void __iomem *dbi_base = pcie->dbi_base;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	if (bus->number == cfg->busr.start) {
308c2ecf20Sopenharmony_ci		/*
318c2ecf20Sopenharmony_ci		 * The DW PCIe core doesn't filter out transactions to other
328c2ecf20Sopenharmony_ci		 * devices/functions on the root bus num, so we do this here.
338c2ecf20Sopenharmony_ci		 */
348c2ecf20Sopenharmony_ci		if (PCI_SLOT(devfn) > 0)
358c2ecf20Sopenharmony_ci			return NULL;
368c2ecf20Sopenharmony_ci		else
378c2ecf20Sopenharmony_ci			return dbi_base + where;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	return pci_ecam_map_bus(bus, devfn, where);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic int al_pcie_init(struct pci_config_window *cfg)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct device *dev = cfg->parent;
468c2ecf20Sopenharmony_ci	struct acpi_device *adev = to_acpi_device(dev);
478c2ecf20Sopenharmony_ci	struct acpi_pci_root *root = acpi_driver_data(adev);
488c2ecf20Sopenharmony_ci	struct al_pcie_acpi *al_pcie;
498c2ecf20Sopenharmony_ci	struct resource *res;
508c2ecf20Sopenharmony_ci	int ret;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL);
538c2ecf20Sopenharmony_ci	if (!al_pcie)
548c2ecf20Sopenharmony_ci		return -ENOMEM;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
578c2ecf20Sopenharmony_ci	if (!res)
588c2ecf20Sopenharmony_ci		return -ENOMEM;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	ret = acpi_get_rc_resources(dev, "AMZN0001", root->segment, res);
618c2ecf20Sopenharmony_ci	if (ret) {
628c2ecf20Sopenharmony_ci		dev_err(dev, "can't get rc dbi base address for SEG %d\n",
638c2ecf20Sopenharmony_ci			root->segment);
648c2ecf20Sopenharmony_ci		return ret;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	dev_dbg(dev, "Root port dbi res: %pR\n", res);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	al_pcie->dbi_base = devm_pci_remap_cfg_resource(dev, res);
708c2ecf20Sopenharmony_ci	if (IS_ERR(al_pcie->dbi_base))
718c2ecf20Sopenharmony_ci		return PTR_ERR(al_pcie->dbi_base);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	cfg->priv = al_pcie;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return 0;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciconst struct pci_ecam_ops al_pcie_ops = {
798c2ecf20Sopenharmony_ci	.bus_shift    = 20,
808c2ecf20Sopenharmony_ci	.init         =  al_pcie_init,
818c2ecf20Sopenharmony_ci	.pci_ops      = {
828c2ecf20Sopenharmony_ci		.map_bus    = al_pcie_map_bus,
838c2ecf20Sopenharmony_ci		.read       = pci_generic_config_read,
848c2ecf20Sopenharmony_ci		.write      = pci_generic_config_write,
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#ifdef CONFIG_PCIE_AL
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#include <linux/of_pci.h>
938c2ecf20Sopenharmony_ci#include "pcie-designware.h"
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#define AL_PCIE_REV_ID_2	2
968c2ecf20Sopenharmony_ci#define AL_PCIE_REV_ID_3	3
978c2ecf20Sopenharmony_ci#define AL_PCIE_REV_ID_4	4
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#define AXI_BASE_OFFSET		0x0
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define DEVICE_ID_OFFSET	0x16c
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define DEVICE_REV_ID			0x0
1048c2ecf20Sopenharmony_ci#define DEVICE_REV_ID_DEV_ID_MASK	GENMASK(31, 16)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#define DEVICE_REV_ID_DEV_ID_X4		0
1078c2ecf20Sopenharmony_ci#define DEVICE_REV_ID_DEV_ID_X8		2
1088c2ecf20Sopenharmony_ci#define DEVICE_REV_ID_DEV_ID_X16	4
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#define OB_CTRL_REV1_2_OFFSET	0x0040
1118c2ecf20Sopenharmony_ci#define OB_CTRL_REV3_5_OFFSET	0x0030
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#define CFG_TARGET_BUS			0x0
1148c2ecf20Sopenharmony_ci#define CFG_TARGET_BUS_MASK_MASK	GENMASK(7, 0)
1158c2ecf20Sopenharmony_ci#define CFG_TARGET_BUS_BUSNUM_MASK	GENMASK(15, 8)
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define CFG_CONTROL			0x4
1188c2ecf20Sopenharmony_ci#define CFG_CONTROL_SUBBUS_MASK		GENMASK(15, 8)
1198c2ecf20Sopenharmony_ci#define CFG_CONTROL_SEC_BUS_MASK	GENMASK(23, 16)
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistruct al_pcie_reg_offsets {
1228c2ecf20Sopenharmony_ci	unsigned int ob_ctrl;
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistruct al_pcie_target_bus_cfg {
1268c2ecf20Sopenharmony_ci	u8 reg_val;
1278c2ecf20Sopenharmony_ci	u8 reg_mask;
1288c2ecf20Sopenharmony_ci	u8 ecam_mask;
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistruct al_pcie {
1328c2ecf20Sopenharmony_ci	struct dw_pcie *pci;
1338c2ecf20Sopenharmony_ci	void __iomem *controller_base; /* base of PCIe unit (not DW core) */
1348c2ecf20Sopenharmony_ci	struct device *dev;
1358c2ecf20Sopenharmony_ci	resource_size_t ecam_size;
1368c2ecf20Sopenharmony_ci	unsigned int controller_rev_id;
1378c2ecf20Sopenharmony_ci	struct al_pcie_reg_offsets reg_offsets;
1388c2ecf20Sopenharmony_ci	struct al_pcie_target_bus_cfg target_bus_cfg;
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci#define PCIE_ECAM_DEVFN(x)		(((x) & 0xff) << 12)
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci#define to_al_pcie(x)		dev_get_drvdata((x)->dev)
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic inline u32 al_pcie_controller_readl(struct al_pcie *pcie, u32 offset)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	return readl_relaxed(pcie->controller_base + offset);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic inline void al_pcie_controller_writel(struct al_pcie *pcie, u32 offset,
1518c2ecf20Sopenharmony_ci					     u32 val)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	writel_relaxed(val, pcie->controller_base + offset);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic int al_pcie_rev_id_get(struct al_pcie *pcie, unsigned int *rev_id)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	u32 dev_rev_id_val;
1598c2ecf20Sopenharmony_ci	u32 dev_id_val;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	dev_rev_id_val = al_pcie_controller_readl(pcie, AXI_BASE_OFFSET +
1628c2ecf20Sopenharmony_ci						  DEVICE_ID_OFFSET +
1638c2ecf20Sopenharmony_ci						  DEVICE_REV_ID);
1648c2ecf20Sopenharmony_ci	dev_id_val = FIELD_GET(DEVICE_REV_ID_DEV_ID_MASK, dev_rev_id_val);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	switch (dev_id_val) {
1678c2ecf20Sopenharmony_ci	case DEVICE_REV_ID_DEV_ID_X4:
1688c2ecf20Sopenharmony_ci		*rev_id = AL_PCIE_REV_ID_2;
1698c2ecf20Sopenharmony_ci		break;
1708c2ecf20Sopenharmony_ci	case DEVICE_REV_ID_DEV_ID_X8:
1718c2ecf20Sopenharmony_ci		*rev_id = AL_PCIE_REV_ID_3;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case DEVICE_REV_ID_DEV_ID_X16:
1748c2ecf20Sopenharmony_ci		*rev_id = AL_PCIE_REV_ID_4;
1758c2ecf20Sopenharmony_ci		break;
1768c2ecf20Sopenharmony_ci	default:
1778c2ecf20Sopenharmony_ci		dev_err(pcie->dev, "Unsupported dev_id_val (0x%x)\n",
1788c2ecf20Sopenharmony_ci			dev_id_val);
1798c2ecf20Sopenharmony_ci		return -EINVAL;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	dev_dbg(pcie->dev, "dev_id_val: 0x%x\n", dev_id_val);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int al_pcie_reg_offsets_set(struct al_pcie *pcie)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	switch (pcie->controller_rev_id) {
1908c2ecf20Sopenharmony_ci	case AL_PCIE_REV_ID_2:
1918c2ecf20Sopenharmony_ci		pcie->reg_offsets.ob_ctrl = OB_CTRL_REV1_2_OFFSET;
1928c2ecf20Sopenharmony_ci		break;
1938c2ecf20Sopenharmony_ci	case AL_PCIE_REV_ID_3:
1948c2ecf20Sopenharmony_ci	case AL_PCIE_REV_ID_4:
1958c2ecf20Sopenharmony_ci		pcie->reg_offsets.ob_ctrl = OB_CTRL_REV3_5_OFFSET;
1968c2ecf20Sopenharmony_ci		break;
1978c2ecf20Sopenharmony_ci	default:
1988c2ecf20Sopenharmony_ci		dev_err(pcie->dev, "Unsupported controller rev_id: 0x%x\n",
1998c2ecf20Sopenharmony_ci			pcie->controller_rev_id);
2008c2ecf20Sopenharmony_ci		return -EINVAL;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic inline void al_pcie_target_bus_set(struct al_pcie *pcie,
2078c2ecf20Sopenharmony_ci					  u8 target_bus,
2088c2ecf20Sopenharmony_ci					  u8 mask_target_bus)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	u32 reg;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	reg = FIELD_PREP(CFG_TARGET_BUS_MASK_MASK, mask_target_bus) |
2138c2ecf20Sopenharmony_ci	      FIELD_PREP(CFG_TARGET_BUS_BUSNUM_MASK, target_bus);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	al_pcie_controller_writel(pcie, AXI_BASE_OFFSET +
2168c2ecf20Sopenharmony_ci				  pcie->reg_offsets.ob_ctrl + CFG_TARGET_BUS,
2178c2ecf20Sopenharmony_ci				  reg);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
2218c2ecf20Sopenharmony_ci					       unsigned int devfn, int where)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct pcie_port *pp = bus->sysdata;
2248c2ecf20Sopenharmony_ci	struct al_pcie *pcie = to_al_pcie(to_dw_pcie_from_pp(pp));
2258c2ecf20Sopenharmony_ci	unsigned int busnr = bus->number;
2268c2ecf20Sopenharmony_ci	struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
2278c2ecf20Sopenharmony_ci	unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
2288c2ecf20Sopenharmony_ci	unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
2298c2ecf20Sopenharmony_ci	void __iomem *pci_base_addr;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
2328c2ecf20Sopenharmony_ci					 (busnr_ecam << 20) +
2338c2ecf20Sopenharmony_ci					 PCIE_ECAM_DEVFN(devfn));
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (busnr_reg != target_bus_cfg->reg_val) {
2368c2ecf20Sopenharmony_ci		dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n",
2378c2ecf20Sopenharmony_ci			target_bus_cfg->reg_val, busnr_reg);
2388c2ecf20Sopenharmony_ci		target_bus_cfg->reg_val = busnr_reg;
2398c2ecf20Sopenharmony_ci		al_pcie_target_bus_set(pcie,
2408c2ecf20Sopenharmony_ci				       target_bus_cfg->reg_val,
2418c2ecf20Sopenharmony_ci				       target_bus_cfg->reg_mask);
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	return pci_base_addr + where;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic struct pci_ops al_child_pci_ops = {
2488c2ecf20Sopenharmony_ci	.map_bus = al_pcie_conf_addr_map_bus,
2498c2ecf20Sopenharmony_ci	.read = pci_generic_config_read,
2508c2ecf20Sopenharmony_ci	.write = pci_generic_config_write,
2518c2ecf20Sopenharmony_ci};
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic void al_pcie_config_prepare(struct al_pcie *pcie)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct al_pcie_target_bus_cfg *target_bus_cfg;
2568c2ecf20Sopenharmony_ci	struct pcie_port *pp = &pcie->pci->pp;
2578c2ecf20Sopenharmony_ci	unsigned int ecam_bus_mask;
2588c2ecf20Sopenharmony_ci	u32 cfg_control_offset;
2598c2ecf20Sopenharmony_ci	u8 subordinate_bus;
2608c2ecf20Sopenharmony_ci	u8 secondary_bus;
2618c2ecf20Sopenharmony_ci	u32 cfg_control;
2628c2ecf20Sopenharmony_ci	u32 reg;
2638c2ecf20Sopenharmony_ci	struct resource *bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	target_bus_cfg = &pcie->target_bus_cfg;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	ecam_bus_mask = (pcie->ecam_size >> 20) - 1;
2688c2ecf20Sopenharmony_ci	if (ecam_bus_mask > 255) {
2698c2ecf20Sopenharmony_ci		dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n");
2708c2ecf20Sopenharmony_ci		ecam_bus_mask = 255;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* This portion is taken from the transaction address */
2748c2ecf20Sopenharmony_ci	target_bus_cfg->ecam_mask = ecam_bus_mask;
2758c2ecf20Sopenharmony_ci	/* This portion is taken from the cfg_target_bus reg */
2768c2ecf20Sopenharmony_ci	target_bus_cfg->reg_mask = ~target_bus_cfg->ecam_mask;
2778c2ecf20Sopenharmony_ci	target_bus_cfg->reg_val = bus->start & target_bus_cfg->reg_mask;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	al_pcie_target_bus_set(pcie, target_bus_cfg->reg_val,
2808c2ecf20Sopenharmony_ci			       target_bus_cfg->reg_mask);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	secondary_bus = bus->start + 1;
2838c2ecf20Sopenharmony_ci	subordinate_bus = bus->end;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Set the valid values of secondary and subordinate buses */
2868c2ecf20Sopenharmony_ci	cfg_control_offset = AXI_BASE_OFFSET + pcie->reg_offsets.ob_ctrl +
2878c2ecf20Sopenharmony_ci			     CFG_CONTROL;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	cfg_control = al_pcie_controller_readl(pcie, cfg_control_offset);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	reg = cfg_control &
2928c2ecf20Sopenharmony_ci	      ~(CFG_CONTROL_SEC_BUS_MASK | CFG_CONTROL_SUBBUS_MASK);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	reg |= FIELD_PREP(CFG_CONTROL_SUBBUS_MASK, subordinate_bus) |
2958c2ecf20Sopenharmony_ci	       FIELD_PREP(CFG_CONTROL_SEC_BUS_MASK, secondary_bus);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	al_pcie_controller_writel(pcie, cfg_control_offset, reg);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int al_pcie_host_init(struct pcie_port *pp)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
3038c2ecf20Sopenharmony_ci	struct al_pcie *pcie = to_al_pcie(pci);
3048c2ecf20Sopenharmony_ci	int rc;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	pp->bridge->child_ops = &al_child_pci_ops;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	rc = al_pcie_rev_id_get(pcie, &pcie->controller_rev_id);
3098c2ecf20Sopenharmony_ci	if (rc)
3108c2ecf20Sopenharmony_ci		return rc;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	rc = al_pcie_reg_offsets_set(pcie);
3138c2ecf20Sopenharmony_ci	if (rc)
3148c2ecf20Sopenharmony_ci		return rc;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	al_pcie_config_prepare(pcie);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return 0;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic const struct dw_pcie_host_ops al_pcie_host_ops = {
3228c2ecf20Sopenharmony_ci	.host_init = al_pcie_host_init,
3238c2ecf20Sopenharmony_ci};
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int al_add_pcie_port(struct pcie_port *pp,
3268c2ecf20Sopenharmony_ci			    struct platform_device *pdev)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3298c2ecf20Sopenharmony_ci	int ret;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	pp->ops = &al_pcie_host_ops;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	ret = dw_pcie_host_init(pp);
3348c2ecf20Sopenharmony_ci	if (ret) {
3358c2ecf20Sopenharmony_ci		dev_err(dev, "failed to initialize host\n");
3368c2ecf20Sopenharmony_ci		return ret;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return 0;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic const struct dw_pcie_ops dw_pcie_ops = {
3438c2ecf20Sopenharmony_ci};
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int al_pcie_probe(struct platform_device *pdev)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3488c2ecf20Sopenharmony_ci	struct resource *controller_res;
3498c2ecf20Sopenharmony_ci	struct resource *ecam_res;
3508c2ecf20Sopenharmony_ci	struct resource *dbi_res;
3518c2ecf20Sopenharmony_ci	struct al_pcie *al_pcie;
3528c2ecf20Sopenharmony_ci	struct dw_pcie *pci;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL);
3558c2ecf20Sopenharmony_ci	if (!al_pcie)
3568c2ecf20Sopenharmony_ci		return -ENOMEM;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
3598c2ecf20Sopenharmony_ci	if (!pci)
3608c2ecf20Sopenharmony_ci		return -ENOMEM;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	pci->dev = dev;
3638c2ecf20Sopenharmony_ci	pci->ops = &dw_pcie_ops;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	al_pcie->pci = pci;
3668c2ecf20Sopenharmony_ci	al_pcie->dev = dev;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
3698c2ecf20Sopenharmony_ci	pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
3708c2ecf20Sopenharmony_ci	if (IS_ERR(pci->dbi_base))
3718c2ecf20Sopenharmony_ci		return PTR_ERR(pci->dbi_base);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
3748c2ecf20Sopenharmony_ci	if (!ecam_res) {
3758c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't find 'config' reg in DT\n");
3768c2ecf20Sopenharmony_ci		return -ENOENT;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci	al_pcie->ecam_size = resource_size(ecam_res);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	controller_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
3818c2ecf20Sopenharmony_ci						      "controller");
3828c2ecf20Sopenharmony_ci	al_pcie->controller_base = devm_ioremap_resource(dev, controller_res);
3838c2ecf20Sopenharmony_ci	if (IS_ERR(al_pcie->controller_base)) {
3848c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't remap controller base %pR\n",
3858c2ecf20Sopenharmony_ci			controller_res);
3868c2ecf20Sopenharmony_ci		return PTR_ERR(al_pcie->controller_base);
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	dev_dbg(dev, "From DT: dbi_base: %pR, controller_base: %pR\n",
3908c2ecf20Sopenharmony_ci		dbi_res, controller_res);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, al_pcie);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return al_add_pcie_port(&pci->pp, pdev);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic const struct of_device_id al_pcie_of_match[] = {
3988c2ecf20Sopenharmony_ci	{ .compatible = "amazon,al-alpine-v2-pcie",
3998c2ecf20Sopenharmony_ci	},
4008c2ecf20Sopenharmony_ci	{ .compatible = "amazon,al-alpine-v3-pcie",
4018c2ecf20Sopenharmony_ci	},
4028c2ecf20Sopenharmony_ci	{},
4038c2ecf20Sopenharmony_ci};
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic struct platform_driver al_pcie_driver = {
4068c2ecf20Sopenharmony_ci	.driver = {
4078c2ecf20Sopenharmony_ci		.name	= "al-pcie",
4088c2ecf20Sopenharmony_ci		.of_match_table = al_pcie_of_match,
4098c2ecf20Sopenharmony_ci		.suppress_bind_attrs = true,
4108c2ecf20Sopenharmony_ci	},
4118c2ecf20Sopenharmony_ci	.probe = al_pcie_probe,
4128c2ecf20Sopenharmony_ci};
4138c2ecf20Sopenharmony_cibuiltin_platform_driver(al_pcie_driver);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci#endif /* CONFIG_PCIE_AL*/
416