aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc/omap_remoteproc.c
diff options
context:
space:
mode:
authorGuzman Lugo, Fernando <fernando.lugo@ti.com>2011-04-20 10:59:34 +0300
committerColin Cross <ccross@android.com>2011-06-14 09:05:04 -0700
commita67f1ca27ae89e6b9213bb974f5a4dda78cde7b5 (patch)
treed51da218a3fb95a2e888e0effa4929e67086e8d5 /drivers/remoteproc/omap_remoteproc.c
parenta306b3e9565d6bcb4d1203cd6971340ccddd65a1 (diff)
downloadkernel_samsung_tuna-a67f1ca27ae89e6b9213bb974f5a4dda78cde7b5.tar.gz
kernel_samsung_tuna-a67f1ca27ae89e6b9213bb974f5a4dda78cde7b5.tar.bz2
kernel_samsung_tuna-a67f1ca27ae89e6b9213bb974f5a4dda78cde7b5.zip
remoteproc: add omap implementation
Add remoteproc implementation for OMAP4, to be able to load the remote dual M3 and DSP processors. Still needs some clean ups here. Based on code by Hari Kanigeri <h-kanigeri2@ti.com> Change-Id: I479553ed58d27ca771f9ce3c60608e8eaab89963 Signed-off-by: Guzman Lugo, Fernando <fernando.lugo@ti.com> [ohad@wizery.com: refactored and simplified, still wip] Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Diffstat (limited to 'drivers/remoteproc/omap_remoteproc.c')
-rw-r--r--drivers/remoteproc/omap_remoteproc.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
new file mode 100644
index 00000000000..01b8ee1f2d8
--- /dev/null
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -0,0 +1,170 @@
+/*
+ * Remote processor machine-specific module for OMAP4
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+
+#include <plat/iommu.h>
+#include <plat/omap_device.h>
+#include <plat/remoteproc.h>
+
+static int
+omap_rproc_map(struct device *dev, struct iommu *obj, u32 da, u32 pa, u32 size)
+{
+ struct iotlb_entry e;
+ u32 all_bits;
+ u32 pg_size[] = {SZ_16M, SZ_1M, SZ_64K, SZ_4K};
+ int size_flag[] = {MMU_CAM_PGSZ_16M, MMU_CAM_PGSZ_1M,
+ MMU_CAM_PGSZ_64K, MMU_CAM_PGSZ_4K};
+ int i, ret;
+
+ while (size) {
+ /*
+ * To find the max. page size with which both PA & VA are
+ * aligned
+ */
+ all_bits = pa | da;
+ for (i = 0; i < 4; i++) {
+ if ((size >= pg_size[i]) &&
+ ((all_bits & (pg_size[i] - 1)) == 0)) {
+ break;
+ }
+ }
+
+ memset(&e, 0, sizeof(e));
+
+ e.da = da;
+ e.pa = pa;
+ e.valid = 1;
+ e.pgsz = size_flag[i];
+ e.endian = MMU_RAM_ENDIAN_LITTLE;
+ e.elsz = MMU_RAM_ELSZ_32;
+
+ ret = iopgtable_store_entry(obj, &e);
+ if (ret) {
+ dev_err(dev, "iopgtable_store_entry fail: %d\n", ret);
+ return ret;
+ }
+
+ size -= pg_size[i];
+ da += pg_size[i];
+ pa += pg_size[i];
+ }
+
+ return 0;
+}
+
+static inline int omap_rproc_start(struct rproc *rproc, u64 bootaddr)
+{
+ struct device *dev = rproc->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_rproc_pdata *pdata = dev->platform_data;
+ struct iommu *iommu;
+ int ret, i;
+
+ iommu = iommu_get(pdata->iommu_name);
+ if (IS_ERR_OR_NULL(iommu)) {
+ dev_err(dev, "iommu_get error: %ld\n", PTR_ERR(iommu));
+ return PTR_ERR(iommu);
+ }
+
+ rproc->priv = iommu;
+
+ /* temporary workaround */
+ clk_enable(iommu->clk);
+
+ for (i = 0; rproc->memory_maps[i].size; i++) {
+ const struct rproc_mem_entry *me = &rproc->memory_maps[i];
+
+ ret = omap_rproc_map(dev, iommu, me->da, me->pa, me->size);
+ if (ret)
+ return ret;
+ }
+
+ ret = omap_device_enable(pdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static inline int omap_rproc_stop(struct rproc *rproc)
+{
+ struct device *dev = rproc->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct iommu *iommu = rproc->priv;
+ int ret;
+
+ ret = omap_device_shutdown(pdev);
+ if (ret)
+ dev_err(dev, "failed to shutdown: %d\n", ret);
+
+ iommu_put(iommu);
+
+ clk_disable(iommu->clk);
+
+ return ret;
+}
+
+static struct rproc_ops omap_rproc_ops = {
+ .start = omap_rproc_start,
+ .stop = omap_rproc_stop,
+};
+
+static int omap_rproc_probe(struct platform_device *pdev)
+{
+ struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+
+ return rproc_register(&pdev->dev, pdata->name, &omap_rproc_ops,
+ pdata->firmware, pdata->memory_maps,
+ THIS_MODULE);
+}
+
+static int __devexit omap_rproc_remove(struct platform_device *pdev)
+{
+ struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+
+ return rproc_unregister(pdata->name);
+}
+
+static struct platform_driver omap_rproc_driver = {
+ .probe = omap_rproc_probe,
+ .remove = __devexit_p(omap_rproc_remove),
+ .driver = {
+ .name = "omap-rproc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_rproc_init(void)
+{
+ return platform_driver_register(&omap_rproc_driver);
+}
+/* must be ready in time for device_initcall users */
+subsys_initcall(omap_rproc_init);
+
+static void __exit omap_rproc_exit(void)
+{
+ platform_driver_unregister(&omap_rproc_driver);
+}
+module_exit(omap_rproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Remote Processor control driver");