1de80f95cSTom Joseph // SPDX-License-Identifier: GPL-2.0 2de80f95cSTom Joseph // Copyright (c) 2017 Cadence 3de80f95cSTom Joseph // Cadence PCIe endpoint controller driver. 4de80f95cSTom Joseph // Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> 5de80f95cSTom Joseph 6de80f95cSTom Joseph #include <linux/delay.h> 7de80f95cSTom Joseph #include <linux/kernel.h> 8de80f95cSTom Joseph #include <linux/of.h> 9de80f95cSTom Joseph #include <linux/pci-epc.h> 10de80f95cSTom Joseph #include <linux/platform_device.h> 11de80f95cSTom Joseph #include <linux/pm_runtime.h> 12de80f95cSTom Joseph #include <linux/sizes.h> 13de80f95cSTom Joseph 14de80f95cSTom Joseph #include "pcie-cadence.h" 15de80f95cSTom Joseph 16de80f95cSTom Joseph #define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */ 17de80f95cSTom Joseph #define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE 0x1 18de80f95cSTom Joseph #define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY 0x3 19de80f95cSTom Joseph 20de80f95cSTom Joseph static int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn, 21de80f95cSTom Joseph struct pci_epf_header *hdr) 22de80f95cSTom Joseph { 23de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 24de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 25de80f95cSTom Joseph 26de80f95cSTom Joseph cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid); 27de80f95cSTom Joseph cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid); 28de80f95cSTom Joseph cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG, hdr->progif_code); 29de80f95cSTom Joseph cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE, 30de80f95cSTom Joseph hdr->subclass_code | hdr->baseclass_code << 8); 31de80f95cSTom Joseph cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE, 32de80f95cSTom Joseph hdr->cache_line_size); 33de80f95cSTom Joseph cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID, hdr->subsys_id); 34de80f95cSTom Joseph cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN, hdr->interrupt_pin); 35de80f95cSTom Joseph 36de80f95cSTom Joseph /* 37de80f95cSTom Joseph * Vendor ID can only be modified from function 0, all other functions 38de80f95cSTom Joseph * use the same vendor ID as function 0. 39de80f95cSTom Joseph */ 40de80f95cSTom Joseph if (fn == 0) { 41de80f95cSTom Joseph /* Update the vendor IDs. */ 42de80f95cSTom Joseph u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) | 43de80f95cSTom Joseph CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id); 44de80f95cSTom Joseph 45de80f95cSTom Joseph cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id); 46de80f95cSTom Joseph } 47de80f95cSTom Joseph 48de80f95cSTom Joseph return 0; 49de80f95cSTom Joseph } 50de80f95cSTom Joseph 51de80f95cSTom Joseph static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, 52de80f95cSTom Joseph struct pci_epf_bar *epf_bar) 53de80f95cSTom Joseph { 54de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 55de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 56de80f95cSTom Joseph dma_addr_t bar_phys = epf_bar->phys_addr; 57de80f95cSTom Joseph enum pci_barno bar = epf_bar->barno; 58de80f95cSTom Joseph int flags = epf_bar->flags; 59de80f95cSTom Joseph u32 addr0, addr1, reg, cfg, b, aperture, ctrl; 60de80f95cSTom Joseph u64 sz; 61de80f95cSTom Joseph 62de80f95cSTom Joseph /* BAR size is 2^(aperture + 7) */ 63de80f95cSTom Joseph sz = max_t(size_t, epf_bar->size, CDNS_PCIE_EP_MIN_APERTURE); 64de80f95cSTom Joseph /* 65de80f95cSTom Joseph * roundup_pow_of_two() returns an unsigned long, which is not suited 66de80f95cSTom Joseph * for 64bit values. 67de80f95cSTom Joseph */ 68de80f95cSTom Joseph sz = 1ULL << fls64(sz - 1); 69de80f95cSTom Joseph aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */ 70de80f95cSTom Joseph 71de80f95cSTom Joseph if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { 72de80f95cSTom Joseph ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS; 73de80f95cSTom Joseph } else { 74de80f95cSTom Joseph bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH); 75de80f95cSTom Joseph bool is_64bits = sz > SZ_2G; 76de80f95cSTom Joseph 77de80f95cSTom Joseph if (is_64bits && (bar & 1)) 78de80f95cSTom Joseph return -EINVAL; 79de80f95cSTom Joseph 80de80f95cSTom Joseph if (is_64bits && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) 81de80f95cSTom Joseph epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; 82de80f95cSTom Joseph 83de80f95cSTom Joseph if (is_64bits && is_prefetch) 84de80f95cSTom Joseph ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS; 85de80f95cSTom Joseph else if (is_prefetch) 86de80f95cSTom Joseph ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS; 87de80f95cSTom Joseph else if (is_64bits) 88de80f95cSTom Joseph ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS; 89de80f95cSTom Joseph else 90de80f95cSTom Joseph ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS; 91de80f95cSTom Joseph } 92de80f95cSTom Joseph 93de80f95cSTom Joseph addr0 = lower_32_bits(bar_phys); 94de80f95cSTom Joseph addr1 = upper_32_bits(bar_phys); 95de80f95cSTom Joseph cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 96de80f95cSTom Joseph addr0); 97de80f95cSTom Joseph cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 98de80f95cSTom Joseph addr1); 99de80f95cSTom Joseph 100de80f95cSTom Joseph if (bar < BAR_4) { 101de80f95cSTom Joseph reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn); 102de80f95cSTom Joseph b = bar; 103de80f95cSTom Joseph } else { 104de80f95cSTom Joseph reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn); 105de80f95cSTom Joseph b = bar - BAR_4; 106de80f95cSTom Joseph } 107de80f95cSTom Joseph 108de80f95cSTom Joseph cfg = cdns_pcie_readl(pcie, reg); 109de80f95cSTom Joseph cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) | 110de80f95cSTom Joseph CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)); 111de80f95cSTom Joseph cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) | 112de80f95cSTom Joseph CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl)); 113de80f95cSTom Joseph cdns_pcie_writel(pcie, reg, cfg); 114de80f95cSTom Joseph 115de80f95cSTom Joseph return 0; 116de80f95cSTom Joseph } 117de80f95cSTom Joseph 118de80f95cSTom Joseph static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, 119de80f95cSTom Joseph struct pci_epf_bar *epf_bar) 120de80f95cSTom Joseph { 121de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 122de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 123de80f95cSTom Joseph enum pci_barno bar = epf_bar->barno; 124de80f95cSTom Joseph u32 reg, cfg, b, ctrl; 125de80f95cSTom Joseph 126de80f95cSTom Joseph if (bar < BAR_4) { 127de80f95cSTom Joseph reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn); 128de80f95cSTom Joseph b = bar; 129de80f95cSTom Joseph } else { 130de80f95cSTom Joseph reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn); 131de80f95cSTom Joseph b = bar - BAR_4; 132de80f95cSTom Joseph } 133de80f95cSTom Joseph 134de80f95cSTom Joseph ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; 135de80f95cSTom Joseph cfg = cdns_pcie_readl(pcie, reg); 136de80f95cSTom Joseph cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) | 137de80f95cSTom Joseph CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)); 138de80f95cSTom Joseph cfg |= CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl); 139de80f95cSTom Joseph cdns_pcie_writel(pcie, reg, cfg); 140de80f95cSTom Joseph 141de80f95cSTom Joseph cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0); 142de80f95cSTom Joseph cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0); 143de80f95cSTom Joseph } 144de80f95cSTom Joseph 145de80f95cSTom Joseph static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr, 146de80f95cSTom Joseph u64 pci_addr, size_t size) 147de80f95cSTom Joseph { 148de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 149de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 150de80f95cSTom Joseph u32 r; 151de80f95cSTom Joseph 152de80f95cSTom Joseph r = find_first_zero_bit(&ep->ob_region_map, 153de80f95cSTom Joseph sizeof(ep->ob_region_map) * BITS_PER_LONG); 154de80f95cSTom Joseph if (r >= ep->max_regions - 1) { 155de80f95cSTom Joseph dev_err(&epc->dev, "no free outbound region\n"); 156de80f95cSTom Joseph return -EINVAL; 157de80f95cSTom Joseph } 158de80f95cSTom Joseph 159de80f95cSTom Joseph cdns_pcie_set_outbound_region(pcie, fn, r, false, addr, pci_addr, size); 160de80f95cSTom Joseph 161de80f95cSTom Joseph set_bit(r, &ep->ob_region_map); 162de80f95cSTom Joseph ep->ob_addr[r] = addr; 163de80f95cSTom Joseph 164de80f95cSTom Joseph return 0; 165de80f95cSTom Joseph } 166de80f95cSTom Joseph 167de80f95cSTom Joseph static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, 168de80f95cSTom Joseph phys_addr_t addr) 169de80f95cSTom Joseph { 170de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 171de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 172de80f95cSTom Joseph u32 r; 173de80f95cSTom Joseph 174de80f95cSTom Joseph for (r = 0; r < ep->max_regions - 1; r++) 175de80f95cSTom Joseph if (ep->ob_addr[r] == addr) 176de80f95cSTom Joseph break; 177de80f95cSTom Joseph 178de80f95cSTom Joseph if (r == ep->max_regions - 1) 179de80f95cSTom Joseph return; 180de80f95cSTom Joseph 181de80f95cSTom Joseph cdns_pcie_reset_outbound_region(pcie, r); 182de80f95cSTom Joseph 183de80f95cSTom Joseph ep->ob_addr[r] = 0; 184de80f95cSTom Joseph clear_bit(r, &ep->ob_region_map); 185de80f95cSTom Joseph } 186de80f95cSTom Joseph 187de80f95cSTom Joseph static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 mmc) 188de80f95cSTom Joseph { 189de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 190de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 191de80f95cSTom Joseph u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; 192de80f95cSTom Joseph u16 flags; 193de80f95cSTom Joseph 194de80f95cSTom Joseph /* 195de80f95cSTom Joseph * Set the Multiple Message Capable bitfield into the Message Control 196de80f95cSTom Joseph * register. 197de80f95cSTom Joseph */ 198de80f95cSTom Joseph flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); 199de80f95cSTom Joseph flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1); 200de80f95cSTom Joseph flags |= PCI_MSI_FLAGS_64BIT; 201de80f95cSTom Joseph flags &= ~PCI_MSI_FLAGS_MASKBIT; 202de80f95cSTom Joseph cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags); 203de80f95cSTom Joseph 204de80f95cSTom Joseph return 0; 205de80f95cSTom Joseph } 206de80f95cSTom Joseph 207de80f95cSTom Joseph static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn) 208de80f95cSTom Joseph { 209de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 210de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 211de80f95cSTom Joseph u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; 212de80f95cSTom Joseph u16 flags, mme; 213de80f95cSTom Joseph 214de80f95cSTom Joseph /* Validate that the MSI feature is actually enabled. */ 215de80f95cSTom Joseph flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); 216de80f95cSTom Joseph if (!(flags & PCI_MSI_FLAGS_ENABLE)) 217de80f95cSTom Joseph return -EINVAL; 218de80f95cSTom Joseph 219de80f95cSTom Joseph /* 220de80f95cSTom Joseph * Get the Multiple Message Enable bitfield from the Message Control 221de80f95cSTom Joseph * register. 222de80f95cSTom Joseph */ 223de80f95cSTom Joseph mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4; 224de80f95cSTom Joseph 225de80f95cSTom Joseph return mme; 226de80f95cSTom Joseph } 227de80f95cSTom Joseph 228de80f95cSTom Joseph static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, 229de80f95cSTom Joseph u8 intx, bool is_asserted) 230de80f95cSTom Joseph { 231de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 232de80f95cSTom Joseph u32 offset; 233de80f95cSTom Joseph u16 status; 234de80f95cSTom Joseph u8 msg_code; 235de80f95cSTom Joseph 236de80f95cSTom Joseph intx &= 3; 237de80f95cSTom Joseph 238de80f95cSTom Joseph /* Set the outbound region if needed. */ 239de80f95cSTom Joseph if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY || 240de80f95cSTom Joseph ep->irq_pci_fn != fn)) { 241de80f95cSTom Joseph /* First region was reserved for IRQ writes. */ 242de80f95cSTom Joseph cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, 0, 243de80f95cSTom Joseph ep->irq_phys_addr); 244de80f95cSTom Joseph ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY; 245de80f95cSTom Joseph ep->irq_pci_fn = fn; 246de80f95cSTom Joseph } 247de80f95cSTom Joseph 248de80f95cSTom Joseph if (is_asserted) { 249de80f95cSTom Joseph ep->irq_pending |= BIT(intx); 250de80f95cSTom Joseph msg_code = MSG_CODE_ASSERT_INTA + intx; 251de80f95cSTom Joseph } else { 252de80f95cSTom Joseph ep->irq_pending &= ~BIT(intx); 253de80f95cSTom Joseph msg_code = MSG_CODE_DEASSERT_INTA + intx; 254de80f95cSTom Joseph } 255de80f95cSTom Joseph 256de80f95cSTom Joseph status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS); 257de80f95cSTom Joseph if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) { 258de80f95cSTom Joseph status ^= PCI_STATUS_INTERRUPT; 259de80f95cSTom Joseph cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status); 260de80f95cSTom Joseph } 261de80f95cSTom Joseph 262de80f95cSTom Joseph offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) | 263de80f95cSTom Joseph CDNS_PCIE_NORMAL_MSG_CODE(msg_code) | 264de80f95cSTom Joseph CDNS_PCIE_MSG_NO_DATA; 265de80f95cSTom Joseph writel(0, ep->irq_cpu_addr + offset); 266de80f95cSTom Joseph } 267de80f95cSTom Joseph 268de80f95cSTom Joseph static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx) 269de80f95cSTom Joseph { 270de80f95cSTom Joseph u16 cmd; 271de80f95cSTom Joseph 272de80f95cSTom Joseph cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND); 273de80f95cSTom Joseph if (cmd & PCI_COMMAND_INTX_DISABLE) 274de80f95cSTom Joseph return -EINVAL; 275de80f95cSTom Joseph 276de80f95cSTom Joseph cdns_pcie_ep_assert_intx(ep, fn, intx, true); 277de80f95cSTom Joseph /* 278de80f95cSTom Joseph * The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq() 279de80f95cSTom Joseph * from drivers/pci/dwc/pci-dra7xx.c 280de80f95cSTom Joseph */ 281de80f95cSTom Joseph mdelay(1); 282de80f95cSTom Joseph cdns_pcie_ep_assert_intx(ep, fn, intx, false); 283de80f95cSTom Joseph return 0; 284de80f95cSTom Joseph } 285de80f95cSTom Joseph 286de80f95cSTom Joseph static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, 287de80f95cSTom Joseph u8 interrupt_num) 288de80f95cSTom Joseph { 289de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 290de80f95cSTom Joseph u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; 291de80f95cSTom Joseph u16 flags, mme, data, data_mask; 292de80f95cSTom Joseph u8 msi_count; 293de80f95cSTom Joseph u64 pci_addr, pci_addr_mask = 0xff; 294de80f95cSTom Joseph 295de80f95cSTom Joseph /* Check whether the MSI feature has been enabled by the PCI host. */ 296de80f95cSTom Joseph flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); 297de80f95cSTom Joseph if (!(flags & PCI_MSI_FLAGS_ENABLE)) 298de80f95cSTom Joseph return -EINVAL; 299de80f95cSTom Joseph 300de80f95cSTom Joseph /* Get the number of enabled MSIs */ 301de80f95cSTom Joseph mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4; 302de80f95cSTom Joseph msi_count = 1 << mme; 303de80f95cSTom Joseph if (!interrupt_num || interrupt_num > msi_count) 304de80f95cSTom Joseph return -EINVAL; 305de80f95cSTom Joseph 306de80f95cSTom Joseph /* Compute the data value to be written. */ 307de80f95cSTom Joseph data_mask = msi_count - 1; 308de80f95cSTom Joseph data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64); 309de80f95cSTom Joseph data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask); 310de80f95cSTom Joseph 311de80f95cSTom Joseph /* Get the PCI address where to write the data into. */ 312de80f95cSTom Joseph pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI); 313de80f95cSTom Joseph pci_addr <<= 32; 314de80f95cSTom Joseph pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO); 315de80f95cSTom Joseph pci_addr &= GENMASK_ULL(63, 2); 316de80f95cSTom Joseph 317de80f95cSTom Joseph /* Set the outbound region if needed. */ 318de80f95cSTom Joseph if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) || 319de80f95cSTom Joseph ep->irq_pci_fn != fn)) { 320de80f95cSTom Joseph /* First region was reserved for IRQ writes. */ 321de80f95cSTom Joseph cdns_pcie_set_outbound_region(pcie, fn, 0, 322de80f95cSTom Joseph false, 323de80f95cSTom Joseph ep->irq_phys_addr, 324de80f95cSTom Joseph pci_addr & ~pci_addr_mask, 325de80f95cSTom Joseph pci_addr_mask + 1); 326de80f95cSTom Joseph ep->irq_pci_addr = (pci_addr & ~pci_addr_mask); 327de80f95cSTom Joseph ep->irq_pci_fn = fn; 328de80f95cSTom Joseph } 329de80f95cSTom Joseph writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask)); 330de80f95cSTom Joseph 331de80f95cSTom Joseph return 0; 332de80f95cSTom Joseph } 333de80f95cSTom Joseph 334de80f95cSTom Joseph static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, 335de80f95cSTom Joseph enum pci_epc_irq_type type, 336de80f95cSTom Joseph u16 interrupt_num) 337de80f95cSTom Joseph { 338de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 339de80f95cSTom Joseph 340de80f95cSTom Joseph switch (type) { 341de80f95cSTom Joseph case PCI_EPC_IRQ_LEGACY: 342de80f95cSTom Joseph return cdns_pcie_ep_send_legacy_irq(ep, fn, 0); 343de80f95cSTom Joseph 344de80f95cSTom Joseph case PCI_EPC_IRQ_MSI: 345de80f95cSTom Joseph return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num); 346de80f95cSTom Joseph 347de80f95cSTom Joseph default: 348de80f95cSTom Joseph break; 349de80f95cSTom Joseph } 350de80f95cSTom Joseph 351de80f95cSTom Joseph return -EINVAL; 352de80f95cSTom Joseph } 353de80f95cSTom Joseph 354de80f95cSTom Joseph static int cdns_pcie_ep_start(struct pci_epc *epc) 355de80f95cSTom Joseph { 356de80f95cSTom Joseph struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 357de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 358de80f95cSTom Joseph struct pci_epf *epf; 359de80f95cSTom Joseph u32 cfg; 360de80f95cSTom Joseph 361de80f95cSTom Joseph /* 362de80f95cSTom Joseph * BIT(0) is hardwired to 1, hence function 0 is always enabled 363de80f95cSTom Joseph * and can't be disabled anyway. 364de80f95cSTom Joseph */ 365de80f95cSTom Joseph cfg = BIT(0); 366de80f95cSTom Joseph list_for_each_entry(epf, &epc->pci_epf, list) 367de80f95cSTom Joseph cfg |= BIT(epf->func_no); 368de80f95cSTom Joseph cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg); 369de80f95cSTom Joseph 370de80f95cSTom Joseph return 0; 371de80f95cSTom Joseph } 372de80f95cSTom Joseph 373de80f95cSTom Joseph static const struct pci_epc_features cdns_pcie_epc_features = { 374de80f95cSTom Joseph .linkup_notifier = false, 375de80f95cSTom Joseph .msi_capable = true, 376de80f95cSTom Joseph .msix_capable = false, 377de80f95cSTom Joseph }; 378de80f95cSTom Joseph 379de80f95cSTom Joseph static const struct pci_epc_features* 380de80f95cSTom Joseph cdns_pcie_ep_get_features(struct pci_epc *epc, u8 func_no) 381de80f95cSTom Joseph { 382de80f95cSTom Joseph return &cdns_pcie_epc_features; 383de80f95cSTom Joseph } 384de80f95cSTom Joseph 385de80f95cSTom Joseph static const struct pci_epc_ops cdns_pcie_epc_ops = { 386de80f95cSTom Joseph .write_header = cdns_pcie_ep_write_header, 387de80f95cSTom Joseph .set_bar = cdns_pcie_ep_set_bar, 388de80f95cSTom Joseph .clear_bar = cdns_pcie_ep_clear_bar, 389de80f95cSTom Joseph .map_addr = cdns_pcie_ep_map_addr, 390de80f95cSTom Joseph .unmap_addr = cdns_pcie_ep_unmap_addr, 391de80f95cSTom Joseph .set_msi = cdns_pcie_ep_set_msi, 392de80f95cSTom Joseph .get_msi = cdns_pcie_ep_get_msi, 393de80f95cSTom Joseph .raise_irq = cdns_pcie_ep_raise_irq, 394de80f95cSTom Joseph .start = cdns_pcie_ep_start, 395de80f95cSTom Joseph .get_features = cdns_pcie_ep_get_features, 396de80f95cSTom Joseph }; 397de80f95cSTom Joseph 398de80f95cSTom Joseph 399de80f95cSTom Joseph int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) 400de80f95cSTom Joseph { 401de80f95cSTom Joseph struct device *dev = ep->pcie.dev; 402de80f95cSTom Joseph struct platform_device *pdev = to_platform_device(dev); 403de80f95cSTom Joseph struct device_node *np = dev->of_node; 404de80f95cSTom Joseph struct cdns_pcie *pcie = &ep->pcie; 405de80f95cSTom Joseph struct resource *res; 406de80f95cSTom Joseph struct pci_epc *epc; 407de80f95cSTom Joseph int ret; 408de80f95cSTom Joseph 409de80f95cSTom Joseph pcie->is_rc = false; 410de80f95cSTom Joseph 411de80f95cSTom Joseph res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); 412de80f95cSTom Joseph pcie->reg_base = devm_ioremap_resource(dev, res); 413de80f95cSTom Joseph if (IS_ERR(pcie->reg_base)) { 414de80f95cSTom Joseph dev_err(dev, "missing \"reg\"\n"); 415de80f95cSTom Joseph return PTR_ERR(pcie->reg_base); 416de80f95cSTom Joseph } 417de80f95cSTom Joseph 418de80f95cSTom Joseph res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); 419de80f95cSTom Joseph if (!res) { 420de80f95cSTom Joseph dev_err(dev, "missing \"mem\"\n"); 421de80f95cSTom Joseph return -EINVAL; 422de80f95cSTom Joseph } 423de80f95cSTom Joseph pcie->mem_res = res; 424de80f95cSTom Joseph 425de80f95cSTom Joseph ret = of_property_read_u32(np, "cdns,max-outbound-regions", 426de80f95cSTom Joseph &ep->max_regions); 427de80f95cSTom Joseph if (ret < 0) { 428de80f95cSTom Joseph dev_err(dev, "missing \"cdns,max-outbound-regions\"\n"); 429de80f95cSTom Joseph return ret; 430de80f95cSTom Joseph } 431de80f95cSTom Joseph ep->ob_addr = devm_kcalloc(dev, 432de80f95cSTom Joseph ep->max_regions, sizeof(*ep->ob_addr), 433de80f95cSTom Joseph GFP_KERNEL); 434de80f95cSTom Joseph if (!ep->ob_addr) 435de80f95cSTom Joseph return -ENOMEM; 436de80f95cSTom Joseph 437de80f95cSTom Joseph /* Disable all but function 0 (anyway BIT(0) is hardwired to 1). */ 438de80f95cSTom Joseph cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0)); 439de80f95cSTom Joseph 440de80f95cSTom Joseph epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops); 441de80f95cSTom Joseph if (IS_ERR(epc)) { 442de80f95cSTom Joseph dev_err(dev, "failed to create epc device\n"); 443de80f95cSTom Joseph ret = PTR_ERR(epc); 444de80f95cSTom Joseph goto err_init; 445de80f95cSTom Joseph } 446de80f95cSTom Joseph 447de80f95cSTom Joseph epc_set_drvdata(epc, ep); 448de80f95cSTom Joseph 449de80f95cSTom Joseph if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0) 450de80f95cSTom Joseph epc->max_functions = 1; 451de80f95cSTom Joseph 452de80f95cSTom Joseph ret = pci_epc_mem_init(epc, pcie->mem_res->start, 453975cf23eSLad Prabhakar resource_size(pcie->mem_res), PAGE_SIZE); 454de80f95cSTom Joseph if (ret < 0) { 455de80f95cSTom Joseph dev_err(dev, "failed to initialize the memory space\n"); 456de80f95cSTom Joseph goto err_init; 457de80f95cSTom Joseph } 458de80f95cSTom Joseph 459de80f95cSTom Joseph ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr, 460de80f95cSTom Joseph SZ_128K); 461de80f95cSTom Joseph if (!ep->irq_cpu_addr) { 462de80f95cSTom Joseph dev_err(dev, "failed to reserve memory space for MSI\n"); 463de80f95cSTom Joseph ret = -ENOMEM; 464de80f95cSTom Joseph goto free_epc_mem; 465de80f95cSTom Joseph } 466de80f95cSTom Joseph ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE; 467de80f95cSTom Joseph /* Reserve region 0 for IRQs */ 468de80f95cSTom Joseph set_bit(0, &ep->ob_region_map); 469de80f95cSTom Joseph 470de80f95cSTom Joseph return 0; 471de80f95cSTom Joseph 472de80f95cSTom Joseph free_epc_mem: 473de80f95cSTom Joseph pci_epc_mem_exit(epc); 474de80f95cSTom Joseph 475de80f95cSTom Joseph err_init: 476de80f95cSTom Joseph pm_runtime_put_sync(dev); 477de80f95cSTom Joseph 478de80f95cSTom Joseph return ret; 479de80f95cSTom Joseph } 480