Blame view
drivers/irqchip/irq-ath79-misc.c
4.99 KB
d2912cb15
|
1 |
// SPDX-License-Identifier: GPL-2.0-only |
07ba4b061
|
2 3 4 5 6 7 8 9 10 |
/* * Atheros AR71xx/AR724x/AR913x MISC interrupt controller * * Copyright (C) 2015 Alban Bedel <albeu@free.fr> * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP |
07ba4b061
|
11 12 13 14 15 16 17 18 19 20 21 |
*/ #include <linux/irqchip.h> #include <linux/irqchip/chained_irq.h> #include <linux/of_address.h> #include <linux/of_irq.h> #define AR71XX_RESET_REG_MISC_INT_STATUS 0 #define AR71XX_RESET_REG_MISC_INT_ENABLE 4 #define ATH79_MISC_IRQ_COUNT 32 |
a1e8783db
|
22 23 24 25 26 27 28 29 30 |
#define ATH79_MISC_PERF_IRQ 5 static int ath79_perfcount_irq; int get_c0_perfcount_int(void) { return ath79_perfcount_irq; } EXPORT_SYMBOL_GPL(get_c0_perfcount_int); |
07ba4b061
|
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
static void ath79_misc_irq_handler(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); void __iomem *base = domain->host_data; u32 pending; chained_irq_enter(chip, desc); pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) & __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); if (!pending) { spurious_interrupt(); chained_irq_exit(chip, desc); return; } while (pending) { int bit = __ffs(pending); generic_handle_irq(irq_linear_revmap(domain, bit)); pending &= ~BIT(bit); } chained_irq_exit(chip, desc); } static void ar71xx_misc_irq_unmask(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); unsigned int irq = d->hwirq; u32 t; t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); __raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); /* flush write */ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); } static void ar71xx_misc_irq_mask(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); unsigned int irq = d->hwirq; u32 t; t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); /* flush write */ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); } static void ar724x_misc_irq_ack(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); unsigned int irq = d->hwirq; u32 t; t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); /* flush write */ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); } static struct irq_chip ath79_misc_irq_chip = { .name = "MISC", .irq_unmask = ar71xx_misc_irq_unmask, .irq_mask = ar71xx_misc_irq_mask, }; static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq); irq_set_chip_data(irq, d->host_data); return 0; } static const struct irq_domain_ops misc_irq_domain_ops = { .xlate = irq_domain_xlate_onecell, .map = misc_map, }; static void __init ath79_misc_intc_domain_init( struct irq_domain *domain, int irq) { void __iomem *base = domain->host_data; |
a1e8783db
|
121 |
ath79_perfcount_irq = irq_create_mapping(domain, ATH79_MISC_PERF_IRQ); |
07ba4b061
|
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
/* Disable and clear all interrupts */ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain); } static int __init ath79_misc_intc_of_init( struct device_node *node, struct device_node *parent) { struct irq_domain *domain; void __iomem *base; int irq; irq = irq_of_parse_and_map(node, 0); if (!irq) { pr_err("Failed to get MISC IRQ "); return -EINVAL; } base = of_iomap(node, 0); if (!base) { pr_err("Failed to get MISC IRQ registers "); return -ENOMEM; } domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT, &misc_irq_domain_ops, base); if (!domain) { pr_err("Failed to add MISC irqdomain "); return -EINVAL; } ath79_misc_intc_domain_init(domain, irq); return 0; } static int __init ar7100_misc_intc_of_init( struct device_node *node, struct device_node *parent) { ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; return ath79_misc_intc_of_init(node, parent); } IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc", ar7100_misc_intc_of_init); static int __init ar7240_misc_intc_of_init( struct device_node *node, struct device_node *parent) { ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; return ath79_misc_intc_of_init(node, parent); } IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc", ar7240_misc_intc_of_init); void __init ath79_misc_irq_init(void __iomem *regs, int irq, int irq_base, bool is_ar71xx) { struct irq_domain *domain; if (is_ar71xx) ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; else ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT, irq_base, 0, &misc_irq_domain_ops, regs); if (!domain) panic("Failed to create MISC irqdomain"); ath79_misc_intc_domain_init(domain, irq); } |