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