162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCIe endpoint driver for Renesas R-Car SoCs 462306a36Sopenharmony_ci * Copyright (c) 2020 Renesas Electronics Europe GmbH 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/of_address.h> 1162306a36Sopenharmony_ci#include <linux/of_platform.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/pci-epc.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "pcie-rcar.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define RCAR_EPC_MAX_FUNCTIONS 1 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Structure representing the PCIe interface */ 2262306a36Sopenharmony_cistruct rcar_pcie_endpoint { 2362306a36Sopenharmony_ci struct rcar_pcie pcie; 2462306a36Sopenharmony_ci phys_addr_t *ob_mapped_addr; 2562306a36Sopenharmony_ci struct pci_epc_mem_window *ob_window; 2662306a36Sopenharmony_ci u8 max_functions; 2762306a36Sopenharmony_ci unsigned int bar_to_atu[MAX_NR_INBOUND_MAPS]; 2862306a36Sopenharmony_ci unsigned long *ib_window_map; 2962306a36Sopenharmony_ci u32 num_ib_windows; 3062306a36Sopenharmony_ci u32 num_ob_windows; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci u32 val; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci rcar_pci_write_reg(pcie, 0, PCIETCTLR); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* Set endpoint mode */ 4062306a36Sopenharmony_ci rcar_pci_write_reg(pcie, 0, PCIEMSR); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* Initialize default capabilities. */ 4362306a36Sopenharmony_ci rcar_rmw32(pcie, REXPCAP(0), 0xff, PCI_CAP_ID_EXP); 4462306a36Sopenharmony_ci rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS), 4562306a36Sopenharmony_ci PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ENDPOINT << 4); 4662306a36Sopenharmony_ci rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f, 4762306a36Sopenharmony_ci PCI_HEADER_TYPE_NORMAL); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* Write out the physical slot number = 0 */ 5062306a36Sopenharmony_ci rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, EXPCAP(1)); 5362306a36Sopenharmony_ci /* device supports fixed 128 bytes MPSS */ 5462306a36Sopenharmony_ci val &= ~GENMASK(2, 0); 5562306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, EXPCAP(1)); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, EXPCAP(2)); 5862306a36Sopenharmony_ci /* read requests size 128 bytes */ 5962306a36Sopenharmony_ci val &= ~GENMASK(14, 12); 6062306a36Sopenharmony_ci /* payload size 128 bytes */ 6162306a36Sopenharmony_ci val &= ~GENMASK(7, 5); 6262306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, EXPCAP(2)); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* Set target link speed to 5.0 GT/s */ 6562306a36Sopenharmony_ci rcar_rmw32(pcie, EXPCAP(12), PCI_EXP_LNKSTA_CLS, 6662306a36Sopenharmony_ci PCI_EXP_LNKSTA_CLS_5_0GB); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* Set the completion timer timeout to the maximum 50ms. */ 6962306a36Sopenharmony_ci rcar_rmw32(pcie, TLCTLR + 1, 0x3f, 50); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Terminate list of capabilities (Next Capability Offset=0) */ 7262306a36Sopenharmony_ci rcar_rmw32(pcie, RVCCAP(0), 0xfff00000, 0); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* flush modifications */ 7562306a36Sopenharmony_ci wmb(); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int rcar_pcie_ep_get_window(struct rcar_pcie_endpoint *ep, 7962306a36Sopenharmony_ci phys_addr_t addr) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci int i; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci for (i = 0; i < ep->num_ob_windows; i++) 8462306a36Sopenharmony_ci if (ep->ob_window[i].phys_base == addr) 8562306a36Sopenharmony_ci return i; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return -EINVAL; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int rcar_pcie_parse_outbound_ranges(struct rcar_pcie_endpoint *ep, 9162306a36Sopenharmony_ci struct platform_device *pdev) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 9462306a36Sopenharmony_ci char outbound_name[10]; 9562306a36Sopenharmony_ci struct resource *res; 9662306a36Sopenharmony_ci unsigned int i = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ep->num_ob_windows = 0; 9962306a36Sopenharmony_ci for (i = 0; i < RCAR_PCI_MAX_RESOURCES; i++) { 10062306a36Sopenharmony_ci sprintf(outbound_name, "memory%u", i); 10162306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, 10262306a36Sopenharmony_ci IORESOURCE_MEM, 10362306a36Sopenharmony_ci outbound_name); 10462306a36Sopenharmony_ci if (!res) { 10562306a36Sopenharmony_ci dev_err(pcie->dev, "missing outbound window %u\n", i); 10662306a36Sopenharmony_ci return -EINVAL; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci if (!devm_request_mem_region(&pdev->dev, res->start, 10962306a36Sopenharmony_ci resource_size(res), 11062306a36Sopenharmony_ci outbound_name)) { 11162306a36Sopenharmony_ci dev_err(pcie->dev, "Cannot request memory region %s.\n", 11262306a36Sopenharmony_ci outbound_name); 11362306a36Sopenharmony_ci return -EIO; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci ep->ob_window[i].phys_base = res->start; 11762306a36Sopenharmony_ci ep->ob_window[i].size = resource_size(res); 11862306a36Sopenharmony_ci /* controller doesn't support multiple allocation 11962306a36Sopenharmony_ci * from same window, so set page_size to window size 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci ep->ob_window[i].page_size = resource_size(res); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci ep->num_ob_windows = i; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int rcar_pcie_ep_get_pdata(struct rcar_pcie_endpoint *ep, 12962306a36Sopenharmony_ci struct platform_device *pdev) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 13262306a36Sopenharmony_ci struct pci_epc_mem_window *window; 13362306a36Sopenharmony_ci struct device *dev = pcie->dev; 13462306a36Sopenharmony_ci struct resource res; 13562306a36Sopenharmony_ci int err; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci err = of_address_to_resource(dev->of_node, 0, &res); 13862306a36Sopenharmony_ci if (err) 13962306a36Sopenharmony_ci return err; 14062306a36Sopenharmony_ci pcie->base = devm_ioremap_resource(dev, &res); 14162306a36Sopenharmony_ci if (IS_ERR(pcie->base)) 14262306a36Sopenharmony_ci return PTR_ERR(pcie->base); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ep->ob_window = devm_kcalloc(dev, RCAR_PCI_MAX_RESOURCES, 14562306a36Sopenharmony_ci sizeof(*window), GFP_KERNEL); 14662306a36Sopenharmony_ci if (!ep->ob_window) 14762306a36Sopenharmony_ci return -ENOMEM; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci rcar_pcie_parse_outbound_ranges(ep, pdev); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci err = of_property_read_u8(dev->of_node, "max-functions", 15262306a36Sopenharmony_ci &ep->max_functions); 15362306a36Sopenharmony_ci if (err < 0 || ep->max_functions > RCAR_EPC_MAX_FUNCTIONS) 15462306a36Sopenharmony_ci ep->max_functions = RCAR_EPC_MAX_FUNCTIONS; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic int rcar_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn, 16062306a36Sopenharmony_ci struct pci_epf_header *hdr) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 16362306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 16462306a36Sopenharmony_ci u32 val; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (!fn) 16762306a36Sopenharmony_ci val = hdr->vendorid; 16862306a36Sopenharmony_ci else 16962306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, IDSETR0); 17062306a36Sopenharmony_ci val |= hdr->deviceid << 16; 17162306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, IDSETR0); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci val = hdr->revid; 17462306a36Sopenharmony_ci val |= hdr->progif_code << 8; 17562306a36Sopenharmony_ci val |= hdr->subclass_code << 16; 17662306a36Sopenharmony_ci val |= hdr->baseclass_code << 24; 17762306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, IDSETR1); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (!fn) 18062306a36Sopenharmony_ci val = hdr->subsys_vendor_id; 18162306a36Sopenharmony_ci else 18262306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, SUBIDSETR); 18362306a36Sopenharmony_ci val |= hdr->subsys_id << 16; 18462306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, SUBIDSETR); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (hdr->interrupt_pin > PCI_INTERRUPT_INTA) 18762306a36Sopenharmony_ci return -EINVAL; 18862306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, PCICONF(15)); 18962306a36Sopenharmony_ci val |= (hdr->interrupt_pin << 8); 19062306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, PCICONF(15)); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int rcar_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 19662306a36Sopenharmony_ci struct pci_epf_bar *epf_bar) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int flags = epf_bar->flags | LAR_ENABLE | LAM_64BIT; 19962306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 20062306a36Sopenharmony_ci u64 size = 1ULL << fls64(epf_bar->size - 1); 20162306a36Sopenharmony_ci dma_addr_t cpu_addr = epf_bar->phys_addr; 20262306a36Sopenharmony_ci enum pci_barno bar = epf_bar->barno; 20362306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 20462306a36Sopenharmony_ci u32 mask; 20562306a36Sopenharmony_ci int idx; 20662306a36Sopenharmony_ci int err; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci idx = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows); 20962306a36Sopenharmony_ci if (idx >= ep->num_ib_windows) { 21062306a36Sopenharmony_ci dev_err(pcie->dev, "no free inbound window\n"); 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) 21562306a36Sopenharmony_ci flags |= IO_SPACE; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ep->bar_to_atu[bar] = idx; 21862306a36Sopenharmony_ci /* use 64-bit BARs */ 21962306a36Sopenharmony_ci set_bit(idx, ep->ib_window_map); 22062306a36Sopenharmony_ci set_bit(idx + 1, ep->ib_window_map); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (cpu_addr > 0) { 22362306a36Sopenharmony_ci unsigned long nr_zeros = __ffs64(cpu_addr); 22462306a36Sopenharmony_ci u64 alignment = 1ULL << nr_zeros; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci size = min(size, alignment); 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci size = min(size, 1ULL << 32); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci mask = roundup_pow_of_two(size) - 1; 23262306a36Sopenharmony_ci mask &= ~0xf; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci rcar_pcie_set_inbound(pcie, cpu_addr, 23562306a36Sopenharmony_ci 0x0, mask | flags, idx, false); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci err = rcar_pcie_wait_for_phyrdy(pcie); 23862306a36Sopenharmony_ci if (err) { 23962306a36Sopenharmony_ci dev_err(pcie->dev, "phy not ready\n"); 24062306a36Sopenharmony_ci return -EINVAL; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void rcar_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn, 24762306a36Sopenharmony_ci struct pci_epf_bar *epf_bar) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 25062306a36Sopenharmony_ci enum pci_barno bar = epf_bar->barno; 25162306a36Sopenharmony_ci u32 atu_index = ep->bar_to_atu[bar]; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci rcar_pcie_set_inbound(&ep->pcie, 0x0, 0x0, 0x0, bar, false); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci clear_bit(atu_index, ep->ib_window_map); 25662306a36Sopenharmony_ci clear_bit(atu_index + 1, ep->ib_window_map); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, 26062306a36Sopenharmony_ci u8 interrupts) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 26362306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 26462306a36Sopenharmony_ci u32 flags; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci flags = rcar_pci_read_reg(pcie, MSICAP(fn)); 26762306a36Sopenharmony_ci flags |= interrupts << MSICAP0_MMESCAP_OFFSET; 26862306a36Sopenharmony_ci rcar_pci_write_reg(pcie, flags, MSICAP(fn)); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return 0; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int rcar_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 27662306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 27762306a36Sopenharmony_ci u32 flags; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci flags = rcar_pci_read_reg(pcie, MSICAP(fn)); 28062306a36Sopenharmony_ci if (!(flags & MSICAP0_MSIE)) 28162306a36Sopenharmony_ci return -EINVAL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return ((flags & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int rcar_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, 28762306a36Sopenharmony_ci phys_addr_t addr, u64 pci_addr, size_t size) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 29062306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 29162306a36Sopenharmony_ci struct resource_entry win; 29262306a36Sopenharmony_ci struct resource res; 29362306a36Sopenharmony_ci int window; 29462306a36Sopenharmony_ci int err; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* check if we have a link. */ 29762306a36Sopenharmony_ci err = rcar_pcie_wait_for_dl(pcie); 29862306a36Sopenharmony_ci if (err) { 29962306a36Sopenharmony_ci dev_err(pcie->dev, "link not up\n"); 30062306a36Sopenharmony_ci return err; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci window = rcar_pcie_ep_get_window(ep, addr); 30462306a36Sopenharmony_ci if (window < 0) { 30562306a36Sopenharmony_ci dev_err(pcie->dev, "failed to get corresponding window\n"); 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci memset(&win, 0x0, sizeof(win)); 31062306a36Sopenharmony_ci memset(&res, 0x0, sizeof(res)); 31162306a36Sopenharmony_ci res.start = pci_addr; 31262306a36Sopenharmony_ci res.end = pci_addr + size - 1; 31362306a36Sopenharmony_ci res.flags = IORESOURCE_MEM; 31462306a36Sopenharmony_ci win.res = &res; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci rcar_pcie_set_outbound(pcie, window, &win); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ep->ob_mapped_addr[window] = addr; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void rcar_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, 32462306a36Sopenharmony_ci phys_addr_t addr) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 32762306a36Sopenharmony_ci struct resource_entry win; 32862306a36Sopenharmony_ci struct resource res; 32962306a36Sopenharmony_ci int idx; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci for (idx = 0; idx < ep->num_ob_windows; idx++) 33262306a36Sopenharmony_ci if (ep->ob_mapped_addr[idx] == addr) 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (idx >= ep->num_ob_windows) 33662306a36Sopenharmony_ci return; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci memset(&win, 0x0, sizeof(win)); 33962306a36Sopenharmony_ci memset(&res, 0x0, sizeof(res)); 34062306a36Sopenharmony_ci win.res = &res; 34162306a36Sopenharmony_ci rcar_pcie_set_outbound(&ep->pcie, idx, &win); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ep->ob_mapped_addr[idx] = 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int rcar_pcie_ep_assert_intx(struct rcar_pcie_endpoint *ep, 34762306a36Sopenharmony_ci u8 fn, u8 intx) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct rcar_pcie *pcie = &ep->pcie; 35062306a36Sopenharmony_ci u32 val; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, PCIEMSITXR); 35362306a36Sopenharmony_ci if ((val & PCI_MSI_FLAGS_ENABLE)) { 35462306a36Sopenharmony_ci dev_err(pcie->dev, "MSI is enabled, cannot assert INTx\n"); 35562306a36Sopenharmony_ci return -EINVAL; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, PCICONF(1)); 35962306a36Sopenharmony_ci if ((val & INTDIS)) { 36062306a36Sopenharmony_ci dev_err(pcie->dev, "INTx message transmission is disabled\n"); 36162306a36Sopenharmony_ci return -EINVAL; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, PCIEINTXR); 36562306a36Sopenharmony_ci if ((val & ASTINTX)) { 36662306a36Sopenharmony_ci dev_err(pcie->dev, "INTx is already asserted\n"); 36762306a36Sopenharmony_ci return -EINVAL; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci val |= ASTINTX; 37162306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, PCIEINTXR); 37262306a36Sopenharmony_ci usleep_range(1000, 1001); 37362306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, PCIEINTXR); 37462306a36Sopenharmony_ci val &= ~ASTINTX; 37562306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val, PCIEINTXR); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int rcar_pcie_ep_assert_msi(struct rcar_pcie *pcie, 38162306a36Sopenharmony_ci u8 fn, u8 interrupt_num) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci u16 msi_count; 38462306a36Sopenharmony_ci u32 val; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Check MSI enable bit */ 38762306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, MSICAP(fn)); 38862306a36Sopenharmony_ci if (!(val & MSICAP0_MSIE)) 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* Get MSI numbers from MME */ 39262306a36Sopenharmony_ci msi_count = ((val & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); 39362306a36Sopenharmony_ci msi_count = 1 << msi_count; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!interrupt_num || interrupt_num > msi_count) 39662306a36Sopenharmony_ci return -EINVAL; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci val = rcar_pci_read_reg(pcie, PCIEMSITXR); 39962306a36Sopenharmony_ci rcar_pci_write_reg(pcie, val | (interrupt_num - 1), PCIEMSITXR); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn, 40562306a36Sopenharmony_ci enum pci_epc_irq_type type, 40662306a36Sopenharmony_ci u16 interrupt_num) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci switch (type) { 41162306a36Sopenharmony_ci case PCI_EPC_IRQ_LEGACY: 41262306a36Sopenharmony_ci return rcar_pcie_ep_assert_intx(ep, fn, 0); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci case PCI_EPC_IRQ_MSI: 41562306a36Sopenharmony_ci return rcar_pcie_ep_assert_msi(&ep->pcie, fn, interrupt_num); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci default: 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int rcar_pcie_ep_start(struct pci_epc *epc) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci rcar_pci_write_reg(&ep->pcie, MACCTLR_INIT_VAL, MACCTLR); 42762306a36Sopenharmony_ci rcar_pci_write_reg(&ep->pcie, CFINIT, PCIETCTLR); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic void rcar_pcie_ep_stop(struct pci_epc *epc) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci rcar_pci_write_reg(&ep->pcie, 0, PCIETCTLR); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic const struct pci_epc_features rcar_pcie_epc_features = { 44062306a36Sopenharmony_ci .linkup_notifier = false, 44162306a36Sopenharmony_ci .msi_capable = true, 44262306a36Sopenharmony_ci .msix_capable = false, 44362306a36Sopenharmony_ci /* use 64-bit BARs so mark BAR[1,3,5] as reserved */ 44462306a36Sopenharmony_ci .reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5, 44562306a36Sopenharmony_ci .bar_fixed_64bit = 1 << BAR_0 | 1 << BAR_2 | 1 << BAR_4, 44662306a36Sopenharmony_ci .bar_fixed_size[0] = 128, 44762306a36Sopenharmony_ci .bar_fixed_size[2] = 256, 44862306a36Sopenharmony_ci .bar_fixed_size[4] = 256, 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic const struct pci_epc_features* 45262306a36Sopenharmony_circar_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci return &rcar_pcie_epc_features; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic const struct pci_epc_ops rcar_pcie_epc_ops = { 45862306a36Sopenharmony_ci .write_header = rcar_pcie_ep_write_header, 45962306a36Sopenharmony_ci .set_bar = rcar_pcie_ep_set_bar, 46062306a36Sopenharmony_ci .clear_bar = rcar_pcie_ep_clear_bar, 46162306a36Sopenharmony_ci .set_msi = rcar_pcie_ep_set_msi, 46262306a36Sopenharmony_ci .get_msi = rcar_pcie_ep_get_msi, 46362306a36Sopenharmony_ci .map_addr = rcar_pcie_ep_map_addr, 46462306a36Sopenharmony_ci .unmap_addr = rcar_pcie_ep_unmap_addr, 46562306a36Sopenharmony_ci .raise_irq = rcar_pcie_ep_raise_irq, 46662306a36Sopenharmony_ci .start = rcar_pcie_ep_start, 46762306a36Sopenharmony_ci .stop = rcar_pcie_ep_stop, 46862306a36Sopenharmony_ci .get_features = rcar_pcie_ep_get_features, 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic const struct of_device_id rcar_pcie_ep_of_match[] = { 47262306a36Sopenharmony_ci { .compatible = "renesas,r8a774c0-pcie-ep", }, 47362306a36Sopenharmony_ci { .compatible = "renesas,rcar-gen3-pcie-ep" }, 47462306a36Sopenharmony_ci { }, 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int rcar_pcie_ep_probe(struct platform_device *pdev) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 48062306a36Sopenharmony_ci struct rcar_pcie_endpoint *ep; 48162306a36Sopenharmony_ci struct rcar_pcie *pcie; 48262306a36Sopenharmony_ci struct pci_epc *epc; 48362306a36Sopenharmony_ci int err; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); 48662306a36Sopenharmony_ci if (!ep) 48762306a36Sopenharmony_ci return -ENOMEM; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci pcie = &ep->pcie; 49062306a36Sopenharmony_ci pcie->dev = dev; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci pm_runtime_enable(dev); 49362306a36Sopenharmony_ci err = pm_runtime_resume_and_get(dev); 49462306a36Sopenharmony_ci if (err < 0) { 49562306a36Sopenharmony_ci dev_err(dev, "pm_runtime_resume_and_get failed\n"); 49662306a36Sopenharmony_ci goto err_pm_disable; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci err = rcar_pcie_ep_get_pdata(ep, pdev); 50062306a36Sopenharmony_ci if (err < 0) { 50162306a36Sopenharmony_ci dev_err(dev, "failed to request resources: %d\n", err); 50262306a36Sopenharmony_ci goto err_pm_put; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci ep->num_ib_windows = MAX_NR_INBOUND_MAPS; 50662306a36Sopenharmony_ci ep->ib_window_map = 50762306a36Sopenharmony_ci devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows), 50862306a36Sopenharmony_ci sizeof(long), GFP_KERNEL); 50962306a36Sopenharmony_ci if (!ep->ib_window_map) { 51062306a36Sopenharmony_ci err = -ENOMEM; 51162306a36Sopenharmony_ci dev_err(dev, "failed to allocate memory for inbound map\n"); 51262306a36Sopenharmony_ci goto err_pm_put; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci ep->ob_mapped_addr = devm_kcalloc(dev, ep->num_ob_windows, 51662306a36Sopenharmony_ci sizeof(*ep->ob_mapped_addr), 51762306a36Sopenharmony_ci GFP_KERNEL); 51862306a36Sopenharmony_ci if (!ep->ob_mapped_addr) { 51962306a36Sopenharmony_ci err = -ENOMEM; 52062306a36Sopenharmony_ci dev_err(dev, "failed to allocate memory for outbound memory pointers\n"); 52162306a36Sopenharmony_ci goto err_pm_put; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci epc = devm_pci_epc_create(dev, &rcar_pcie_epc_ops); 52562306a36Sopenharmony_ci if (IS_ERR(epc)) { 52662306a36Sopenharmony_ci dev_err(dev, "failed to create epc device\n"); 52762306a36Sopenharmony_ci err = PTR_ERR(epc); 52862306a36Sopenharmony_ci goto err_pm_put; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci epc->max_functions = ep->max_functions; 53262306a36Sopenharmony_ci epc_set_drvdata(epc, ep); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci rcar_pcie_ep_hw_init(pcie); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci err = pci_epc_multi_mem_init(epc, ep->ob_window, ep->num_ob_windows); 53762306a36Sopenharmony_ci if (err < 0) { 53862306a36Sopenharmony_ci dev_err(dev, "failed to initialize the epc memory space\n"); 53962306a36Sopenharmony_ci goto err_pm_put; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cierr_pm_put: 54562306a36Sopenharmony_ci pm_runtime_put(dev); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cierr_pm_disable: 54862306a36Sopenharmony_ci pm_runtime_disable(dev); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return err; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic struct platform_driver rcar_pcie_ep_driver = { 55462306a36Sopenharmony_ci .driver = { 55562306a36Sopenharmony_ci .name = "rcar-pcie-ep", 55662306a36Sopenharmony_ci .of_match_table = rcar_pcie_ep_of_match, 55762306a36Sopenharmony_ci .suppress_bind_attrs = true, 55862306a36Sopenharmony_ci }, 55962306a36Sopenharmony_ci .probe = rcar_pcie_ep_probe, 56062306a36Sopenharmony_ci}; 56162306a36Sopenharmony_cibuiltin_platform_driver(rcar_pcie_ep_driver); 562