162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Synopsys DesignWare PCIe Endpoint controller driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 Texas Instruments 662306a36Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/align.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "pcie-designware.h" 1462306a36Sopenharmony_ci#include <linux/pci-epc.h> 1562306a36Sopenharmony_ci#include <linux/pci-epf.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_civoid dw_pcie_ep_linkup(struct dw_pcie_ep *ep) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct pci_epc *epc = ep->epc; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci pci_epc_linkup(epc); 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_ep_linkup); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_civoid dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct pci_epc *epc = ep->epc; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci pci_epc_init_notify(epc); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct dw_pcie_ep_func * 3462306a36Sopenharmony_cidw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci list_for_each_entry(ep_func, &ep->func_list, list) { 3962306a36Sopenharmony_ci if (ep_func->func_no == func_no) 4062306a36Sopenharmony_ci return ep_func; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return NULL; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci unsigned int func_offset = 0; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (ep->ops->func_conf_select) 5162306a36Sopenharmony_ci func_offset = ep->ops->func_conf_select(ep, func_no); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return func_offset; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, 5762306a36Sopenharmony_ci enum pci_barno bar, int flags) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci u32 reg; 6062306a36Sopenharmony_ci unsigned int func_offset = 0; 6162306a36Sopenharmony_ci struct dw_pcie_ep *ep = &pci->ep; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar); 6662306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 6762306a36Sopenharmony_ci dw_pcie_writel_dbi2(pci, reg, 0x0); 6862306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, reg, 0x0); 6962306a36Sopenharmony_ci if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) { 7062306a36Sopenharmony_ci dw_pcie_writel_dbi2(pci, reg + 4, 0x0); 7162306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, reg + 4, 0x0); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_civoid dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci u8 func_no, funcs; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci funcs = pci->ep.epc->max_functions; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci for (func_no = 0; func_no < funcs; func_no++) 8362306a36Sopenharmony_ci __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, 8862306a36Sopenharmony_ci u8 cap_ptr, u8 cap) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 9162306a36Sopenharmony_ci unsigned int func_offset = 0; 9262306a36Sopenharmony_ci u8 cap_id, next_cap_ptr; 9362306a36Sopenharmony_ci u16 reg; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (!cap_ptr) 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr); 10162306a36Sopenharmony_ci cap_id = (reg & 0x00ff); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (cap_id > PCI_CAP_ID_MAX) 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (cap_id == cap) 10762306a36Sopenharmony_ci return cap_ptr; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci next_cap_ptr = (reg & 0xff00) >> 8; 11062306a36Sopenharmony_ci return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 11662306a36Sopenharmony_ci unsigned int func_offset = 0; 11762306a36Sopenharmony_ci u8 next_cap_ptr; 11862306a36Sopenharmony_ci u16 reg; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST); 12362306a36Sopenharmony_ci next_cap_ptr = (reg & 0x00ff); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 12962306a36Sopenharmony_ci struct pci_epf_header *hdr) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 13262306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 13362306a36Sopenharmony_ci unsigned int func_offset = 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 13862306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid); 13962306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid); 14062306a36Sopenharmony_ci dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid); 14162306a36Sopenharmony_ci dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code); 14262306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE, 14362306a36Sopenharmony_ci hdr->subclass_code | hdr->baseclass_code << 8); 14462306a36Sopenharmony_ci dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE, 14562306a36Sopenharmony_ci hdr->cache_line_size); 14662306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID, 14762306a36Sopenharmony_ci hdr->subsys_vendor_id); 14862306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id); 14962306a36Sopenharmony_ci dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN, 15062306a36Sopenharmony_ci hdr->interrupt_pin); 15162306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type, 15762306a36Sopenharmony_ci dma_addr_t cpu_addr, enum pci_barno bar) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci int ret; 16062306a36Sopenharmony_ci u32 free_win; 16162306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (!ep->bar_to_atu[bar]) 16462306a36Sopenharmony_ci free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows); 16562306a36Sopenharmony_ci else 16662306a36Sopenharmony_ci free_win = ep->bar_to_atu[bar]; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (free_win >= pci->num_ib_windows) { 16962306a36Sopenharmony_ci dev_err(pci->dev, "No free inbound window\n"); 17062306a36Sopenharmony_ci return -EINVAL; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci ret = dw_pcie_prog_ep_inbound_atu(pci, func_no, free_win, type, 17462306a36Sopenharmony_ci cpu_addr, bar); 17562306a36Sopenharmony_ci if (ret < 0) { 17662306a36Sopenharmony_ci dev_err(pci->dev, "Failed to program IB window\n"); 17762306a36Sopenharmony_ci return ret; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ep->bar_to_atu[bar] = free_win; 18162306a36Sopenharmony_ci set_bit(free_win, ep->ib_window_map); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no, 18762306a36Sopenharmony_ci phys_addr_t phys_addr, 18862306a36Sopenharmony_ci u64 pci_addr, size_t size) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 19162306a36Sopenharmony_ci u32 free_win; 19262306a36Sopenharmony_ci int ret; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci free_win = find_first_zero_bit(ep->ob_window_map, pci->num_ob_windows); 19562306a36Sopenharmony_ci if (free_win >= pci->num_ob_windows) { 19662306a36Sopenharmony_ci dev_err(pci->dev, "No free outbound window\n"); 19762306a36Sopenharmony_ci return -EINVAL; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ret = dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM, 20162306a36Sopenharmony_ci phys_addr, pci_addr, size); 20262306a36Sopenharmony_ci if (ret) 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci set_bit(free_win, ep->ob_window_map); 20662306a36Sopenharmony_ci ep->outbound_addr[free_win] = phys_addr; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 21262306a36Sopenharmony_ci struct pci_epf_bar *epf_bar) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 21562306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 21662306a36Sopenharmony_ci enum pci_barno bar = epf_bar->barno; 21762306a36Sopenharmony_ci u32 atu_index = ep->bar_to_atu[bar]; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); 22262306a36Sopenharmony_ci clear_bit(atu_index, ep->ib_window_map); 22362306a36Sopenharmony_ci ep->epf_bar[bar] = NULL; 22462306a36Sopenharmony_ci ep->bar_to_atu[bar] = 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 22862306a36Sopenharmony_ci struct pci_epf_bar *epf_bar) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 23162306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 23262306a36Sopenharmony_ci enum pci_barno bar = epf_bar->barno; 23362306a36Sopenharmony_ci size_t size = epf_bar->size; 23462306a36Sopenharmony_ci int flags = epf_bar->flags; 23562306a36Sopenharmony_ci unsigned int func_offset = 0; 23662306a36Sopenharmony_ci int ret, type; 23762306a36Sopenharmony_ci u32 reg; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!(flags & PCI_BASE_ADDRESS_SPACE)) 24462306a36Sopenharmony_ci type = PCIE_ATU_TYPE_MEM; 24562306a36Sopenharmony_ci else 24662306a36Sopenharmony_ci type = PCIE_ATU_TYPE_IO; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar); 24962306a36Sopenharmony_ci if (ret) 25062306a36Sopenharmony_ci return ret; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (ep->epf_bar[bar]) 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dw_pcie_writel_dbi2(pci, reg, lower_32_bits(size - 1)); 25862306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, reg, flags); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) { 26162306a36Sopenharmony_ci dw_pcie_writel_dbi2(pci, reg + 4, upper_32_bits(size - 1)); 26262306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, reg + 4, 0); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci ep->epf_bar[bar] = epf_bar; 26662306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr, 27262306a36Sopenharmony_ci u32 *atu_index) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci u32 index; 27562306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci for (index = 0; index < pci->num_ob_windows; index++) { 27862306a36Sopenharmony_ci if (ep->outbound_addr[index] != addr) 27962306a36Sopenharmony_ci continue; 28062306a36Sopenharmony_ci *atu_index = index; 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return -EINVAL; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void dw_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 28862306a36Sopenharmony_ci phys_addr_t addr) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci int ret; 29162306a36Sopenharmony_ci u32 atu_index; 29262306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 29362306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ret = dw_pcie_find_index(ep, addr, &atu_index); 29662306a36Sopenharmony_ci if (ret < 0) 29762306a36Sopenharmony_ci return; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, atu_index); 30062306a36Sopenharmony_ci clear_bit(atu_index, ep->ob_window_map); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 30462306a36Sopenharmony_ci phys_addr_t addr, u64 pci_addr, size_t size) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci int ret; 30762306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 30862306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ret = dw_pcie_ep_outbound_atu(ep, func_no, addr, pci_addr, size); 31162306a36Sopenharmony_ci if (ret) { 31262306a36Sopenharmony_ci dev_err(pci->dev, "Failed to enable address\n"); 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 32262306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 32362306a36Sopenharmony_ci u32 val, reg; 32462306a36Sopenharmony_ci unsigned int func_offset = 0; 32562306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); 32862306a36Sopenharmony_ci if (!ep_func || !ep_func->msi_cap) 32962306a36Sopenharmony_ci return -EINVAL; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; 33462306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, reg); 33562306a36Sopenharmony_ci if (!(val & PCI_MSI_FLAGS_ENABLE)) 33662306a36Sopenharmony_ci return -EINVAL; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci val = (val & PCI_MSI_FLAGS_QSIZE) >> 4; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return val; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 34462306a36Sopenharmony_ci u8 interrupts) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 34762306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 34862306a36Sopenharmony_ci u32 val, reg; 34962306a36Sopenharmony_ci unsigned int func_offset = 0; 35062306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); 35362306a36Sopenharmony_ci if (!ep_func || !ep_func->msi_cap) 35462306a36Sopenharmony_ci return -EINVAL; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; 35962306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, reg); 36062306a36Sopenharmony_ci val &= ~PCI_MSI_FLAGS_QMASK; 36162306a36Sopenharmony_ci val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; 36262306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 36362306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, reg, val); 36462306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 37262306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 37362306a36Sopenharmony_ci u32 val, reg; 37462306a36Sopenharmony_ci unsigned int func_offset = 0; 37562306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); 37862306a36Sopenharmony_ci if (!ep_func || !ep_func->msix_cap) 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS; 38462306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, reg); 38562306a36Sopenharmony_ci if (!(val & PCI_MSIX_FLAGS_ENABLE)) 38662306a36Sopenharmony_ci return -EINVAL; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci val &= PCI_MSIX_FLAGS_QSIZE; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return val; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 39462306a36Sopenharmony_ci u16 interrupts, enum pci_barno bir, u32 offset) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 39762306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 39862306a36Sopenharmony_ci u32 val, reg; 39962306a36Sopenharmony_ci unsigned int func_offset = 0; 40062306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); 40362306a36Sopenharmony_ci if (!ep_func || !ep_func->msix_cap) 40462306a36Sopenharmony_ci return -EINVAL; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS; 41162306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, reg); 41262306a36Sopenharmony_ci val &= ~PCI_MSIX_FLAGS_QSIZE; 41362306a36Sopenharmony_ci val |= interrupts; 41462306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, reg, val); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE; 41762306a36Sopenharmony_ci val = offset | bir; 41862306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, reg, val); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci reg = ep_func->msix_cap + func_offset + PCI_MSIX_PBA; 42162306a36Sopenharmony_ci val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; 42262306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, reg, val); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 43062306a36Sopenharmony_ci enum pci_epc_irq_type type, u16 interrupt_num) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (!ep->ops->raise_irq) 43562306a36Sopenharmony_ci return -EINVAL; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return ep->ops->raise_irq(ep, func_no, type, interrupt_num); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void dw_pcie_ep_stop(struct pci_epc *epc) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 44362306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci dw_pcie_stop_link(pci); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int dw_pcie_ep_start(struct pci_epc *epc) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 45162306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return dw_pcie_start_link(pci); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic const struct pci_epc_features* 45762306a36Sopenharmony_cidw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct dw_pcie_ep *ep = epc_get_drvdata(epc); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (!ep->ops->get_features) 46262306a36Sopenharmony_ci return NULL; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return ep->ops->get_features(ep); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic const struct pci_epc_ops epc_ops = { 46862306a36Sopenharmony_ci .write_header = dw_pcie_ep_write_header, 46962306a36Sopenharmony_ci .set_bar = dw_pcie_ep_set_bar, 47062306a36Sopenharmony_ci .clear_bar = dw_pcie_ep_clear_bar, 47162306a36Sopenharmony_ci .map_addr = dw_pcie_ep_map_addr, 47262306a36Sopenharmony_ci .unmap_addr = dw_pcie_ep_unmap_addr, 47362306a36Sopenharmony_ci .set_msi = dw_pcie_ep_set_msi, 47462306a36Sopenharmony_ci .get_msi = dw_pcie_ep_get_msi, 47562306a36Sopenharmony_ci .set_msix = dw_pcie_ep_set_msix, 47662306a36Sopenharmony_ci .get_msix = dw_pcie_ep_get_msix, 47762306a36Sopenharmony_ci .raise_irq = dw_pcie_ep_raise_irq, 47862306a36Sopenharmony_ci .start = dw_pcie_ep_start, 47962306a36Sopenharmony_ci .stop = dw_pcie_ep_stop, 48062306a36Sopenharmony_ci .get_features = dw_pcie_ep_get_features, 48162306a36Sopenharmony_ci}; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ciint dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 48662306a36Sopenharmony_ci struct device *dev = pci->dev; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci dev_err(dev, "EP cannot trigger legacy IRQs\n"); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return -EINVAL; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_ep_raise_legacy_irq); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciint dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, 49562306a36Sopenharmony_ci u8 interrupt_num) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 49862306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 49962306a36Sopenharmony_ci struct pci_epc *epc = ep->epc; 50062306a36Sopenharmony_ci unsigned int aligned_offset; 50162306a36Sopenharmony_ci unsigned int func_offset = 0; 50262306a36Sopenharmony_ci u16 msg_ctrl, msg_data; 50362306a36Sopenharmony_ci u32 msg_addr_lower, msg_addr_upper, reg; 50462306a36Sopenharmony_ci u64 msg_addr; 50562306a36Sopenharmony_ci bool has_upper; 50662306a36Sopenharmony_ci int ret; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); 50962306a36Sopenharmony_ci if (!ep_func || !ep_func->msi_cap) 51062306a36Sopenharmony_ci return -EINVAL; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ 51562306a36Sopenharmony_ci reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; 51662306a36Sopenharmony_ci msg_ctrl = dw_pcie_readw_dbi(pci, reg); 51762306a36Sopenharmony_ci has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); 51862306a36Sopenharmony_ci reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_LO; 51962306a36Sopenharmony_ci msg_addr_lower = dw_pcie_readl_dbi(pci, reg); 52062306a36Sopenharmony_ci if (has_upper) { 52162306a36Sopenharmony_ci reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_HI; 52262306a36Sopenharmony_ci msg_addr_upper = dw_pcie_readl_dbi(pci, reg); 52362306a36Sopenharmony_ci reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_64; 52462306a36Sopenharmony_ci msg_data = dw_pcie_readw_dbi(pci, reg); 52562306a36Sopenharmony_ci } else { 52662306a36Sopenharmony_ci msg_addr_upper = 0; 52762306a36Sopenharmony_ci reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_32; 52862306a36Sopenharmony_ci msg_data = dw_pcie_readw_dbi(pci, reg); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1); 53162306a36Sopenharmony_ci msg_addr = ((u64)msg_addr_upper) << 32 | 53262306a36Sopenharmony_ci (msg_addr_lower & ~aligned_offset); 53362306a36Sopenharmony_ci ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, 53462306a36Sopenharmony_ci epc->mem->window.page_size); 53562306a36Sopenharmony_ci if (ret) 53662306a36Sopenharmony_ci return ret; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci writel(msg_data | (interrupt_num - 1), ep->msi_mem + aligned_offset); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_ep_raise_msi_irq); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ciint dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, 54762306a36Sopenharmony_ci u16 interrupt_num) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 55062306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 55162306a36Sopenharmony_ci u32 msg_data; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); 55462306a36Sopenharmony_ci if (!ep_func || !ep_func->msix_cap) 55562306a36Sopenharmony_ci return -EINVAL; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) | 55862306a36Sopenharmony_ci (interrupt_num - 1); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ciint dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, 56662306a36Sopenharmony_ci u16 interrupt_num) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 56962306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 57062306a36Sopenharmony_ci struct pci_epf_msix_tbl *msix_tbl; 57162306a36Sopenharmony_ci struct pci_epc *epc = ep->epc; 57262306a36Sopenharmony_ci unsigned int func_offset = 0; 57362306a36Sopenharmony_ci u32 reg, msg_data, vec_ctrl; 57462306a36Sopenharmony_ci unsigned int aligned_offset; 57562306a36Sopenharmony_ci u32 tbl_offset; 57662306a36Sopenharmony_ci u64 msg_addr; 57762306a36Sopenharmony_ci int ret; 57862306a36Sopenharmony_ci u8 bir; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); 58162306a36Sopenharmony_ci if (!ep_func || !ep_func->msix_cap) 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci func_offset = dw_pcie_ep_func_select(ep, func_no); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE; 58762306a36Sopenharmony_ci tbl_offset = dw_pcie_readl_dbi(pci, reg); 58862306a36Sopenharmony_ci bir = (tbl_offset & PCI_MSIX_TABLE_BIR); 58962306a36Sopenharmony_ci tbl_offset &= PCI_MSIX_TABLE_OFFSET; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci msix_tbl = ep->epf_bar[bir]->addr + tbl_offset; 59262306a36Sopenharmony_ci msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr; 59362306a36Sopenharmony_ci msg_data = msix_tbl[(interrupt_num - 1)].msg_data; 59462306a36Sopenharmony_ci vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) { 59762306a36Sopenharmony_ci dev_dbg(pci->dev, "MSI-X entry ctrl set\n"); 59862306a36Sopenharmony_ci return -EPERM; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci aligned_offset = msg_addr & (epc->mem->window.page_size - 1); 60262306a36Sopenharmony_ci msg_addr = ALIGN_DOWN(msg_addr, epc->mem->window.page_size); 60362306a36Sopenharmony_ci ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, 60462306a36Sopenharmony_ci epc->mem->window.page_size); 60562306a36Sopenharmony_ci if (ret) 60662306a36Sopenharmony_ci return ret; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci writel(msg_data, ep->msi_mem + aligned_offset); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_civoid dw_pcie_ep_exit(struct dw_pcie_ep *ep) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 61862306a36Sopenharmony_ci struct pci_epc *epc = ep->epc; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci dw_pcie_edma_remove(pci); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, 62362306a36Sopenharmony_ci epc->mem->window.page_size); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci pci_epc_mem_exit(epc); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci u32 header; 63162306a36Sopenharmony_ci int pos = PCI_CFG_SPACE_SIZE; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci while (pos) { 63462306a36Sopenharmony_ci header = dw_pcie_readl_dbi(pci, pos); 63562306a36Sopenharmony_ci if (PCI_EXT_CAP_ID(header) == cap) 63662306a36Sopenharmony_ci return pos; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci pos = PCI_EXT_CAP_NEXT(header); 63962306a36Sopenharmony_ci if (!pos) 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ciint dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 64962306a36Sopenharmony_ci unsigned int offset, ptm_cap_base; 65062306a36Sopenharmony_ci unsigned int nbars; 65162306a36Sopenharmony_ci u8 hdr_type; 65262306a36Sopenharmony_ci u32 reg; 65362306a36Sopenharmony_ci int i; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) & 65662306a36Sopenharmony_ci PCI_HEADER_TYPE_MASK; 65762306a36Sopenharmony_ci if (hdr_type != PCI_HEADER_TYPE_NORMAL) { 65862306a36Sopenharmony_ci dev_err(pci->dev, 65962306a36Sopenharmony_ci "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n", 66062306a36Sopenharmony_ci hdr_type); 66162306a36Sopenharmony_ci return -EIO; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); 66562306a36Sopenharmony_ci ptm_cap_base = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_PTM); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (offset) { 67062306a36Sopenharmony_ci reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); 67162306a36Sopenharmony_ci nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> 67262306a36Sopenharmony_ci PCI_REBAR_CTRL_NBAR_SHIFT; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * PCIe r6.0, sec 7.8.6.2 require us to support at least one 67662306a36Sopenharmony_ci * size in the range from 1 MB to 512 GB. Advertise support 67762306a36Sopenharmony_ci * for 1 MB BAR size only. 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) 68062306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, BIT(4)); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* 68462306a36Sopenharmony_ci * PTM responder capability can be disabled only after disabling 68562306a36Sopenharmony_ci * PTM root capability. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ci if (ptm_cap_base) { 68862306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_en(pci); 68962306a36Sopenharmony_ci reg = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP); 69062306a36Sopenharmony_ci reg &= ~PCI_PTM_CAP_ROOT; 69162306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, reg); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci reg = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP); 69462306a36Sopenharmony_ci reg &= ~(PCI_PTM_CAP_RES | PCI_PTM_GRANULARITY_MASK); 69562306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, reg); 69662306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci dw_pcie_setup(pci); 70062306a36Sopenharmony_ci dw_pcie_dbi_ro_wr_dis(pci); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci return 0; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ciint dw_pcie_ep_init(struct dw_pcie_ep *ep) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci int ret; 70962306a36Sopenharmony_ci void *addr; 71062306a36Sopenharmony_ci u8 func_no; 71162306a36Sopenharmony_ci struct resource *res; 71262306a36Sopenharmony_ci struct pci_epc *epc; 71362306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 71462306a36Sopenharmony_ci struct device *dev = pci->dev; 71562306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 71662306a36Sopenharmony_ci struct device_node *np = dev->of_node; 71762306a36Sopenharmony_ci const struct pci_epc_features *epc_features; 71862306a36Sopenharmony_ci struct dw_pcie_ep_func *ep_func; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci INIT_LIST_HEAD(&ep->func_list); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ret = dw_pcie_get_resources(pci); 72362306a36Sopenharmony_ci if (ret) 72462306a36Sopenharmony_ci return ret; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 72762306a36Sopenharmony_ci if (!res) 72862306a36Sopenharmony_ci return -EINVAL; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ep->phys_base = res->start; 73162306a36Sopenharmony_ci ep->addr_size = resource_size(res); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci dw_pcie_version_detect(pci); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci dw_pcie_iatu_detect(pci); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci ep->ib_window_map = devm_bitmap_zalloc(dev, pci->num_ib_windows, 73862306a36Sopenharmony_ci GFP_KERNEL); 73962306a36Sopenharmony_ci if (!ep->ib_window_map) 74062306a36Sopenharmony_ci return -ENOMEM; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci ep->ob_window_map = devm_bitmap_zalloc(dev, pci->num_ob_windows, 74362306a36Sopenharmony_ci GFP_KERNEL); 74462306a36Sopenharmony_ci if (!ep->ob_window_map) 74562306a36Sopenharmony_ci return -ENOMEM; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t), 74862306a36Sopenharmony_ci GFP_KERNEL); 74962306a36Sopenharmony_ci if (!addr) 75062306a36Sopenharmony_ci return -ENOMEM; 75162306a36Sopenharmony_ci ep->outbound_addr = addr; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci epc = devm_pci_epc_create(dev, &epc_ops); 75462306a36Sopenharmony_ci if (IS_ERR(epc)) { 75562306a36Sopenharmony_ci dev_err(dev, "Failed to create epc device\n"); 75662306a36Sopenharmony_ci return PTR_ERR(epc); 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci ep->epc = epc; 76062306a36Sopenharmony_ci epc_set_drvdata(epc, ep); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci ret = of_property_read_u8(np, "max-functions", &epc->max_functions); 76362306a36Sopenharmony_ci if (ret < 0) 76462306a36Sopenharmony_ci epc->max_functions = 1; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci for (func_no = 0; func_no < epc->max_functions; func_no++) { 76762306a36Sopenharmony_ci ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL); 76862306a36Sopenharmony_ci if (!ep_func) 76962306a36Sopenharmony_ci return -ENOMEM; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci ep_func->func_no = func_no; 77262306a36Sopenharmony_ci ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no, 77362306a36Sopenharmony_ci PCI_CAP_ID_MSI); 77462306a36Sopenharmony_ci ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no, 77562306a36Sopenharmony_ci PCI_CAP_ID_MSIX); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci list_add_tail(&ep_func->list, &ep->func_list); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (ep->ops->ep_init) 78162306a36Sopenharmony_ci ep->ops->ep_init(ep); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size, 78462306a36Sopenharmony_ci ep->page_size); 78562306a36Sopenharmony_ci if (ret < 0) { 78662306a36Sopenharmony_ci dev_err(dev, "Failed to initialize address space\n"); 78762306a36Sopenharmony_ci return ret; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, 79162306a36Sopenharmony_ci epc->mem->window.page_size); 79262306a36Sopenharmony_ci if (!ep->msi_mem) { 79362306a36Sopenharmony_ci ret = -ENOMEM; 79462306a36Sopenharmony_ci dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n"); 79562306a36Sopenharmony_ci goto err_exit_epc_mem; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci ret = dw_pcie_edma_detect(pci); 79962306a36Sopenharmony_ci if (ret) 80062306a36Sopenharmony_ci goto err_free_epc_mem; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (ep->ops->get_features) { 80362306a36Sopenharmony_ci epc_features = ep->ops->get_features(ep); 80462306a36Sopenharmony_ci if (epc_features->core_init_notifier) 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci ret = dw_pcie_ep_init_complete(ep); 80962306a36Sopenharmony_ci if (ret) 81062306a36Sopenharmony_ci goto err_remove_edma; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cierr_remove_edma: 81562306a36Sopenharmony_ci dw_pcie_edma_remove(pci); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cierr_free_epc_mem: 81862306a36Sopenharmony_ci pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, 81962306a36Sopenharmony_ci epc->mem->window.page_size); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cierr_exit_epc_mem: 82262306a36Sopenharmony_ci pci_epc_mem_exit(epc); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return ret; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_pcie_ep_init); 827