1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * |
4 | * Copyright (C) 2013 John Crispin <john@phrozen.org> |
5 | */ |
6 | |
7 | #include <linux/interrupt.h> |
8 | #include <linux/of.h> |
9 | #include <linux/of_platform.h> |
10 | #include <linux/of_irq.h> |
11 | #include <linux/platform_device.h> |
12 | |
13 | #include <asm/mach-ralink/ralink_regs.h> |
14 | |
15 | #define REG_ILL_ACC_ADDR 0x10 |
16 | #define REG_ILL_ACC_TYPE 0x14 |
17 | |
18 | #define ILL_INT_STATUS BIT(31) |
19 | #define ILL_ACC_WRITE BIT(30) |
20 | #define ILL_ACC_LEN_M 0xff |
21 | #define ILL_ACC_OFF_M 0xf |
22 | #define ILL_ACC_OFF_S 16 |
23 | #define ILL_ACC_ID_M 0x7 |
24 | #define ILL_ACC_ID_S 8 |
25 | |
26 | #define DRV_NAME "ill_acc" |
27 | |
28 | static const char * const ill_acc_ids[] = { |
29 | "cpu" , "dma" , "ppe" , "pdma rx" , "pdma tx" , "pci/e" , "wmac" , "usb" , |
30 | }; |
31 | |
32 | static irqreturn_t ill_acc_irq_handler(int irq, void *_priv) |
33 | { |
34 | struct device *dev = (struct device *) _priv; |
35 | u32 addr = rt_memc_r32(REG_ILL_ACC_ADDR); |
36 | u32 type = rt_memc_r32(REG_ILL_ACC_TYPE); |
37 | |
38 | dev_err(dev, "illegal %s access from %s - addr:0x%08x offset:%d len:%d\n" , |
39 | (type & ILL_ACC_WRITE) ? ("write" ) : ("read" ), |
40 | ill_acc_ids[(type >> ILL_ACC_ID_S) & ILL_ACC_ID_M], |
41 | addr, (type >> ILL_ACC_OFF_S) & ILL_ACC_OFF_M, |
42 | type & ILL_ACC_LEN_M); |
43 | |
44 | rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); |
45 | |
46 | return IRQ_HANDLED; |
47 | } |
48 | |
49 | static int __init ill_acc_of_setup(void) |
50 | { |
51 | struct platform_device *pdev; |
52 | struct device_node *np; |
53 | int irq; |
54 | |
55 | /* somehow this driver breaks on RT5350 */ |
56 | if (of_machine_is_compatible(compat: "ralink,rt5350-soc" )) |
57 | return -EINVAL; |
58 | |
59 | np = of_find_compatible_node(NULL, NULL, compat: "ralink,rt3050-memc" ); |
60 | if (!np) |
61 | return -EINVAL; |
62 | |
63 | pdev = of_find_device_by_node(np); |
64 | if (!pdev) { |
65 | pr_err("%pOFn: failed to lookup pdev\n" , np); |
66 | of_node_put(node: np); |
67 | return -EINVAL; |
68 | } |
69 | |
70 | irq = irq_of_parse_and_map(node: np, index: 0); |
71 | of_node_put(node: np); |
72 | if (!irq) { |
73 | dev_err(&pdev->dev, "failed to get irq\n" ); |
74 | put_device(dev: &pdev->dev); |
75 | return -EINVAL; |
76 | } |
77 | |
78 | if (request_irq(irq, handler: ill_acc_irq_handler, flags: 0, name: "ill_acc" , dev: &pdev->dev)) { |
79 | dev_err(&pdev->dev, "failed to request irq\n" ); |
80 | put_device(dev: &pdev->dev); |
81 | return -EINVAL; |
82 | } |
83 | |
84 | rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); |
85 | |
86 | dev_info(&pdev->dev, "irq registered\n" ); |
87 | |
88 | return 0; |
89 | } |
90 | |
91 | arch_initcall(ill_acc_of_setup); |
92 | |