1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 207ba4b06SAlban Bedel /* 307ba4b06SAlban Bedel * Atheros AR71xx/AR724x/AR913x MISC interrupt controller 407ba4b06SAlban Bedel * 507ba4b06SAlban Bedel * Copyright (C) 2015 Alban Bedel <albeu@free.fr> 607ba4b06SAlban Bedel * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> 707ba4b06SAlban Bedel * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> 807ba4b06SAlban Bedel * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 907ba4b06SAlban Bedel * 1007ba4b06SAlban Bedel * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP 1107ba4b06SAlban Bedel */ 1207ba4b06SAlban Bedel 1307ba4b06SAlban Bedel #include <linux/irqchip.h> 1407ba4b06SAlban Bedel #include <linux/irqchip/chained_irq.h> 1507ba4b06SAlban Bedel #include <linux/of_address.h> 1607ba4b06SAlban Bedel #include <linux/of_irq.h> 1707ba4b06SAlban Bedel 1807ba4b06SAlban Bedel #define AR71XX_RESET_REG_MISC_INT_STATUS 0 1907ba4b06SAlban Bedel #define AR71XX_RESET_REG_MISC_INT_ENABLE 4 2007ba4b06SAlban Bedel 2107ba4b06SAlban Bedel #define ATH79_MISC_IRQ_COUNT 32 22a1e8783dSPetr Štetiar #define ATH79_MISC_PERF_IRQ 5 23a1e8783dSPetr Štetiar 24a1e8783dSPetr Štetiar static int ath79_perfcount_irq; 25a1e8783dSPetr Štetiar 26a1e8783dSPetr Štetiar int get_c0_perfcount_int(void) 27a1e8783dSPetr Štetiar { 28a1e8783dSPetr Štetiar return ath79_perfcount_irq; 29a1e8783dSPetr Štetiar } 30a1e8783dSPetr Štetiar EXPORT_SYMBOL_GPL(get_c0_perfcount_int); 3107ba4b06SAlban Bedel 3207ba4b06SAlban Bedel static void ath79_misc_irq_handler(struct irq_desc *desc) 3307ba4b06SAlban Bedel { 3407ba4b06SAlban Bedel struct irq_domain *domain = irq_desc_get_handler_data(desc); 3507ba4b06SAlban Bedel struct irq_chip *chip = irq_desc_get_chip(desc); 3607ba4b06SAlban Bedel void __iomem *base = domain->host_data; 3707ba4b06SAlban Bedel u32 pending; 3807ba4b06SAlban Bedel 3907ba4b06SAlban Bedel chained_irq_enter(chip, desc); 4007ba4b06SAlban Bedel 4107ba4b06SAlban Bedel pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) & 4207ba4b06SAlban Bedel __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 4307ba4b06SAlban Bedel 4407ba4b06SAlban Bedel if (!pending) { 4507ba4b06SAlban Bedel spurious_interrupt(); 4607ba4b06SAlban Bedel chained_irq_exit(chip, desc); 4707ba4b06SAlban Bedel return; 4807ba4b06SAlban Bedel } 4907ba4b06SAlban Bedel 5007ba4b06SAlban Bedel while (pending) { 5107ba4b06SAlban Bedel int bit = __ffs(pending); 5207ba4b06SAlban Bedel 5307ba4b06SAlban Bedel generic_handle_irq(irq_linear_revmap(domain, bit)); 5407ba4b06SAlban Bedel pending &= ~BIT(bit); 5507ba4b06SAlban Bedel } 5607ba4b06SAlban Bedel 5707ba4b06SAlban Bedel chained_irq_exit(chip, desc); 5807ba4b06SAlban Bedel } 5907ba4b06SAlban Bedel 6007ba4b06SAlban Bedel static void ar71xx_misc_irq_unmask(struct irq_data *d) 6107ba4b06SAlban Bedel { 6207ba4b06SAlban Bedel void __iomem *base = irq_data_get_irq_chip_data(d); 6307ba4b06SAlban Bedel unsigned int irq = d->hwirq; 6407ba4b06SAlban Bedel u32 t; 6507ba4b06SAlban Bedel 6607ba4b06SAlban Bedel t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 6707ba4b06SAlban Bedel __raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); 6807ba4b06SAlban Bedel 6907ba4b06SAlban Bedel /* flush write */ 7007ba4b06SAlban Bedel __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 7107ba4b06SAlban Bedel } 7207ba4b06SAlban Bedel 7307ba4b06SAlban Bedel static void ar71xx_misc_irq_mask(struct irq_data *d) 7407ba4b06SAlban Bedel { 7507ba4b06SAlban Bedel void __iomem *base = irq_data_get_irq_chip_data(d); 7607ba4b06SAlban Bedel unsigned int irq = d->hwirq; 7707ba4b06SAlban Bedel u32 t; 7807ba4b06SAlban Bedel 7907ba4b06SAlban Bedel t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 8007ba4b06SAlban Bedel __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); 8107ba4b06SAlban Bedel 8207ba4b06SAlban Bedel /* flush write */ 8307ba4b06SAlban Bedel __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); 8407ba4b06SAlban Bedel } 8507ba4b06SAlban Bedel 8607ba4b06SAlban Bedel static void ar724x_misc_irq_ack(struct irq_data *d) 8707ba4b06SAlban Bedel { 8807ba4b06SAlban Bedel void __iomem *base = irq_data_get_irq_chip_data(d); 8907ba4b06SAlban Bedel unsigned int irq = d->hwirq; 9007ba4b06SAlban Bedel u32 t; 9107ba4b06SAlban Bedel 9207ba4b06SAlban Bedel t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); 9307ba4b06SAlban Bedel __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); 9407ba4b06SAlban Bedel 9507ba4b06SAlban Bedel /* flush write */ 9607ba4b06SAlban Bedel __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); 9707ba4b06SAlban Bedel } 9807ba4b06SAlban Bedel 9907ba4b06SAlban Bedel static struct irq_chip ath79_misc_irq_chip = { 10007ba4b06SAlban Bedel .name = "MISC", 10107ba4b06SAlban Bedel .irq_unmask = ar71xx_misc_irq_unmask, 10207ba4b06SAlban Bedel .irq_mask = ar71xx_misc_irq_mask, 10307ba4b06SAlban Bedel }; 10407ba4b06SAlban Bedel 10507ba4b06SAlban Bedel static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 10607ba4b06SAlban Bedel { 10707ba4b06SAlban Bedel irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq); 10807ba4b06SAlban Bedel irq_set_chip_data(irq, d->host_data); 10907ba4b06SAlban Bedel return 0; 11007ba4b06SAlban Bedel } 11107ba4b06SAlban Bedel 11207ba4b06SAlban Bedel static const struct irq_domain_ops misc_irq_domain_ops = { 11307ba4b06SAlban Bedel .xlate = irq_domain_xlate_onecell, 11407ba4b06SAlban Bedel .map = misc_map, 11507ba4b06SAlban Bedel }; 11607ba4b06SAlban Bedel 11707ba4b06SAlban Bedel static void __init ath79_misc_intc_domain_init( 11807ba4b06SAlban Bedel struct irq_domain *domain, int irq) 11907ba4b06SAlban Bedel { 12007ba4b06SAlban Bedel void __iomem *base = domain->host_data; 12107ba4b06SAlban Bedel 122a1e8783dSPetr Štetiar ath79_perfcount_irq = irq_create_mapping(domain, ATH79_MISC_PERF_IRQ); 123a1e8783dSPetr Štetiar 12407ba4b06SAlban Bedel /* Disable and clear all interrupts */ 12507ba4b06SAlban Bedel __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); 12607ba4b06SAlban Bedel __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); 12707ba4b06SAlban Bedel 12807ba4b06SAlban Bedel irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain); 12907ba4b06SAlban Bedel } 13007ba4b06SAlban Bedel 13107ba4b06SAlban Bedel static int __init ath79_misc_intc_of_init( 13207ba4b06SAlban Bedel struct device_node *node, struct device_node *parent) 13307ba4b06SAlban Bedel { 13407ba4b06SAlban Bedel struct irq_domain *domain; 13507ba4b06SAlban Bedel void __iomem *base; 13607ba4b06SAlban Bedel int irq; 13707ba4b06SAlban Bedel 13807ba4b06SAlban Bedel irq = irq_of_parse_and_map(node, 0); 13907ba4b06SAlban Bedel if (!irq) { 14007ba4b06SAlban Bedel pr_err("Failed to get MISC IRQ\n"); 14107ba4b06SAlban Bedel return -EINVAL; 14207ba4b06SAlban Bedel } 14307ba4b06SAlban Bedel 14407ba4b06SAlban Bedel base = of_iomap(node, 0); 14507ba4b06SAlban Bedel if (!base) { 14607ba4b06SAlban Bedel pr_err("Failed to get MISC IRQ registers\n"); 14707ba4b06SAlban Bedel return -ENOMEM; 14807ba4b06SAlban Bedel } 14907ba4b06SAlban Bedel 15007ba4b06SAlban Bedel domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT, 15107ba4b06SAlban Bedel &misc_irq_domain_ops, base); 15207ba4b06SAlban Bedel if (!domain) { 15307ba4b06SAlban Bedel pr_err("Failed to add MISC irqdomain\n"); 15407ba4b06SAlban Bedel return -EINVAL; 15507ba4b06SAlban Bedel } 15607ba4b06SAlban Bedel 15707ba4b06SAlban Bedel ath79_misc_intc_domain_init(domain, irq); 15807ba4b06SAlban Bedel return 0; 15907ba4b06SAlban Bedel } 16007ba4b06SAlban Bedel 16107ba4b06SAlban Bedel static int __init ar7100_misc_intc_of_init( 16207ba4b06SAlban Bedel struct device_node *node, struct device_node *parent) 16307ba4b06SAlban Bedel { 16407ba4b06SAlban Bedel ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; 16507ba4b06SAlban Bedel return ath79_misc_intc_of_init(node, parent); 16607ba4b06SAlban Bedel } 16707ba4b06SAlban Bedel 16807ba4b06SAlban Bedel IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc", 16907ba4b06SAlban Bedel ar7100_misc_intc_of_init); 17007ba4b06SAlban Bedel 17107ba4b06SAlban Bedel static int __init ar7240_misc_intc_of_init( 17207ba4b06SAlban Bedel struct device_node *node, struct device_node *parent) 17307ba4b06SAlban Bedel { 17407ba4b06SAlban Bedel ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; 17507ba4b06SAlban Bedel return ath79_misc_intc_of_init(node, parent); 17607ba4b06SAlban Bedel } 17707ba4b06SAlban Bedel 17807ba4b06SAlban Bedel IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc", 17907ba4b06SAlban Bedel ar7240_misc_intc_of_init); 18007ba4b06SAlban Bedel 18107ba4b06SAlban Bedel void __init ath79_misc_irq_init(void __iomem *regs, int irq, 18207ba4b06SAlban Bedel int irq_base, bool is_ar71xx) 18307ba4b06SAlban Bedel { 18407ba4b06SAlban Bedel struct irq_domain *domain; 18507ba4b06SAlban Bedel 18607ba4b06SAlban Bedel if (is_ar71xx) 18707ba4b06SAlban Bedel ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; 18807ba4b06SAlban Bedel else 18907ba4b06SAlban Bedel ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; 19007ba4b06SAlban Bedel 19107ba4b06SAlban Bedel domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT, 19207ba4b06SAlban Bedel irq_base, 0, &misc_irq_domain_ops, regs); 19307ba4b06SAlban Bedel if (!domain) 19407ba4b06SAlban Bedel panic("Failed to create MISC irqdomain"); 19507ba4b06SAlban Bedel 19607ba4b06SAlban Bedel ath79_misc_intc_domain_init(domain, irq); 19707ba4b06SAlban Bedel } 198