aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/coresight-funnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/coresight-funnel.c')
-rw-r--r--arch/arm/mach-exynos/coresight-funnel.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/coresight-funnel.c b/arch/arm/mach-exynos/coresight-funnel.c
new file mode 100644
index 0000000..e7e399d
--- /dev/null
+++ b/arch/arm/mach-exynos/coresight-funnel.c
@@ -0,0 +1,224 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "coresight.h"
+#include <mach/sec_debug.h>
+
+#define funnel_writel(funnel, id, val, off) \
+ __raw_writel((val), funnel.base + (SZ_4K * id) + off)
+#define funnel_readl(funnel, id, off) \
+ __raw_readl(funnel.base + (SZ_4K * id) + off)
+
+#define FUNNEL_FUNCTL (0x000)
+#define FUNNEL_PRICTL (0x004)
+#define FUNNEL_ITATBDATA0 (0xEEC)
+#define FUNNEL_ITATBCTR2 (0xEF0)
+#define FUNNEL_ITATBCTR1 (0xEF4)
+#define FUNNEL_ITATBCTR0 (0xEF8)
+
+
+#define FUNNEL_LOCK(id) \
+do { \
+ mb(); \
+ funnel_writel(funnel, id, 0x0, CS_LAR); \
+} while (0)
+#define FUNNEL_UNLOCK(id) \
+do { \
+ funnel_writel(funnel, id, CS_UNLOCK_MAGIC, CS_LAR); \
+ mb(); \
+} while (0)
+
+#define FUNNEL_HOLDTIME_MASK (0xF00)
+#define FUNNEL_HOLDTIME_SHFT (0x8)
+#define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT)
+
+struct funnel_ctx {
+ void __iomem *base;
+ bool enabled;
+ struct device *dev;
+ struct kobject *kobj;
+ uint32_t priority;
+};
+
+static struct funnel_ctx funnel = {
+ .priority = 0xFAC680,
+};
+
+static void __funnel_enable(uint8_t id, uint32_t port_mask)
+{
+ uint32_t functl;
+
+ FUNNEL_UNLOCK(id);
+
+ functl = funnel_readl(funnel, id, FUNNEL_FUNCTL);
+ functl &= ~FUNNEL_HOLDTIME_MASK;
+ functl |= FUNNEL_HOLDTIME;
+ functl |= port_mask;
+ funnel_writel(funnel, id, functl, FUNNEL_FUNCTL);
+ funnel_writel(funnel, id, funnel.priority, FUNNEL_PRICTL);
+
+ FUNNEL_LOCK(id);
+}
+
+void funnel_enable(uint8_t id, uint32_t port_mask)
+{
+ __funnel_enable(id, port_mask);
+ funnel.enabled = true;
+}
+
+static void __funnel_disable(uint8_t id, uint32_t port_mask)
+{
+ uint32_t functl;
+
+ FUNNEL_UNLOCK(id);
+
+ functl = funnel_readl(funnel, id, FUNNEL_FUNCTL);
+ functl &= ~port_mask;
+ funnel_writel(funnel, id, functl, FUNNEL_FUNCTL);
+
+ FUNNEL_LOCK(id);
+}
+
+void funnel_disable(uint8_t id, uint32_t port_mask)
+{
+ __funnel_disable(id, port_mask);
+ funnel.enabled = false;
+}
+
+#define FUNNEL_ATTR(name) \
+static struct kobj_attribute name##_attr = \
+ __ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
+
+static ssize_t priority_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long val;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ funnel.priority = val;
+ return n;
+}
+static ssize_t priority_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ unsigned long val = funnel.priority;
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+FUNNEL_ATTR(priority);
+
+static int __init funnel_sysfs_init(void)
+{
+ int ret;
+
+ funnel.kobj = kobject_create_and_add("funnel", \
+ coresight_get_modulekobj());
+ if (!funnel.kobj) {
+ dev_err(funnel.dev, "failed to create FUNNEL sysfs kobject\n");
+ ret = -ENOMEM;
+ goto err_create;
+ }
+
+ ret = sysfs_create_file(funnel.kobj, &priority_attr.attr);
+ if (ret) {
+ dev_err(funnel.dev, "failed to create FUNNEL sysfs priority"
+ " attribute\n");
+ goto err_file;
+ }
+
+ return 0;
+err_file:
+ kobject_put(funnel.kobj);
+err_create:
+ return ret;
+}
+
+static void funnel_sysfs_exit(void)
+{
+ sysfs_remove_file(funnel.kobj, &priority_attr.attr);
+ kobject_put(funnel.kobj);
+}
+
+static int __devinit funnel_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+
+ if (!sec_debug_level.en.kernel_fault) {
+ pr_info("%s: debug level is low\n",__func__);
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -EINVAL;
+ goto err_res;
+ }
+
+ funnel.base = ioremap_nocache(res->start, resource_size(res));
+ if (!funnel.base) {
+ ret = -EINVAL;
+ goto err_ioremap;
+ }
+
+ funnel.dev = &pdev->dev;
+
+ funnel_sysfs_init();
+
+ dev_info(funnel.dev, "FUNNEL initialized\n");
+ return 0;
+
+err_ioremap:
+err_res:
+ dev_err(funnel.dev, "FUNNEL init failed\n");
+ return ret;
+}
+
+static int funnel_remove(struct platform_device *pdev)
+{
+ if (funnel.enabled)
+ funnel_disable(0x0, 0xFF);
+ funnel_sysfs_exit();
+ iounmap(funnel.base);
+
+ return 0;
+}
+
+static struct platform_driver funnel_driver = {
+ .probe = funnel_probe,
+ .remove = funnel_remove,
+ .driver = {
+ .name = "coresight_funnel",
+ },
+};
+
+int __init funnel_init(void)
+{
+ return platform_driver_register(&funnel_driver);
+}
+
+void funnel_exit(void)
+{
+ platform_driver_unregister(&funnel_driver);
+}