162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2013 John Crispin <john@phrozen.org> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/interrupt.h> 862306a36Sopenharmony_ci#include <linux/of.h> 962306a36Sopenharmony_ci#include <linux/of_platform.h> 1062306a36Sopenharmony_ci#include <linux/of_irq.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/mach-ralink/ralink_regs.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define REG_ILL_ACC_ADDR 0x10 1662306a36Sopenharmony_ci#define REG_ILL_ACC_TYPE 0x14 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define ILL_INT_STATUS BIT(31) 1962306a36Sopenharmony_ci#define ILL_ACC_WRITE BIT(30) 2062306a36Sopenharmony_ci#define ILL_ACC_LEN_M 0xff 2162306a36Sopenharmony_ci#define ILL_ACC_OFF_M 0xf 2262306a36Sopenharmony_ci#define ILL_ACC_OFF_S 16 2362306a36Sopenharmony_ci#define ILL_ACC_ID_M 0x7 2462306a36Sopenharmony_ci#define ILL_ACC_ID_S 8 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define DRV_NAME "ill_acc" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const char * const ill_acc_ids[] = { 2962306a36Sopenharmony_ci "cpu", "dma", "ppe", "pdma rx", "pdma tx", "pci/e", "wmac", "usb", 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic irqreturn_t ill_acc_irq_handler(int irq, void *_priv) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct device *dev = (struct device *) _priv; 3562306a36Sopenharmony_ci u32 addr = rt_memc_r32(REG_ILL_ACC_ADDR); 3662306a36Sopenharmony_ci u32 type = rt_memc_r32(REG_ILL_ACC_TYPE); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci dev_err(dev, "illegal %s access from %s - addr:0x%08x offset:%d len:%d\n", 3962306a36Sopenharmony_ci (type & ILL_ACC_WRITE) ? ("write") : ("read"), 4062306a36Sopenharmony_ci ill_acc_ids[(type >> ILL_ACC_ID_S) & ILL_ACC_ID_M], 4162306a36Sopenharmony_ci addr, (type >> ILL_ACC_OFF_S) & ILL_ACC_OFF_M, 4262306a36Sopenharmony_ci type & ILL_ACC_LEN_M); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return IRQ_HANDLED; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int __init ill_acc_of_setup(void) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct platform_device *pdev; 5262306a36Sopenharmony_ci struct device_node *np; 5362306a36Sopenharmony_ci int irq; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* somehow this driver breaks on RT5350 */ 5662306a36Sopenharmony_ci if (of_machine_is_compatible("ralink,rt5350-soc")) 5762306a36Sopenharmony_ci return -EINVAL; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "ralink,rt3050-memc"); 6062306a36Sopenharmony_ci if (!np) 6162306a36Sopenharmony_ci return -EINVAL; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci pdev = of_find_device_by_node(np); 6462306a36Sopenharmony_ci if (!pdev) { 6562306a36Sopenharmony_ci pr_err("%pOFn: failed to lookup pdev\n", np); 6662306a36Sopenharmony_ci of_node_put(np); 6762306a36Sopenharmony_ci return -EINVAL; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 7162306a36Sopenharmony_ci of_node_put(np); 7262306a36Sopenharmony_ci if (!irq) { 7362306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get irq\n"); 7462306a36Sopenharmony_ci put_device(&pdev->dev); 7562306a36Sopenharmony_ci return -EINVAL; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (request_irq(irq, ill_acc_irq_handler, 0, "ill_acc", &pdev->dev)) { 7962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to request irq\n"); 8062306a36Sopenharmony_ci put_device(&pdev->dev); 8162306a36Sopenharmony_ci return -EINVAL; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci dev_info(&pdev->dev, "irq registered\n"); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciarch_initcall(ill_acc_of_setup); 92