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 <john@phrozen.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 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("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("%pOFn: failed to lookup pdev\n", np); 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); 88