aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc/rpres_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/remoteproc/rpres_dev.c')
-rw-r--r--drivers/remoteproc/rpres_dev.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/drivers/remoteproc/rpres_dev.c b/drivers/remoteproc/rpres_dev.c
new file mode 100644
index 0000000..8ecd950
--- /dev/null
+++ b/drivers/remoteproc/rpres_dev.c
@@ -0,0 +1,220 @@
+/*
+ * Remote processor resources
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
+#include <plat/clock.h>
+#include <plat/rpres.h>
+#include <linux/pm_qos_params.h>
+#include <plat/common.h>
+#include <plat/omap-pm.h>
+#include "../../arch/arm/mach-omap2/dvfs.h"
+
+static void _enable_optional_clocks(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_opt_clk *oc;
+ int i;
+
+ pr_debug("%s: %s: enabling optional clocks\n", __func__, oh->name);
+
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+ if (oc->_clk)
+ clk_enable(oc->_clk);
+}
+
+static void _disable_optional_clocks(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_opt_clk *oc;
+ int i;
+
+ pr_debug("%s: %s: disabling optional clocks\n", __func__, oh->name);
+
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+ if (oc->_clk)
+ clk_disable(oc->_clk);
+}
+
+static int rpres_iss_enable(struct platform_device *pdev)
+{
+ int ret;
+ struct rpres_platform_data *pdata = pdev->dev.platform_data;
+
+ ret = omap_device_enable(pdev);
+ if (!ret)
+ _enable_optional_clocks(pdata->oh);
+
+ return ret;
+}
+
+static int rpres_iss_shutdown(struct platform_device *pdev)
+{
+ int ret;
+ struct rpres_platform_data *pdata = pdev->dev.platform_data;
+
+ omap_hwmod_reset(pdata->oh);
+
+ ret = omap_device_idle(pdev);
+ if (!ret)
+ _disable_optional_clocks(pdata->oh);
+
+ return ret;
+}
+
+static int rpres_fdif_shutdown(struct platform_device *pdev)
+{
+ struct rpres_platform_data *pdata = pdev->dev.platform_data;
+
+ omap_hwmod_reset(pdata->oh);
+
+ return omap_device_idle(pdev);
+}
+
+static int rpres_scale_dev(struct platform_device *pdev, long val)
+{
+ return omap_device_scale(&pdev->dev, &pdev->dev, val);
+}
+
+static int rpres_set_dev_lat(struct platform_device *pdev, long val)
+{
+ return omap_pm_set_max_dev_wakeup_lat(&pdev->dev, &pdev->dev, val);
+}
+
+static int rpres_set_l3_bw(struct platform_device *pdev, long val)
+{
+ return omap_pm_set_min_bus_tput(&pdev->dev, OCP_INITIATOR_AGENT, val);
+}
+
+static struct rpres_ops iss_ops = {
+ .start = rpres_iss_enable,
+ .stop = rpres_iss_shutdown,
+ .set_lat = rpres_set_dev_lat,
+ .set_bw = rpres_set_l3_bw,
+};
+
+static struct rpres_ops ivahd_ops = {
+ .start = omap_device_enable,
+ .stop = omap_device_shutdown,
+ .set_lat = rpres_set_dev_lat,
+ .set_bw = rpres_set_l3_bw,
+ .scale_dev = rpres_scale_dev,
+};
+
+static struct rpres_ops fdif_ops = {
+ .start = omap_device_enable,
+ .stop = rpres_fdif_shutdown,
+ .set_lat = rpres_set_dev_lat,
+ .set_bw = rpres_set_l3_bw,
+ .scale_dev = rpres_scale_dev,
+};
+
+static struct rpres_ops gen_ops = {
+ .start = omap_device_enable,
+ .stop = omap_device_shutdown,
+};
+
+static struct omap_device_pm_latency rpres_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static struct rpres_platform_data rpres_data[] = {
+ {
+ .name = "rpres_iva",
+ .oh_name = "iva",
+ .ops = &ivahd_ops,
+ .get_dev = omap2_get_iva_device,
+ },
+ {
+ .name = "rpres_iva_seq0",
+ .oh_name = "iva_seq0",
+ .ops = &gen_ops,
+ },
+ {
+ .name = "rpres_iva_seq1",
+ .oh_name = "iva_seq1",
+ .ops = &gen_ops,
+ },
+ {
+ .name = "rpres_iss",
+ .oh_name = "iss",
+ .ops = &iss_ops,
+ .opt_clk_name = "ctrlclk",
+ },
+ {
+ .name = "rpres_fdif",
+ .oh_name = "fdif",
+ .ops = &fdif_ops,
+ .get_dev = omap4_get_fdif_device,
+ },
+ {
+ .name = "rpres_sl2if",
+ .oh_name = "sl2if",
+ .ops = &gen_ops,
+ },
+};
+
+static int __init init(void)
+{
+ int i, ret;
+ struct omap_hwmod *oh;
+ struct omap_device_pm_latency *ohl = rpres_latency;
+ int ohl_cnt = ARRAY_SIZE(rpres_latency);
+ struct omap_device *od;
+ struct device *dev;
+ struct platform_device *pdev;
+
+ for (i = 0; i < ARRAY_SIZE(rpres_data); i++) {
+ oh = omap_hwmod_lookup(rpres_data[i].oh_name);
+ if (!oh) {
+ pr_err("No hdmod for %s\n", rpres_data[i].name);
+ continue;
+ }
+ rpres_data[i].oh = oh;
+
+ if (rpres_data[i].get_dev) {
+ dev = rpres_data[i].get_dev();
+ if (!dev) {
+ pr_err("No dev for %s\n", rpres_data[i].name);
+ continue;
+ }
+ pdev = to_platform_device(dev);
+ ret = platform_device_add_data(pdev, &rpres_data[i],
+ sizeof(struct rpres_platform_data));
+ if (ret) {
+ pr_err("Error pdev add for %s\n",
+ rpres_data[i].name);
+ continue;
+ }
+ od = to_omap_device(pdev);
+ od->pm_lats = ohl;
+ od->pm_lats_cnt = ohl_cnt;
+ } else {
+ od = omap_device_build("rpres", i, oh,
+ &rpres_data[i],
+ sizeof(struct rpres_platform_data),
+ ohl, ohl_cnt, false);
+ if (IS_ERR(od))
+ pr_err("Error building device for %s\n",
+ rpres_data[i].name);
+ }
+ }
+ return 0;
+}
+device_initcall(init);