ath79: fix irq-ath79-intc driver and add support for other ath79 SoCs

Add the missing enable and disable function.
Remove dummy mask and unmask function and use the one provided by
irq_dummy_chip.
Allow interrupt status register being defined from dts.
Add ddr_wb_flush for ar934x/qca953x.
Rename controller name to qca,ar9340-intc because this design was
first introduced in AR934x.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>

Signed-off-by: Johann Neuhauser <johann@it-neuhauser.de>
v19.07.3_mercusys_ac12_duma
Johann Neuhauser 6 years ago committed by John Crispin
parent 189815462c
commit c7efc93509

@ -23,7 +23,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
--- /dev/null --- /dev/null
+++ b/drivers/irqchip/irq-ath79-intc.c +++ b/drivers/irqchip/irq-ath79-intc.c
@@ -0,0 +1,104 @@ @@ -0,0 +1,142 @@
+/* +/*
+ * Atheros AR71xx/AR724x/AR913x specific interrupt handling + * Atheros AR71xx/AR724x/AR913x specific interrupt handling
+ * + *
@ -50,7 +50,9 @@ Signed-off-by: John Crispin <john@phrozen.org>
+ struct irq_chip chip; + struct irq_chip chip;
+ u32 irq; + u32 irq;
+ u32 pending_mask; + u32 pending_mask;
+ u32 int_status;
+ u32 irq_mask[ATH79_MAX_INTC_CASCADE]; + u32 irq_mask[ATH79_MAX_INTC_CASCADE];
+ u32 irq_wb_chan[ATH79_MAX_INTC_CASCADE];
+}; +};
+ +
+static void ath79_intc_irq_handler(struct irq_desc *desc) +static void ath79_intc_irq_handler(struct irq_desc *desc)
@ -59,26 +61,33 @@ Signed-off-by: John Crispin <john@phrozen.org>
+ struct ath79_intc *intc = domain->host_data; + struct ath79_intc *intc = domain->host_data;
+ u32 pending; + u32 pending;
+ +
+ pending = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); + pending = ath79_reset_rr(intc->int_status);
+ pending &= intc->pending_mask; + pending &= intc->pending_mask;
+ +
+ if (pending) { + if (pending) {
+ int i; + int i;
+ +
+ for (i = 0; i < domain->hwirq_max; i++) + for (i = 0; i < domain->hwirq_max; i++)
+ if (pending & intc->irq_mask[i]) + if (pending & intc->irq_mask[i]) {
+ if (intc->irq_wb_chan[i] != 0xffffffff)
+ ath79_ddr_wb_flush(intc->irq_wb_chan[i]);
+ generic_handle_irq(irq_find_mapping(domain, i)); + generic_handle_irq(irq_find_mapping(domain, i));
+ }
+ } else { + } else {
+ spurious_interrupt(); + spurious_interrupt();
+ } + }
+} +}
+ +
+static void ath79_intc_irq_unmask(struct irq_data *d) +static void ath79_intc_irq_enable(struct irq_data *d)
+{ +{
+ struct ath79_intc *intc = d->domain->host_data;
+ enable_irq(intc->irq);
+} +}
+ +
+static void ath79_intc_irq_mask(struct irq_data *d) +static void ath79_intc_irq_disable(struct irq_data *d)
+{ +{
+ struct ath79_intc *intc = d->domain->host_data;
+ disable_irq(intc->irq);
+} +}
+ +
+static int ath79_intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +static int ath79_intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
@ -95,27 +104,56 @@ Signed-off-by: John Crispin <john@phrozen.org>
+ .map = ath79_intc_map, + .map = ath79_intc_map,
+}; +};
+ +
+static int __init qca9556_intc_of_init( +static int __init ath79_intc_of_init(
+ struct device_node *node, struct device_node *parent) + struct device_node *node, struct device_node *parent)
+{ +{
+ struct irq_domain *domain; + struct irq_domain *domain;
+ struct ath79_intc *intc; + struct ath79_intc *intc;
+ int cnt, i; + int cnt, cntwb, i, err;
+ +
+ cnt = of_property_count_u32_elems(node, "qcom,pending-bits"); + cnt = of_property_count_u32_elems(node, "qca,pending-bits");
+ if (cnt > ATH79_MAX_INTC_CASCADE) + if (cnt > ATH79_MAX_INTC_CASCADE)
+ panic("Too many INTC pending bits\n"); + panic("Too many INTC pending bits\n");
+ +
+ intc = kzalloc(sizeof(*intc), GFP_KERNEL); + intc = kzalloc(sizeof(*intc), GFP_KERNEL);
+ if (!intc) + if (!intc)
+ panic("Failed to allocate INTC memory\n"); + panic("Failed to allocate INTC memory\n");
+ intc->chip = dummy_irq_chip;
+ intc->chip.name = "INTC"; + intc->chip.name = "INTC";
+ intc->chip.irq_unmask = ath79_intc_irq_unmask, + intc->chip.irq_disable = ath79_intc_irq_disable;
+ intc->chip.irq_mask = ath79_intc_irq_mask, + intc->chip.irq_enable = ath79_intc_irq_enable;
+ +
+ of_property_read_u32_array(node, "qcom,pending-bits", intc->irq_mask, cnt); + if (of_property_read_u32(node, "qca,int-status-addr", &intc->int_status) < 0) {
+ for (i = 0; i < cnt; i++) + panic("Missing address of interrupt status register\n");
+ }
+
+ of_property_read_u32_array(node, "qca,pending-bits", intc->irq_mask, cnt);
+ for (i = 0; i < cnt; i++) {
+ intc->pending_mask |= intc->irq_mask[i]; + intc->pending_mask |= intc->irq_mask[i];
+ intc->irq_wb_chan[i] = 0xffffffff;
+ }
+
+ cntwb = of_count_phandle_with_args(
+ node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
+
+ for (i = 0; i < cntwb; i++) {
+ struct of_phandle_args args;
+ u32 irq = i;
+
+ of_property_read_u32_index(
+ node, "qca,ddr-wb-channel-interrupts", i, &irq);
+ if (irq >= ATH79_MAX_INTC_CASCADE)
+ continue;
+
+ err = of_parse_phandle_with_args(
+ node, "qca,ddr-wb-channels",
+ "#qca,ddr-wb-channel-cells",
+ i, &args);
+ if (err)
+ return err;
+
+ intc->irq_wb_chan[irq] = args.args[0];
+ }
+ +
+ intc->irq = irq_of_parse_and_map(node, 0); + intc->irq = irq_of_parse_and_map(node, 0);
+ if (!intc->irq) + if (!intc->irq)
@ -126,5 +164,5 @@ Signed-off-by: John Crispin <john@phrozen.org>
+ +
+ return 0; + return 0;
+} +}
+IRQCHIP_DECLARE(qca9556_intc, "qcom,qca9556-intc", +IRQCHIP_DECLARE(ath79_intc, "qca,ar9340-intc",
+ qca9556_intc_of_init); + ath79_intc_of_init);

Loading…
Cancel
Save