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
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.20 (GNU/Linux)
 
 iQEcBAABAgAGBQJSVCLqAAoJEAi3KVZQDZAe7WgH/RI+S0rSXcIy6vdF3vAweQhF
 NNjNKi6ZHsQHAJwva62lzS+zNMLLGpG0NAZ8h+o0I+kFJ8cTYoUDFSiszcVuDKz2
 LM/0+JZiMTUmKV8D/XLqYZuQSBgQvxEyxwpcsTOZ2K0q8VQbXAdXt+uY9DUlg9sm
 /VqiAJzV5I7+V+iStQ/zLSYO9NVWe5TZOGjQiqkZIJa23tZ1mOLXsyWXw6SEZBNk
 ZbFjwQ6jicE/4fRvcbZk+4EeePI66PrUC1X0MoYQ3TLiHepWbkFdpV7LIBlOedcf
 0Feq+C1J6DKfSvuCocfTkjygOpcMieyZ+h512NKRry86sWOq1cuZC7MFqvNrMzg=
 =AiMP
 -----END PGP SIGNATURE-----

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: Kevin Hilman <khilman@linaro.org>
This commit is contained in:
Kevin Hilman 2013-10-09 12:59:23 -07:00
Родитель 3d729d33ee 96ae0b5486
Коммит 0397bb85b5
7 изменённых файлов: 307 добавлений и 84 удалений

Просмотреть файл

@ -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>;
};

Просмотреть файл

@ -1,10 +1,10 @@
* 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

Просмотреть файл

@ -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";
};

Просмотреть файл

@ -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,

Просмотреть файл

@ -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;

Просмотреть файл

@ -3,7 +3,7 @@ menu "PCI host controller drivers"
config PCI_MVEBU
bool "Marvell EBU PCIe controller"
depends on ARCH_MVEBU || ARCH_KIRKWOOD
depends on ARCH_MVEBU || ARCH_DOVE || ARCH_KIRKWOOD
depends on OF
config PCIE_DW

Просмотреть файл

@ -9,13 +9,17 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/mbus.h>
#include <linux/msi.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
/*
@ -103,6 +107,7 @@ struct mvebu_pcie_port;
struct mvebu_pcie {
struct platform_device *pdev;
struct mvebu_pcie_port *ports;
struct msi_chip *msi;
struct resource io;
struct resource realio;
struct resource mem;
@ -124,6 +129,9 @@ struct mvebu_pcie_port {
unsigned int io_target;
unsigned int io_attr;
struct clk *clk;
int reset_gpio;
int reset_active_low;
char *reset_name;
struct mvebu_sw_pci_bridge bridge;
struct device_node *dn;
struct mvebu_pcie *pcie;
@ -163,7 +171,7 @@ static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr)
* BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks
* WIN[0-3] -> DRAM bank[0-3]
*/
static void __init mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
{
const struct mbus_dram_target_info *dram;
u32 size;
@ -215,7 +223,7 @@ static void __init mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
port->base + PCIE_BAR_CTRL_OFF(1));
}
static void __init mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
{
u16 cmd;
u32 mask;
@ -626,7 +634,7 @@ static struct pci_ops mvebu_pcie_ops = {
.write = mvebu_pcie_wr_conf,
};
static int __init mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
{
struct mvebu_pcie *pcie = sys_to_pcie(sys);
int i;
@ -645,7 +653,7 @@ static int __init mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
return 1;
}
static int __init mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
static int mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct of_irq oirq;
int ret;
@ -673,6 +681,12 @@ static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
return bus;
}
void mvebu_pcie_add_bus(struct pci_bus *bus)
{
struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
bus->msi = pcie->msi;
}
resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
const struct resource *res,
resource_size_t start,
@ -696,7 +710,7 @@ resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
return start;
}
static void __init mvebu_pcie_enable(struct mvebu_pcie *pcie)
static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
{
struct hw_pci hw;
@ -709,6 +723,7 @@ static void __init mvebu_pcie_enable(struct mvebu_pcie *pcie)
hw.map_irq = mvebu_pcie_map_irq;
hw.ops = &mvebu_pcie_ops;
hw.align_resource = mvebu_pcie_align_resource;
hw.add_bus = mvebu_pcie_add_bus;
pci_common_init(&hw);
}
@ -718,10 +733,8 @@ static void __init mvebu_pcie_enable(struct mvebu_pcie *pcie)
* <...> property for one that matches the given port/lane. Once
* found, maps it.
*/
static void __iomem * __init
mvebu_pcie_map_registers(struct platform_device *pdev,
struct device_node *np,
struct mvebu_pcie_port *port)
static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
struct device_node *np, struct mvebu_pcie_port *port)
{
struct resource regs;
int ret = 0;
@ -777,7 +790,22 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
return -ENOENT;
}
static int __init mvebu_pcie_probe(struct platform_device *pdev)
static void mvebu_pcie_msi_enable(struct mvebu_pcie *pcie)
{
struct device_node *msi_node;
msi_node = of_parse_phandle(pcie->pdev->dev.of_node,
"msi-parent", 0);
if (!msi_node)
return;
pcie->msi = of_pci_find_msi_chip_by_node(msi_node);
if (pcie->msi)
pcie->msi->dev = &pcie->pdev->dev;
}
static int mvebu_pcie_probe(struct platform_device *pdev)
{
struct mvebu_pcie *pcie;
struct device_node *np = pdev->dev.of_node;
@ -790,6 +818,7 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
return -ENOMEM;
pcie->pdev = pdev;
platform_set_drvdata(pdev, pcie);
/* Get the PCIe memory and I/O aperture */
mvebu_mbus_get_pcie_mem_aperture(&pcie->mem);
@ -818,13 +847,14 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
return ret;
}
i = 0;
for_each_child_of_node(pdev->dev.of_node, child) {
if (!of_device_is_available(child))
continue;
pcie->nports++;
i++;
}
pcie->ports = devm_kzalloc(&pdev->dev, pcie->nports *
pcie->ports = devm_kzalloc(&pdev->dev, i *
sizeof(struct mvebu_pcie_port),
GFP_KERNEL);
if (!pcie->ports)
@ -833,6 +863,7 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
i = 0;
for_each_child_of_node(pdev->dev.of_node, child) {
struct mvebu_pcie_port *port = &pcie->ports[i];
enum of_gpio_flags flags;
if (!of_device_is_available(child))
continue;
@ -873,11 +904,47 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
continue;
}
port->reset_gpio = of_get_named_gpio_flags(child,
"reset-gpios", 0, &flags);
if (gpio_is_valid(port->reset_gpio)) {
u32 reset_udelay = 20000;
port->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
port->reset_name = kasprintf(GFP_KERNEL,
"pcie%d.%d-reset", port->port, port->lane);
of_property_read_u32(child, "reset-delay-us",
&reset_udelay);
ret = devm_gpio_request_one(&pdev->dev,
port->reset_gpio, GPIOF_DIR_OUT, port->reset_name);
if (ret) {
if (ret == -EPROBE_DEFER)
return ret;
continue;
}
gpio_set_value(port->reset_gpio,
(port->reset_active_low) ? 1 : 0);
msleep(reset_udelay/1000);
}
port->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(port->clk)) {
dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
port->port, port->lane);
continue;
}
ret = clk_prepare_enable(port->clk);
if (ret)
continue;
port->base = mvebu_pcie_map_registers(pdev, child, port);
if (IS_ERR(port->base)) {
dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
port->port, port->lane);
port->base = NULL;
clk_disable_unprepare(port->clk);
continue;
}
@ -893,25 +960,14 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
port->port, port->lane);
}
port->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(port->clk)) {
dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
port->port, port->lane);
iounmap(port->base);
port->haslink = 0;
continue;
}
port->dn = child;
clk_prepare_enable(port->clk);
spin_lock_init(&port->conf_lock);
mvebu_sw_pci_bridge_init(port);
i++;
}
pcie->nports = i;
mvebu_pcie_msi_enable(pcie);
mvebu_pcie_enable(pcie);
return 0;
@ -920,6 +976,7 @@ static int __init mvebu_pcie_probe(struct platform_device *pdev)
static const struct of_device_id mvebu_pcie_of_match_table[] = {
{ .compatible = "marvell,armada-xp-pcie", },
{ .compatible = "marvell,armada-370-pcie", },
{ .compatible = "marvell,dove-pcie", },
{ .compatible = "marvell,kirkwood-pcie", },
{},
};
@ -931,16 +988,12 @@ static struct platform_driver mvebu_pcie_driver = {
.name = "mvebu-pcie",
.of_match_table =
of_match_ptr(mvebu_pcie_of_match_table),
/* driver unloading/unbinding currently not supported */
.suppress_bind_attrs = true,
},
.probe = mvebu_pcie_probe,
};
static int __init mvebu_pcie_init(void)
{
return platform_driver_probe(&mvebu_pcie_driver,
mvebu_pcie_probe);
}
subsys_initcall(mvebu_pcie_init);
module_platform_driver(mvebu_pcie_driver);
MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
MODULE_DESCRIPTION("Marvell EBU PCIe driver");