162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCI EPF driver for MHI Endpoint devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2023 Linaro Ltd. 662306a36Sopenharmony_ci * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/dmaengine.h> 1062306a36Sopenharmony_ci#include <linux/mhi_ep.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/of_dma.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/pci-epc.h> 1562306a36Sopenharmony_ci#include <linux/pci-epf.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define MHI_VERSION_1_0 0x01000000 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define to_epf_mhi(cntrl) container_of(cntrl, struct pci_epf_mhi, cntrl) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Platform specific flags */ 2262306a36Sopenharmony_ci#define MHI_EPF_USE_DMA BIT(0) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct pci_epf_mhi_ep_info { 2562306a36Sopenharmony_ci const struct mhi_ep_cntrl_config *config; 2662306a36Sopenharmony_ci struct pci_epf_header *epf_header; 2762306a36Sopenharmony_ci enum pci_barno bar_num; 2862306a36Sopenharmony_ci u32 epf_flags; 2962306a36Sopenharmony_ci u32 msi_count; 3062306a36Sopenharmony_ci u32 mru; 3162306a36Sopenharmony_ci u32 flags; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define MHI_EP_CHANNEL_CONFIG(ch_num, ch_name, direction) \ 3562306a36Sopenharmony_ci { \ 3662306a36Sopenharmony_ci .num = ch_num, \ 3762306a36Sopenharmony_ci .name = ch_name, \ 3862306a36Sopenharmony_ci .dir = direction, \ 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define MHI_EP_CHANNEL_CONFIG_UL(ch_num, ch_name) \ 4262306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG(ch_num, ch_name, DMA_TO_DEVICE) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define MHI_EP_CHANNEL_CONFIG_DL(ch_num, ch_name) \ 4562306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG(ch_num, ch_name, DMA_FROM_DEVICE) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const struct mhi_ep_channel_config mhi_v1_channels[] = { 4862306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(0, "LOOPBACK"), 4962306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(1, "LOOPBACK"), 5062306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(2, "SAHARA"), 5162306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(3, "SAHARA"), 5262306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(4, "DIAG"), 5362306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(5, "DIAG"), 5462306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(6, "SSR"), 5562306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(7, "SSR"), 5662306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(8, "QDSS"), 5762306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(9, "QDSS"), 5862306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(10, "EFS"), 5962306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(11, "EFS"), 6062306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(12, "MBIM"), 6162306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(13, "MBIM"), 6262306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(14, "QMI"), 6362306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(15, "QMI"), 6462306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(16, "QMI"), 6562306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(17, "QMI"), 6662306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(18, "IP-CTRL-1"), 6762306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(19, "IP-CTRL-1"), 6862306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(20, "IPCR"), 6962306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(21, "IPCR"), 7062306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(32, "DUN"), 7162306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(33, "DUN"), 7262306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_UL(46, "IP_SW0"), 7362306a36Sopenharmony_ci MHI_EP_CHANNEL_CONFIG_DL(47, "IP_SW0"), 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const struct mhi_ep_cntrl_config mhi_v1_config = { 7762306a36Sopenharmony_ci .max_channels = 128, 7862306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(mhi_v1_channels), 7962306a36Sopenharmony_ci .ch_cfg = mhi_v1_channels, 8062306a36Sopenharmony_ci .mhi_version = MHI_VERSION_1_0, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct pci_epf_header sdx55_header = { 8462306a36Sopenharmony_ci .vendorid = PCI_VENDOR_ID_QCOM, 8562306a36Sopenharmony_ci .deviceid = 0x0306, 8662306a36Sopenharmony_ci .baseclass_code = PCI_BASE_CLASS_COMMUNICATION, 8762306a36Sopenharmony_ci .subclass_code = PCI_CLASS_COMMUNICATION_MODEM & 0xff, 8862306a36Sopenharmony_ci .interrupt_pin = PCI_INTERRUPT_INTA, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct pci_epf_mhi_ep_info sdx55_info = { 9262306a36Sopenharmony_ci .config = &mhi_v1_config, 9362306a36Sopenharmony_ci .epf_header = &sdx55_header, 9462306a36Sopenharmony_ci .bar_num = BAR_0, 9562306a36Sopenharmony_ci .epf_flags = PCI_BASE_ADDRESS_MEM_TYPE_32, 9662306a36Sopenharmony_ci .msi_count = 32, 9762306a36Sopenharmony_ci .mru = 0x8000, 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic struct pci_epf_header sm8450_header = { 10162306a36Sopenharmony_ci .vendorid = PCI_VENDOR_ID_QCOM, 10262306a36Sopenharmony_ci .deviceid = 0x0306, 10362306a36Sopenharmony_ci .baseclass_code = PCI_CLASS_OTHERS, 10462306a36Sopenharmony_ci .interrupt_pin = PCI_INTERRUPT_INTA, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic const struct pci_epf_mhi_ep_info sm8450_info = { 10862306a36Sopenharmony_ci .config = &mhi_v1_config, 10962306a36Sopenharmony_ci .epf_header = &sm8450_header, 11062306a36Sopenharmony_ci .bar_num = BAR_0, 11162306a36Sopenharmony_ci .epf_flags = PCI_BASE_ADDRESS_MEM_TYPE_32, 11262306a36Sopenharmony_ci .msi_count = 32, 11362306a36Sopenharmony_ci .mru = 0x8000, 11462306a36Sopenharmony_ci .flags = MHI_EPF_USE_DMA, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistruct pci_epf_mhi { 11862306a36Sopenharmony_ci const struct pci_epc_features *epc_features; 11962306a36Sopenharmony_ci const struct pci_epf_mhi_ep_info *info; 12062306a36Sopenharmony_ci struct mhi_ep_cntrl mhi_cntrl; 12162306a36Sopenharmony_ci struct pci_epf *epf; 12262306a36Sopenharmony_ci struct mutex lock; 12362306a36Sopenharmony_ci void __iomem *mmio; 12462306a36Sopenharmony_ci resource_size_t mmio_phys; 12562306a36Sopenharmony_ci struct dma_chan *dma_chan_tx; 12662306a36Sopenharmony_ci struct dma_chan *dma_chan_rx; 12762306a36Sopenharmony_ci u32 mmio_size; 12862306a36Sopenharmony_ci int irq; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic size_t get_align_offset(struct pci_epf_mhi *epf_mhi, u64 addr) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci return addr & (epf_mhi->epc_features->align -1); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int __pci_epf_mhi_alloc_map(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, 13762306a36Sopenharmony_ci phys_addr_t *paddr, void __iomem **vaddr, 13862306a36Sopenharmony_ci size_t offset, size_t size) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 14162306a36Sopenharmony_ci struct pci_epf *epf = epf_mhi->epf; 14262306a36Sopenharmony_ci struct pci_epc *epc = epf->epc; 14362306a36Sopenharmony_ci int ret; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci *vaddr = pci_epc_mem_alloc_addr(epc, paddr, size + offset); 14662306a36Sopenharmony_ci if (!*vaddr) 14762306a36Sopenharmony_ci return -ENOMEM; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, *paddr, 15062306a36Sopenharmony_ci pci_addr - offset, size + offset); 15162306a36Sopenharmony_ci if (ret) { 15262306a36Sopenharmony_ci pci_epc_mem_free_addr(epc, *paddr, *vaddr, size + offset); 15362306a36Sopenharmony_ci return ret; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci *paddr = *paddr + offset; 15762306a36Sopenharmony_ci *vaddr = *vaddr + offset; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int pci_epf_mhi_alloc_map(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, 16362306a36Sopenharmony_ci phys_addr_t *paddr, void __iomem **vaddr, 16462306a36Sopenharmony_ci size_t size) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 16762306a36Sopenharmony_ci size_t offset = get_align_offset(epf_mhi, pci_addr); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return __pci_epf_mhi_alloc_map(mhi_cntrl, pci_addr, paddr, vaddr, 17062306a36Sopenharmony_ci offset, size); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic void __pci_epf_mhi_unmap_free(struct mhi_ep_cntrl *mhi_cntrl, 17462306a36Sopenharmony_ci u64 pci_addr, phys_addr_t paddr, 17562306a36Sopenharmony_ci void __iomem *vaddr, size_t offset, 17662306a36Sopenharmony_ci size_t size) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 17962306a36Sopenharmony_ci struct pci_epf *epf = epf_mhi->epf; 18062306a36Sopenharmony_ci struct pci_epc *epc = epf->epc; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, paddr - offset); 18362306a36Sopenharmony_ci pci_epc_mem_free_addr(epc, paddr - offset, vaddr - offset, 18462306a36Sopenharmony_ci size + offset); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void pci_epf_mhi_unmap_free(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, 18862306a36Sopenharmony_ci phys_addr_t paddr, void __iomem *vaddr, 18962306a36Sopenharmony_ci size_t size) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 19262306a36Sopenharmony_ci size_t offset = get_align_offset(epf_mhi, pci_addr); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci __pci_epf_mhi_unmap_free(mhi_cntrl, pci_addr, paddr, vaddr, offset, 19562306a36Sopenharmony_ci size); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void pci_epf_mhi_raise_irq(struct mhi_ep_cntrl *mhi_cntrl, u32 vector) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 20162306a36Sopenharmony_ci struct pci_epf *epf = epf_mhi->epf; 20262306a36Sopenharmony_ci struct pci_epc *epc = epf->epc; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* 20562306a36Sopenharmony_ci * MHI supplies 0 based MSI vectors but the API expects the vector 20662306a36Sopenharmony_ci * number to start from 1, so we need to increment the vector by 1. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no, PCI_EPC_IRQ_MSI, 20962306a36Sopenharmony_ci vector + 1); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int pci_epf_mhi_iatu_read(struct mhi_ep_cntrl *mhi_cntrl, 21362306a36Sopenharmony_ci struct mhi_ep_buf_info *buf_info) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 21662306a36Sopenharmony_ci size_t offset = get_align_offset(epf_mhi, buf_info->host_addr); 21762306a36Sopenharmony_ci void __iomem *tre_buf; 21862306a36Sopenharmony_ci phys_addr_t tre_phys; 21962306a36Sopenharmony_ci int ret; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci mutex_lock(&epf_mhi->lock); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = __pci_epf_mhi_alloc_map(mhi_cntrl, buf_info->host_addr, &tre_phys, 22462306a36Sopenharmony_ci &tre_buf, offset, buf_info->size); 22562306a36Sopenharmony_ci if (ret) { 22662306a36Sopenharmony_ci mutex_unlock(&epf_mhi->lock); 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci memcpy_fromio(buf_info->dev_addr, tre_buf, buf_info->size); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci __pci_epf_mhi_unmap_free(mhi_cntrl, buf_info->host_addr, tre_phys, 23362306a36Sopenharmony_ci tre_buf, offset, buf_info->size); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci mutex_unlock(&epf_mhi->lock); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int pci_epf_mhi_iatu_write(struct mhi_ep_cntrl *mhi_cntrl, 24162306a36Sopenharmony_ci struct mhi_ep_buf_info *buf_info) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 24462306a36Sopenharmony_ci size_t offset = get_align_offset(epf_mhi, buf_info->host_addr); 24562306a36Sopenharmony_ci void __iomem *tre_buf; 24662306a36Sopenharmony_ci phys_addr_t tre_phys; 24762306a36Sopenharmony_ci int ret; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci mutex_lock(&epf_mhi->lock); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = __pci_epf_mhi_alloc_map(mhi_cntrl, buf_info->host_addr, &tre_phys, 25262306a36Sopenharmony_ci &tre_buf, offset, buf_info->size); 25362306a36Sopenharmony_ci if (ret) { 25462306a36Sopenharmony_ci mutex_unlock(&epf_mhi->lock); 25562306a36Sopenharmony_ci return ret; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci memcpy_toio(tre_buf, buf_info->dev_addr, buf_info->size); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci __pci_epf_mhi_unmap_free(mhi_cntrl, buf_info->host_addr, tre_phys, 26162306a36Sopenharmony_ci tre_buf, offset, buf_info->size); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci mutex_unlock(&epf_mhi->lock); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic void pci_epf_mhi_dma_callback(void *param) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci complete(param); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl, 27462306a36Sopenharmony_ci struct mhi_ep_buf_info *buf_info) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 27762306a36Sopenharmony_ci struct device *dma_dev = epf_mhi->epf->epc->dev.parent; 27862306a36Sopenharmony_ci struct dma_chan *chan = epf_mhi->dma_chan_rx; 27962306a36Sopenharmony_ci struct device *dev = &epf_mhi->epf->dev; 28062306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(complete); 28162306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc; 28262306a36Sopenharmony_ci struct dma_slave_config config = {}; 28362306a36Sopenharmony_ci dma_cookie_t cookie; 28462306a36Sopenharmony_ci dma_addr_t dst_addr; 28562306a36Sopenharmony_ci int ret; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (buf_info->size < SZ_4K) 28862306a36Sopenharmony_ci return pci_epf_mhi_iatu_read(mhi_cntrl, buf_info); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci mutex_lock(&epf_mhi->lock); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci config.direction = DMA_DEV_TO_MEM; 29362306a36Sopenharmony_ci config.src_addr = buf_info->host_addr; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ret = dmaengine_slave_config(chan, &config); 29662306a36Sopenharmony_ci if (ret) { 29762306a36Sopenharmony_ci dev_err(dev, "Failed to configure DMA channel\n"); 29862306a36Sopenharmony_ci goto err_unlock; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size, 30262306a36Sopenharmony_ci DMA_FROM_DEVICE); 30362306a36Sopenharmony_ci ret = dma_mapping_error(dma_dev, dst_addr); 30462306a36Sopenharmony_ci if (ret) { 30562306a36Sopenharmony_ci dev_err(dev, "Failed to map remote memory\n"); 30662306a36Sopenharmony_ci goto err_unlock; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size, 31062306a36Sopenharmony_ci DMA_DEV_TO_MEM, 31162306a36Sopenharmony_ci DMA_CTRL_ACK | DMA_PREP_INTERRUPT); 31262306a36Sopenharmony_ci if (!desc) { 31362306a36Sopenharmony_ci dev_err(dev, "Failed to prepare DMA\n"); 31462306a36Sopenharmony_ci ret = -EIO; 31562306a36Sopenharmony_ci goto err_unmap; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci desc->callback = pci_epf_mhi_dma_callback; 31962306a36Sopenharmony_ci desc->callback_param = &complete; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci cookie = dmaengine_submit(desc); 32262306a36Sopenharmony_ci ret = dma_submit_error(cookie); 32362306a36Sopenharmony_ci if (ret) { 32462306a36Sopenharmony_ci dev_err(dev, "Failed to do DMA submit\n"); 32562306a36Sopenharmony_ci goto err_unmap; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci dma_async_issue_pending(chan); 32962306a36Sopenharmony_ci ret = wait_for_completion_timeout(&complete, msecs_to_jiffies(1000)); 33062306a36Sopenharmony_ci if (!ret) { 33162306a36Sopenharmony_ci dev_err(dev, "DMA transfer timeout\n"); 33262306a36Sopenharmony_ci dmaengine_terminate_sync(chan); 33362306a36Sopenharmony_ci ret = -ETIMEDOUT; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cierr_unmap: 33762306a36Sopenharmony_ci dma_unmap_single(dma_dev, dst_addr, buf_info->size, DMA_FROM_DEVICE); 33862306a36Sopenharmony_cierr_unlock: 33962306a36Sopenharmony_ci mutex_unlock(&epf_mhi->lock); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return ret; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl, 34562306a36Sopenharmony_ci struct mhi_ep_buf_info *buf_info) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl); 34862306a36Sopenharmony_ci struct device *dma_dev = epf_mhi->epf->epc->dev.parent; 34962306a36Sopenharmony_ci struct dma_chan *chan = epf_mhi->dma_chan_tx; 35062306a36Sopenharmony_ci struct device *dev = &epf_mhi->epf->dev; 35162306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(complete); 35262306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc; 35362306a36Sopenharmony_ci struct dma_slave_config config = {}; 35462306a36Sopenharmony_ci dma_cookie_t cookie; 35562306a36Sopenharmony_ci dma_addr_t src_addr; 35662306a36Sopenharmony_ci int ret; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (buf_info->size < SZ_4K) 35962306a36Sopenharmony_ci return pci_epf_mhi_iatu_write(mhi_cntrl, buf_info); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mutex_lock(&epf_mhi->lock); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci config.direction = DMA_MEM_TO_DEV; 36462306a36Sopenharmony_ci config.dst_addr = buf_info->host_addr; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci ret = dmaengine_slave_config(chan, &config); 36762306a36Sopenharmony_ci if (ret) { 36862306a36Sopenharmony_ci dev_err(dev, "Failed to configure DMA channel\n"); 36962306a36Sopenharmony_ci goto err_unlock; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size, 37362306a36Sopenharmony_ci DMA_TO_DEVICE); 37462306a36Sopenharmony_ci ret = dma_mapping_error(dma_dev, src_addr); 37562306a36Sopenharmony_ci if (ret) { 37662306a36Sopenharmony_ci dev_err(dev, "Failed to map remote memory\n"); 37762306a36Sopenharmony_ci goto err_unlock; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size, 38162306a36Sopenharmony_ci DMA_MEM_TO_DEV, 38262306a36Sopenharmony_ci DMA_CTRL_ACK | DMA_PREP_INTERRUPT); 38362306a36Sopenharmony_ci if (!desc) { 38462306a36Sopenharmony_ci dev_err(dev, "Failed to prepare DMA\n"); 38562306a36Sopenharmony_ci ret = -EIO; 38662306a36Sopenharmony_ci goto err_unmap; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci desc->callback = pci_epf_mhi_dma_callback; 39062306a36Sopenharmony_ci desc->callback_param = &complete; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci cookie = dmaengine_submit(desc); 39362306a36Sopenharmony_ci ret = dma_submit_error(cookie); 39462306a36Sopenharmony_ci if (ret) { 39562306a36Sopenharmony_ci dev_err(dev, "Failed to do DMA submit\n"); 39662306a36Sopenharmony_ci goto err_unmap; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci dma_async_issue_pending(chan); 40062306a36Sopenharmony_ci ret = wait_for_completion_timeout(&complete, msecs_to_jiffies(1000)); 40162306a36Sopenharmony_ci if (!ret) { 40262306a36Sopenharmony_ci dev_err(dev, "DMA transfer timeout\n"); 40362306a36Sopenharmony_ci dmaengine_terminate_sync(chan); 40462306a36Sopenharmony_ci ret = -ETIMEDOUT; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cierr_unmap: 40862306a36Sopenharmony_ci dma_unmap_single(dma_dev, src_addr, buf_info->size, DMA_TO_DEVICE); 40962306a36Sopenharmony_cierr_unlock: 41062306a36Sopenharmony_ci mutex_unlock(&epf_mhi->lock); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistruct epf_dma_filter { 41662306a36Sopenharmony_ci struct device *dev; 41762306a36Sopenharmony_ci u32 dma_mask; 41862306a36Sopenharmony_ci}; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic bool pci_epf_mhi_filter(struct dma_chan *chan, void *node) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct epf_dma_filter *filter = node; 42362306a36Sopenharmony_ci struct dma_slave_caps caps; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci memset(&caps, 0, sizeof(caps)); 42662306a36Sopenharmony_ci dma_get_slave_caps(chan, &caps); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return chan->device->dev == filter->dev && filter->dma_mask & 42962306a36Sopenharmony_ci caps.directions; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int pci_epf_mhi_dma_init(struct pci_epf_mhi *epf_mhi) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct device *dma_dev = epf_mhi->epf->epc->dev.parent; 43562306a36Sopenharmony_ci struct device *dev = &epf_mhi->epf->dev; 43662306a36Sopenharmony_ci struct epf_dma_filter filter; 43762306a36Sopenharmony_ci dma_cap_mask_t mask; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci dma_cap_zero(mask); 44062306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci filter.dev = dma_dev; 44362306a36Sopenharmony_ci filter.dma_mask = BIT(DMA_MEM_TO_DEV); 44462306a36Sopenharmony_ci epf_mhi->dma_chan_tx = dma_request_channel(mask, pci_epf_mhi_filter, 44562306a36Sopenharmony_ci &filter); 44662306a36Sopenharmony_ci if (IS_ERR_OR_NULL(epf_mhi->dma_chan_tx)) { 44762306a36Sopenharmony_ci dev_err(dev, "Failed to request tx channel\n"); 44862306a36Sopenharmony_ci return -ENODEV; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci filter.dma_mask = BIT(DMA_DEV_TO_MEM); 45262306a36Sopenharmony_ci epf_mhi->dma_chan_rx = dma_request_channel(mask, pci_epf_mhi_filter, 45362306a36Sopenharmony_ci &filter); 45462306a36Sopenharmony_ci if (IS_ERR_OR_NULL(epf_mhi->dma_chan_rx)) { 45562306a36Sopenharmony_ci dev_err(dev, "Failed to request rx channel\n"); 45662306a36Sopenharmony_ci dma_release_channel(epf_mhi->dma_chan_tx); 45762306a36Sopenharmony_ci epf_mhi->dma_chan_tx = NULL; 45862306a36Sopenharmony_ci return -ENODEV; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic void pci_epf_mhi_dma_deinit(struct pci_epf_mhi *epf_mhi) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci dma_release_channel(epf_mhi->dma_chan_tx); 46762306a36Sopenharmony_ci dma_release_channel(epf_mhi->dma_chan_rx); 46862306a36Sopenharmony_ci epf_mhi->dma_chan_tx = NULL; 46962306a36Sopenharmony_ci epf_mhi->dma_chan_rx = NULL; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int pci_epf_mhi_core_init(struct pci_epf *epf) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); 47562306a36Sopenharmony_ci const struct pci_epf_mhi_ep_info *info = epf_mhi->info; 47662306a36Sopenharmony_ci struct pci_epf_bar *epf_bar = &epf->bar[info->bar_num]; 47762306a36Sopenharmony_ci struct pci_epc *epc = epf->epc; 47862306a36Sopenharmony_ci struct device *dev = &epf->dev; 47962306a36Sopenharmony_ci int ret; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci epf_bar->phys_addr = epf_mhi->mmio_phys; 48262306a36Sopenharmony_ci epf_bar->size = epf_mhi->mmio_size; 48362306a36Sopenharmony_ci epf_bar->barno = info->bar_num; 48462306a36Sopenharmony_ci epf_bar->flags = info->epf_flags; 48562306a36Sopenharmony_ci ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, epf_bar); 48662306a36Sopenharmony_ci if (ret) { 48762306a36Sopenharmony_ci dev_err(dev, "Failed to set BAR: %d\n", ret); 48862306a36Sopenharmony_ci return ret; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci ret = pci_epc_set_msi(epc, epf->func_no, epf->vfunc_no, 49262306a36Sopenharmony_ci order_base_2(info->msi_count)); 49362306a36Sopenharmony_ci if (ret) { 49462306a36Sopenharmony_ci dev_err(dev, "Failed to set MSI configuration: %d\n", ret); 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ret = pci_epc_write_header(epc, epf->func_no, epf->vfunc_no, 49962306a36Sopenharmony_ci epf->header); 50062306a36Sopenharmony_ci if (ret) { 50162306a36Sopenharmony_ci dev_err(dev, "Failed to set Configuration header: %d\n", ret); 50262306a36Sopenharmony_ci return ret; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci epf_mhi->epc_features = pci_epc_get_features(epc, epf->func_no, epf->vfunc_no); 50662306a36Sopenharmony_ci if (!epf_mhi->epc_features) 50762306a36Sopenharmony_ci return -ENODATA; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int pci_epf_mhi_link_up(struct pci_epf *epf) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); 51562306a36Sopenharmony_ci const struct pci_epf_mhi_ep_info *info = epf_mhi->info; 51662306a36Sopenharmony_ci struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl; 51762306a36Sopenharmony_ci struct pci_epc *epc = epf->epc; 51862306a36Sopenharmony_ci struct device *dev = &epf->dev; 51962306a36Sopenharmony_ci int ret; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (info->flags & MHI_EPF_USE_DMA) { 52262306a36Sopenharmony_ci ret = pci_epf_mhi_dma_init(epf_mhi); 52362306a36Sopenharmony_ci if (ret) { 52462306a36Sopenharmony_ci dev_err(dev, "Failed to initialize DMA: %d\n", ret); 52562306a36Sopenharmony_ci return ret; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci mhi_cntrl->mmio = epf_mhi->mmio; 53062306a36Sopenharmony_ci mhi_cntrl->irq = epf_mhi->irq; 53162306a36Sopenharmony_ci mhi_cntrl->mru = info->mru; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Assign the struct dev of PCI EP as MHI controller device */ 53462306a36Sopenharmony_ci mhi_cntrl->cntrl_dev = epc->dev.parent; 53562306a36Sopenharmony_ci mhi_cntrl->raise_irq = pci_epf_mhi_raise_irq; 53662306a36Sopenharmony_ci mhi_cntrl->alloc_map = pci_epf_mhi_alloc_map; 53762306a36Sopenharmony_ci mhi_cntrl->unmap_free = pci_epf_mhi_unmap_free; 53862306a36Sopenharmony_ci if (info->flags & MHI_EPF_USE_DMA) { 53962306a36Sopenharmony_ci mhi_cntrl->read_from_host = pci_epf_mhi_edma_read; 54062306a36Sopenharmony_ci mhi_cntrl->write_to_host = pci_epf_mhi_edma_write; 54162306a36Sopenharmony_ci } else { 54262306a36Sopenharmony_ci mhi_cntrl->read_from_host = pci_epf_mhi_iatu_read; 54362306a36Sopenharmony_ci mhi_cntrl->write_to_host = pci_epf_mhi_iatu_write; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Register the MHI EP controller */ 54762306a36Sopenharmony_ci ret = mhi_ep_register_controller(mhi_cntrl, info->config); 54862306a36Sopenharmony_ci if (ret) { 54962306a36Sopenharmony_ci dev_err(dev, "Failed to register MHI EP controller: %d\n", ret); 55062306a36Sopenharmony_ci if (info->flags & MHI_EPF_USE_DMA) 55162306a36Sopenharmony_ci pci_epf_mhi_dma_deinit(epf_mhi); 55262306a36Sopenharmony_ci return ret; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic int pci_epf_mhi_link_down(struct pci_epf *epf) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); 56162306a36Sopenharmony_ci const struct pci_epf_mhi_ep_info *info = epf_mhi->info; 56262306a36Sopenharmony_ci struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (mhi_cntrl->mhi_dev) { 56562306a36Sopenharmony_ci mhi_ep_power_down(mhi_cntrl); 56662306a36Sopenharmony_ci if (info->flags & MHI_EPF_USE_DMA) 56762306a36Sopenharmony_ci pci_epf_mhi_dma_deinit(epf_mhi); 56862306a36Sopenharmony_ci mhi_ep_unregister_controller(mhi_cntrl); 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic int pci_epf_mhi_bme(struct pci_epf *epf) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); 57762306a36Sopenharmony_ci const struct pci_epf_mhi_ep_info *info = epf_mhi->info; 57862306a36Sopenharmony_ci struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl; 57962306a36Sopenharmony_ci struct device *dev = &epf->dev; 58062306a36Sopenharmony_ci int ret; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* 58362306a36Sopenharmony_ci * Power up the MHI EP stack if link is up and stack is in power down 58462306a36Sopenharmony_ci * state. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci if (!mhi_cntrl->enabled && mhi_cntrl->mhi_dev) { 58762306a36Sopenharmony_ci ret = mhi_ep_power_up(mhi_cntrl); 58862306a36Sopenharmony_ci if (ret) { 58962306a36Sopenharmony_ci dev_err(dev, "Failed to power up MHI EP: %d\n", ret); 59062306a36Sopenharmony_ci if (info->flags & MHI_EPF_USE_DMA) 59162306a36Sopenharmony_ci pci_epf_mhi_dma_deinit(epf_mhi); 59262306a36Sopenharmony_ci mhi_ep_unregister_controller(mhi_cntrl); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int pci_epf_mhi_bind(struct pci_epf *epf) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); 60262306a36Sopenharmony_ci struct pci_epc *epc = epf->epc; 60362306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(epc->dev.parent); 60462306a36Sopenharmony_ci struct resource *res; 60562306a36Sopenharmony_ci int ret; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Get MMIO base address from Endpoint controller */ 60862306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mmio"); 60962306a36Sopenharmony_ci epf_mhi->mmio_phys = res->start; 61062306a36Sopenharmony_ci epf_mhi->mmio_size = resource_size(res); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci epf_mhi->mmio = ioremap(epf_mhi->mmio_phys, epf_mhi->mmio_size); 61362306a36Sopenharmony_ci if (!epf_mhi->mmio) 61462306a36Sopenharmony_ci return -ENOMEM; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci ret = platform_get_irq_byname(pdev, "doorbell"); 61762306a36Sopenharmony_ci if (ret < 0) { 61862306a36Sopenharmony_ci iounmap(epf_mhi->mmio); 61962306a36Sopenharmony_ci return ret; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci epf_mhi->irq = ret; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic void pci_epf_mhi_unbind(struct pci_epf *epf) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); 63062306a36Sopenharmony_ci const struct pci_epf_mhi_ep_info *info = epf_mhi->info; 63162306a36Sopenharmony_ci struct pci_epf_bar *epf_bar = &epf->bar[info->bar_num]; 63262306a36Sopenharmony_ci struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl; 63362306a36Sopenharmony_ci struct pci_epc *epc = epf->epc; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * Forcefully power down the MHI EP stack. Only way to bring the MHI EP 63762306a36Sopenharmony_ci * stack back to working state after successive bind is by getting BME 63862306a36Sopenharmony_ci * from host. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci if (mhi_cntrl->mhi_dev) { 64162306a36Sopenharmony_ci mhi_ep_power_down(mhi_cntrl); 64262306a36Sopenharmony_ci if (info->flags & MHI_EPF_USE_DMA) 64362306a36Sopenharmony_ci pci_epf_mhi_dma_deinit(epf_mhi); 64462306a36Sopenharmony_ci mhi_ep_unregister_controller(mhi_cntrl); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci iounmap(epf_mhi->mmio); 64862306a36Sopenharmony_ci pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no, epf_bar); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic struct pci_epc_event_ops pci_epf_mhi_event_ops = { 65262306a36Sopenharmony_ci .core_init = pci_epf_mhi_core_init, 65362306a36Sopenharmony_ci .link_up = pci_epf_mhi_link_up, 65462306a36Sopenharmony_ci .link_down = pci_epf_mhi_link_down, 65562306a36Sopenharmony_ci .bme = pci_epf_mhi_bme, 65662306a36Sopenharmony_ci}; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int pci_epf_mhi_probe(struct pci_epf *epf, 65962306a36Sopenharmony_ci const struct pci_epf_device_id *id) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct pci_epf_mhi_ep_info *info = 66262306a36Sopenharmony_ci (struct pci_epf_mhi_ep_info *)id->driver_data; 66362306a36Sopenharmony_ci struct pci_epf_mhi *epf_mhi; 66462306a36Sopenharmony_ci struct device *dev = &epf->dev; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci epf_mhi = devm_kzalloc(dev, sizeof(*epf_mhi), GFP_KERNEL); 66762306a36Sopenharmony_ci if (!epf_mhi) 66862306a36Sopenharmony_ci return -ENOMEM; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci epf->header = info->epf_header; 67162306a36Sopenharmony_ci epf_mhi->info = info; 67262306a36Sopenharmony_ci epf_mhi->epf = epf; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci epf->event_ops = &pci_epf_mhi_event_ops; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci mutex_init(&epf_mhi->lock); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci epf_set_drvdata(epf, epf_mhi); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic const struct pci_epf_device_id pci_epf_mhi_ids[] = { 68462306a36Sopenharmony_ci { .name = "sdx55", .driver_data = (kernel_ulong_t)&sdx55_info }, 68562306a36Sopenharmony_ci { .name = "sm8450", .driver_data = (kernel_ulong_t)&sm8450_info }, 68662306a36Sopenharmony_ci {}, 68762306a36Sopenharmony_ci}; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic struct pci_epf_ops pci_epf_mhi_ops = { 69062306a36Sopenharmony_ci .unbind = pci_epf_mhi_unbind, 69162306a36Sopenharmony_ci .bind = pci_epf_mhi_bind, 69262306a36Sopenharmony_ci}; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic struct pci_epf_driver pci_epf_mhi_driver = { 69562306a36Sopenharmony_ci .driver.name = "pci_epf_mhi", 69662306a36Sopenharmony_ci .probe = pci_epf_mhi_probe, 69762306a36Sopenharmony_ci .id_table = pci_epf_mhi_ids, 69862306a36Sopenharmony_ci .ops = &pci_epf_mhi_ops, 69962306a36Sopenharmony_ci .owner = THIS_MODULE, 70062306a36Sopenharmony_ci}; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic int __init pci_epf_mhi_init(void) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci return pci_epf_register_driver(&pci_epf_mhi_driver); 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_cimodule_init(pci_epf_mhi_init); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic void __exit pci_epf_mhi_exit(void) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci pci_epf_unregister_driver(&pci_epf_mhi_driver); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_cimodule_exit(pci_epf_mhi_exit); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ciMODULE_DESCRIPTION("PCI EPF driver for MHI Endpoint devices"); 71562306a36Sopenharmony_ciMODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 71662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 717