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