summaryrefslogtreecommitdiff
path: root/drivers/misc/mic/imx-card/imx_mic_boot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mic/imx-card/imx_mic_boot.c')
-rw-r--r--drivers/misc/mic/imx-card/imx_mic_boot.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/misc/mic/imx-card/imx_mic_boot.c b/drivers/misc/mic/imx-card/imx_mic_boot.c
new file mode 100644
index 000000000000..49dd160ed9b6
--- /dev/null
+++ b/drivers/misc/mic/imx-card/imx_mic_boot.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2020 NXP
+
+#include <linux/imx_mic_epf.h>
+#include "imx_mic_boot.h"
+#include "../common/imx_mic_common.h"
+
+static const char imx_mic_driver_name[] = "imx_mic";
+
+static struct imx_mic_driver *g_mdrv;
+
+/*
+ * Just enable irq here since irq is requested in imx_mic_driver_init function.
+ */
+static struct mic_irq *_imx_mic_request_irq(struct vop_device *vpdev,
+ irqreturn_t (*func)(int irq, void *data),
+ const char *name, void *data, int intr_src)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+ struct imx_mic_intr *mintr = mdrv->mintr;
+ unsigned long cookie = intr_src;
+ int ret;
+
+ if (cookie == MIC_CONFIG_DB) {
+ mintr->config_intr = func;
+ mintr->config_intr_priv = data;
+ } else if (cookie == MIC_DATA_DB) {
+ mintr->data_intr = func;
+ mintr->data_intr_priv = data;
+ } else {
+ dev_err(mdrv->dev, "invalid doorbell index\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ imx_mic_intr_enable(mdrv, cookie);
+
+ return (struct mic_irq *)cookie;
+
+err:
+ return ERR_PTR(ret);
+}
+
+/*
+ * Just disable irq here since irq is freed in imx_mic_driver_uninit function.
+ */
+static void _imx_mic_free_irq(struct vop_device *vpdev,
+ struct mic_irq *cookie, void *data)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+ int index = (unsigned long)cookie;
+
+ imx_mic_intr_disable(mdrv, index);
+}
+
+static void _imx_mic_ack_interrupt(struct vop_device *vpdev, int num)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+
+ imx_mic_intr_ack(mdrv, num);
+}
+
+static int _imx_mic_next_db(struct vop_device *vpdev)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+ static unsigned int i;
+ unsigned int db_index = MIC_CONFIG_DB;
+
+ if (i == 0)
+ db_index = MIC_CONFIG_DB;
+ if (i == 1)
+ db_index = MIC_DATA_DB;
+
+ i++;
+ if (i > 2)
+ dev_err(mdrv->dev, "doorbell cannot be trusted\n");
+
+ return db_index;
+}
+
+static void __iomem *_imx_mic_get_remote_dp(struct vop_device *vpdev)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+ struct imx_mic_device *mdev = &mdrv->mdev;
+
+ return mdev->mmio.va;
+}
+
+static void _imx_mic_send_intr(struct vop_device *vpdev, int db)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+ struct imx_mic_epf *mepf = mdrv->mepf;
+ struct pci_epf *epf = mepf->epf;
+ struct pci_epc *epc = epf->epc;
+
+ pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, MIC_PCI_MSI_INDEX);
+}
+
+static void __iomem *_imx_mic_ioremap(struct vop_device *vpdev,
+ dma_addr_t pa, size_t len)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+ struct imx_mic_device *mdev = &mdrv->mdev;
+
+ /* Note: pa should be RC's absolute physical address */
+ return (mdev->mmio.va + (pa - mdev->mmio.pa));
+}
+
+static void _imx_mic_iounmap(struct vop_device *vpdev, void __iomem *va)
+{
+ /* nothing to do */
+}
+
+static struct vop_hw_ops imx_mic_hw_ops = {
+ .request_irq = _imx_mic_request_irq,
+ .free_irq = _imx_mic_free_irq,
+ .ack_interrupt = _imx_mic_ack_interrupt,
+ .next_db = _imx_mic_next_db,
+ .get_remote_dp = _imx_mic_get_remote_dp,
+ .send_intr = _imx_mic_send_intr,
+ .remap = _imx_mic_ioremap,
+ .unmap = _imx_mic_iounmap,
+};
+
+static int __init imx_mic_driver_init(struct imx_mic_driver *mdrv)
+{
+ int ret;
+
+ ret = imx_mic_intr_init(mdrv);
+ if (ret) {
+ dev_err(mdrv->dev, "imx_mic_intr_init failed\n");
+ return ret;
+ }
+
+ mdrv->vpdev = vop_register_device(mdrv->dev, VOP_DEV_TRNSP,
+ NULL, &imx_mic_hw_ops, 0,
+ NULL, NULL);
+ if (IS_ERR(mdrv->vpdev)) {
+ ret = PTR_ERR(mdrv->vpdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void imx_mic_driver_uninit(struct imx_mic_driver *mdrv)
+{
+ vop_unregister_device(mdrv->vpdev);
+ imx_mic_intr_uninit(mdrv);
+}
+
+int imx_mic_probe(struct imx_mic_epf *mic_epf)
+{
+ struct imx_mic_driver *mdrv;
+ struct imx_mic_device *mdev;
+ int ret;
+
+ mdrv = devm_kzalloc(mic_epf->dev, sizeof(*mdrv), GFP_KERNEL);
+ if (!mdrv)
+ return -ENOMEM;
+ g_mdrv = mdrv;
+ mdev = &mdrv->mdev;
+
+ mdrv->mepf = mic_epf;
+ mdrv->dev = mic_epf->dev;
+ snprintf(mdrv->name, sizeof(imx_mic_driver_name), imx_mic_driver_name);
+
+ /* fetch reserved memory from rc side */
+ mdev->mmio.pa = mic_epf->aper.rc_shmem_pa;
+ mdev->mmio.va = mic_epf->aper.pci_va;
+ mdev->mmio.len = mic_epf->aper.pci_len;
+
+ ret = imx_mic_driver_init(mdrv);
+ if (ret) {
+ dev_err(mic_epf->dev, "imx_mic_driver_init failed\n");
+ return ret;
+ }
+
+ mdrv->vpdev->dev.dma_pfn_offset = (SWIOTLB_REGION_ADDR - mic_epf->aper.rc_map_addr) >> PAGE_SHIFT;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_mic_probe);
+
+void imx_mic_remove(void)
+{
+ struct imx_mic_driver *mdrv = g_mdrv;
+
+ imx_mic_driver_uninit(mdrv);
+}
+EXPORT_SYMBOL_GPL(imx_mic_remove);