[RAMEN9610-14210][COMMON] samsung: handler: introduce exynos-handler functions
authorDonghyeok Choe <d7271.choe@samsung.com>
Mon, 18 Mar 2019 02:27:27 +0000 (11:27 +0900)
committerhskang <hs1218.kang@samsung.com>
Fri, 5 Apr 2019 08:31:40 +0000 (17:31 +0900)
This patch adds new feature of exynos-hanlder. It can include
several specific interrupt handler for debugging.

Change-Id: I23f1a9775ea7ea44ec07d9b1979666f621a9d047
Signed-off-by: Donghyeok Choe <d7271.choe@samsung.com>
drivers/soc/samsung/debug/Makefile
drivers/soc/samsung/debug/exynos-handler.c [new file with mode: 0644]

index 388e0b1a3f64f24efdb6e713c38c84dc89b51a0b..b8df2478710f3f6fe3cd8fc9631a9e2802cd24c4 100644 (file)
@@ -14,5 +14,6 @@ obj-$(CONFIG_EXYNOS_ITMON)            += exynos9820-itmon.o
 endif
 ifeq ($(CONFIG_DEBUG_SNAPSHOT),y)
 obj-$(CONFIG_ARCH_EXYNOS)              += exynos-helper.o
+obj-$(CONFIG_ARCH_EXYNOS)              += exynos-handler.o
 endif
 obj-$(CONFIG_EXYNOS_CORESIGHT_ETM)     += exynos-coresight-etm.o
diff --git a/drivers/soc/samsung/debug/exynos-handler.c b/drivers/soc/samsung/debug/exynos-handler.c
new file mode 100644 (file)
index 0000000..401ec4a
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *           http://www.samsung.com/
+ *
+ * Exynos - Support SoC specific handler
+ * Author: Hosung Kim <hosung0.kim@samsung.com>
+ *         Youngmin Nam <youngmin.nam@samsung.com>
+ *
+ * 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/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/soc/samsung/exynos-soc.h>
+#include <linux/interrupt.h>
+#include <linux/debug-snapshot-helper.h>
+
+extern struct dbg_snapshot_helper_ops *dss_soc_ops;
+
+struct exynos_handler {
+       int             irq;
+       char            name[SZ_16];
+       irqreturn_t     (*handle_irq)(int irq, void *data);
+};
+
+static int handler_nr_irq;
+static struct exynos_handler *ecc_handler;
+
+static irqreturn_t exynos_ecc_handler(int irq, void *data)
+{
+       struct exynos_handler *ecc = (struct exynos_handler *)data;
+
+       dss_soc_ops->soc_dump_info(NULL);
+
+       panic("Detected ECC error: irq: %d, name: %s", ecc->irq, ecc->name);
+       return 0;
+}
+
+static int __init exynos_handler_setup(struct device_node *np)
+{
+       int err = 0, i;
+
+       if (of_property_read_u32(np, "handler_nr_irq", &handler_nr_irq)) {
+               handler_nr_irq = 0;
+               pr_err("%s: handler_nr_irq property is not defined in device tree\n", __func__);
+       }
+       pr_info("%s: handler_nr_irq = %d\n", __func__, handler_nr_irq);
+
+       /* memory alloc for handler */
+       if (handler_nr_irq > 0) {
+               ecc_handler = kzalloc(sizeof(struct exynos_handler) * handler_nr_irq,
+                                       GFP_KERNEL);
+               if (!ecc_handler) {
+                       pr_err("%s: fail to kzalloc\n", __func__);
+                       err = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       /* setup ecc_handler */
+       for (i = 0; i < handler_nr_irq; i++) {
+               ecc_handler[i].irq = irq_of_parse_and_map(np, i);
+               snprintf(ecc_handler[i].name, sizeof(ecc_handler[i].name),
+                               "ecc_handler%d", i);
+               ecc_handler[i].handle_irq = exynos_ecc_handler;
+
+               err = request_irq(ecc_handler[i].irq,
+                               ecc_handler[i].handle_irq,
+                               IRQ_TYPE_LEVEL_HIGH | IRQF_NOBALANCING | IRQF_GIC_MULTI_TARGET,
+                               ecc_handler[i].name, &ecc_handler[i]);
+               if (err) {
+                       pr_err("unable to request irq%d for %s ecc handler\n",
+                                       ecc_handler[i].irq, ecc_handler[i].name);
+                       break;
+               } else {
+                       pr_info("Success to request irq%d for %s ecc handler\n",
+                                       ecc_handler[i].irq, ecc_handler[i].name);
+               }
+       }
+
+out:
+       of_node_put(np);
+       return err;
+}
+
+static const struct of_device_id handler_of_match[] __initconst = {
+       { .compatible = "samsung,exynos-handler", .data = exynos_handler_setup},
+       {},
+};
+
+typedef int (*handler_initcall_t)(const struct device_node *);
+static int __init exynos_handler_init(void)
+{
+       struct device_node *np;
+       const struct of_device_id *matched_np;
+       handler_initcall_t init_fn;
+
+       np = of_find_matching_node_and_match(NULL, handler_of_match, &matched_np);
+       if (!np)
+               return -ENODEV;
+
+       init_fn = (handler_initcall_t)matched_np->data;
+
+       return init_fn(np);
+}
+subsys_initcall(exynos_handler_init);