Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b7230e7 authored by Kevin Cernekee's avatar Kevin Cernekee Committed by Ralf Baechle
Browse files

IRQCHIP: bcm7120-l2: Add support for BCM3380-style controllers



These controllers support multiple enable/status pairs (64+ IRQs),
can put the enable/status words at different offsets, and do not
support multiple parent IRQs.

Signed-off-by: default avatarKevin Cernekee <cernekee@gmail.com>
Cc: f.fainelli@gmail.com
Cc: jaedon.shin@gmail.com
Cc: abrestic@chromium.org
Cc: tglx@linutronix.de
Cc: jason@lakedaemon.net
Cc: jogo@openwrt.org
Cc: arnd@arndb.de
Cc: computersforpeace@gmail.com
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/8843/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent ca40f1b2
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
Broadcom BCM3380-style Level 1 / Level 2 interrupt controller

This interrupt controller shows up in various forms on many BCM338x/BCM63xx
chipsets.  It has the following properties:

- outputs a single interrupt signal to its interrupt controller parent

- contains one or more enable/status word pairs, which often appear at
  different offsets in different blocks

- no atomic set/clear operations

Required properties:

- compatible: should be "brcm,bcm3380-l2-intc"
- reg: specifies one or more enable/status pairs, in the following format:
  <enable_reg 0x4 status_reg 0x4>...
- interrupt-controller: identifies the node as an interrupt controller
- #interrupt-cells: specifies the number of cells needed to encode an interrupt
  source, should be 1.
- interrupt-parent: specifies the phandle to the parent interrupt controller
  this one is cascaded from
- interrupts: specifies the interrupt line in the interrupt-parent controller
  node, valid values depend on the type of parent interrupt controller

Optional properties:

- brcm,irq-can-wake: if present, this means the L2 controller can be used as a
  wakeup source for system suspend/resume.

Example:

irq0_intc: interrupt-controller@10000020 {
	compatible = "brcm,bcm3380-l2-intc";
	reg = <0x10000024 0x4 0x1000002c 0x4>,
	      <0x10000020 0x4 0x10000028 0x4>;
	interrupt-controller;
	#interrupt-cells = <1>;
	interrupt-parent = <&cpu_intc>;
	interrupts = <2>;
};
+51 −4
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -120,10 +121,15 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
	/* For multiple parent IRQs with multiple words, this looks like:
	 * <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...>
	 */
	for (idx = 0; idx < data->n_words; idx++)
	for (idx = 0; idx < data->n_words; idx++) {
		if (data->map_mask_prop) {
			data->irq_map_mask[idx] |=
				be32_to_cpup(data->map_mask_prop +
					     irq * data->n_words + idx);
		} else {
			data->irq_map_mask[idx] = 0xffffffff;
		}
	}

	irq_set_handler_data(parent_irq, data);
	irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle);
@@ -165,6 +171,37 @@ static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn,
	return 0;
}

static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn,
					     struct bcm7120_l2_intc_data *data)
{
	unsigned int gc_idx;

	for (gc_idx = 0; gc_idx < MAX_WORDS; gc_idx++) {
		unsigned int map_idx = gc_idx * 2;
		void __iomem *en = of_iomap(dn, map_idx + 0);
		void __iomem *stat = of_iomap(dn, map_idx + 1);
		void __iomem *base = min(en, stat);

		data->map_base[map_idx + 0] = en;
		data->map_base[map_idx + 1] = stat;

		if (!base)
			break;

		data->pair_base[gc_idx] = base;
		data->en_offset[gc_idx] = en - base;
		data->stat_offset[gc_idx] = stat - base;
	}

	if (!gc_idx) {
		pr_err("unable to map registers\n");
		return -EINVAL;
	}

	data->n_words = gc_idx;
	return 0;
}

int __init bcm7120_l2_intc_probe(struct device_node *dn,
				 struct device_node *parent,
				 int (*iomap_regs_fn)(struct device_node *,
@@ -279,5 +316,15 @@ int __init bcm7120_l2_intc_probe_7120(struct device_node *dn,
				     "BCM7120 L2");
}

int __init bcm7120_l2_intc_probe_3380(struct device_node *dn,
				      struct device_node *parent)
{
	return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380,
				     "BCM3380 L2");
}

IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc",
		bcm7120_l2_intc_probe_7120);

IRQCHIP_DECLARE(bcm3380_l2_intc, "brcm,bcm3380-l2-intc",
		bcm7120_l2_intc_probe_3380);