113 lines
3.0 KiB
C
Executable File
113 lines
3.0 KiB
C
Executable File
/*
|
|
* 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);
|