mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-24 01:54:01 -05:00
Merge branch 'pci/controller/brcmstb'
- Add missing of_node refcount release after of_parse_phandle() (Stanimir Varbanov) - Add BCM2712 MSI-X DT binding and interrupt controller drivers (Stanimir Varbanov) - Add brcmstb softdep on irq_bcm2712_mip MIP MSI-X interrupt controller driver to ensure that it is loaded first (Stanimir Varbanov) - Add struct brcm_pcie pointer to pcie_cfg_data so we can reference the pcie_cfg_data directly instead of copying it to brcm_pcie (Stanimir Varbanov) - Expand inbound window map to 64GB so it can accommodate BCM2712 (Stanimir Varbanov) - Add BCM2712 support and DT updates (Stanimir Varbanov) - Apply link speed restriction before bringing link up, not after (Jim Quinlan) - Update Max Link Speed in Link Capabilities via the internal writable register, not the read-only config register (Jim Quinlan) - Handle regulator_bulk_get() error to avoid panic when we call regulator_bulk_free() later (Jim Quinlan) - Disable regulators only when removing the bus immediately below a Root Port because we don't support regulators deeper in the hierarchy (Jim Quinlan) - Consistently use config access index/data register offsets from the SoC-specific pcie_offsets[] table (Jim Quinlan) - Update MDIO register fields that reduced CMD from 12 bits to 1 and widened PORT from 4 bits to 5 and split it into two parts (Jim Quinlan) - Make const read-only arrays static (Colin Ian King) * pci/controller/brcmstb: PCI: brcmstb: Make const read-only arrays static PCI: brcmstb: Make irq_domain_set_info() parameter cast explicit PCI: brcmstb: Make two changes in MDIO register fields PCI: brcmstb: Use same constant table for config space access PCI: brcmstb: Fix potential premature regulator disabling PCI: brcmstb: Fix error path after a call to regulator_bulk_get() PCI: brcmstb: Do not assume that register field starts at LSB PCI: brcmstb: Use internal register to change link capability PCI: brcmstb: Set generation limit before PCIe link up PCI: brcmstb: Add BCM2712 support PCI: brcmstb: Expand inbound window size up to 64GB PCI: brcmstb: Reuse pcie_cfg_data structure PCI: brcmstb: Add a softdep to MIP MSI-X driver irqchip: Add Broadcom BCM2712 MSI-X interrupt controller dt-bindings: PCI: brcmstb: Update bindings for PCIe on BCM2712 dt-bindings: interrupt-controller: Add BCM2712 MSI-X bindings PCI: brcmstb: Fix missing of_node_put() in brcm_pcie_probe()
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/brcm,bcm2712-msix.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom bcm2712 MSI-X Interrupt Peripheral support
|
||||
|
||||
maintainers:
|
||||
- Stanimir Varbanov <svarbanov@suse.de>
|
||||
|
||||
description:
|
||||
This interrupt controller is used to provide interrupt vectors to the
|
||||
generic interrupt controller (GIC) on bcm2712. It will be used as
|
||||
external MSI-X controller for PCIe root complex.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/interrupt-controller/msi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm2712-mip
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Base register address
|
||||
- description: PCIe message address
|
||||
|
||||
"#msi-cells":
|
||||
const: 0
|
||||
|
||||
brcm,msi-offset:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Shift the allocated MSI's.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- msi-controller
|
||||
- msi-ranges
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
axi {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
msi-controller@1000130000 {
|
||||
compatible = "brcm,bcm2712-mip";
|
||||
reg = <0x10 0x00130000 0x00 0xc0>,
|
||||
<0xff 0xfffff000 0x00 0x1000>;
|
||||
msi-controller;
|
||||
#msi-cells = <0>;
|
||||
msi-ranges = <&gicv2 GIC_SPI 128 IRQ_TYPE_EDGE_RISING 64>;
|
||||
};
|
||||
};
|
||||
@@ -14,6 +14,7 @@ properties:
|
||||
items:
|
||||
- enum:
|
||||
- brcm,bcm2711-pcie # The Raspberry Pi 4
|
||||
- brcm,bcm2712-pcie # Raspberry Pi 5
|
||||
- brcm,bcm4908-pcie
|
||||
- brcm,bcm7211-pcie # Broadcom STB version of RPi4
|
||||
- brcm,bcm7216-pcie # Broadcom 7216 Arm
|
||||
@@ -101,7 +102,10 @@ properties:
|
||||
|
||||
reset-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
- enum: [perst, rescal]
|
||||
- const: bridge
|
||||
- const: swinit
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
@@ -109,6 +109,22 @@ config I8259
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
|
||||
config BCM2712_MIP
|
||||
tristate "Broadcom BCM2712 MSI-X Interrupt Peripheral support"
|
||||
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
default m if ARCH_BRCMSTB
|
||||
depends on ARM_GIC
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select GENERIC_MSI_IRQ
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Enable support for the Broadcom BCM2712 MSI-X target peripheral
|
||||
(MIP) needed by brcmstb PCIe to handle MSI-X interrupts on
|
||||
Raspberry Pi 5.
|
||||
|
||||
If unsure say n.
|
||||
|
||||
config BCM6345_L1_IRQ
|
||||
bool
|
||||
select GENERIC_IRQ_CHIP
|
||||
|
||||
@@ -63,6 +63,7 @@ obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
|
||||
obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o
|
||||
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
|
||||
obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o
|
||||
obj-$(CONFIG_BCM2712_MIP) += irq-bcm2712-mip.o
|
||||
obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o
|
||||
obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o
|
||||
obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
|
||||
|
||||
292
drivers/irqchip/irq-bcm2712-mip.c
Normal file
292
drivers/irqchip/irq-bcm2712-mip.c
Normal file
@@ -0,0 +1,292 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2024 Raspberry Pi Ltd., All Rights Reserved.
|
||||
* Copyright (c) 2024 SUSE
|
||||
*/
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include "irq-msi-lib.h"
|
||||
|
||||
#define MIP_INT_RAISE 0x00
|
||||
#define MIP_INT_CLEAR 0x10
|
||||
#define MIP_INT_CFGL_HOST 0x20
|
||||
#define MIP_INT_CFGH_HOST 0x30
|
||||
#define MIP_INT_MASKL_HOST 0x40
|
||||
#define MIP_INT_MASKH_HOST 0x50
|
||||
#define MIP_INT_MASKL_VPU 0x60
|
||||
#define MIP_INT_MASKH_VPU 0x70
|
||||
#define MIP_INT_STATUSL_HOST 0x80
|
||||
#define MIP_INT_STATUSH_HOST 0x90
|
||||
#define MIP_INT_STATUSL_VPU 0xa0
|
||||
#define MIP_INT_STATUSH_VPU 0xb0
|
||||
|
||||
/**
|
||||
* struct mip_priv - MSI-X interrupt controller data
|
||||
* @lock: Used to protect bitmap alloc/free
|
||||
* @base: Base address of MMIO area
|
||||
* @msg_addr: PCIe MSI-X address
|
||||
* @msi_base: MSI base
|
||||
* @num_msis: Count of MSIs
|
||||
* @msi_offset: MSI offset
|
||||
* @bitmap: A bitmap for hwirqs
|
||||
* @parent: Parent domain (GIC)
|
||||
* @dev: A device pointer
|
||||
*/
|
||||
struct mip_priv {
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
u64 msg_addr;
|
||||
u32 msi_base;
|
||||
u32 num_msis;
|
||||
u32 msi_offset;
|
||||
unsigned long *bitmap;
|
||||
struct irq_domain *parent;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static void mip_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
||||
{
|
||||
struct mip_priv *mip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
msg->address_hi = upper_32_bits(mip->msg_addr);
|
||||
msg->address_lo = lower_32_bits(mip->msg_addr);
|
||||
msg->data = d->hwirq;
|
||||
}
|
||||
|
||||
static struct irq_chip mip_middle_irq_chip = {
|
||||
.name = "MIP",
|
||||
.irq_mask = irq_chip_mask_parent,
|
||||
.irq_unmask = irq_chip_unmask_parent,
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_set_type = irq_chip_set_type_parent,
|
||||
.irq_compose_msi_msg = mip_compose_msi_msg,
|
||||
};
|
||||
|
||||
static int mip_alloc_hwirq(struct mip_priv *mip, unsigned int nr_irqs)
|
||||
{
|
||||
guard(spinlock)(&mip->lock);
|
||||
return bitmap_find_free_region(mip->bitmap, mip->num_msis, ilog2(nr_irqs));
|
||||
}
|
||||
|
||||
static void mip_free_hwirq(struct mip_priv *mip, unsigned int hwirq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
guard(spinlock)(&mip->lock);
|
||||
bitmap_release_region(mip->bitmap, hwirq, ilog2(nr_irqs));
|
||||
}
|
||||
|
||||
static int mip_middle_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct mip_priv *mip = domain->host_data;
|
||||
struct irq_fwspec fwspec = {0};
|
||||
unsigned int hwirq, i;
|
||||
struct irq_data *irqd;
|
||||
int irq, ret;
|
||||
|
||||
irq = mip_alloc_hwirq(mip, nr_irqs);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
hwirq = irq + mip->msi_offset;
|
||||
|
||||
fwspec.fwnode = domain->parent->fwnode;
|
||||
fwspec.param_count = 3;
|
||||
fwspec.param[0] = 0;
|
||||
fwspec.param[1] = hwirq + mip->msi_base;
|
||||
fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
|
||||
|
||||
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &fwspec);
|
||||
if (ret)
|
||||
goto err_free_hwirq;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
irqd = irq_domain_get_irq_data(domain->parent, virq + i);
|
||||
irqd->chip->irq_set_type(irqd, IRQ_TYPE_EDGE_RISING);
|
||||
|
||||
ret = irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
|
||||
&mip_middle_irq_chip, mip);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
irqd = irq_get_irq_data(virq + i);
|
||||
irqd_set_single_target(irqd);
|
||||
irqd_set_affinity_on_activate(irqd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
irq_domain_free_irqs_parent(domain, virq, nr_irqs);
|
||||
err_free_hwirq:
|
||||
mip_free_hwirq(mip, irq, nr_irqs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mip_middle_domain_free(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
struct irq_data *irqd = irq_domain_get_irq_data(domain, virq);
|
||||
struct mip_priv *mip;
|
||||
unsigned int hwirq;
|
||||
|
||||
if (!irqd)
|
||||
return;
|
||||
|
||||
mip = irq_data_get_irq_chip_data(irqd);
|
||||
hwirq = irqd_to_hwirq(irqd);
|
||||
irq_domain_free_irqs_parent(domain, virq, nr_irqs);
|
||||
mip_free_hwirq(mip, hwirq - mip->msi_offset, nr_irqs);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops mip_middle_domain_ops = {
|
||||
.select = msi_lib_irq_domain_select,
|
||||
.alloc = mip_middle_domain_alloc,
|
||||
.free = mip_middle_domain_free,
|
||||
};
|
||||
|
||||
#define MIP_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_PCI_MSI_MASK_PARENT)
|
||||
|
||||
#define MIP_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_MULTI_PCI_MSI | \
|
||||
MSI_FLAG_PCI_MSIX)
|
||||
|
||||
static const struct msi_parent_ops mip_msi_parent_ops = {
|
||||
.supported_flags = MIP_MSI_FLAGS_SUPPORTED,
|
||||
.required_flags = MIP_MSI_FLAGS_REQUIRED,
|
||||
.bus_select_token = DOMAIN_BUS_GENERIC_MSI,
|
||||
.bus_select_mask = MATCH_PCI_MSI,
|
||||
.prefix = "MIP-MSI-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int mip_init_domains(struct mip_priv *mip, struct device_node *np)
|
||||
{
|
||||
struct irq_domain *middle;
|
||||
|
||||
middle = irq_domain_add_hierarchy(mip->parent, 0, mip->num_msis, np,
|
||||
&mip_middle_domain_ops, mip);
|
||||
if (!middle)
|
||||
return -ENOMEM;
|
||||
|
||||
irq_domain_update_bus_token(middle, DOMAIN_BUS_GENERIC_MSI);
|
||||
middle->dev = mip->dev;
|
||||
middle->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
|
||||
middle->msi_parent_ops = &mip_msi_parent_ops;
|
||||
|
||||
/*
|
||||
* All MSI-X unmasked for the host, masked for the VPU, and edge-triggered.
|
||||
*/
|
||||
writel(0, mip->base + MIP_INT_MASKL_HOST);
|
||||
writel(0, mip->base + MIP_INT_MASKH_HOST);
|
||||
writel(~0, mip->base + MIP_INT_MASKL_VPU);
|
||||
writel(~0, mip->base + MIP_INT_MASKH_VPU);
|
||||
writel(~0, mip->base + MIP_INT_CFGL_HOST);
|
||||
writel(~0, mip->base + MIP_INT_CFGH_HOST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mip_parse_dt(struct mip_priv *mip, struct device_node *np)
|
||||
{
|
||||
struct of_phandle_args args;
|
||||
u64 size;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "brcm,msi-offset", &mip->msi_offset);
|
||||
if (ret)
|
||||
mip->msi_offset = 0;
|
||||
|
||||
ret = of_parse_phandle_with_args(np, "msi-ranges", "#interrupt-cells",
|
||||
0, &args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = of_property_read_u32_index(np, "msi-ranges", args.args_count + 1,
|
||||
&mip->num_msis);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
|
||||
ret = of_property_read_reg(np, 1, &mip->msg_addr, &size);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
|
||||
mip->msi_base = args.args[1];
|
||||
|
||||
mip->parent = irq_find_host(args.np);
|
||||
if (!mip->parent)
|
||||
ret = -EINVAL;
|
||||
|
||||
err_put:
|
||||
of_node_put(args.np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init mip_of_msi_init(struct device_node *node, struct device_node *parent)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct mip_priv *mip;
|
||||
int ret;
|
||||
|
||||
pdev = of_find_device_by_node(node);
|
||||
of_node_put(node);
|
||||
if (!pdev)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
mip = kzalloc(sizeof(*mip), GFP_KERNEL);
|
||||
if (!mip)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&mip->lock);
|
||||
mip->dev = &pdev->dev;
|
||||
|
||||
ret = mip_parse_dt(mip, node);
|
||||
if (ret)
|
||||
goto err_priv;
|
||||
|
||||
mip->base = of_iomap(node, 0);
|
||||
if (!mip->base) {
|
||||
ret = -ENXIO;
|
||||
goto err_priv;
|
||||
}
|
||||
|
||||
mip->bitmap = bitmap_zalloc(mip->num_msis, GFP_KERNEL);
|
||||
if (!mip->bitmap) {
|
||||
ret = -ENOMEM;
|
||||
goto err_base;
|
||||
}
|
||||
|
||||
ret = mip_init_domains(mip, node);
|
||||
if (ret)
|
||||
goto err_map;
|
||||
|
||||
dev_dbg(&pdev->dev, "MIP: MSI-X count: %u, base: %u, offset: %u, msg_addr: %llx\n",
|
||||
mip->num_msis, mip->msi_base, mip->msi_offset, mip->msg_addr);
|
||||
|
||||
return 0;
|
||||
|
||||
err_map:
|
||||
bitmap_free(mip->bitmap);
|
||||
err_base:
|
||||
iounmap(mip->base);
|
||||
err_priv:
|
||||
kfree(mip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRQCHIP_PLATFORM_DRIVER_BEGIN(mip_msi)
|
||||
IRQCHIP_MATCH("brcm,bcm2712-mip", mip_of_msi_init)
|
||||
IRQCHIP_PLATFORM_DRIVER_END(mip_msi)
|
||||
MODULE_DESCRIPTION("Broadcom BCM2712 MSI-X interrupt controller");
|
||||
MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");
|
||||
MODULE_AUTHOR("Stanimir Varbanov <svarbanov@suse.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -55,6 +55,10 @@
|
||||
#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
|
||||
#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
|
||||
|
||||
#define PCIE_RC_PL_PHY_CTL_15 0x184c
|
||||
#define PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK 0x400000
|
||||
#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff
|
||||
|
||||
#define PCIE_MISC_MISC_CTRL 0x4008
|
||||
#define PCIE_MISC_MISC_CTRL_PCIE_RCB_64B_MODE_MASK 0x80
|
||||
#define PCIE_MISC_MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400
|
||||
@@ -146,9 +150,6 @@
|
||||
#define MSI_INT_MASK_SET 0x10
|
||||
#define MSI_INT_MASK_CLR 0x14
|
||||
|
||||
#define PCIE_EXT_CFG_DATA 0x8000
|
||||
#define PCIE_EXT_CFG_INDEX 0x9000
|
||||
|
||||
#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
|
||||
#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
|
||||
|
||||
@@ -174,8 +175,9 @@
|
||||
#define MDIO_PORT0 0x0
|
||||
#define MDIO_DATA_MASK 0x7fffffff
|
||||
#define MDIO_PORT_MASK 0xf0000
|
||||
#define MDIO_PORT_EXT_MASK 0x200000
|
||||
#define MDIO_REGAD_MASK 0xffff
|
||||
#define MDIO_CMD_MASK 0xfff00000
|
||||
#define MDIO_CMD_MASK 0x00100000
|
||||
#define MDIO_CMD_READ 0x1
|
||||
#define MDIO_CMD_WRITE 0x0
|
||||
#define MDIO_DATA_DONE_MASK 0x80000000
|
||||
@@ -191,11 +193,11 @@
|
||||
#define SSC_STATUS_PLL_LOCK_MASK 0x800
|
||||
#define PCIE_BRCM_MAX_MEMC 3
|
||||
|
||||
#define IDX_ADDR(pcie) ((pcie)->reg_offsets[EXT_CFG_INDEX])
|
||||
#define DATA_ADDR(pcie) ((pcie)->reg_offsets[EXT_CFG_DATA])
|
||||
#define PCIE_RGR1_SW_INIT_1(pcie) ((pcie)->reg_offsets[RGR1_SW_INIT_1])
|
||||
#define HARD_DEBUG(pcie) ((pcie)->reg_offsets[PCIE_HARD_DEBUG])
|
||||
#define INTR2_CPU_BASE(pcie) ((pcie)->reg_offsets[PCIE_INTR2_CPU_BASE])
|
||||
#define IDX_ADDR(pcie) ((pcie)->cfg->offsets[EXT_CFG_INDEX])
|
||||
#define DATA_ADDR(pcie) ((pcie)->cfg->offsets[EXT_CFG_DATA])
|
||||
#define PCIE_RGR1_SW_INIT_1(pcie) ((pcie)->cfg->offsets[RGR1_SW_INIT_1])
|
||||
#define HARD_DEBUG(pcie) ((pcie)->cfg->offsets[PCIE_HARD_DEBUG])
|
||||
#define INTR2_CPU_BASE(pcie) ((pcie)->cfg->offsets[PCIE_INTR2_CPU_BASE])
|
||||
|
||||
/* Rescal registers */
|
||||
#define PCIE_DVT_PMU_PCIE_PHY_CTRL 0xc700
|
||||
@@ -234,13 +236,24 @@ struct inbound_win {
|
||||
u64 cpu_addr;
|
||||
};
|
||||
|
||||
/*
|
||||
* The RESCAL block is tied to PCIe controller #1, regardless of the number of
|
||||
* controllers, and turning off PCIe controller #1 prevents access to the RESCAL
|
||||
* register blocks, therefore no other controller can access this register
|
||||
* space, and depending upon the bus fabric we may get a timeout (UBUS/GISB),
|
||||
* or a hang (AXI).
|
||||
*/
|
||||
#define CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN BIT(0)
|
||||
|
||||
struct pcie_cfg_data {
|
||||
const int *offsets;
|
||||
const enum pcie_soc_base soc_base;
|
||||
const bool has_phy;
|
||||
const u32 quirks;
|
||||
u8 num_inbound_wins;
|
||||
int (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
||||
int (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
||||
int (*post_setup)(struct brcm_pcie *pcie);
|
||||
};
|
||||
|
||||
struct subdev_regulators {
|
||||
@@ -276,8 +289,6 @@ struct brcm_pcie {
|
||||
int gen;
|
||||
u64 msi_target_addr;
|
||||
struct brcm_msi *msi;
|
||||
const int *reg_offsets;
|
||||
enum pcie_soc_base soc_base;
|
||||
struct reset_control *rescal;
|
||||
struct reset_control *perst_reset;
|
||||
struct reset_control *bridge_reset;
|
||||
@@ -285,17 +296,14 @@ struct brcm_pcie {
|
||||
int num_memc;
|
||||
u64 memc_size[PCIE_BRCM_MAX_MEMC];
|
||||
u32 hw_rev;
|
||||
int (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
||||
int (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
||||
struct subdev_regulators *sr;
|
||||
bool ep_wakeup_capable;
|
||||
bool has_phy;
|
||||
u8 num_inbound_wins;
|
||||
const struct pcie_cfg_data *cfg;
|
||||
};
|
||||
|
||||
static inline bool is_bmips(const struct brcm_pcie *pcie)
|
||||
{
|
||||
return pcie->soc_base == BCM7435 || pcie->soc_base == BCM7425;
|
||||
return pcie->cfg->soc_base == BCM7435 || pcie->cfg->soc_base == BCM7425;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -309,8 +317,8 @@ static int brcm_pcie_encode_ibar_size(u64 size)
|
||||
if (log2_in >= 12 && log2_in <= 15)
|
||||
/* Covers 4KB to 32KB (inclusive) */
|
||||
return (log2_in - 12) + 0x1c;
|
||||
else if (log2_in >= 16 && log2_in <= 35)
|
||||
/* Covers 64KB to 32GB, (inclusive) */
|
||||
else if (log2_in >= 16 && log2_in <= 36)
|
||||
/* Covers 64KB to 64GB, (inclusive) */
|
||||
return log2_in - 15;
|
||||
/* Something is awry so disable */
|
||||
return 0;
|
||||
@@ -320,6 +328,7 @@ static u32 brcm_pcie_mdio_form_pkt(int port, int regad, int cmd)
|
||||
{
|
||||
u32 pkt = 0;
|
||||
|
||||
pkt |= FIELD_PREP(MDIO_PORT_EXT_MASK, port >> 4);
|
||||
pkt |= FIELD_PREP(MDIO_PORT_MASK, port);
|
||||
pkt |= FIELD_PREP(MDIO_REGAD_MASK, regad);
|
||||
pkt |= FIELD_PREP(MDIO_CMD_MASK, cmd);
|
||||
@@ -403,12 +412,12 @@ static int brcm_pcie_set_ssc(struct brcm_pcie *pcie)
|
||||
static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen)
|
||||
{
|
||||
u16 lnkctl2 = readw(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
|
||||
u32 lnkcap = readl(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
|
||||
u32 lnkcap = readl(pcie->base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
|
||||
|
||||
lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
|
||||
writel(lnkcap, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP);
|
||||
u32p_replace_bits(&lnkcap, gen, PCI_EXP_LNKCAP_SLS);
|
||||
writel(lnkcap, pcie->base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
|
||||
|
||||
lnkctl2 = (lnkctl2 & ~0xf) | gen;
|
||||
u16p_replace_bits(&lnkctl2, gen, PCI_EXP_LNKCTL2_TLS);
|
||||
writew(lnkctl2, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2);
|
||||
}
|
||||
|
||||
@@ -550,7 +559,7 @@ static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
return hwirq;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_set_info(domain, virq + i, hwirq + i,
|
||||
irq_domain_set_info(domain, virq + i, (irq_hw_number_t)hwirq + i,
|
||||
&brcm_msi_bottom_irq_chip, domain->host_data,
|
||||
handle_edge_irq, NULL, NULL);
|
||||
return 0;
|
||||
@@ -717,8 +726,8 @@ static void __iomem *brcm_pcie_map_bus(struct pci_bus *bus,
|
||||
|
||||
/* For devices, write to the config space index register */
|
||||
idx = PCIE_ECAM_OFFSET(bus->number, devfn, 0);
|
||||
writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
|
||||
return base + PCIE_EXT_CFG_DATA + PCIE_ECAM_REG(where);
|
||||
writel(idx, base + IDX_ADDR(pcie));
|
||||
return base + DATA_ADDR(pcie) + PCIE_ECAM_REG(where);
|
||||
}
|
||||
|
||||
static void __iomem *brcm7425_pcie_map_bus(struct pci_bus *bus,
|
||||
@@ -821,6 +830,39 @@ static int brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int brcm_pcie_post_setup_bcm2712(struct brcm_pcie *pcie)
|
||||
{
|
||||
static const u16 data[] = { 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030,
|
||||
0x5030, 0x0007 };
|
||||
static const u8 regs[] = { 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e };
|
||||
int ret, i;
|
||||
u32 tmp;
|
||||
|
||||
/* Allow a 54MHz (xosc) refclk source */
|
||||
ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, 0x1600);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, regs[i], data[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(100, 200);
|
||||
|
||||
/*
|
||||
* Set L1SS sub-state timers to avoid lengthy state transitions,
|
||||
* PM clock period is 18.52ns (1/54MHz, round down).
|
||||
*/
|
||||
tmp = readl(pcie->base + PCIE_RC_PL_PHY_CTL_15);
|
||||
tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK;
|
||||
tmp |= 0x12;
|
||||
writel(tmp, pcie->base + PCIE_RC_PL_PHY_CTL_15);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_inbound_win(struct inbound_win *b, u8 *count, u64 size,
|
||||
u64 cpu_addr, u64 pci_offset)
|
||||
{
|
||||
@@ -855,7 +897,7 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie,
|
||||
* security considerations, and is not implemented in our modern
|
||||
* SoCs.
|
||||
*/
|
||||
if (pcie->soc_base != BCM7712)
|
||||
if (pcie->cfg->soc_base != BCM7712)
|
||||
add_inbound_win(b++, &n, 0, 0, 0);
|
||||
|
||||
resource_list_for_each_entry(entry, &bridge->dma_ranges) {
|
||||
@@ -872,10 +914,10 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie,
|
||||
* That being said, each BARs size must still be a power of
|
||||
* two.
|
||||
*/
|
||||
if (pcie->soc_base == BCM7712)
|
||||
if (pcie->cfg->soc_base == BCM7712)
|
||||
add_inbound_win(b++, &n, size, cpu_start, pcie_start);
|
||||
|
||||
if (n > pcie->num_inbound_wins)
|
||||
if (n > pcie->cfg->num_inbound_wins)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -889,7 +931,7 @@ static int brcm_pcie_get_inbound_wins(struct brcm_pcie *pcie,
|
||||
* that enables multiple memory controllers. As such, it can return
|
||||
* now w/o doing special configuration.
|
||||
*/
|
||||
if (pcie->soc_base == BCM7712)
|
||||
if (pcie->cfg->soc_base == BCM7712)
|
||||
return n;
|
||||
|
||||
ret = of_property_read_variable_u64_array(pcie->np, "brcm,scb-sizes", pcie->memc_size, 1,
|
||||
@@ -1012,7 +1054,7 @@ static void set_inbound_win_registers(struct brcm_pcie *pcie,
|
||||
* 7712:
|
||||
* All of their BARs need to be set.
|
||||
*/
|
||||
if (pcie->soc_base == BCM7712) {
|
||||
if (pcie->cfg->soc_base == BCM7712) {
|
||||
/* BUS remap register settings */
|
||||
reg_offset = brcm_ubus_reg_offset(i);
|
||||
tmp = lower_32_bits(cpu_addr) & ~0xfff;
|
||||
@@ -1036,15 +1078,15 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
int memc, ret;
|
||||
|
||||
/* Reset the bridge */
|
||||
ret = pcie->bridge_sw_init_set(pcie, 1);
|
||||
ret = pcie->cfg->bridge_sw_init_set(pcie, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Ensure that PERST# is asserted; some bootloaders may deassert it. */
|
||||
if (pcie->soc_base == BCM2711) {
|
||||
ret = pcie->perst_set(pcie, 1);
|
||||
if (pcie->cfg->soc_base == BCM2711) {
|
||||
ret = pcie->cfg->perst_set(pcie, 1);
|
||||
if (ret) {
|
||||
pcie->bridge_sw_init_set(pcie, 0);
|
||||
pcie->cfg->bridge_sw_init_set(pcie, 0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -1052,7 +1094,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
usleep_range(100, 200);
|
||||
|
||||
/* Take the bridge out of reset */
|
||||
ret = pcie->bridge_sw_init_set(pcie, 0);
|
||||
ret = pcie->cfg->bridge_sw_init_set(pcie, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1072,9 +1114,9 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
*/
|
||||
if (is_bmips(pcie))
|
||||
burst = 0x1; /* 256 bytes */
|
||||
else if (pcie->soc_base == BCM2711)
|
||||
else if (pcie->cfg->soc_base == BCM2711)
|
||||
burst = 0x0; /* 128 bytes */
|
||||
else if (pcie->soc_base == BCM7278)
|
||||
else if (pcie->cfg->soc_base == BCM7278)
|
||||
burst = 0x3; /* 512 bytes */
|
||||
else
|
||||
burst = 0x2; /* 512 bytes */
|
||||
@@ -1184,6 +1226,12 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK);
|
||||
writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
|
||||
|
||||
if (pcie->cfg->post_setup) {
|
||||
ret = pcie->cfg->post_setup(pcie);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1199,7 +1247,7 @@ static void brcm_extend_rbus_timeout(struct brcm_pcie *pcie)
|
||||
u32 timeout_us = 4000000; /* 4 seconds, our setting for L1SS */
|
||||
|
||||
/* 7712 does not have this (RGR1) timer */
|
||||
if (pcie->soc_base == BCM7712)
|
||||
if (pcie->cfg->soc_base == BCM7712)
|
||||
return;
|
||||
|
||||
/* Each unit in timeout register is 1/216,000,000 seconds */
|
||||
@@ -1276,8 +1324,12 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
|
||||
bool ssc_good = false;
|
||||
int ret, i;
|
||||
|
||||
/* Limit the generation if specified */
|
||||
if (pcie->gen)
|
||||
brcm_pcie_set_gen(pcie, pcie->gen);
|
||||
|
||||
/* Unassert the fundamental reset */
|
||||
ret = pcie->perst_set(pcie, 0);
|
||||
ret = pcie->cfg->perst_set(pcie, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1302,9 +1354,6 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
|
||||
|
||||
brcm_config_clkreq(pcie);
|
||||
|
||||
if (pcie->gen)
|
||||
brcm_pcie_set_gen(pcie, pcie->gen);
|
||||
|
||||
if (pcie->ssc) {
|
||||
ret = brcm_pcie_set_ssc(pcie);
|
||||
if (ret == 0)
|
||||
@@ -1367,7 +1416,8 @@ static int brcm_pcie_add_bus(struct pci_bus *bus)
|
||||
|
||||
ret = regulator_bulk_get(dev, sr->num_supplies, sr->supplies);
|
||||
if (ret) {
|
||||
dev_info(dev, "No regulators for downstream device\n");
|
||||
dev_info(dev, "Did not get regulators, err=%d\n", ret);
|
||||
pcie->sr = NULL;
|
||||
goto no_regulators;
|
||||
}
|
||||
|
||||
@@ -1390,7 +1440,7 @@ static void brcm_pcie_remove_bus(struct pci_bus *bus)
|
||||
struct subdev_regulators *sr = pcie->sr;
|
||||
struct device *dev = &bus->dev;
|
||||
|
||||
if (!sr)
|
||||
if (!sr || !bus->parent || !pci_is_root_bus(bus->parent))
|
||||
return;
|
||||
|
||||
if (regulator_bulk_disable(sr->num_supplies, sr->supplies))
|
||||
@@ -1463,12 +1513,12 @@ static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start)
|
||||
|
||||
static inline int brcm_phy_start(struct brcm_pcie *pcie)
|
||||
{
|
||||
return pcie->has_phy ? brcm_phy_cntl(pcie, 1) : 0;
|
||||
return pcie->cfg->has_phy ? brcm_phy_cntl(pcie, 1) : 0;
|
||||
}
|
||||
|
||||
static inline int brcm_phy_stop(struct brcm_pcie *pcie)
|
||||
{
|
||||
return pcie->has_phy ? brcm_phy_cntl(pcie, 0) : 0;
|
||||
return pcie->cfg->has_phy ? brcm_phy_cntl(pcie, 0) : 0;
|
||||
}
|
||||
|
||||
static int brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
||||
@@ -1479,7 +1529,7 @@ static int brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
||||
if (brcm_pcie_link_up(pcie))
|
||||
brcm_pcie_enter_l23(pcie);
|
||||
/* Assert fundamental reset */
|
||||
ret = pcie->perst_set(pcie, 1);
|
||||
ret = pcie->cfg->perst_set(pcie, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1493,8 +1543,9 @@ static int brcm_pcie_turn_off(struct brcm_pcie *pcie)
|
||||
u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
|
||||
writel(tmp, base + HARD_DEBUG(pcie));
|
||||
|
||||
/* Shutdown PCIe bridge */
|
||||
ret = pcie->bridge_sw_init_set(pcie, 1);
|
||||
if (!(pcie->cfg->quirks & CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN))
|
||||
/* Shutdown PCIe bridge */
|
||||
ret = pcie->cfg->bridge_sw_init_set(pcie, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1582,7 +1633,7 @@ static int brcm_pcie_resume_noirq(struct device *dev)
|
||||
goto err_reset;
|
||||
|
||||
/* Take bridge out of reset so we can access the SERDES reg */
|
||||
pcie->bridge_sw_init_set(pcie, 0);
|
||||
pcie->cfg->bridge_sw_init_set(pcie, 0);
|
||||
|
||||
/* SERDES_IDDQ = 0 */
|
||||
tmp = readl(base + HARD_DEBUG(pcie));
|
||||
@@ -1660,7 +1711,7 @@ static void brcm_pcie_remove(struct platform_device *pdev)
|
||||
static const int pcie_offsets[] = {
|
||||
[RGR1_SW_INIT_1] = 0x9210,
|
||||
[EXT_CFG_INDEX] = 0x9000,
|
||||
[EXT_CFG_DATA] = 0x9004,
|
||||
[EXT_CFG_DATA] = 0x8000,
|
||||
[PCIE_HARD_DEBUG] = 0x4204,
|
||||
[PCIE_INTR2_CPU_BASE] = 0x4300,
|
||||
};
|
||||
@@ -1668,7 +1719,7 @@ static const int pcie_offsets[] = {
|
||||
static const int pcie_offsets_bcm7278[] = {
|
||||
[RGR1_SW_INIT_1] = 0xc010,
|
||||
[EXT_CFG_INDEX] = 0x9000,
|
||||
[EXT_CFG_DATA] = 0x9004,
|
||||
[EXT_CFG_DATA] = 0x8000,
|
||||
[PCIE_HARD_DEBUG] = 0x4204,
|
||||
[PCIE_INTR2_CPU_BASE] = 0x4300,
|
||||
};
|
||||
@@ -1682,8 +1733,9 @@ static const int pcie_offsets_bcm7425[] = {
|
||||
};
|
||||
|
||||
static const int pcie_offsets_bcm7712[] = {
|
||||
[RGR1_SW_INIT_1] = 0x9210,
|
||||
[EXT_CFG_INDEX] = 0x9000,
|
||||
[EXT_CFG_DATA] = 0x9004,
|
||||
[EXT_CFG_DATA] = 0x8000,
|
||||
[PCIE_HARD_DEBUG] = 0x4304,
|
||||
[PCIE_INTR2_CPU_BASE] = 0x4400,
|
||||
};
|
||||
@@ -1704,6 +1756,16 @@ static const struct pcie_cfg_data bcm2711_cfg = {
|
||||
.num_inbound_wins = 3,
|
||||
};
|
||||
|
||||
static const struct pcie_cfg_data bcm2712_cfg = {
|
||||
.offsets = pcie_offsets_bcm7712,
|
||||
.soc_base = BCM7712,
|
||||
.perst_set = brcm_pcie_perst_set_7278,
|
||||
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
|
||||
.post_setup = brcm_pcie_post_setup_bcm2712,
|
||||
.quirks = CFG_QUIRK_AVOID_BRIDGE_SHUTDOWN,
|
||||
.num_inbound_wins = 10,
|
||||
};
|
||||
|
||||
static const struct pcie_cfg_data bcm4908_cfg = {
|
||||
.offsets = pcie_offsets,
|
||||
.soc_base = BCM4908,
|
||||
@@ -1755,6 +1817,7 @@ static const struct pcie_cfg_data bcm7712_cfg = {
|
||||
|
||||
static const struct of_device_id brcm_pcie_match[] = {
|
||||
{ .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
|
||||
{ .compatible = "brcm,bcm2712-pcie", .data = &bcm2712_cfg },
|
||||
{ .compatible = "brcm,bcm4908-pcie", .data = &bcm4908_cfg },
|
||||
{ .compatible = "brcm,bcm7211-pcie", .data = &generic_cfg },
|
||||
{ .compatible = "brcm,bcm7216-pcie", .data = &bcm7216_cfg },
|
||||
@@ -1784,7 +1847,7 @@ static struct pci_ops brcm7425_pcie_ops = {
|
||||
|
||||
static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node, *msi_np;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct pci_host_bridge *bridge;
|
||||
const struct pcie_cfg_data *data;
|
||||
struct brcm_pcie *pcie;
|
||||
@@ -1803,12 +1866,7 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
pcie = pci_host_bridge_priv(bridge);
|
||||
pcie->dev = &pdev->dev;
|
||||
pcie->np = np;
|
||||
pcie->reg_offsets = data->offsets;
|
||||
pcie->soc_base = data->soc_base;
|
||||
pcie->perst_set = data->perst_set;
|
||||
pcie->bridge_sw_init_set = data->bridge_sw_init_set;
|
||||
pcie->has_phy = data->has_phy;
|
||||
pcie->num_inbound_wins = data->num_inbound_wins;
|
||||
pcie->cfg = data;
|
||||
|
||||
pcie->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(pcie->base))
|
||||
@@ -1843,7 +1901,7 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "could not enable clock\n");
|
||||
|
||||
pcie->bridge_sw_init_set(pcie, 0);
|
||||
pcie->cfg->bridge_sw_init_set(pcie, 0);
|
||||
|
||||
if (pcie->swinit_reset) {
|
||||
ret = reset_control_assert(pcie->swinit_reset);
|
||||
@@ -1882,22 +1940,29 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
goto fail;
|
||||
|
||||
pcie->hw_rev = readl(pcie->base + PCIE_MISC_REVISION);
|
||||
if (pcie->soc_base == BCM4908 && pcie->hw_rev >= BRCM_PCIE_HW_REV_3_20) {
|
||||
if (pcie->cfg->soc_base == BCM4908 &&
|
||||
pcie->hw_rev >= BRCM_PCIE_HW_REV_3_20) {
|
||||
dev_err(pcie->dev, "hardware revision with unsupported PERST# setup\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);
|
||||
if (pci_msi_enabled() && msi_np == pcie->np) {
|
||||
ret = brcm_pcie_enable_msi(pcie);
|
||||
if (pci_msi_enabled()) {
|
||||
struct device_node *msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);
|
||||
|
||||
if (msi_np == pcie->np)
|
||||
ret = brcm_pcie_enable_msi(pcie);
|
||||
|
||||
of_node_put(msi_np);
|
||||
|
||||
if (ret) {
|
||||
dev_err(pcie->dev, "probe of internal MSI failed");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
bridge->ops = pcie->soc_base == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops;
|
||||
bridge->ops = pcie->cfg->soc_base == BCM7425 ?
|
||||
&brcm7425_pcie_ops : &brcm_pcie_ops;
|
||||
bridge->sysdata = pcie;
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
@@ -1940,3 +2005,4 @@ module_platform_driver(brcm_pcie_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Broadcom STB PCIe RC driver");
|
||||
MODULE_AUTHOR("Broadcom");
|
||||
MODULE_SOFTDEP("pre: irq_bcm2712_mip");
|
||||
|
||||
Reference in New Issue
Block a user