summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/ipu_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/ipu_dev.c')
-rw-r--r--arch/arm/mach-omap2/ipu_dev.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/ipu_dev.c b/arch/arm/mach-omap2/ipu_dev.c
new file mode 100644
index 00000000000..8ffbfc40907
--- /dev/null
+++ b/arch/arm/mach-omap2/ipu_dev.c
@@ -0,0 +1,388 @@
+/**
+ * linux/arch/arm/mach-omap2/ipu_dev.c
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Paul Hunt <hunt@ti.com>
+ *
+ * OMAP4 Image Processing Unit
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include <mach/irqs.h>
+#include <plat/omap_hwmod.h>
+#include <plat/common.h>
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+#include <linux/platform_device.h>
+#include <plat/remoteproc.h>
+
+#include <plat/ipu_dev.h>
+
+#include "../../../drivers/dsp/syslink/ipu_pm/ipu_pm.h"
+
+#define IPU_DRIVER_NAME "omap-ipu-pm"
+#define ISS_IPU_BUS_ID 0
+#define IVA_IPU_BUS_ID 1
+
+struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void);
+
+static char *hwmod_state_strings[] = {
+ "_HWMOD_STATE_UNKNOWN",
+ "_HWMOD_STATE_REGISTERED",
+ "_HWMOD_STATE_CLKS_INITED",
+ "_HWMOD_STATE_INITIALIZED",
+ "_HWMOD_STATE_ENABLED",
+ "_HWMOD_STATE_IDLE",
+ "_HWMOD_STATE_DISABLED",
+};
+static void print_hwmod_state(struct omap_hwmod *oh, char *desc)
+{
+ u32 _state = (u32) oh->_state;
+ pr_debug("HWMOD name = %s\n", oh->name);
+ if (_state > _HWMOD_STATE_LAST)
+ WARN(1, "Illegal hwmod _state = %d\n", _state);
+ else
+ pr_debug("%s state = %s\n", desc, hwmod_state_strings[_state]);
+}
+
+inline int ipu_pm_module_start(unsigned rsrc)
+{
+ int ret;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ print_hwmod_state(pd[rsrc].oh, "Previous");
+ ret = omap_device_enable(pd[rsrc].pdev);
+ if (ret)
+ pr_err("device enable failed %s", pd[rsrc].oh_name);
+ print_hwmod_state(pd[rsrc].oh, "New");
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_start);
+
+inline int ipu_pm_module_stop(unsigned rsrc)
+{
+ int ret;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ print_hwmod_state(pd[rsrc].oh, "Previous");
+ ret = omap_device_shutdown(pd[rsrc].pdev);
+ print_hwmod_state(pd[rsrc].oh, "New");
+
+ if (ret)
+ pr_err("device disable failed %s", pd[rsrc].oh_name);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_stop);
+
+inline int ipu_pm_module_set_rate(unsigned rsrc,
+ unsigned target_rsrc,
+ unsigned rate)
+{
+ int ret = 0;
+ unsigned target;
+ struct device *dp;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ if (target_rsrc == IPU_PM_MPU)
+ dp = omap2_get_mpuss_device();
+ else if (target_rsrc == IPU_PM_CORE)
+ dp = omap2_get_l3_device();
+ else {
+ if (target_rsrc == IPU_PM_SELF)
+ target = rsrc;
+ else
+ target = target_rsrc;
+
+ if ((pd[target].caps & IPUPM_CAPS_PERF) == 0) {
+ pr_err("device set rate not supported for %s",
+ pd[target].oh_name);
+ ret = -EINVAL;
+ goto err_ret;
+ } else
+ dp = pd[target].dev;
+ }
+#ifdef CONFIG_OMAP_PM
+ ret = omap_device_set_rate(pd[rsrc].dev, dp, rate);
+#endif
+ if (ret)
+ pr_err("device set rate failed %s", pd[target_rsrc].oh_name);
+err_ret:
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_set_rate);
+
+inline int ipu_pm_module_set_latency(unsigned rsrc,
+ unsigned target_rsrc,
+ int latency)
+{
+ int ret = 0;
+ unsigned target;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ if (target_rsrc == IPU_PM_MPU) {
+#ifdef CONFIG_OMAP_PM
+ ret = omap_pm_set_max_mpu_wakeup_lat(&pd[rsrc].qos_request,
+ latency);
+#endif
+ if (ret)
+ goto err_ret;
+ } else if (target_rsrc == IPU_PM_CORE) {
+#ifdef CONFIG_OMAP_PM
+ ret = omap_pm_set_max_sdma_lat(&pd[rsrc].qos_request,
+ latency);
+#endif
+ if (ret)
+ goto err_ret;
+ } else {
+ if (target_rsrc == IPU_PM_SELF)
+ target = rsrc;
+ else
+ target = target_rsrc;
+
+ if ((pd[target].caps & IPUPM_CAPS_LAT) == 0) {
+ pr_err("device set latency not supported for %s",
+ pd[target].oh_name);
+ ret = -EINVAL;
+ } else {
+#ifdef CONFIG_OMAP_PM
+ ret = omap_pm_set_max_dev_wakeup_lat(pd[rsrc].dev,
+ pd[target].dev,
+ latency);
+#endif
+ }
+ }
+
+ if (ret)
+ pr_err("module set latency failed %s", pd[target].oh_name);
+err_ret:
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_set_latency);
+
+inline int ipu_pm_module_set_bandwidth(unsigned rsrc,
+ unsigned target_rsrc,
+ int bandwidth)
+{
+ int ret = 0;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ if ((pd[target_rsrc].caps & IPUPM_CAPS_BDW) == 0) {
+ pr_err("device set bandwidth not supported for %s",
+ pd[target_rsrc].oh_name);
+ ret = -EINVAL;
+ } else {
+#ifdef CONFIG_OMAP_PM
+ struct device *dp;
+ dp = omap2_get_l3_device();
+ ret = omap_pm_set_min_bus_tput(dp,
+ OCP_INITIATOR_AGENT,
+ bandwidth);
+#endif
+ }
+
+ if (ret)
+ pr_err("module set bandwidth failed %s",
+ pd[target_rsrc].oh_name);
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_set_bandwidth);
+
+/* FIXME: not in use now
+ * static struct omap_ipupm_mod_ops omap_ipu_ops = {
+ * .start = NULL,
+ * .stop = NULL,
+ * };
+ *
+ * static struct omap_ipupm_mod_ops omap_ipu0_ops = {
+ * .start = NULL,
+ * .stop = NULL,
+ * };
+ *
+ * static struct omap_ipupm_mod_ops omap_ipu1_ops = {
+ * .start = NULL,
+ * .stop = NULL,
+ * };
+ */
+
+/* ipupm generic operations */
+static struct omap_ipupm_mod_ops omap_ipupm_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
+static struct omap_ipupm_mod_platform_data omap_ipupm_data[] = {
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "fdif",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "ipu",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "ipu_c0",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "ipu_c1",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iss",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iva",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iva_seq0",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iva_seq1",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "l3_main_1",
+ .caps = IPUPM_CAPS_LAT | IPUPM_CAPS_BDW
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "mpu",
+ .caps = IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "sl2if",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "dsp",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+};
+
+struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void)
+{
+ return omap_ipupm_data;
+}
+EXPORT_SYMBOL(ipupm_get_plat_data);
+
+static struct omap_device_pm_latency omap_ipupm_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static int __init omap_ipussdev_init(void)
+{
+ int status = -ENODEV;
+ int i;
+ int first = 1;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ char *oh_name;
+ char *pdev_name = IPU_DRIVER_NAME;
+ struct omap_device_pm_latency *ohl = omap_ipupm_latency;
+ int ohl_cnt = ARRAY_SIZE(omap_ipupm_latency);
+
+ for (i = 0; i < ARRAY_SIZE(omap_ipupm_data); i++) {
+ oh_name = omap_ipupm_data[i].oh_name;
+
+ if (omap_ipupm_data[i].caps & IPUPM_CAPS_EXTINIT)
+ continue;
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("%s: could not look up %s\n", __func__, oh_name);
+
+ continue; /* to allow init to continue with other IPs
+ * we probably do not want to completely stop progress
+ * due to one module anyway, but need to be able to
+ * not try to use it if init fails
+ * this was put in to handle disabled hwmods
+ */
+
+ status = -ENODEV;
+ goto err_init;
+ }
+ omap_ipupm_data[i].oh = oh;
+
+ od = omap_device_build(pdev_name, IVA_IPU_BUS_ID+i, oh,
+ &omap_ipupm_data[i],
+ sizeof(struct omap_ipupm_mod_platform_data),
+ ohl, ohl_cnt, false);
+
+ status = IS_ERR(od);
+ WARN(status, "Could not build omap_device for %s %s\n",
+ pdev_name, oh_name);
+ if (!status) {
+ /* Save the id of the first registered dev */
+ if (first) {
+ ipu_pm_first_dev = od->pdev.id;
+ first = 0;
+ }
+ omap_ipupm_data[i].pdev = &od->pdev;
+ omap_ipupm_data[i].dev = &od->pdev.dev;
+ }
+ }
+
+err_init:
+ return status;
+}
+
+arch_initcall(omap_ipussdev_init);