1#include <linux/irqdomain.h> 2#include <linux/irq.h> 3#include <linux/of.h> 4#include <linux/of_address.h> 5#include <linux/of_irq.h> 6#include <linux/irqchip/chained_irq.h> 7#include <linux/err.h> 8#include <linux/io.h> 9#include <linux/version.h> 10 11#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) 12# include "irqchip.h" 13#else 14# include <linux/irqchip.h> 15#endif 16 17struct rps_chip_data { 18 void __iomem *base; 19 struct irq_chip chip; 20 struct irq_domain *domain; 21} rps_data; 22 23enum { 24 RPS_IRQ_BASE = 64, 25 RPS_IRQ_COUNT = 32, 26 PRS_HWIRQ_BASE = 0, 27 28 RPS_STATUS = 0, 29 RPS_RAW_STATUS = 4, 30 RPS_UNMASK = 8, 31 RPS_MASK = 0xc, 32}; 33 34/* 35 * Routines to acknowledge, disable and enable interrupts 36 */ 37static void rps_mask_irq(struct irq_data *d) 38{ 39 struct rps_chip_data *chip_data = irq_data_get_irq_chip_data(d); 40 u32 mask = BIT(d->hwirq); 41 42 iowrite32(mask, chip_data->base + RPS_MASK); 43} 44 45static void rps_unmask_irq(struct irq_data *d) 46{ 47 struct rps_chip_data *chip_data = irq_data_get_irq_chip_data(d); 48 u32 mask = BIT(d->hwirq); 49 50 iowrite32(mask, chip_data->base + RPS_UNMASK); 51} 52 53static struct irq_chip rps_chip = { 54 .name = "RPS", 55 .irq_mask = rps_mask_irq, 56 .irq_unmask = rps_unmask_irq, 57}; 58 59static int rps_irq_domain_xlate(struct irq_domain *d, 60 struct device_node *controller, 61 const u32 *intspec, unsigned int intsize, 62 unsigned long *out_hwirq, 63 unsigned int *out_type) 64{ 65#if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) 66 if (d->of_node != controller) 67#else 68 if (irq_domain_get_of_node(d) != controller) 69#endif 70 return -EINVAL; 71 if (intsize < 1) 72 return -EINVAL; 73 74 *out_hwirq = intspec[0]; 75 /* Honestly I do not know the type */ 76 *out_type = IRQ_TYPE_LEVEL_HIGH; 77 78 return 0; 79} 80 81static int rps_irq_domain_map(struct irq_domain *d, unsigned int irq, 82 irq_hw_number_t hw) 83{ 84 irq_set_chip_and_handler(irq, &rps_chip, handle_level_irq); 85#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) 86 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); 87#else 88 irq_set_probe(irq); 89#endif 90 irq_set_chip_data(irq, d->host_data); 91 return 0; 92} 93 94const struct irq_domain_ops rps_irq_domain_ops = { 95 .map = rps_irq_domain_map, 96 .xlate = rps_irq_domain_xlate, 97}; 98 99#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) 100static void rps_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) 101#else 102static void rps_handle_cascade_irq(struct irq_desc *desc) 103#endif 104{ 105 struct rps_chip_data *chip_data = irq_desc_get_handler_data(desc); 106 struct irq_chip *chip = irq_desc_get_chip(desc); 107 unsigned int cascade_irq, rps_irq; 108 u32 status; 109 110 chained_irq_enter(chip, desc); 111 112 status = ioread32(chip_data->base + RPS_STATUS); 113 rps_irq = __ffs(status); 114 cascade_irq = irq_find_mapping(chip_data->domain, rps_irq); 115 116 if (unlikely(rps_irq >= RPS_IRQ_COUNT)) 117#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) 118 handle_bad_irq(cascade_irq, desc); 119#else 120 handle_bad_irq(desc); 121#endif 122 else 123 generic_handle_irq(cascade_irq); 124 125 chained_irq_exit(chip, desc); 126} 127 128#ifdef CONFIG_OF 129int __init rps_of_init(struct device_node *node, struct device_node *parent) 130{ 131 void __iomem *rps_base; 132 int irq_start = RPS_IRQ_BASE; 133 int irq_base; 134 int irq; 135 136 if (WARN_ON(!node)) 137 return -ENODEV; 138 139 rps_base = of_iomap(node, 0); 140 WARN(!rps_base, "unable to map rps registers\n"); 141 rps_data.base = rps_base; 142 143 irq_base = irq_alloc_descs(irq_start, 0, RPS_IRQ_COUNT, numa_node_id()); 144 if (IS_ERR_VALUE(irq_base)) { 145 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", 146 irq_start); 147 irq_base = irq_start; 148 } 149 150 rps_data.domain = irq_domain_add_legacy(node, RPS_IRQ_COUNT, irq_base, 151 PRS_HWIRQ_BASE, &rps_irq_domain_ops, &rps_data); 152 153 if (WARN_ON(!rps_data.domain)) 154 return -ENOMEM; 155 156 if (parent) { 157 irq = irq_of_parse_and_map(node, 0); 158 if (irq_set_handler_data(irq, &rps_data) != 0) 159 BUG(); 160 irq_set_chained_handler(irq, rps_handle_cascade_irq); 161 } 162 return 0; 163 164} 165 166IRQCHIP_DECLARE(nas782x, "plxtech,nas782x-rps", rps_of_init); 167#endif 168