John Crispin | 5433acd | 2013-05-16 23:28:23 +0200 | [diff] [blame] | 1 | /* |
| 2 | * This program is free software; you can redistribute it and/or modify it |
| 3 | * under the terms of the GNU General Public License version 2 as published |
| 4 | * by the Free Software Foundation. |
| 5 | * |
| 6 | * Copyright (C) 2013 John Crispin <blogic@openwrt.org> |
| 7 | */ |
| 8 | |
| 9 | #include <linux/interrupt.h> |
| 10 | #include <linux/of_platform.h> |
| 11 | #include <linux/of_irq.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 | |
Jonas Gorski | 9dd6f1c | 2015-05-25 19:53:54 +0200 | [diff] [blame] | 44 | rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); |
John Crispin | 5433acd | 2013-05-16 23:28:23 +0200 | [diff] [blame] | 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("ralink,rt5350-soc")) |
| 57 | return -EINVAL; |
| 58 | |
| 59 | np = of_find_compatible_node(NULL, NULL, "ralink,rt3050-memc"); |
| 60 | if (!np) |
| 61 | return -EINVAL; |
| 62 | |
| 63 | pdev = of_find_device_by_node(np); |
| 64 | if (!pdev) { |
| 65 | pr_err("%s: failed to lookup pdev\n", np->name); |
| 66 | return -EINVAL; |
| 67 | } |
| 68 | |
| 69 | irq = irq_of_parse_and_map(np, 0); |
| 70 | if (!irq) { |
| 71 | dev_err(&pdev->dev, "failed to get irq\n"); |
| 72 | return -EINVAL; |
| 73 | } |
| 74 | |
| 75 | if (request_irq(irq, ill_acc_irq_handler, 0, "ill_acc", &pdev->dev)) { |
| 76 | dev_err(&pdev->dev, "failed to request irq\n"); |
| 77 | return -EINVAL; |
| 78 | } |
| 79 | |
| 80 | rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); |
| 81 | |
| 82 | dev_info(&pdev->dev, "irq registered\n"); |
| 83 | |
| 84 | return 0; |
| 85 | } |
| 86 | |
| 87 | arch_initcall(ill_acc_of_setup); |