1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2015 Broadcom Corporation 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/pci.h> 8 #include <linux/clk.h> 9 #include <linux/module.h> 10 #include <linux/slab.h> 11 #include <linux/interrupt.h> 12 #include <linux/platform_device.h> 13 #include <linux/of_address.h> 14 #include <linux/of_pci.h> 15 #include <linux/of_platform.h> 16 #include <linux/phy/phy.h> 17 18 #include "../pci.h" 19 #include "pcie-iproc.h" 20 21 static const struct of_device_id iproc_pcie_of_match_table[] = { 22 { 23 .compatible = "brcm,iproc-pcie", 24 .data = (int *)IPROC_PCIE_PAXB, 25 }, { 26 .compatible = "brcm,iproc-pcie-paxb-v2", 27 .data = (int *)IPROC_PCIE_PAXB_V2, 28 }, { 29 .compatible = "brcm,iproc-pcie-paxc", 30 .data = (int *)IPROC_PCIE_PAXC, 31 }, { 32 .compatible = "brcm,iproc-pcie-paxc-v2", 33 .data = (int *)IPROC_PCIE_PAXC_V2, 34 }, 35 { /* sentinel */ } 36 }; 37 MODULE_DEVICE_TABLE(of, iproc_pcie_of_match_table); 38 39 static int iproc_pltfm_pcie_probe(struct platform_device *pdev) 40 { 41 struct device *dev = &pdev->dev; 42 struct iproc_pcie *pcie; 43 struct device_node *np = dev->of_node; 44 struct resource reg; 45 struct pci_host_bridge *bridge; 46 int ret; 47 48 bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); 49 if (!bridge) 50 return -ENOMEM; 51 52 pcie = pci_host_bridge_priv(bridge); 53 54 pcie->dev = dev; 55 pcie->type = (enum iproc_pcie_type) of_device_get_match_data(dev); 56 57 ret = of_address_to_resource(np, 0, ®); 58 if (ret < 0) { 59 dev_err(dev, "unable to obtain controller resources\n"); 60 return ret; 61 } 62 63 pcie->base = devm_pci_remap_cfgspace(dev, reg.start, 64 resource_size(®)); 65 if (!pcie->base) { 66 dev_err(dev, "unable to map controller registers\n"); 67 return -ENOMEM; 68 } 69 pcie->base_addr = reg.start; 70 71 if (of_property_read_bool(np, "brcm,pcie-ob")) { 72 u32 val; 73 74 ret = of_property_read_u32(np, "brcm,pcie-ob-axi-offset", 75 &val); 76 if (ret) { 77 dev_err(dev, 78 "missing brcm,pcie-ob-axi-offset property\n"); 79 return ret; 80 } 81 pcie->ob.axi_offset = val; 82 pcie->need_ob_cfg = true; 83 } 84 85 /* 86 * DT nodes are not used by all platforms that use the iProc PCIe 87 * core driver. For platforms that require explicit inbound mapping 88 * configuration, "dma-ranges" would have been present in DT 89 */ 90 pcie->need_ib_cfg = of_property_read_bool(np, "dma-ranges"); 91 92 /* PHY use is optional */ 93 pcie->phy = devm_phy_optional_get(dev, "pcie-phy"); 94 if (IS_ERR(pcie->phy)) 95 return PTR_ERR(pcie->phy); 96 97 /* PAXC doesn't support legacy IRQs, skip mapping */ 98 switch (pcie->type) { 99 case IPROC_PCIE_PAXC: 100 case IPROC_PCIE_PAXC_V2: 101 pcie->map_irq = NULL; 102 break; 103 default: 104 break; 105 } 106 107 ret = iproc_pcie_setup(pcie, &bridge->windows); 108 if (ret) { 109 dev_err(dev, "PCIe controller setup failed\n"); 110 return ret; 111 } 112 113 platform_set_drvdata(pdev, pcie); 114 return 0; 115 } 116 117 static void iproc_pltfm_pcie_remove(struct platform_device *pdev) 118 { 119 struct iproc_pcie *pcie = platform_get_drvdata(pdev); 120 121 iproc_pcie_remove(pcie); 122 } 123 124 static void iproc_pltfm_pcie_shutdown(struct platform_device *pdev) 125 { 126 struct iproc_pcie *pcie = platform_get_drvdata(pdev); 127 128 iproc_pcie_shutdown(pcie); 129 } 130 131 static struct platform_driver iproc_pltfm_pcie_driver = { 132 .driver = { 133 .name = "iproc-pcie", 134 .of_match_table = of_match_ptr(iproc_pcie_of_match_table), 135 }, 136 .probe = iproc_pltfm_pcie_probe, 137 .remove_new = iproc_pltfm_pcie_remove, 138 .shutdown = iproc_pltfm_pcie_shutdown, 139 }; 140 module_platform_driver(iproc_pltfm_pcie_driver); 141 142 MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>"); 143 MODULE_DESCRIPTION("Broadcom iPROC PCIe platform driver"); 144 MODULE_LICENSE("GPL v2"); 145