mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 18:47:06 +00:00
2e715fb4fc
Add support for BCM2712 (Raspberry Pi 5).
3bb5880ab3
Patches were generated from the diff between linux kernel branch linux-6.1.y
and rpi-6.1.y from raspberry pi kernel source:
- git format-patch linux-6.1.y...rpi-6.1.y
Build system: x86_64
Build-tested: bcm2708, bcm2709, bcm2710, bcm2711
Run-tested: bcm2710/RPi3B, bcm2711/RPi4B
Signed-off-by: Marty Jones <mj8263788@gmail.com>
[Remove applied and reverted patches, squash patches and config commits]
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
1109 lines
37 KiB
Diff
1109 lines
37 KiB
Diff
From 29702857d1ab71243ea6c247dfe9b5bc43dd422f Mon Sep 17 00:00:00 2001
|
|
From: Jim Quinlan <james.quinlan@broadcom.com>
|
|
Date: Fri, 23 Jun 2023 10:40:57 -0400
|
|
Subject: [PATCH] PCI: brcmstb: Add BCM2712 support
|
|
|
|
PCI: brcmstb: differing register offsets on 2712
|
|
|
|
pcie-brcmstb: Add 2712 bridge reset support
|
|
|
|
pcie: 2712 PORT_MASK and rescal support
|
|
|
|
pcie-brcmstb: don't alter the L1SS debug register
|
|
|
|
For reasons unknown, this disables the reference clock
|
|
|
|
pcie-brcmstb: fix BAR2 enable and window decode
|
|
|
|
Set UBUS ACCESS_EN to let inbound DMA work. Also BCM2712 has grown
|
|
an index in the inbound window size decode register.
|
|
|
|
PCIe: brcmstb: Enable support for 64 MSI-Xs
|
|
|
|
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
|
|
|
pcie-brcmstb: Suppress read error responses
|
|
|
|
If the link is down or the EP fails to return a read completion, the
|
|
RC's default behaviour is to return an AXI error. This causes fatal
|
|
exceptions on A76, so it's better to respond with all 1s instead.
|
|
|
|
pcie-brcmstb: increase UBUS timeout to cater for link retrain events
|
|
|
|
pcie-brcmstb: Handle additional inbound regions
|
|
|
|
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
|
|
|
pcie-brcmstb: Add support for external MSI controller
|
|
|
|
pcie-brcmstb: add a reasonable default traffic class to priority map
|
|
|
|
BCM2712 supports multiple traffic classes (TCs) with independent
|
|
maximally sized transfer queues for each TC. Traffic classes have no
|
|
transaction ordering requirements between them, which facilitates
|
|
out-of-order completions and arbitration between posted writes for
|
|
data streams that have no dependence on each other.
|
|
|
|
In addition to the above benefits of splitting endpoint traffic into
|
|
individual queues, priorities can be assigned to traffic classes by
|
|
a heuristic or deterministic mechanism. The heuristic elevates AXI
|
|
QOS priority in accordance with the number of pending transfers in
|
|
each TC's queue, but for true priority signalling a forwarding
|
|
mechanism using vendor-defined messages is implemented.
|
|
|
|
Receipt of a 3 DWORD VDM assigns a priority tag to a TC on-the-fly,
|
|
and this tag corresponds to a configurable AXI QOS value.
|
|
|
|
As a simple baseline, assign a linear map of AXI QOS to each tag.
|
|
|
|
pcie: brcmstb: set up the VDM forwarding interface when setting up QoS
|
|
|
|
pcie-brcmstb: add DT bindings for MPS-size Read Completion Mode
|
|
|
|
This controller has an optional feature that allows read completion
|
|
TLPs to be sized up to the Maximum Packet Size of a configured link.
|
|
|
|
This can exceed the Read Completion Boundary of 128B specified in
|
|
the PCIe specification, but depending on endpoint support may increase
|
|
link read bandwidth significantly.
|
|
|
|
pcie-brcmstb: clean up debug messages
|
|
|
|
pcie-brcmstb: fix BCM2712A0 PHY PM errata
|
|
|
|
The power management clock is 54MHz not 50MHz, so adjust the PM clock period
|
|
to suit. Powering off the PHY PLL in L1.2 is unsafe, so force it on.
|
|
|
|
pcie-brcmstb: set CLKREQ functionality according to link partner support
|
|
|
|
The RC supports either L1 with clock PM or L1 sub-state control, not both
|
|
at the same time. Examine the link partner's capabilities to determine
|
|
which is the most suitable scheme to use.
|
|
|
|
pcie: brcmstb: don't reset block bridges in suspend or removal cases
|
|
|
|
BCM2712 has a single rescal block for all three root complexes, and
|
|
holding PCIE1's bridge in reset will hang the chip if a different
|
|
RC wants to access any of the rescal registers.
|
|
|
|
pcie: brcmstb: guard 2712-specific setup with a RC type check
|
|
|
|
BCM2711 doesn't implement the UBUS control registers.
|
|
|
|
pcie: brcmstb: On 2712 keeping the PLL powered in L1.x is not required
|
|
|
|
A separate misconfiguration when enabling SSC (the MDIO registers no
|
|
longer do the same thing on BCM2712) had the side-effect of breaking
|
|
PLL powerdown and resume sequencing.
|
|
|
|
Allow entry into a true L1.2 state where analogue is depowered.
|
|
|
|
pcie: brcmstb: Fix reset warning on probe failure
|
|
|
|
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
|
|
|
bcm2712: pcie: adjust PHY PLL setup to use a 54MHz input refclk
|
|
|
|
Use canned MDIO writes from Broadcom that switch the ref_clk output
|
|
pair to run from the internal fractional PLL, and set the internal PLL
|
|
to expect a 54MHz input reference clock.
|
|
|
|
Gen3 operation is not guaranteed to be stable in this setup, so default
|
|
to gen2.
|
|
|
|
This only works if the LCPLL is bypassed (requires latest bootloader).
|
|
|
|
pcie: brcmstb: add missing register writes
|
|
|
|
drivers: pcie: brcmstb: cater for BCM2712C0 bug dropping QoS on the floor
|
|
|
|
The AXI QoS value extracted from the request fifo ends up as zero forever.
|
|
Disabling this means that "panic" signalling doesn't do anything useful,
|
|
but static priorites do work.
|
|
|
|
Also align the selected TC:QoS map with RP1's expectations of service.
|
|
|
|
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
|
|
|
drivers: pcie: brcmstb: shuffle TC priorities up to 8
|
|
|
|
Use the range 8-11 which puts the highest below HVS but leaves space
|
|
below for other 2712 masters.
|
|
|
|
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
|
|
|
drivers: pcie: brcmstb: optionally enable QoS features by DT for BCM2712
|
|
|
|
It's a bad idea to universally enable "realtime" priorities for TCs
|
|
across all the RC instances on the chip. Endpoints other than RP1 may
|
|
make use of these, so you don't want e.g. NVMe descriptor fetches getting
|
|
higher priority than your remote display.
|
|
|
|
Add two optional DT properties controlling the behaviour - FIFO-based
|
|
backpressure QoS or "message-based". Message-based signalling is
|
|
fundamentally broken due to a chip bug, so it collapses into a set of
|
|
static assignments that RP1 needs.
|
|
|
|
The default if neither property is specified is to assign everything a
|
|
QoS of 0.
|
|
|
|
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
|
|
|
drivers: pcie: brcmstb: adjust completion timeouts for bcm2712
|
|
|
|
Setting the RC config retry timeout makes CRS auto-polling work, but
|
|
the UBUS timeout will override the config retry. Both need to be large.
|
|
|
|
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
|
---
|
|
drivers/pci/controller/pcie-brcmstb.c | 507 +++++++++++++++++++++++---
|
|
1 file changed, 458 insertions(+), 49 deletions(-)
|
|
|
|
--- a/drivers/pci/controller/pcie-brcmstb.c
|
|
+++ b/drivers/pci/controller/pcie-brcmstb.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <linux/irqchip/chained_irq.h>
|
|
#include <linux/irqdomain.h>
|
|
#include <linux/kernel.h>
|
|
+#include <linux/kthread.h>
|
|
#include <linux/list.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/module.h>
|
|
@@ -47,11 +48,25 @@
|
|
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc
|
|
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
|
|
|
|
+#define PCIE_RC_TL_VDM_CTL0 0x0a20
|
|
+#define PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK 0x10000
|
|
+#define PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK 0x20000
|
|
+#define PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK 0x40000
|
|
+
|
|
+#define PCIE_RC_TL_VDM_CTL1 0x0a0c
|
|
+#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID0_MASK 0x0000ffff
|
|
+#define PCIE_RC_TL_VDM_CTL1_VDM_VNDRID1_MASK 0xffff0000
|
|
+
|
|
#define PCIE_RC_DL_MDIO_ADDR 0x1100
|
|
#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_RCB_MPS_MODE_MASK 0x400
|
|
#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
|
|
#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
|
|
#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
|
|
@@ -71,6 +86,7 @@
|
|
|
|
#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
|
|
#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
|
|
+#define PCIE_MISC_RC_BAR1_CONFIG_HI 0x4030
|
|
|
|
#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
|
|
#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f
|
|
@@ -78,6 +94,7 @@
|
|
|
|
#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
|
|
#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
|
|
+#define PCIE_MISC_RC_BAR3_CONFIG_HI 0x4040
|
|
|
|
#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044
|
|
#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048
|
|
@@ -86,12 +103,15 @@
|
|
#define PCIE_MISC_MSI_DATA_CONFIG_VAL_32 0xffe06540
|
|
#define PCIE_MISC_MSI_DATA_CONFIG_VAL_8 0xfff86540
|
|
|
|
+#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT 0x405c
|
|
+
|
|
#define PCIE_MISC_PCIE_CTRL 0x4064
|
|
#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1
|
|
#define PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK 0x4
|
|
|
|
#define PCIE_MISC_PCIE_STATUS 0x4068
|
|
#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80
|
|
+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712 0x40
|
|
#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20
|
|
#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10
|
|
#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40
|
|
@@ -116,14 +136,73 @@
|
|
#define PCIE_MEM_WIN0_LIMIT_HI(win) \
|
|
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
|
|
|
|
-#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
|
|
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG pcie->reg_offsets[PCIE_HARD_DEBUG]
|
|
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
|
|
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
|
|
#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000
|
|
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK 0x00200000
|
|
|
|
+#define PCIE_MISC_CTRL_1 0x40A0
|
|
+#define PCIE_MISC_CTRL_1_OUTBOUND_TC_MASK 0xf
|
|
+#define PCIE_MISC_CTRL_1_OUTBOUND_NO_SNOOP_MASK BIT(3)
|
|
+#define PCIE_MISC_CTRL_1_OUTBOUND_RO_MASK BIT(4)
|
|
+#define PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK BIT(5)
|
|
+
|
|
+#define PCIE_MISC_UBUS_CTRL 0x40a4
|
|
+#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK BIT(13)
|
|
+#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK BIT(19)
|
|
+
|
|
+#define PCIE_MISC_UBUS_TIMEOUT 0x40A8
|
|
+
|
|
+#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac
|
|
+#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0)
|
|
+#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI 0x40b0
|
|
+
|
|
+#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP 0x40b4
|
|
+#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0)
|
|
+
|
|
+/* Additional RC BARs */
|
|
+#define PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK 0x1f
|
|
+#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4
|
|
+#define PCIE_MISC_RC_BAR4_CONFIG_HI 0x40d8
|
|
+/* ... */
|
|
+#define PCIE_MISC_RC_BAR10_CONFIG_LO 0x4104
|
|
+#define PCIE_MISC_RC_BAR10_CONFIG_HI 0x4108
|
|
+
|
|
+#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE 0x1
|
|
+#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK 0xfffff000
|
|
+#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK 0xff
|
|
+#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO 0x410c
|
|
+#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI 0x4110
|
|
+/* ... */
|
|
+#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_LO 0x413c
|
|
+#define PCIE_MISC_UBUS_BAR10_CONFIG_REMAP_HI 0x4140
|
|
+
|
|
+/* AXI priority forwarding - automatic level-based */
|
|
+#define PCIE_MISC_TC_QUEUE_TO_QOS_MAP(x) (0x4160 - (x) * 4)
|
|
+/* Defined in quarter-fullness */
|
|
+#define QUEUE_THRESHOLD_34_TO_QOS_MAP_SHIFT 12
|
|
+#define QUEUE_THRESHOLD_23_TO_QOS_MAP_SHIFT 8
|
|
+#define QUEUE_THRESHOLD_12_TO_QOS_MAP_SHIFT 4
|
|
+#define QUEUE_THRESHOLD_01_TO_QOS_MAP_SHIFT 0
|
|
+#define QUEUE_THRESHOLD_MASK 0xf
|
|
+
|
|
+/* VDM messages indexing TCs to AXI priorities */
|
|
+/* Indexes 8-15 */
|
|
+#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI 0x4164
|
|
+/* Indexes 0-7 */
|
|
+#define PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO 0x4168
|
|
+#define VDM_PRIORITY_TO_QOS_MAP_SHIFT(x) (4 * (x))
|
|
+#define VDM_PRIORITY_TO_QOS_MAP_MASK 0xf
|
|
+
|
|
+#define PCIE_MISC_AXI_INTF_CTRL 0x416C
|
|
+#define AXI_REQFIFO_EN_QOS_PROPAGATION BIT(7)
|
|
+#define AXI_BRIDGE_LOW_LATENCY_MODE BIT(6)
|
|
+#define AXI_MASTER_MAX_OUTSTANDING_REQUESTS_MASK 0x3f
|
|
|
|
-#define PCIE_INTR2_CPU_BASE 0x4300
|
|
+#define PCIE_MISC_AXI_READ_ERROR_DATA 0x4170
|
|
+
|
|
+#define PCIE_INTR2_CPU_BASE (pcie->reg_offsets[INTR2_CPU])
|
|
#define PCIE_MSI_INTR2_BASE 0x4500
|
|
/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */
|
|
#define MSI_INT_STATUS 0x0
|
|
@@ -197,6 +276,8 @@ enum {
|
|
RGR1_SW_INIT_1,
|
|
EXT_CFG_INDEX,
|
|
EXT_CFG_DATA,
|
|
+ PCIE_HARD_DEBUG,
|
|
+ INTR2_CPU,
|
|
};
|
|
|
|
enum {
|
|
@@ -211,6 +292,7 @@ enum pcie_type {
|
|
BCM4908,
|
|
BCM7278,
|
|
BCM2711,
|
|
+ BCM2712,
|
|
};
|
|
|
|
struct pcie_cfg_data {
|
|
@@ -218,6 +300,7 @@ struct pcie_cfg_data {
|
|
const enum pcie_type type;
|
|
void (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
|
void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
|
+ bool (*rc_mode)(struct brcm_pcie *pcie);
|
|
};
|
|
|
|
struct subdev_regulators {
|
|
@@ -234,7 +317,7 @@ struct brcm_msi {
|
|
struct mutex lock; /* guards the alloc/free operations */
|
|
u64 target_addr;
|
|
int irq;
|
|
- DECLARE_BITMAP(used, BRCM_INT_PCI_MSI_NR);
|
|
+ DECLARE_BITMAP(used, 64);
|
|
bool legacy;
|
|
/* Some chips have MSIs in bits [31..24] of a shared register. */
|
|
int legacy_shift;
|
|
@@ -251,6 +334,7 @@ struct brcm_pcie {
|
|
struct device_node *np;
|
|
bool ssc;
|
|
bool l1ss;
|
|
+ bool rcb_mps_mode;
|
|
int gen;
|
|
u64 msi_target_addr;
|
|
struct brcm_msi *msi;
|
|
@@ -258,11 +342,14 @@ struct brcm_pcie {
|
|
enum pcie_type type;
|
|
struct reset_control *rescal;
|
|
struct reset_control *perst_reset;
|
|
+ struct reset_control *bridge_reset;
|
|
int num_memc;
|
|
u64 memc_size[PCIE_BRCM_MAX_MEMC];
|
|
u32 hw_rev;
|
|
+ u32 qos_map;
|
|
void (*perst_set)(struct brcm_pcie *pcie, u32 val);
|
|
void (*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
|
|
+ bool (*rc_mode)(struct brcm_pcie *pcie);
|
|
struct subdev_regulators *sr;
|
|
bool ep_wakeup_capable;
|
|
};
|
|
@@ -283,8 +370,8 @@ static int brcm_pcie_encode_ibar_size(u6
|
|
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;
|
|
@@ -381,6 +468,35 @@ static int brcm_pcie_set_ssc(struct brcm
|
|
return ssc && pll ? 0 : -EIO;
|
|
}
|
|
|
|
+static void brcm_pcie_munge_pll(struct brcm_pcie *pcie)
|
|
+{
|
|
+ //print "MDIO block 0x1600 written per Dannys instruction"
|
|
+ //tmp = pcie_mdio_write(phyad, &h16&, &h50b9&)
|
|
+ //tmp = pcie_mdio_write(phyad, &h17&, &hbd1a&)
|
|
+ //tmp = pcie_mdio_write(phyad, &h1b&, &h5030&)
|
|
+ //tmp = pcie_mdio_write(phyad, &h1e&, &h0007&)
|
|
+
|
|
+ u32 tmp;
|
|
+ int ret, i;
|
|
+ u8 regs[] = { 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e };
|
|
+ u16 data[] = { 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030, 0x5030, 0x0007 };
|
|
+
|
|
+ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET,
|
|
+ 0x1600);
|
|
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
|
+ brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp);
|
|
+ dev_dbg(pcie->dev, "PCIE MDIO pre_refclk 0x%02x = 0x%04x\n",
|
|
+ regs[i], tmp);
|
|
+ }
|
|
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
|
+ brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, regs[i], data[i]);
|
|
+ brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp);
|
|
+ dev_dbg(pcie->dev, "PCIE MDIO post_refclk 0x%02x = 0x%04x\n",
|
|
+ regs[i], tmp);
|
|
+ }
|
|
+ usleep_range(100, 200);
|
|
+}
|
|
+
|
|
/* Limits operation to a specific generation (1, 2, or 3) */
|
|
static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen)
|
|
{
|
|
@@ -438,6 +554,97 @@ static void brcm_pcie_set_outbound_win(s
|
|
writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
|
|
}
|
|
|
|
+static void brcm_pcie_set_tc_qos(struct brcm_pcie *pcie)
|
|
+{
|
|
+ int i;
|
|
+ u32 reg;
|
|
+
|
|
+ if (pcie->type != BCM2712)
|
|
+ return;
|
|
+
|
|
+ /* XXX: BCM2712C0 is broken, disable the forwarding search */
|
|
+ reg = readl(pcie->base + PCIE_MISC_AXI_INTF_CTRL);
|
|
+ reg &= ~AXI_REQFIFO_EN_QOS_PROPAGATION;
|
|
+ writel(reg, pcie->base + PCIE_MISC_AXI_INTF_CTRL);
|
|
+
|
|
+ /* Disable VDM reception by default - QoS map defaults to 0 */
|
|
+ reg = readl(pcie->base + PCIE_MISC_CTRL_1);
|
|
+ reg &= ~PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK;
|
|
+ writel(reg, pcie->base + PCIE_MISC_CTRL_1);
|
|
+
|
|
+ if (!of_property_read_u32(pcie->np, "brcm,fifo-qos-map", &pcie->qos_map)) {
|
|
+ /*
|
|
+ * Backpressure mode - bottom 4 nibbles are QoS for each
|
|
+ * quartile of FIFO level. Each TC gets the same map, because
|
|
+ * this mode is intended for nonrealtime EPs.
|
|
+ */
|
|
+
|
|
+ pcie->qos_map &= 0x0000ffff;
|
|
+ for (i = 0; i < 8; i++)
|
|
+ writel(pcie->qos_map, pcie->base + PCIE_MISC_TC_QUEUE_TO_QOS_MAP(i));
|
|
+
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!of_property_read_u32(pcie->np, "brcm,vdm-qos-map", &pcie->qos_map)) {
|
|
+
|
|
+ reg = readl(pcie->base + PCIE_MISC_CTRL_1);
|
|
+ reg |= PCIE_MISC_CTRL_1_EN_VDM_QOS_CONTROL_MASK;
|
|
+ writel(reg, pcie->base + PCIE_MISC_CTRL_1);
|
|
+
|
|
+ /* No forwarding means no point separating panic priorities from normal */
|
|
+ writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_LO);
|
|
+ writel(pcie->qos_map, pcie->base + PCIE_MISC_VDM_PRIORITY_TO_QOS_MAP_HI);
|
|
+
|
|
+ /* Match Vendor ID of 0 */
|
|
+ writel(0, pcie->base + PCIE_RC_TL_VDM_CTL1);
|
|
+ /* Forward VDMs to priority interface - at least the rx counters work */
|
|
+ reg = readl(pcie->base + PCIE_RC_TL_VDM_CTL0);
|
|
+ reg |= PCIE_RC_TL_VDM_CTL0_VDM_ENABLED_MASK |
|
|
+ PCIE_RC_TL_VDM_CTL0_VDM_IGNORETAG_MASK |
|
|
+ PCIE_RC_TL_VDM_CTL0_VDM_IGNOREVNDRID_MASK;
|
|
+ writel(reg, pcie->base + PCIE_RC_TL_VDM_CTL0);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void brcm_pcie_config_clkreq(struct brcm_pcie *pcie)
|
|
+{
|
|
+ void __iomem *base = pcie->base;
|
|
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
|
+ int domain = pci_domain_nr(bridge->bus);
|
|
+ const struct pci_bus *bus = pci_find_bus(domain, 1);
|
|
+ struct pci_dev *pdev = (struct pci_dev *)bus->devices.next;
|
|
+ u32 tmp, link_cap = 0;
|
|
+ u16 link_ctl = 0;
|
|
+ int clkpm = 0;
|
|
+ int substates = 0;
|
|
+
|
|
+ pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap);
|
|
+ if ((link_cap & PCI_EXP_LNKCAP_CLKPM))
|
|
+ clkpm = 1;
|
|
+
|
|
+ pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctl);
|
|
+ if (!(link_ctl & PCI_EXP_LNKCTL_CLKREQ_EN))
|
|
+ clkpm = 0;
|
|
+
|
|
+ if (pcie->l1ss && pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS))
|
|
+ substates = 1;
|
|
+
|
|
+ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
|
+ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
|
|
+ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK;
|
|
+
|
|
+ if (substates)
|
|
+ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK;
|
|
+ else if (clkpm)
|
|
+ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
|
|
+
|
|
+ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
|
+
|
|
+ if (substates || clkpm)
|
|
+ dev_info(pcie->dev, "clkreq control enabled\n");
|
|
+}
|
|
+
|
|
static struct irq_chip brcm_msi_irq_chip = {
|
|
.name = "BRCM STB PCIe MSI",
|
|
.irq_ack = irq_chip_ack_parent,
|
|
@@ -455,7 +662,7 @@ static struct msi_domain_info brcm_msi_d
|
|
static void brcm_pcie_msi_isr(struct irq_desc *desc)
|
|
{
|
|
struct irq_chip *chip = irq_desc_get_chip(desc);
|
|
- unsigned long status;
|
|
+ unsigned long status, virq;
|
|
struct brcm_msi *msi;
|
|
struct device *dev;
|
|
u32 bit;
|
|
@@ -467,10 +674,22 @@ static void brcm_pcie_msi_isr(struct irq
|
|
status = readl(msi->intr_base + MSI_INT_STATUS);
|
|
status >>= msi->legacy_shift;
|
|
|
|
- for_each_set_bit(bit, &status, msi->nr) {
|
|
- int ret;
|
|
- ret = generic_handle_domain_irq(msi->inner_domain, bit);
|
|
- if (ret)
|
|
+ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR/*msi->nr*/) {
|
|
+ bool found = false;
|
|
+
|
|
+ virq = irq_find_mapping(msi->inner_domain, bit);
|
|
+ if (virq) {
|
|
+ found = true;
|
|
+ dev_dbg(dev, "MSI -> %ld\n", virq);
|
|
+ generic_handle_irq(virq);
|
|
+ }
|
|
+ virq = irq_find_mapping(msi->inner_domain, bit + 32);
|
|
+ if (virq) {
|
|
+ found = true;
|
|
+ dev_dbg(dev, "MSI -> %ld\n", virq);
|
|
+ generic_handle_irq(virq);
|
|
+ }
|
|
+ if (!found)
|
|
dev_dbg(dev, "unexpected MSI\n");
|
|
}
|
|
|
|
@@ -483,7 +702,7 @@ static void brcm_msi_compose_msi_msg(str
|
|
|
|
msg->address_lo = lower_32_bits(msi->target_addr);
|
|
msg->address_hi = upper_32_bits(msi->target_addr);
|
|
- msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq;
|
|
+ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | (data->hwirq & 0x1f);
|
|
}
|
|
|
|
static int brcm_msi_set_affinity(struct irq_data *irq_data,
|
|
@@ -495,7 +714,7 @@ static int brcm_msi_set_affinity(struct
|
|
static void brcm_msi_ack_irq(struct irq_data *data)
|
|
{
|
|
struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
|
|
- const int shift_amt = data->hwirq + msi->legacy_shift;
|
|
+ const int shift_amt = (data->hwirq & 0x1f) + msi->legacy_shift;
|
|
|
|
writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR);
|
|
}
|
|
@@ -653,7 +872,7 @@ static int brcm_pcie_enable_msi(struct b
|
|
msi->legacy_shift = 24;
|
|
} else {
|
|
msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
|
|
- msi->nr = BRCM_INT_PCI_MSI_NR;
|
|
+ msi->nr = 64; //BRCM_INT_PCI_MSI_NR;
|
|
msi->legacy_shift = 0;
|
|
}
|
|
|
|
@@ -670,7 +889,7 @@ static int brcm_pcie_enable_msi(struct b
|
|
}
|
|
|
|
/* The controller is capable of serving in both RC and EP roles */
|
|
-static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie)
|
|
+static bool brcm_pcie_rc_mode_generic(struct brcm_pcie *pcie)
|
|
{
|
|
void __iomem *base = pcie->base;
|
|
u32 val = readl(base + PCIE_MISC_PCIE_STATUS);
|
|
@@ -678,6 +897,14 @@ static bool brcm_pcie_rc_mode(struct brc
|
|
return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val);
|
|
}
|
|
|
|
+static bool brcm_pcie_rc_mode_2712(struct brcm_pcie *pcie)
|
|
+{
|
|
+ void __iomem *base = pcie->base;
|
|
+ u32 val = readl(base + PCIE_MISC_PCIE_STATUS);
|
|
+
|
|
+ return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK_2712, val) | 1; //XXX
|
|
+}
|
|
+
|
|
static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
|
|
{
|
|
u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS);
|
|
@@ -749,6 +976,18 @@ static inline void brcm_pcie_bridge_sw_i
|
|
writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1(pcie));
|
|
}
|
|
|
|
+static inline void brcm_pcie_bridge_sw_init_set_2712(struct brcm_pcie *pcie, u32 val)
|
|
+{
|
|
+ if (WARN_ONCE(!pcie->bridge_reset,
|
|
+ "missing bridge reset controller\n"))
|
|
+ return;
|
|
+
|
|
+ if (val)
|
|
+ reset_control_assert(pcie->bridge_reset);
|
|
+ else
|
|
+ reset_control_deassert(pcie->bridge_reset);
|
|
+}
|
|
+
|
|
static inline void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val)
|
|
{
|
|
if (WARN_ONCE(!pcie->perst_reset, "missing PERST# reset controller\n"))
|
|
@@ -770,6 +1009,16 @@ static inline void brcm_pcie_perst_set_7
|
|
writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL);
|
|
}
|
|
|
|
+static inline void brcm_pcie_perst_set_2712(struct brcm_pcie *pcie, u32 val)
|
|
+{
|
|
+ u32 tmp;
|
|
+
|
|
+ /* Perst bit has moved and assert value is 0 */
|
|
+ tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL);
|
|
+ u32p_replace_bits(&tmp, !val, PCIE_MISC_PCIE_CTRL_PCIE_PERSTB_MASK);
|
|
+ writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL);
|
|
+}
|
|
+
|
|
static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val)
|
|
{
|
|
u32 tmp;
|
|
@@ -796,6 +1045,8 @@ static inline int brcm_pcie_get_rc_bar2_
|
|
size += entry->res->end - entry->res->start + 1;
|
|
if (pcie_beg < lowest_pcie_addr)
|
|
lowest_pcie_addr = pcie_beg;
|
|
+ if (pcie->type == BCM2711 || pcie->type == BCM2712)
|
|
+ break; // Only consider the first entry
|
|
}
|
|
|
|
if (lowest_pcie_addr == ~(u64)0) {
|
|
@@ -866,6 +1117,30 @@ static inline int brcm_pcie_get_rc_bar2_
|
|
return 0;
|
|
}
|
|
|
|
+static int brcm_pcie_get_rc_bar_n(struct brcm_pcie *pcie,
|
|
+ int idx,
|
|
+ u64 *rc_bar_cpu,
|
|
+ u64 *rc_bar_size,
|
|
+ u64 *rc_bar_pci)
|
|
+{
|
|
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
|
|
+ struct resource_entry *entry;
|
|
+ int i = 0;
|
|
+
|
|
+ resource_list_for_each_entry(entry, &bridge->dma_ranges) {
|
|
+ if (i == idx) {
|
|
+ *rc_bar_cpu = entry->res->start;
|
|
+ *rc_bar_size = entry->res->end - entry->res->start + 1;
|
|
+ *rc_bar_pci = entry->res->start - entry->offset;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ i++;
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
|
{
|
|
u64 rc_bar2_offset, rc_bar2_size;
|
|
@@ -874,11 +1149,14 @@ static int brcm_pcie_setup(struct brcm_p
|
|
struct resource_entry *entry;
|
|
u32 tmp, burst, aspm_support;
|
|
int num_out_wins = 0;
|
|
- int ret, memc;
|
|
+ int ret, memc, count, i;
|
|
|
|
/* Reset the bridge */
|
|
pcie->bridge_sw_init_set(pcie, 1);
|
|
- pcie->perst_set(pcie, 1);
|
|
+
|
|
+ /* Ensure that PERST# is asserted; some bootloaders may deassert it. */
|
|
+ if (pcie->type == BCM2711)
|
|
+ pcie->perst_set(pcie, 1);
|
|
|
|
usleep_range(100, 200);
|
|
|
|
@@ -894,6 +1172,17 @@ static int brcm_pcie_setup(struct brcm_p
|
|
/* Wait for SerDes to be stable */
|
|
usleep_range(100, 200);
|
|
|
|
+ if (pcie->type == BCM2712) {
|
|
+ /* Allow a 54MHz (xosc) refclk source */
|
|
+ brcm_pcie_munge_pll(pcie);
|
|
+ /* Fix for L1SS errata */
|
|
+ tmp = readl(base + PCIE_RC_PL_PHY_CTL_15);
|
|
+ tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK;
|
|
+ /* PM clock period is 18.52ns (round down) */
|
|
+ tmp |= 0x12;
|
|
+ writel(tmp, base + PCIE_RC_PL_PHY_CTL_15);
|
|
+ }
|
|
+
|
|
/*
|
|
* SCB_MAX_BURST_SIZE is a two bit field. For GENERIC chips it
|
|
* is encoded as 0=128, 1=256, 2=512, 3=Rsvd, for BCM7278 it
|
|
@@ -903,18 +1192,25 @@ static int brcm_pcie_setup(struct brcm_p
|
|
burst = 0x1; /* 256 bytes */
|
|
else if (pcie->type == BCM2711)
|
|
burst = 0x0; /* 128 bytes */
|
|
+ else if (pcie->type == BCM2712)
|
|
+ burst = 0x1; /* 128 bytes */
|
|
else if (pcie->type == BCM7278)
|
|
burst = 0x3; /* 512 bytes */
|
|
else
|
|
burst = 0x2; /* 512 bytes */
|
|
|
|
- /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
|
|
+ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN, RCB_MPS_MODE */
|
|
tmp = readl(base + PCIE_MISC_MISC_CTRL);
|
|
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
|
|
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
|
|
u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
|
|
+ if (pcie->rcb_mps_mode)
|
|
+ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_RCB_MPS_MODE_MASK);
|
|
+ dev_info(pcie->dev, "setting SCB_ACCESS_EN, READ_UR_MODE, MAX_BURST_SIZE\n");
|
|
writel(tmp, base + PCIE_MISC_MISC_CTRL);
|
|
|
|
+ brcm_pcie_set_tc_qos(pcie);
|
|
+
|
|
ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size,
|
|
&rc_bar2_offset);
|
|
if (ret)
|
|
@@ -927,7 +1223,11 @@ static int brcm_pcie_setup(struct brcm_p
|
|
writel(upper_32_bits(rc_bar2_offset),
|
|
base + PCIE_MISC_RC_BAR2_CONFIG_HI);
|
|
|
|
+ tmp = readl(base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP);
|
|
+ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK);
|
|
+ writel(tmp, base + PCIE_MISC_UBUS_BAR2_CONFIG_REMAP);
|
|
tmp = readl(base + PCIE_MISC_MISC_CTRL);
|
|
+
|
|
for (memc = 0; memc < pcie->num_memc; memc++) {
|
|
u32 scb_size_val = ilog2(pcie->memc_size[memc]) - 15;
|
|
|
|
@@ -938,8 +1238,32 @@ static int brcm_pcie_setup(struct brcm_p
|
|
else if (memc == 2)
|
|
u32p_replace_bits(&tmp, scb_size_val, SCB_SIZE_MASK(2));
|
|
}
|
|
+
|
|
writel(tmp, base + PCIE_MISC_MISC_CTRL);
|
|
|
|
+ if (pcie->type == BCM2712) {
|
|
+ /* Suppress AXI error responses and return 1s for read failures */
|
|
+ tmp = readl(base + PCIE_MISC_UBUS_CTRL);
|
|
+ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK);
|
|
+ u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK);
|
|
+ writel(tmp, base + PCIE_MISC_UBUS_CTRL);
|
|
+ writel(0xffffffff, base + PCIE_MISC_AXI_READ_ERROR_DATA);
|
|
+
|
|
+ /*
|
|
+ * Adjust timeouts. The UBUS timeout also affects CRS
|
|
+ * completion retries, as the request will get terminated if
|
|
+ * either timeout expires, so both have to be a large value
|
|
+ * (in clocks of 750MHz).
|
|
+ * Set UBUS timeout to 250ms, then set RC config retry timeout
|
|
+ * to be ~240ms.
|
|
+ *
|
|
+ * Setting CRSVis=1 will stop the core from blocking on a CRS
|
|
+ * response, but does require the device to be well-behaved...
|
|
+ */
|
|
+ writel(0xB2D0000, base + PCIE_MISC_UBUS_TIMEOUT);
|
|
+ writel(0xABA0000, base + PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT);
|
|
+ }
|
|
+
|
|
/*
|
|
* We ideally want the MSI target address to be located in the 32bit
|
|
* addressable memory area. Some devices might depend on it. This is
|
|
@@ -952,7 +1276,7 @@ static int brcm_pcie_setup(struct brcm_p
|
|
else
|
|
pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB;
|
|
|
|
- if (!brcm_pcie_rc_mode(pcie)) {
|
|
+ if (!pcie->rc_mode(pcie)) {
|
|
dev_err(pcie->dev, "PCIe RC controller misconfigured as Endpoint\n");
|
|
return -EINVAL;
|
|
}
|
|
@@ -976,6 +1300,38 @@ static int brcm_pcie_setup(struct brcm_p
|
|
PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK);
|
|
writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
|
|
|
|
+ /* program additional inbound windows (RC_BAR4..RC_BAR10) */
|
|
+ count = (pcie->type == BCM2712) ? 7 : 0;
|
|
+ for (i = 0; i < count; i++) {
|
|
+ u64 bar_cpu, bar_size, bar_pci;
|
|
+
|
|
+ ret = brcm_pcie_get_rc_bar_n(pcie, 1 + i, &bar_cpu, &bar_size,
|
|
+ &bar_pci);
|
|
+ if (ret)
|
|
+ break;
|
|
+
|
|
+ tmp = lower_32_bits(bar_pci);
|
|
+ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size),
|
|
+ PCIE_MISC_RC_BAR_CONFIG_LO_SIZE_MASK);
|
|
+ writel(tmp, base + PCIE_MISC_RC_BAR4_CONFIG_LO + i * 8);
|
|
+ writel(upper_32_bits(bar_pci),
|
|
+ base + PCIE_MISC_RC_BAR4_CONFIG_HI + i * 8);
|
|
+
|
|
+ tmp = upper_32_bits(bar_cpu) &
|
|
+ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK;
|
|
+ writel(tmp,
|
|
+ base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI + i * 8);
|
|
+ tmp = lower_32_bits(bar_cpu) &
|
|
+ PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK;
|
|
+ writel(tmp | PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE,
|
|
+ base + PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO + i * 8);
|
|
+ }
|
|
+
|
|
+ if (pcie->gen) {
|
|
+ dev_info(pcie->dev, "Forcing gen %d\n", pcie->gen);
|
|
+ brcm_pcie_set_gen(pcie, pcie->gen);
|
|
+ }
|
|
+
|
|
/*
|
|
* For config space accesses on the RC, show the right class for
|
|
* a PCIe-PCIe bridge (the default setting is to be EP mode).
|
|
@@ -1031,7 +1387,6 @@ static int brcm_pcie_start_link(struct b
|
|
void __iomem *base = pcie->base;
|
|
u16 nlw, cls, lnksta;
|
|
bool ssc_good = false;
|
|
- u32 tmp;
|
|
int ret, i;
|
|
|
|
/* Unassert the fundamental reset */
|
|
@@ -1067,6 +1422,7 @@ static int brcm_pcie_start_link(struct b
|
|
dev_err(dev, "failed attempt to enter ssc mode\n");
|
|
}
|
|
|
|
+
|
|
lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA);
|
|
cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta);
|
|
nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta);
|
|
@@ -1074,27 +1430,6 @@ static int brcm_pcie_start_link(struct b
|
|
pci_speed_string(pcie_link_speed[cls]), nlw,
|
|
ssc_good ? "(SSC)" : "(!SSC)");
|
|
|
|
- tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
|
- if (pcie->l1ss) {
|
|
- /*
|
|
- * Enable CLKREQ# signalling include L1 Substate control of
|
|
- * the CLKREQ# signal and the external reference clock buffer.
|
|
- * meet requirement for Endpoints that require CLKREQ#
|
|
- * assertion to clock active within 400ns.
|
|
- */
|
|
- tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
|
|
- tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK;
|
|
- } else {
|
|
- /*
|
|
- * Refclk from RC should be gated with CLKREQ# input when
|
|
- * ASPM L0s,L1 is enabled => setting the CLKREQ_DEBUG_ENABLE
|
|
- * field to 1.
|
|
- */
|
|
- tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK;
|
|
- tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
|
|
- }
|
|
- writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
@@ -1202,6 +1537,7 @@ static void brcm_pcie_enter_l23(struct b
|
|
|
|
static int brcm_phy_cntl(struct brcm_pcie *pcie, const int start)
|
|
{
|
|
+#if 0
|
|
static const u32 shifts[PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_NFLDS] = {
|
|
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_PWRDN_SHIFT,
|
|
PCIE_DVT_PMU_PCIE_PHY_CTRL_DAST_RESET_SHIFT,
|
|
@@ -1234,6 +1570,9 @@ static int brcm_phy_cntl(struct brcm_pci
|
|
dev_err(pcie->dev, "failed to %s phy\n", (start ? "start" : "stop"));
|
|
|
|
return ret;
|
|
+#else
|
|
+ return 0;
|
|
+#endif
|
|
}
|
|
|
|
static inline int brcm_phy_start(struct brcm_pcie *pcie)
|
|
@@ -1266,6 +1605,12 @@ static void brcm_pcie_turn_off(struct br
|
|
u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
|
|
writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
|
|
|
|
+ /*
|
|
+ * Shutting down this bridge on pcie1 means accesses to rescal block
|
|
+ * will hang the chip if another RC wants to assert/deassert rescal.
|
|
+ */
|
|
+ if (pcie->type == BCM2712)
|
|
+ return;
|
|
/* Shutdown PCIe bridge */
|
|
pcie->bridge_sw_init_set(pcie, 1);
|
|
}
|
|
@@ -1296,9 +1641,9 @@ static int brcm_pcie_suspend_noirq(struc
|
|
if (brcm_phy_stop(pcie))
|
|
dev_err(dev, "Could not stop phy for suspend\n");
|
|
|
|
- ret = reset_control_rearm(pcie->rescal);
|
|
+ ret = reset_control_assert(pcie->rescal);
|
|
if (ret) {
|
|
- dev_err(dev, "Could not rearm rescal reset\n");
|
|
+ dev_err(dev, "Could not assert rescal reset\n");
|
|
return ret;
|
|
}
|
|
|
|
@@ -1393,7 +1738,7 @@ err_regulator:
|
|
if (pcie->sr)
|
|
regulator_bulk_disable(pcie->sr->num_supplies, pcie->sr->supplies);
|
|
err_reset:
|
|
- reset_control_rearm(pcie->rescal);
|
|
+ reset_control_assert(pcie->rescal);
|
|
err_disable_clk:
|
|
clk_disable_unprepare(pcie->clk);
|
|
return ret;
|
|
@@ -1405,8 +1750,8 @@ static void __brcm_pcie_remove(struct br
|
|
brcm_pcie_turn_off(pcie);
|
|
if (brcm_phy_stop(pcie))
|
|
dev_err(pcie->dev, "Could not stop phy\n");
|
|
- if (reset_control_rearm(pcie->rescal))
|
|
- dev_err(pcie->dev, "Could not rearm rescal reset\n");
|
|
+ if (reset_control_assert(pcie->rescal))
|
|
+ dev_err(pcie->dev, "Could not assert rescal reset\n");
|
|
clk_disable_unprepare(pcie->clk);
|
|
}
|
|
|
|
@@ -1426,12 +1771,16 @@ static const int pcie_offsets[] = {
|
|
[RGR1_SW_INIT_1] = 0x9210,
|
|
[EXT_CFG_INDEX] = 0x9000,
|
|
[EXT_CFG_DATA] = 0x9004,
|
|
+ [PCIE_HARD_DEBUG] = 0x4204,
|
|
+ [INTR2_CPU] = 0x4300,
|
|
};
|
|
|
|
static const int pcie_offsets_bmips_7425[] = {
|
|
[RGR1_SW_INIT_1] = 0x8010,
|
|
[EXT_CFG_INDEX] = 0x8300,
|
|
[EXT_CFG_DATA] = 0x8304,
|
|
+ [PCIE_HARD_DEBUG] = 0x4204,
|
|
+ [INTR2_CPU] = 0x4300,
|
|
};
|
|
|
|
static const struct pcie_cfg_data generic_cfg = {
|
|
@@ -1439,6 +1788,7 @@ static const struct pcie_cfg_data generi
|
|
.type = GENERIC,
|
|
.perst_set = brcm_pcie_perst_set_generic,
|
|
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
|
|
+ .rc_mode = brcm_pcie_rc_mode_generic,
|
|
};
|
|
|
|
static const struct pcie_cfg_data bcm7425_cfg = {
|
|
@@ -1446,6 +1796,7 @@ static const struct pcie_cfg_data bcm742
|
|
.type = BCM7425,
|
|
.perst_set = brcm_pcie_perst_set_generic,
|
|
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
|
|
+ .rc_mode = brcm_pcie_rc_mode_generic,
|
|
};
|
|
|
|
static const struct pcie_cfg_data bcm7435_cfg = {
|
|
@@ -1460,12 +1811,15 @@ static const struct pcie_cfg_data bcm490
|
|
.type = BCM4908,
|
|
.perst_set = brcm_pcie_perst_set_4908,
|
|
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
|
|
+ .rc_mode = brcm_pcie_rc_mode_generic,
|
|
};
|
|
|
|
static const int pcie_offset_bcm7278[] = {
|
|
[RGR1_SW_INIT_1] = 0xc010,
|
|
[EXT_CFG_INDEX] = 0x9000,
|
|
[EXT_CFG_DATA] = 0x9004,
|
|
+ [PCIE_HARD_DEBUG] = 0x4204,
|
|
+ [INTR2_CPU] = 0x4300,
|
|
};
|
|
|
|
static const struct pcie_cfg_data bcm7278_cfg = {
|
|
@@ -1473,6 +1827,7 @@ static const struct pcie_cfg_data bcm727
|
|
.type = BCM7278,
|
|
.perst_set = brcm_pcie_perst_set_7278,
|
|
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_7278,
|
|
+ .rc_mode = brcm_pcie_rc_mode_generic,
|
|
};
|
|
|
|
static const struct pcie_cfg_data bcm2711_cfg = {
|
|
@@ -1480,10 +1835,27 @@ static const struct pcie_cfg_data bcm271
|
|
.type = BCM2711,
|
|
.perst_set = brcm_pcie_perst_set_generic,
|
|
.bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_generic,
|
|
+ .rc_mode = brcm_pcie_rc_mode_generic,
|
|
+};
|
|
+
|
|
+static const int pcie_offsets_bcm2712[] = {
|
|
+ [EXT_CFG_INDEX] = 0x9000,
|
|
+ [EXT_CFG_DATA] = 0x9004,
|
|
+ [PCIE_HARD_DEBUG] = 0x4304,
|
|
+ [INTR2_CPU] = 0x4400,
|
|
+};
|
|
+
|
|
+static const struct pcie_cfg_data bcm2712_cfg = {
|
|
+ .offsets = pcie_offsets_bcm2712,
|
|
+ .type = BCM2712,
|
|
+ .perst_set = brcm_pcie_perst_set_2712,
|
|
+ .bridge_sw_init_set = brcm_pcie_bridge_sw_init_set_2712,
|
|
+ .rc_mode = brcm_pcie_rc_mode_2712,
|
|
};
|
|
|
|
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,bcm7278-pcie", .data = &bcm7278_cfg },
|
|
@@ -1524,7 +1896,7 @@ static int brcm_pcie_probe(struct platfo
|
|
|
|
data = of_device_get_match_data(&pdev->dev);
|
|
if (!data) {
|
|
- pr_err("failed to look up compatible string\n");
|
|
+ dev_err(&pdev->dev, "failed to look up compatible string\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
@@ -1535,6 +1907,7 @@ static int brcm_pcie_probe(struct platfo
|
|
pcie->type = data->type;
|
|
pcie->perst_set = data->perst_set;
|
|
pcie->bridge_sw_init_set = data->bridge_sw_init_set;
|
|
+ pcie->rc_mode = data->rc_mode;
|
|
|
|
pcie->base = devm_platform_ioremap_resource(pdev, 0);
|
|
if (IS_ERR(pcie->base))
|
|
@@ -1549,6 +1922,7 @@ static int brcm_pcie_probe(struct platfo
|
|
|
|
pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc");
|
|
pcie->l1ss = of_property_read_bool(np, "brcm,enable-l1ss");
|
|
+ pcie->rcb_mps_mode = of_property_read_bool(np, "brcm,enable-mps-rcb");
|
|
|
|
ret = clk_prepare_enable(pcie->clk);
|
|
if (ret) {
|
|
@@ -1565,14 +1939,20 @@ static int brcm_pcie_probe(struct platfo
|
|
clk_disable_unprepare(pcie->clk);
|
|
return PTR_ERR(pcie->perst_reset);
|
|
}
|
|
+ pcie->bridge_reset =
|
|
+ devm_reset_control_get_optional_exclusive(&pdev->dev, "bridge");
|
|
+ if (IS_ERR(pcie->bridge_reset)) {
|
|
+ clk_disable_unprepare(pcie->clk);
|
|
+ return PTR_ERR(pcie->bridge_reset);
|
|
+ }
|
|
|
|
- ret = reset_control_reset(pcie->rescal);
|
|
+ ret = reset_control_deassert(pcie->rescal);
|
|
if (ret)
|
|
dev_err(&pdev->dev, "failed to deassert 'rescal'\n");
|
|
|
|
ret = brcm_phy_start(pcie);
|
|
if (ret) {
|
|
- reset_control_rearm(pcie->rescal);
|
|
+ reset_control_assert(pcie->rescal);
|
|
clk_disable_unprepare(pcie->clk);
|
|
return ret;
|
|
}
|
|
@@ -1595,6 +1975,33 @@ static int brcm_pcie_probe(struct platfo
|
|
dev_err(pcie->dev, "probe of internal MSI failed");
|
|
goto fail;
|
|
}
|
|
+ } else if (pci_msi_enabled() && msi_np != pcie->np) {
|
|
+ /* Use RC_BAR1 for MIP access */
|
|
+ u64 msi_pci_addr;
|
|
+ u64 msi_phys_addr;
|
|
+
|
|
+ if (of_property_read_u64(msi_np, "brcm,msi-pci-addr", &msi_pci_addr)) {
|
|
+ dev_err(pcie->dev, "Unable to find MSI PCI address\n");
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ if (of_property_read_u64(msi_np, "reg", &msi_phys_addr)) {
|
|
+ dev_err(pcie->dev, "Unable to find MSI physical address\n");
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ writel(lower_32_bits(msi_pci_addr) | brcm_pcie_encode_ibar_size(0x1000),
|
|
+ pcie->base + PCIE_MISC_RC_BAR1_CONFIG_LO);
|
|
+ writel(upper_32_bits(msi_pci_addr),
|
|
+ pcie->base + PCIE_MISC_RC_BAR1_CONFIG_HI);
|
|
+
|
|
+ writel(lower_32_bits(msi_phys_addr) |
|
|
+ PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_ACCESS_ENABLE_MASK,
|
|
+ pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP);
|
|
+ writel(upper_32_bits(msi_phys_addr),
|
|
+ pcie->base + PCIE_MISC_UBUS_BAR1_CONFIG_REMAP_HI);
|
|
}
|
|
|
|
bridge->ops = pcie->type == BCM7425 ? &brcm7425_pcie_ops : &brcm_pcie_ops;
|
|
@@ -1611,6 +2018,8 @@ static int brcm_pcie_probe(struct platfo
|
|
return ret;
|
|
}
|
|
|
|
+ brcm_pcie_config_clkreq(pcie);
|
|
+
|
|
return 0;
|
|
|
|
fail:
|