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

Commit 0397bb85 authored by Kevin Hilman's avatar Kevin Hilman
Browse files

Merge tag 'drivers-3.13' of git://git.infradead.org/linux-mvebu into next/drivers

From Jason Cooper:
mvebu drivers changes for v3.13

 - irqchip
    - add MSI support for armada-370/XP

 - pci
    - add MSI support
    - add support for Marvell Dove SoCs

 - mvebu (soc changes depending on the pci and irq changes)
    - probe mbus windows via DT
    - probe pcie and clock via DT

 - docs for mvebu
    - update gated clock documentation

* tag 'drivers-3.13' of git://git.infradead.org/linux-mvebu

:
  ARM: mvebu: fix gated clock documentation
  ARM: dove: remove legacy pcie and clock init
  ARM: dove: switch to DT probed mbus address windows
  PCI: mvebu: add support for Marvell Dove SoCs
  PCI: mvebu: add support for reset on GPIO
  PCI: mvebu: remove subsys_initcall
  PCI: mvebu: increment nports only for registered ports
  PCI: mvebu: move clock enable before register access
  PCI: mvebu: add support for MSI
  irqchip: armada-370-xp: implement MSI support
  irqchip: armada-370-xp: properly request resources

Signed-off-by: default avatarKevin Hilman <khilman@linaro.org>
parents 3d729d33 96ae0b54
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@ Marvell Armada 370 and Armada XP Interrupt Controller
Required properties:
- compatible: Should be "marvell,mpic"
- interrupt-controller: Identifies the node as an interrupt controller.
- msi-controller: Identifies the node as an PCI Message Signaled
  Interrupt controller.
- #interrupt-cells: The number of cells to define the interrupts. Should be 1.
  The cell is the IRQ number

@@ -24,6 +26,7 @@ Example:
              #address-cells = <1>;
              #size-cells = <1>;
              interrupt-controller;
              msi-controller;
              reg = <0xd0020a00 0x1d0>,
                    <0xd0021070 0x58>;
        };
+8 −6
Original line number Diff line number Diff line
* Gated Clock bindings for Marvell Orion SoCs
* Gated Clock bindings for Marvell EBU SoCs

Marvell Dove and Kirkwood allow some peripheral clocks to be gated to save
some power. The clock consumer should specify the desired clock by having
the clock ID in its "clocks" phandle cell. The clock ID is directly mapped to
the corresponding clock gating control bit in HW to ease manual clock lookup
in datasheet.
Marvell Armada 370/XP, Dove and Kirkwood allow some peripheral clocks to be
gated to save some power. The clock consumer should specify the desired clock
by having the clock ID in its "clocks" phandle cell. The clock ID is directly
mapped to the corresponding clock gating control bit in HW to ease manual clock
lookup in datasheet.

The following is a list of provided IDs for Armada 370:
ID	Clock	Peripheral
@@ -94,6 +94,8 @@ ID Clock Peripheral

Required properties:
- compatible : shall be one of the following:
	"marvell,armada-370-gating-clock" - for Armada 370 SoC clock gating
	"marvell,armada-xp-gating-clock" - for Armada XP SoC clock gating
	"marvell,dove-gating-clock" - for Dove SoC clock gating
	"marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating
- reg : shall be the register address of the Clock Gating Control register
+10 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ Mandatory properties:
- compatible: one of the following values:
    marvell,armada-370-pcie
    marvell,armada-xp-pcie
    marvell,dove-pcie
    marvell,kirkwood-pcie
- #address-cells, set to <3>
- #size-cells, set to <2>
@@ -14,6 +15,8 @@ Mandatory properties:
- ranges: ranges describing the MMIO registers to control the PCIe
  interfaces, and ranges describing the MBus windows needed to access
  the memory and I/O regions of each PCIe interface.
- msi-parent: Link to the hardware entity that serves as the Message
  Signaled Interrupt controller for this PCI controller.

The ranges describing the MMIO registers have the following layout:

@@ -74,6 +77,8 @@ and the following optional properties:
- marvell,pcie-lane: the physical PCIe lane number, for ports having
  multiple lanes. If this property is not found, we assume that the
  value is 0.
- reset-gpios: optional gpio to PERST#
- reset-delay-us: delay in us to wait after reset de-assertion

Example:

@@ -86,6 +91,7 @@ pcie-controller {
	#size-cells = <2>;

	bus-range = <0x00 0xff>;
	msi-parent = <&mpic>;

	ranges =
	       <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000	/* Port 0.0 registers */
@@ -135,6 +141,10 @@ pcie-controller {
		interrupt-map = <0 0 0 0 &mpic 58>;
		marvell,pcie-port = <0>;
		marvell,pcie-lane = <0>;
		/* low-active PERST# reset on GPIO 25 */
		reset-gpios = <&gpio0 25 1>;
		/* wait 20ms for device settle after reset deassertion */
		reset-delay-us = <20000>;
		clocks = <&gateclk 5>;
		status = "disabled";
	};
+1 −38
Original line number Diff line number Diff line
@@ -23,41 +23,12 @@
#include <plat/irq.h>
#include "common.h"

/*
 * There are still devices that doesn't even know about DT,
 * get clock gates here and add a clock lookup.
 */
static void __init dove_legacy_clk_init(void)
{
	struct device_node *np = of_find_compatible_node(NULL, NULL,
					 "marvell,dove-gating-clock");
	struct of_phandle_args clkspec;

	clkspec.np = np;
	clkspec.args_count = 1;

	clkspec.args[0] = CLOCK_GATING_BIT_PCIE0;
	orion_clkdev_add("0", "pcie",
			 of_clk_get_from_provider(&clkspec));

	clkspec.args[0] = CLOCK_GATING_BIT_PCIE1;
	orion_clkdev_add("1", "pcie",
			 of_clk_get_from_provider(&clkspec));
}

static void __init dove_dt_time_init(void)
{
	of_clk_init(NULL);
	clocksource_of_init();
}

static void __init dove_dt_init_early(void)
{
	mvebu_mbus_init("marvell,dove-mbus",
			BRIDGE_WINS_BASE, BRIDGE_WINS_SZ,
			DOVE_MC_WINS_BASE, DOVE_MC_WINS_SZ);
}

static void __init dove_dt_init(void)
{
	pr_info("Dove 88AP510 SoC\n");
@@ -65,14 +36,7 @@ static void __init dove_dt_init(void)
#ifdef CONFIG_CACHE_TAUROS2
	tauros2_init(0);
#endif
	dove_setup_cpu_wins();

	/* Setup clocks for legacy devices */
	dove_legacy_clk_init();

	/* Internal devices not ported to DT yet */
	dove_pcie_init(1, 1);

	BUG_ON(mvebu_mbus_dt_init());
	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}

@@ -83,7 +47,6 @@ static const char * const dove_dt_board_compat[] = {

DT_MACHINE_START(DOVE_DT, "Marvell Dove (Flattened Device Tree)")
	.map_io		= dove_map_io,
	.init_early	= dove_dt_init_early,
	.init_time	= dove_dt_time_init,
	.init_machine	= dove_dt_init,
	.restart	= dove_restart,
+197 −5
Original line number Diff line number Diff line
@@ -21,7 +21,10 @@
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/irqdomain.h>
#include <linux/slab.h>
#include <linux/msi.h>
#include <asm/mach/arch.h>
#include <asm/exception.h>
#include <asm/smp_plat.h>
@@ -51,12 +54,22 @@
#define IPI_DOORBELL_START                      (0)
#define IPI_DOORBELL_END                        (8)
#define IPI_DOORBELL_MASK                       0xFF
#define PCI_MSI_DOORBELL_START                  (16)
#define PCI_MSI_DOORBELL_NR                     (16)
#define PCI_MSI_DOORBELL_END                    (32)
#define PCI_MSI_DOORBELL_MASK                   0xFFFF0000

static DEFINE_RAW_SPINLOCK(irq_controller_lock);

static void __iomem *per_cpu_int_base;
static void __iomem *main_int_base;
static struct irq_domain *armada_370_xp_mpic_domain;
#ifdef CONFIG_PCI_MSI
static struct irq_domain *armada_370_xp_msi_domain;
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
static DEFINE_MUTEX(msi_used_lock);
static phys_addr_t msi_doorbell_addr;
#endif

/*
 * In SMP mode:
@@ -87,6 +100,144 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
				ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
}

#ifdef CONFIG_PCI_MSI

static int armada_370_xp_alloc_msi(void)
{
	int hwirq;

	mutex_lock(&msi_used_lock);
	hwirq = find_first_zero_bit(&msi_used, PCI_MSI_DOORBELL_NR);
	if (hwirq >= PCI_MSI_DOORBELL_NR)
		hwirq = -ENOSPC;
	else
		set_bit(hwirq, msi_used);
	mutex_unlock(&msi_used_lock);

	return hwirq;
}

static void armada_370_xp_free_msi(int hwirq)
{
	mutex_lock(&msi_used_lock);
	if (!test_bit(hwirq, msi_used))
		pr_err("trying to free unused MSI#%d\n", hwirq);
	else
		clear_bit(hwirq, msi_used);
	mutex_unlock(&msi_used_lock);
}

static int armada_370_xp_setup_msi_irq(struct msi_chip *chip,
				       struct pci_dev *pdev,
				       struct msi_desc *desc)
{
	struct msi_msg msg;
	irq_hw_number_t hwirq;
	int virq;

	hwirq = armada_370_xp_alloc_msi();
	if (hwirq < 0)
		return hwirq;

	virq = irq_create_mapping(armada_370_xp_msi_domain, hwirq);
	if (!virq) {
		armada_370_xp_free_msi(hwirq);
		return -EINVAL;
	}

	irq_set_msi_desc(virq, desc);

	msg.address_lo = msi_doorbell_addr;
	msg.address_hi = 0;
	msg.data = 0xf00 | (hwirq + 16);

	write_msi_msg(virq, &msg);
	return 0;
}

static void armada_370_xp_teardown_msi_irq(struct msi_chip *chip,
					   unsigned int irq)
{
	struct irq_data *d = irq_get_irq_data(irq);
	irq_dispose_mapping(irq);
	armada_370_xp_free_msi(d->hwirq);
}

static struct irq_chip armada_370_xp_msi_irq_chip = {
	.name = "armada_370_xp_msi_irq",
	.irq_enable = unmask_msi_irq,
	.irq_disable = mask_msi_irq,
	.irq_mask = mask_msi_irq,
	.irq_unmask = unmask_msi_irq,
};

static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq,
				 irq_hw_number_t hw)
{
	irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip,
				 handle_simple_irq);
	set_irq_flags(virq, IRQF_VALID);

	return 0;
}

static const struct irq_domain_ops armada_370_xp_msi_irq_ops = {
	.map = armada_370_xp_msi_map,
};

static int armada_370_xp_msi_init(struct device_node *node,
				  phys_addr_t main_int_phys_base)
{
	struct msi_chip *msi_chip;
	u32 reg;
	int ret;

	msi_doorbell_addr = main_int_phys_base +
		ARMADA_370_XP_SW_TRIG_INT_OFFS;

	msi_chip = kzalloc(sizeof(*msi_chip), GFP_KERNEL);
	if (!msi_chip)
		return -ENOMEM;

	msi_chip->setup_irq = armada_370_xp_setup_msi_irq;
	msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq;
	msi_chip->of_node = node;

	armada_370_xp_msi_domain =
		irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
				      &armada_370_xp_msi_irq_ops,
				      NULL);
	if (!armada_370_xp_msi_domain) {
		kfree(msi_chip);
		return -ENOMEM;
	}

	ret = of_pci_msi_chip_add(msi_chip);
	if (ret < 0) {
		irq_domain_remove(armada_370_xp_msi_domain);
		kfree(msi_chip);
		return ret;
	}

	reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
		| PCI_MSI_DOORBELL_MASK;

	writel(reg, per_cpu_int_base +
	       ARMADA_370_XP_IN_DRBEL_MSK_OFFS);

	/* Unmask IPI interrupt */
	writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);

	return 0;
}
#else
static inline int armada_370_xp_msi_init(struct device_node *node,
					 phys_addr_t main_int_phys_base)
{
	return 0;
}
#endif

#ifdef CONFIG_SMP
static int armada_xp_set_affinity(struct irq_data *d,
				  const struct cpumask *mask_val, bool force)
@@ -214,12 +365,39 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
		if (irqnr > 1022)
			break;

		if (irqnr > 0) {
		if (irqnr > 1) {
			irqnr =	irq_find_mapping(armada_370_xp_mpic_domain,
					irqnr);
			handle_IRQ(irqnr, regs);
			continue;
		}

#ifdef CONFIG_PCI_MSI
		/* MSI handling */
		if (irqnr == 1) {
			u32 msimask, msinr;

			msimask = readl_relaxed(per_cpu_int_base +
						ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
				& PCI_MSI_DOORBELL_MASK;

			writel(~PCI_MSI_DOORBELL_MASK, per_cpu_int_base +
			       ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);

			for (msinr = PCI_MSI_DOORBELL_START;
			     msinr < PCI_MSI_DOORBELL_END; msinr++) {
				int irq;

				if (!(msimask & BIT(msinr)))
					continue;

				irq = irq_find_mapping(armada_370_xp_msi_domain,
						       msinr - 16);
				handle_IRQ(irq, regs);
			}
		}
#endif

#ifdef CONFIG_SMP
		/* IPI Handling */
		if (irqnr == 0) {
@@ -248,12 +426,25 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
static int __init armada_370_xp_mpic_of_init(struct device_node *node,
					     struct device_node *parent)
{
	struct resource main_int_res, per_cpu_int_res;
	u32 control;

	main_int_base = of_iomap(node, 0);
	per_cpu_int_base = of_iomap(node, 1);
	BUG_ON(of_address_to_resource(node, 0, &main_int_res));
	BUG_ON(of_address_to_resource(node, 1, &per_cpu_int_res));

	BUG_ON(!request_mem_region(main_int_res.start,
				   resource_size(&main_int_res),
				   node->full_name));
	BUG_ON(!request_mem_region(per_cpu_int_res.start,
				   resource_size(&per_cpu_int_res),
				   node->full_name));

	main_int_base = ioremap(main_int_res.start,
				resource_size(&main_int_res));
	BUG_ON(!main_int_base);

	per_cpu_int_base = ioremap(per_cpu_int_res.start,
				   resource_size(&per_cpu_int_res));
	BUG_ON(!per_cpu_int_base);

	control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
@@ -262,8 +453,7 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
		irq_domain_add_linear(node, (control >> 2) & 0x3ff,
				&armada_370_xp_mpic_irq_ops, NULL);

	if (!armada_370_xp_mpic_domain)
		panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n");
	BUG_ON(!armada_370_xp_mpic_domain);

	irq_set_default_host(armada_370_xp_mpic_domain);

@@ -280,6 +470,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,

#endif

	armada_370_xp_msi_init(node, main_int_res.start);

	set_handle_irq(armada_370_xp_handle_irq);

	return 0;
Loading