From 646a1522478a30889354a378b2617b4c08d2c9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 23 Sep 2021 11:07:18 +0200 Subject: [PATCH 01/23] arm: a37xx: pci: Increase PCIe IO size from 64 KiB to 1 MiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 079b35a26111 ("arm: a37xx: pci: Increase PCIe MEM size from 16 MiB to 127 MiB") increased size of PCIe MEM to 127 MiB, which is the maximal possible size for allocated 128 MiB PCIe window. PCIe IO size in that commit was unchanged. Armada 3720 PCIe controller supports 32-bit IO space mapping so it is possible to assign more than 64 KiB if address space for IO. Currently controller has assigned 127 MiB + 64 KiB memory and therefore there is 960 KiB of unused memory. So assign it to IO space by increasing IO window from 64 KiB to 1 MiB. Signed-off-by: Pali Rohár Fixes: 079b35a26111 ("arm: a37xx: pci: Increase PCIe MEM size from 16 MiB to 127 MiB") Reviewed-by: Stefan Roese --- arch/arm/dts/armada-37xx.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/armada-37xx.dtsi b/arch/arm/dts/armada-37xx.dtsi index 2615b8c748..fec34609cf 100644 --- a/arch/arm/dts/armada-37xx.dtsi +++ b/arch/arm/dts/armada-37xx.dtsi @@ -335,14 +335,14 @@ /* * The 128 MiB address range [0xe8000000-0xf0000000] is * dedicated for PCIe and can be assigned to 8 windows - * with size a power of two. Use one 64 KiB window for + * with size a power of two. Use one 1 MiB window for * IO at the end and the remaining seven windows * (totaling 127 MiB) for MEM. */ ranges = <0x82000000 0 0xe8000000 0 0xe8000000 0 0x7f00000 /* Port 0 MEM */ - 0x81000000 0 0xefff0000 - 0 0xefff0000 0 0x10000>; /* Port 0 IO*/ + 0x81000000 0 0xeff00000 + 0 0xeff00000 0 0x100000>; /* Port 0 IO*/ }; }; }; From 4adb16b29a31590f536b72e635370aff73732b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 16:11:55 +0200 Subject: [PATCH 02/23] phy: marvell: a3700: Set TXDCLK_2X_SEL bit during PCIe initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marvell Armada 3700 Functional Specifications, section 52.2 PCIe Link Initialization says that TXDCLK_2X_SEL bit needs to be enabled for PCIe Root Complex mode. Same change was included in TF-A project: https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/9408 Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- drivers/phy/marvell/comphy_a3700.c | 2 +- drivers/phy/marvell/comphy_a3700.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/marvell/comphy_a3700.c b/drivers/phy/marvell/comphy_a3700.c index 06822d1d12..504f4b2bb1 100644 --- a/drivers/phy/marvell/comphy_a3700.c +++ b/drivers/phy/marvell/comphy_a3700.c @@ -200,7 +200,7 @@ static int comphy_pcie_power_up(u32 speed, u32 invert) * 6. Enable the output of 100M/125M/500M clock */ reg_set16(phy_addr(PCIE, MISC_REG0), - 0xA00D | rb_clk500m_en | rb_clk100m_125m_en, 0xFFFF); + 0xA00D | rb_clk500m_en | rb_txdclk_2x_sel | rb_clk100m_125m_en, 0xFFFF); /* * 7. Enable TX diff --git a/drivers/phy/marvell/comphy_a3700.h b/drivers/phy/marvell/comphy_a3700.h index 8748c6c84a..23c8ffbff4 100644 --- a/drivers/phy/marvell/comphy_a3700.h +++ b/drivers/phy/marvell/comphy_a3700.h @@ -120,6 +120,7 @@ static inline void __iomem *phy_addr(enum phy_unit unit, u32 addr) #define MISC_REG0 0x4f #define rb_clk100m_125m_en BIT(4) +#define rb_txdclk_2x_sel BIT(6) #define rb_clk500m_en BIT(7) #define rb_ref_clk_sel BIT(10) From 4ca474d3067ba7278c6a5f94ff4340ca5a07ca0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 16:11:56 +0200 Subject: [PATCH 03/23] phy: marvell: a3700: Fix configuring polarity invert bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit phy_txd_inv or phy_rxd_inv needs to be set only in case when appropriate polarity is inverted. Otherwise these bits should be cleared. Same change was included in TF-A project: https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/9406 Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- drivers/phy/marvell/comphy_a3700.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/phy/marvell/comphy_a3700.c b/drivers/phy/marvell/comphy_a3700.c index 504f4b2bb1..69cd63edb1 100644 --- a/drivers/phy/marvell/comphy_a3700.c +++ b/drivers/phy/marvell/comphy_a3700.c @@ -230,9 +230,13 @@ static int comphy_pcie_power_up(u32 speed, u32 invert) */ if (invert & COMPHY_POLARITY_TXD_INVERT) reg_set16(phy_addr(PCIE, SYNC_PATTERN), phy_txd_inv, 0); + else + reg_set16(phy_addr(PCIE, SYNC_PATTERN), 0, phy_txd_inv); if (invert & COMPHY_POLARITY_RXD_INVERT) reg_set16(phy_addr(PCIE, SYNC_PATTERN), phy_rxd_inv, 0); + else + reg_set16(phy_addr(PCIE, SYNC_PATTERN), 0, phy_rxd_inv); /* * 11. Release SW reset @@ -467,9 +471,13 @@ static int comphy_usb3_power_up(u32 lane, u32 type, u32 speed, u32 invert) */ if (invert & COMPHY_POLARITY_TXD_INVERT) usb3_reg_set16(SYNC_PATTERN, phy_txd_inv, 0, lane); + else + usb3_reg_set16(SYNC_PATTERN, 0, phy_txd_inv, lane); if (invert & COMPHY_POLARITY_RXD_INVERT) usb3_reg_set16(SYNC_PATTERN, phy_rxd_inv, 0, lane); + else + usb3_reg_set16(SYNC_PATTERN, 0, phy_rxd_inv, lane); /* * 10. Set max speed generation to USB3.0 5Gbps @@ -839,9 +847,13 @@ static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert) */ if (invert & COMPHY_POLARITY_TXD_INVERT) reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), phy_txd_inv, 0); + else + reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), 0, phy_txd_inv); if (invert & COMPHY_POLARITY_RXD_INVERT) reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), phy_rxd_inv, 0); + else + reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), 0, phy_rxd_inv); /* * 19. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 From 021a98a2d6512bf59581675a997d659b18c09306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 16:11:57 +0200 Subject: [PATCH 04/23] phy: marvell: a3700: Return correct error code when power up fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Subroutines in comphy_usb2_power_up() and comphy_sgmii_power_up() functions may fail. In this case, do not continue execution of current function and instead jump to the end. Return value in 'ret' variable is already set. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- drivers/phy/marvell/comphy_a3700.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/phy/marvell/comphy_a3700.c b/drivers/phy/marvell/comphy_a3700.c index 69cd63edb1..047c8bb045 100644 --- a/drivers/phy/marvell/comphy_a3700.c +++ b/drivers/phy/marvell/comphy_a3700.c @@ -594,24 +594,30 @@ static int comphy_usb2_power_up(u8 usb32) rb_usb2phy_pllcal_done, /* value */ rb_usb2phy_pllcal_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to end USB2 PLL calibration\n"); + goto out; + } /* Assert impedance calibration done */ ret = comphy_poll_reg(USB2_PHY_CAL_CTRL_ADDR(usb32), rb_usb2phy_impcal_done, /* value */ rb_usb2phy_impcal_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to end USB2 impedance calibration\n"); + goto out; + } /* Assert squetch calibration done */ ret = comphy_poll_reg(USB2_PHY_RX_CHAN_CTRL1_ADDR(usb32), rb_usb2phy_sqcal_done, /* value */ rb_usb2phy_sqcal_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to end USB2 unknown calibration\n"); + goto out; + } /* Assert PLL is ready */ ret = comphy_poll_reg(USB2_PHY_PLL_CTRL0_ADDR(usb32), @@ -619,9 +625,12 @@ static int comphy_usb2_power_up(u8 usb32) rb_usb2phy_pll_ready, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to lock USB2 PLL\n"); + goto out; + } +out: debug_exit(); return ret; @@ -873,8 +882,10 @@ static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert) rb_pll_ready_tx | rb_pll_ready_rx, /* value */ rb_pll_ready_tx | rb_pll_ready_rx, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to lock PLL for SGMII PHY %d\n", lane); + goto out; + } /* * 21. Set COMPHY input port PIN_TX_IDLE=0 @@ -895,14 +906,17 @@ static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert) rb_rx_init_done, /* value */ rb_rx_init_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to init RX of SGMII PHY %d\n", lane); + goto out; + } /* * Restore saved selector. */ reg_set(COMPHY_SEL_ADDR, saved_selector, 0xFFFFFFFF); +out: debug_exit(); return ret; From cfd4a8ad0f205be4270c382a1a2ce2701b2ddde7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:14 +0200 Subject: [PATCH 05/23] arm: mvebu: a38x: serdes: Add comments and use macros in PCIe code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace magic register offsets by macros to make code more readable. Add comments about what this code is doing. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- .../serdes/a38x/high_speed_env_spec.c | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c index bb7d24b4b7..7b4710501d 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c @@ -1721,31 +1721,44 @@ int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, reg_data &= ~0x4000; reg_write(SOC_CONTROL_REG1, reg_data); - reg_data = - reg_read(((PEX_IF_REGS_BASE(pex_idx)) + - 0x6c)); + /* Set Maximum Link Width to X1 or X4 */ + reg_data = reg_read(PEX_CFG_DIRECT_ACCESS( + pex_idx, + PEX_LINK_CAPABILITY_REG)); reg_data &= ~0x3f0; if (is_pex_by1 == 1) reg_data |= 0x10; else reg_data |= 0x40; - reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c), + reg_write(PEX_CFG_DIRECT_ACCESS( + pex_idx, + PEX_LINK_CAPABILITY_REG), reg_data); - reg_data = - reg_read(((PEX_IF_REGS_BASE(pex_idx)) + - 0x6c)); + /* Set Maximum Link Speed to 5 GT/s */ + reg_data = reg_read(PEX_CFG_DIRECT_ACCESS( + pex_idx, + PEX_LINK_CAPABILITY_REG)); reg_data &= ~0xf; reg_data |= 0x2; - reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x6c), + reg_write(PEX_CFG_DIRECT_ACCESS( + pex_idx, + PEX_LINK_CAPABILITY_REG), reg_data); - reg_data = - reg_read(((PEX_IF_REGS_BASE(pex_idx)) + - 0x70)); + /* + * Set Common Clock Configuration to indicates + * that both devices on the link use a + * distributed common reference clock. + */ + reg_data = reg_read(PEX_CFG_DIRECT_ACCESS( + pex_idx, + PEX_LINK_CTRL_STAT_REG)); reg_data &= ~0x40; reg_data |= 0x40; - reg_write(((PEX_IF_REGS_BASE(pex_idx)) + 0x70), + reg_write(PEX_CFG_DIRECT_ACCESS( + pex_idx, + PEX_LINK_CTRL_STAT_REG), reg_data); } From eb5d31645e1160345389d68b263d72112f5b9c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:15 +0200 Subject: [PATCH 06/23] arm: mvebu: a38x: serdes: Remove duplicate macro SOC_CTRL_REG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SoC Control 1 Register (offset 0x18204) is already defined by macro SOC_CONTROL_REG1. Use macro SOC_CONTROL_REG1 instead of macro SOC_CTRL_REG in ctrl_pex.c code and remove the other definition. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 4 ++-- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c index adef3331a7..717bcfb29c 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -49,7 +49,7 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp); } - tmp = reg_read(SOC_CTRL_REG); + tmp = reg_read(SOC_CONTROL_REG1); tmp &= ~0x03; for (idx = 0; idx < count; idx++) { @@ -79,7 +79,7 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) } } - reg_write(SOC_CTRL_REG, tmp); + reg_write(SOC_CONTROL_REG1, tmp); /* Support gen1/gen2 */ DEBUG_INIT_FULL_S("Support gen1/gen2\n"); diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h index 3f30b6bf97..a882d24208 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h @@ -14,10 +14,6 @@ /* PCI Express Control and Status Registers */ #define MAX_PEX_BUSSES 256 -#define MISC_REGS_OFFSET 0x18200 -#define MV_MISC_REGS_BASE MISC_REGS_OFFSET -#define SOC_CTRL_REG (MV_MISC_REGS_BASE + 0x4) - #define PEX_IF_REGS_OFFSET(if) ((if) > 0 ? \ (0x40000 + ((if) - 1) * 0x4000) : \ 0x80000) From 2d5f51f680be9461f87f0c99b55c68ad68633078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:16 +0200 Subject: [PATCH 07/23] arm: mvebu: a38x: serdes: Add comments for hws_pex_config() code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comments to understand what this magic code is doing. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c index 717bcfb29c..0eb31d589c 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -42,6 +42,7 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) continue; } + /* Set Device/Port Type to RootComplex */ pex_idx = serdes_type - PEX0; tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx)); tmp &= ~(0xf << 20); @@ -122,12 +123,18 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) } next_busno++; + + /* + * Read maximum link speed. It must be 0x2 (5.0 GT/s) as this + * value was set in serdes_power_up_ctrl() function. + */ temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS (pex_idx, PEX_LINK_CAPABILITY_REG))); temp_pex_reg &= 0xf; if (temp_pex_reg != 0x2) continue; + /* Read negotiated link speed */ temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS( pex_idx, PEX_LINK_CTRL_STAT_REG)) & @@ -155,6 +162,7 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) continue; } + /* Find start of the PCI Express Capability registers */ while ((pex_config_read(pex_idx, first_busno, 0, 0, addr) & 0xff) != 0x10) { addr = (pex_config_read(pex_idx, first_busno, 0, @@ -173,11 +181,15 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx)); DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); tmp &= ~(BIT(0) | BIT(1)); - tmp |= BIT(1); + tmp |= BIT(1); /* Force Target Link Speed to 5.0 GT/s */ tmp |= BIT(6); /* Select Deemphasize (-3.5d_b) */ reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); + /* + * Enable Auto Speed change. When set, link will issue link + * speed change to max possible link speed. + */ tmp = reg_read(PEX_CTRL_REG(pex_idx)); DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp); tmp |= BIT(10); From 3bedbcc3aa1865de3de55ca1abfa8d06d33df3b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:17 +0200 Subject: [PATCH 08/23] arm: mvebu: a38x: serdes: Don't overwrite read-only SAR PCIe registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device/Port Type bits of PCIe Root Port PCI Express Capabilities Register are read-only SAR registers and are initialized according to current mode configured by PCIe controller. Changing PCIe controller mode (from Root Complex mode to Endpoint mode or the other way) is possible via PCI Express Control Register (offset 0x41A00), bit 1 (ConfRoot Complex). This has to be done in PCIe controller driver (in our case pci_mvebu.c). Note that default mode is Root Complex. Maximum Link Speed bits of PCIe Root Port Link Capabilities Register are platform specific and overwriting them does not make sense. They are set by PCIe controller according to current SerDes configuration. For A38x it is 5.0 GT/s if SerDes supports appropriate speed. Maximum Link Width bits of PCIe Root Port Link Capabilities Register are read-only SAR registers, but unfortunately if this is not set correctly here, then access PCI config space of the endpoint card behind this Root Port does not work. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 22 ---------- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 4 ++ .../serdes/a38x/high_speed_env_spec.c | 40 +++++++------------ 3 files changed, 19 insertions(+), 47 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c index 0eb31d589c..7c18df8113 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -28,28 +28,6 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n"); - for (idx = 0; idx < count; idx++) { - serdes_type = serdes_map[idx].serdes_type; - /* configuration for PEX only */ - if ((serdes_type != PEX0) && (serdes_type != PEX1) && - (serdes_type != PEX2) && (serdes_type != PEX3)) - continue; - - if ((serdes_type != PEX0) && - ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || - (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { - /* for PEX by4 - relevant for the first port only */ - continue; - } - - /* Set Device/Port Type to RootComplex */ - pex_idx = serdes_type - PEX0; - tmp = reg_read(PEX_CAPABILITIES_REG(pex_idx)); - tmp &= ~(0xf << 20); - tmp |= (0x4 << 20); - reg_write(PEX_CAPABILITIES_REG(pex_idx), tmp); - } - tmp = reg_read(SOC_CONTROL_REG1); tmp &= ~0x03; diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h index a882d24208..5d70166fc5 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h @@ -6,8 +6,12 @@ #ifndef _CTRL_PEX_H #define _CTRL_PEX_H +#include #include "high_speed_env_spec.h" +/* Direct access to PEX0 Root Port's PCIe Capability structure */ +#define PEX0_RP_PCIE_CFG_OFFSET (0x00080000 + 0x60) + /* Sample at Reset */ #define MPP_SAMPLE_AT_RESET(id) (0xe4200 + (id * 4)) diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c index 7b4710501d..c089479a9b 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c @@ -1712,7 +1712,7 @@ int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, (serdes_mode == PEX_END_POINT_X1); pex_idx = serdes_type - PEX0; - if ((is_pex_by1 == 1) || (serdes_type == PEX0)) { + if (serdes_type == PEX0) { /* For PEX by 4, init only the PEX 0 */ reg_data = reg_read(SOC_CONTROL_REG1); if (is_pex_by1 == 1) @@ -1721,30 +1721,20 @@ int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, reg_data &= ~0x4000; reg_write(SOC_CONTROL_REG1, reg_data); - /* Set Maximum Link Width to X1 or X4 */ - reg_data = reg_read(PEX_CFG_DIRECT_ACCESS( - pex_idx, - PEX_LINK_CAPABILITY_REG)); - reg_data &= ~0x3f0; - if (is_pex_by1 == 1) - reg_data |= 0x10; - else - reg_data |= 0x40; - reg_write(PEX_CFG_DIRECT_ACCESS( - pex_idx, - PEX_LINK_CAPABILITY_REG), - reg_data); - - /* Set Maximum Link Speed to 5 GT/s */ - reg_data = reg_read(PEX_CFG_DIRECT_ACCESS( - pex_idx, - PEX_LINK_CAPABILITY_REG)); - reg_data &= ~0xf; - reg_data |= 0x2; - reg_write(PEX_CFG_DIRECT_ACCESS( - pex_idx, - PEX_LINK_CAPABILITY_REG), - reg_data); + /* + * Set Maximum Link Width to X1 or X4 in Root + * Port's PCIe Link Capability register. + * This register is read-only but if is not set + * correctly then access to PCI config space of + * endpoint card behind this Root Port does not + * work. + */ + reg_data = reg_read(PEX0_RP_PCIE_CFG_OFFSET + + PCI_EXP_LNKCAP); + reg_data &= ~PCI_EXP_LNKCAP_MLW; + reg_data |= (is_pex_by1 ? 1 : 4) << 4; + reg_write(PEX0_RP_PCIE_CFG_OFFSET + + PCI_EXP_LNKCAP, reg_data); /* * Set Common Clock Configuration to indicates From 3fc8b90d68e1524275a126d659dc31d8b1246772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:18 +0200 Subject: [PATCH 09/23] arm: mvebu: a38x: serdes: Don't set PCIe Common Clock Configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling Common Clock Configuration bit in PCIe Root Port Link Control Register should not be done unconditionally. It is enabled by operating system as part of ASPM. Also after enabling Common Clock Configuration it is required to do more work, like retraining link. Some cards may be broken due to this incomplete Common Clock Configuration and some cards are broken and do not support ASPM at all. Remove this incomplete code for Common Clock Configuration. It really should not be done in SerDes code as it is not related to SerDes, but to PCIe subsystem. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- .../mach-mvebu/serdes/a38x/high_speed_env_spec.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c index c089479a9b..d2bc3ab25c 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c @@ -1735,21 +1735,6 @@ int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, reg_data |= (is_pex_by1 ? 1 : 4) << 4; reg_write(PEX0_RP_PCIE_CFG_OFFSET + PCI_EXP_LNKCAP, reg_data); - - /* - * Set Common Clock Configuration to indicates - * that both devices on the link use a - * distributed common reference clock. - */ - reg_data = reg_read(PEX_CFG_DIRECT_ACCESS( - pex_idx, - PEX_LINK_CTRL_STAT_REG)); - reg_data &= ~0x40; - reg_data |= 0x40; - reg_write(PEX_CFG_DIRECT_ACCESS( - pex_idx, - PEX_LINK_CTRL_STAT_REG), - reg_data); } CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ)); From db5ea818ce8fed95931169bbc487a64e959552d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:19 +0200 Subject: [PATCH 10/23] arm: mvebu: a38x: serdes: Don't overwrite PCI device ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCI device ID is part of the PCIe controller SoC / revision. For Root Complex mode (which is the default and the only mode supported currently by U-Boot and Linux kernel), it is PCI device ID of PCIe Root Port device. If there is some issue with this device ID, it should be set / updated by PCIe controller driver (pci_mvebu.c), as this register resides in address space of the controller. It shouldn't be done in SerDes initialization code. In the worst case (a specific board for example) it could be done via U-Boot's weak function board_pex_config(). But it should not be overwritten globally for all A38x devices. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 27 ---------------------- 1 file changed, 27 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c index 7c18df8113..a7e45a5550 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -186,33 +186,6 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) (": Link upgraded to Gen2 based on client capabilities\n"); } - /* Update pex DEVICE ID */ - ctrl_mode = sys_env_model_get(); - - for (idx = 0; idx < count; idx++) { - serdes_type = serdes_map[idx].serdes_type; - /* configuration for PEX only */ - if ((serdes_type != PEX0) && (serdes_type != PEX1) && - (serdes_type != PEX2) && (serdes_type != PEX3)) - continue; - - if ((serdes_type != PEX0) && - ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || - (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { - /* for PEX by4 - relevant for the first port only */ - continue; - } - - pex_idx = serdes_type - PEX0; - dev_id = reg_read(PEX_CFG_DIRECT_ACCESS - (pex_idx, PEX_DEVICE_AND_VENDOR_ID)); - dev_id &= 0xffff; - dev_id |= ((ctrl_mode << 16) & 0xffff0000); - reg_write(PEX_CFG_DIRECT_ACCESS - (pex_idx, PEX_DEVICE_AND_VENDOR_ID), dev_id); - } - DEBUG_INIT_FULL_C("Update PEX Device ID ", ctrl_mode, 4); - return MV_OK; } From 177ee6c77ed5de8f3a2c468d24a92b22d73b2239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:20 +0200 Subject: [PATCH 11/23] arm: mvebu: a38x: serdes: Don't configure PCIe cards in SerDes init code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code is trying to parse PCIe config space of PCIe card connected on the other end of link and then is trying to force 5.0 GT/s speed via Target Link Speed bits in PCIe Root Port Link Control 2 Register on the local part of link if it sees that card supports 5.0 GT/s via Max Link Speed bits in Link Capabilities Register. The code is incorrect for more reasons: - Accessing config space of an endpoint card cannot be done immediately. If the PCIe link is not up, reading vendor/device ID registers will return all ones. - Parsing is incomplete, so it can cause issues even for working cards. Moreover there is no need to force speed to 5.0 GT/s via Target Link Speed bits on PCIe Root Port Link Control 2 Register. Hardware changes speed from 2.5 GT/s to 5.0 GT/s autonomously when it is supported. Most importantly, this code does not change link speed at all, since because after updating Target Link Speed bits on PCIe Root Port Link Control 2 Register, it is required to retrain the link, and the code for that is completely missing. The code was probably needed for making buggy endpoint cards work. Such a workaround, though, should be implemented via PCIe subsystem (via quirks, for example), as buggy cards could also affect other PCIe controllers. Note that this code is fully unrelated to a38x SerDes code and really should not have been included in SerDes initialization. Usage of magic constants without names and comments made this SerDes code hard to read and understand. Remove this PCIe application code from low level SerDes code. As this code is configuring only 5.0 GT/s part, in the worst case, it could leave buggy cards at the initial speed of 2.5 GT/s (if somehow before this change they could have been "upgraded" to 5.0 GT/s speed even with missing link retraining). Compliant cards which just need longer initialization should work better after this change. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 128 +-------------------- 1 file changed, 1 insertion(+), 127 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c index a7e45a5550..0445b43def 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -21,10 +21,8 @@ __weak void board_pex_config(void) int hws_pex_config(const struct serdes_map *serdes_map, u8 count) { - u32 pex_idx, tmp, next_busno, first_busno, temp_pex_reg, - temp_reg, addr, dev_id, ctrl_mode; enum serdes_type serdes_type; - u32 idx; + u32 idx, tmp; DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n"); @@ -60,132 +58,8 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) reg_write(SOC_CONTROL_REG1, tmp); - /* Support gen1/gen2 */ - DEBUG_INIT_FULL_S("Support gen1/gen2\n"); - board_pex_config(); - next_busno = 0; - mdelay(150); - - for (idx = 0; idx < count; idx++) { - serdes_type = serdes_map[idx].serdes_type; - DEBUG_INIT_FULL_S(" serdes_type=0x"); - DEBUG_INIT_FULL_D(serdes_type, 8); - DEBUG_INIT_FULL_S("\n"); - DEBUG_INIT_FULL_S(" idx=0x"); - DEBUG_INIT_FULL_D(idx, 8); - DEBUG_INIT_FULL_S("\n"); - - /* Configuration for PEX only */ - if ((serdes_type != PEX0) && (serdes_type != PEX1) && - (serdes_type != PEX2) && (serdes_type != PEX3)) - continue; - - if ((serdes_type != PEX0) && - ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || - (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { - /* for PEX by4 - relevant for the first port only */ - continue; - } - - pex_idx = serdes_type - PEX0; - tmp = reg_read(PEX_DBG_STATUS_REG(pex_idx)); - - first_busno = next_busno; - if ((tmp & 0x7f) != 0x7e) { - DEBUG_INIT_S("PCIe, Idx "); - DEBUG_INIT_D(pex_idx, 1); - DEBUG_INIT_S(": detected no link\n"); - continue; - } - - next_busno++; - - /* - * Read maximum link speed. It must be 0x2 (5.0 GT/s) as this - * value was set in serdes_power_up_ctrl() function. - */ - temp_pex_reg = reg_read((PEX_CFG_DIRECT_ACCESS - (pex_idx, PEX_LINK_CAPABILITY_REG))); - temp_pex_reg &= 0xf; - if (temp_pex_reg != 0x2) - continue; - - /* Read negotiated link speed */ - temp_reg = (reg_read(PEX_CFG_DIRECT_ACCESS( - pex_idx, - PEX_LINK_CTRL_STAT_REG)) & - 0xf0000) >> 16; - - /* Check if the link established is GEN1 */ - DEBUG_INIT_FULL_S - ("Checking if the link established is gen1\n"); - if (temp_reg != 0x1) - continue; - - pex_local_bus_num_set(pex_idx, first_busno); - pex_local_dev_num_set(pex_idx, 1); - DEBUG_INIT_FULL_S("PCIe, Idx "); - DEBUG_INIT_FULL_D(pex_idx, 1); - - DEBUG_INIT_S(":** Link is Gen1, check the EP capability\n"); - /* link is Gen1, check the EP capability */ - addr = pex_config_read(pex_idx, first_busno, 0, 0, 0x34) & 0xff; - DEBUG_INIT_FULL_C("pex_config_read: return addr=0x%x", addr, 4); - if (addr == 0xff) { - DEBUG_INIT_FULL_C - ("pex_config_read: return 0xff -->PCIe (%d): Detected No Link.", - pex_idx, 1); - continue; - } - - /* Find start of the PCI Express Capability registers */ - while ((pex_config_read(pex_idx, first_busno, 0, 0, addr) - & 0xff) != 0x10) { - addr = (pex_config_read(pex_idx, first_busno, 0, - 0, addr) & 0xff00) >> 8; - } - - /* Check for Gen2 and above */ - if ((pex_config_read(pex_idx, first_busno, 0, 0, - addr + 0xc) & 0xf) < 0x2) { - DEBUG_INIT_S("PCIe, Idx "); - DEBUG_INIT_D(pex_idx, 1); - DEBUG_INIT_S(": remains Gen1\n"); - continue; - } - - tmp = reg_read(PEX_LINK_CTRL_STATUS2_REG(pex_idx)); - DEBUG_RD_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); - tmp &= ~(BIT(0) | BIT(1)); - tmp |= BIT(1); /* Force Target Link Speed to 5.0 GT/s */ - tmp |= BIT(6); /* Select Deemphasize (-3.5d_b) */ - reg_write(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); - DEBUG_WR_REG(PEX_LINK_CTRL_STATUS2_REG(pex_idx), tmp); - - /* - * Enable Auto Speed change. When set, link will issue link - * speed change to max possible link speed. - */ - tmp = reg_read(PEX_CTRL_REG(pex_idx)); - DEBUG_RD_REG(PEX_CTRL_REG(pex_idx), tmp); - tmp |= BIT(10); - reg_write(PEX_CTRL_REG(pex_idx), tmp); - DEBUG_WR_REG(PEX_CTRL_REG(pex_idx), tmp); - - /* - * We need to wait 10ms before reading the PEX_DBG_STATUS_REG - * in order not to read the status of the former state - */ - mdelay(10); - - DEBUG_INIT_S("PCIe, Idx "); - DEBUG_INIT_D(pex_idx, 1); - DEBUG_INIT_S - (": Link upgraded to Gen2 based on client capabilities\n"); - } - return MV_OK; } From 28c935b5ee3ab8d437f28df739c0ea1027db6b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:21 +0200 Subject: [PATCH 12/23] arm: mvebu: a38x: serdes: Remove unused PCIe macros and functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused PCIe functions from SerDes code. They are unused and are duplicated either from generic PCIe code or from pci_mvebu.c. Remove also unused PCIe macros from SerDes code. They are just obfuscated variants of standards macros in include/pci.h or in pci_mvebu.c. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 128 --------------------- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 60 ---------- 2 files changed, 188 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c index 0445b43def..55c3f9ca39 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -62,131 +62,3 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) return MV_OK; } - -int pex_local_bus_num_set(u32 pex_if, u32 bus_num) -{ - u32 pex_status; - - DEBUG_INIT_FULL_S("\n### pex_local_bus_num_set ###\n"); - - if (bus_num >= MAX_PEX_BUSSES) { - DEBUG_INIT_C("pex_local_bus_num_set: Illegal bus number %d\n", - bus_num, 4); - return MV_BAD_PARAM; - } - - pex_status = reg_read(PEX_STATUS_REG(pex_if)); - pex_status &= ~PXSR_PEX_BUS_NUM_MASK; - pex_status |= - (bus_num << PXSR_PEX_BUS_NUM_OFFS) & PXSR_PEX_BUS_NUM_MASK; - reg_write(PEX_STATUS_REG(pex_if), pex_status); - - return MV_OK; -} - -int pex_local_dev_num_set(u32 pex_if, u32 dev_num) -{ - u32 pex_status; - - DEBUG_INIT_FULL_S("\n### pex_local_dev_num_set ###\n"); - - pex_status = reg_read(PEX_STATUS_REG(pex_if)); - pex_status &= ~PXSR_PEX_DEV_NUM_MASK; - pex_status |= - (dev_num << PXSR_PEX_DEV_NUM_OFFS) & PXSR_PEX_DEV_NUM_MASK; - reg_write(PEX_STATUS_REG(pex_if), pex_status); - - return MV_OK; -} - -/* - * pex_config_read - Read from configuration space - * - * DESCRIPTION: - * This function performs a 32 bit read from PEX configuration space. - * It supports both type 0 and type 1 of Configuration Transactions - * (local and over bridge). In order to read from local bus segment, use - * bus number retrieved from pex_local_bus_num_get(). Other bus numbers - * will result configuration transaction of type 1 (over bridge). - * - * INPUT: - * pex_if - PEX interface number. - * bus - PEX segment bus number. - * dev - PEX device number. - * func - Function number. - * reg_offs - Register offset. - * - * OUTPUT: - * None. - * - * RETURN: - * 32bit register data, 0xffffffff on error - */ -u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off) -{ - u32 pex_data = 0; - u32 local_dev, local_bus; - u32 pex_status; - - pex_status = reg_read(PEX_STATUS_REG(pex_if)); - local_dev = - ((pex_status & PXSR_PEX_DEV_NUM_MASK) >> PXSR_PEX_DEV_NUM_OFFS); - local_bus = - ((pex_status & PXSR_PEX_BUS_NUM_MASK) >> PXSR_PEX_BUS_NUM_OFFS); - - /* - * In PCI Express we have only one device number - * and this number is the first number we encounter - * else that the local_dev - * spec pex define return on config read/write on any device - */ - if (bus == local_bus) { - if (local_dev == 0) { - /* - * if local dev is 0 then the first number we encounter - * after 0 is 1 - */ - if ((dev != 1) && (dev != local_dev)) - return MV_ERROR; - } else { - /* - * if local dev is not 0 then the first number we - * encounter is 0 - */ - if ((dev != 0) && (dev != local_dev)) - return MV_ERROR; - } - } - - /* Creating PEX address to be passed */ - pex_data = (bus << PXCAR_BUS_NUM_OFFS); - pex_data |= (dev << PXCAR_DEVICE_NUM_OFFS); - pex_data |= (func << PXCAR_FUNC_NUM_OFFS); - /* Legacy register space */ - pex_data |= (reg_off & PXCAR_REG_NUM_MASK); - /* Extended register space */ - pex_data |= (((reg_off & PXCAR_REAL_EXT_REG_NUM_MASK) >> - PXCAR_REAL_EXT_REG_NUM_OFFS) << PXCAR_EXT_REG_NUM_OFFS); - pex_data |= PXCAR_CONFIG_EN; - - /* Write the address to the PEX configuration address register */ - reg_write(PEX_CFG_ADDR_REG(pex_if), pex_data); - - /* - * In order to let the PEX controller absorbed the address - * of the read transaction we perform a validity check that - * the address was written - */ - if (pex_data != reg_read(PEX_CFG_ADDR_REG(pex_if))) - return MV_ERROR; - - /* Cleaning Master Abort */ - reg_bit_set(PEX_CFG_DIRECT_ACCESS(pex_if, PEX_STATUS_AND_COMMAND), - PXSAC_MABORT); - /* Read the Data returned in the PEX Data register */ - pex_data = reg_read(PEX_CFG_DATA_REG(pex_if)); - - DEBUG_INIT_FULL_C(" --> ", pex_data, 4); - - return pex_data; -} diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h index 5d70166fc5..55a4c267c4 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h @@ -12,28 +12,6 @@ /* Direct access to PEX0 Root Port's PCIe Capability structure */ #define PEX0_RP_PCIE_CFG_OFFSET (0x00080000 + 0x60) -/* Sample at Reset */ -#define MPP_SAMPLE_AT_RESET(id) (0xe4200 + (id * 4)) - -/* PCI Express Control and Status Registers */ -#define MAX_PEX_BUSSES 256 - -#define PEX_IF_REGS_OFFSET(if) ((if) > 0 ? \ - (0x40000 + ((if) - 1) * 0x4000) : \ - 0x80000) -#define PEX_IF_REGS_BASE(if) (PEX_IF_REGS_OFFSET(if)) -#define PEX_CAPABILITIES_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x60) -#define PEX_LINK_CTRL_STATUS2_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x90) -#define PEX_CTRL_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a00) -#define PEX_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a04) -#define PEX_DBG_STATUS_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x1a64) -#define PEX_LINK_CAPABILITY_REG 0x6c -#define PEX_LINK_CTRL_STAT_REG 0x70 -#define PXSR_PEX_DEV_NUM_OFFS 16 /* Device Number Indication */ -#define PXSR_PEX_DEV_NUM_MASK (0x1f << PXSR_PEX_DEV_NUM_OFFS) -#define PXSR_PEX_BUS_NUM_OFFS 8 /* Bus Number Indication */ -#define PXSR_PEX_BUS_NUM_MASK (0xff << PXSR_PEX_BUS_NUM_OFFS) - /* PEX_CAPABILITIES_REG fields */ #define PCIE0_ENABLE_OFFS 0 #define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS) @@ -44,45 +22,7 @@ #define PCIE3_ENABLE_OFFS 3 #define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS) -/* Controller revision info */ -#define PEX_DEVICE_AND_VENDOR_ID 0x000 -#define PEX_CFG_DIRECT_ACCESS(if, reg) (PEX_IF_REGS_BASE(if) + (reg)) - -/* PCI Express Configuration Address Register */ -#define PXCAR_REG_NUM_OFFS 2 -#define PXCAR_REG_NUM_MAX 0x3f -#define PXCAR_REG_NUM_MASK (PXCAR_REG_NUM_MAX << \ - PXCAR_REG_NUM_OFFS) -#define PXCAR_FUNC_NUM_OFFS 8 -#define PXCAR_FUNC_NUM_MAX 0x7 -#define PXCAR_FUNC_NUM_MASK (PXCAR_FUNC_NUM_MAX << \ - PXCAR_FUNC_NUM_OFFS) -#define PXCAR_DEVICE_NUM_OFFS 11 -#define PXCAR_DEVICE_NUM_MAX 0x1f -#define PXCAR_DEVICE_NUM_MASK (PXCAR_DEVICE_NUM_MAX << \ - PXCAR_DEVICE_NUM_OFFS) -#define PXCAR_BUS_NUM_OFFS 16 -#define PXCAR_BUS_NUM_MAX 0xff -#define PXCAR_BUS_NUM_MASK (PXCAR_BUS_NUM_MAX << \ - PXCAR_BUS_NUM_OFFS) -#define PXCAR_EXT_REG_NUM_OFFS 24 -#define PXCAR_EXT_REG_NUM_MAX 0xf - -#define PEX_CFG_ADDR_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18f8) -#define PEX_CFG_DATA_REG(if) ((PEX_IF_REGS_BASE(if)) + 0x18fc) - -#define PXCAR_REAL_EXT_REG_NUM_OFFS 8 -#define PXCAR_REAL_EXT_REG_NUM_MASK (0xf << PXCAR_REAL_EXT_REG_NUM_OFFS) - -#define PXCAR_CONFIG_EN BIT(31) -#define PEX_STATUS_AND_COMMAND 0x004 -#define PXSAC_MABORT BIT(29) /* Recieved Master Abort */ - int hws_pex_config(const struct serdes_map *serdes_map, u8 count); -int pex_local_bus_num_set(u32 pex_if, u32 bus_num); -int pex_local_dev_num_set(u32 pex_if, u32 dev_num); -u32 pex_config_read(u32 pex_if, u32 bus, u32 dev, u32 func, u32 reg_off); - void board_pex_config(void); #endif From de7293043329c6d230b7f81861867c6a645f4dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 24 Sep 2021 22:59:22 +0200 Subject: [PATCH 13/23] arm: mvebu: a38x: serdes: Update comment about PCIE*_ENABLE_* defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are part of SOC_CONTROL_REG1 register, not PEX_CAPABILITIES_REG. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h index 55a4c267c4..64193d5288 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h @@ -12,7 +12,7 @@ /* Direct access to PEX0 Root Port's PCIe Capability structure */ #define PEX0_RP_PCIE_CFG_OFFSET (0x00080000 + 0x60) -/* PEX_CAPABILITIES_REG fields */ +/* SOC_CONTROL_REG1 fields */ #define PCIE0_ENABLE_OFFS 0 #define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS) #define PCIE1_ENABLE_OFFS 1 From 6b2771cb19623f7028085e47a52e30813130f61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 26 Sep 2021 00:54:41 +0200 Subject: [PATCH 14/23] arm: a37xx: pci: Fix pcie_advk_link_up() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aardvark reports Disabled and Hot Reset LTSSM states as values >= 0x20. Link is not up in these states, so fix pcie_advk_link_up() function. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- drivers/pci/pci-aardvark.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index cf6e30f936..741e0431e1 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -145,6 +145,7 @@ #define LTSSM_SHIFT 24 #define LTSSM_MASK 0x3f #define LTSSM_L0 0x10 +#define LTSSM_DISABLED 0x20 #define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44) /* PCIe core controller registers */ @@ -569,7 +570,7 @@ static int pcie_advk_link_up(struct pcie_advk *pcie) val = advk_readl(pcie, CFG_REG); ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK; - return ltssm_state >= LTSSM_L0; + return ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED; } /** From cb056005dc674fb5fce89d2b7bdc37594b180b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 26 Sep 2021 00:54:42 +0200 Subject: [PATCH 15/23] arm: a37xx: pci: Add support for accessing PCI Bridge on root bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aardvark does not have a real PCIe Root Port device on the root bus. Instead it has PCIe registers of PCIe Root Port device mapped in internal Aardvark memory space starting at offset 0xc0. The PCIe Root Port itself is normally available as a PCI Bridge device on the root bus with bus number zero. Aardvark instead has the configuration registers of this PCI Bridge at offset 0x00 of Aardvark's memory space, but the class code of this device is Mass Storage Controller (0x010400), instead of PCI Bridge (0x600400), which causes U-Boot to fail to recognize it as a P2P Bridge Add a hook into the pcie_advk_read_config() / pcie_advk_write_config() functions to redirect access for root bus from PIO transfer to this internal Aardvark memory space. This will allow U-Boot to access configuration space of this PCI Bridge which represents PCIe Root Port. Redirect access to PCI Bridge registers in range 0x10 - 0x34 to driver's internal buffer (cfgcache[]). This is because at those addresses Aardvark has different registers, incompatible with config space of a PCI Bridge. Redirect access to PCI Bridge register PCI_ROM_ADDRESS1 (0x38) to Aardvark internal address for that register (0x30). When reading PCI Bridge register PCI_HEADER_TYPE, set it explicitly to value Type 1 (PCI_HEADER_TYPE_BRIDGE) as PCI Bridge must be of Type 1. When writing to PCI_PRIMARY_BUS or PCI_SECONDARY_BUS registers on this PCI Bridge, correctly update driver's first_busno and sec_busno variables, so that pcie_advk_addr_valid() function can check if address of any device behind the root bus is valid and that PIO transfers are started with correct config type (1 vs 0), which is required for accessing devices behind some PCI bridge after the root bus. U-Boot's PCI_PNP code sets primary and secondary bus numbers as relative to the configured bus number of the root bus. This is done so that U-Boot can support multiple PCIe host bridges or multiple root port buses, when internal bus numbers are different. Now that root bus is available, update code in pcie_advk_read_config() and pcie_advk_write_config() functions to correctly calculate real Aardvark bus number of the target device from U-Boot's bus number as: busno = PCI_BUS(bdf) - dev_seq(bus) Stefan: Small fix of header masking as suggested by Pali. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- drivers/pci/pci-aardvark.c | 147 +++++++++++++++++++++++++++++++------ 1 file changed, 126 insertions(+), 21 deletions(-) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 741e0431e1..082fdc3b74 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -39,6 +39,8 @@ #define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0) #define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1) #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) +#define PCIE_CORE_DEV_REV_REG 0x8 +#define PCIE_CORE_EXP_ROM_BAR_REG 0x30 #define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 #define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) @@ -163,7 +165,7 @@ #define PCIE_CONFIG_WR_TYPE1 0xb /* PCI_BDF shifts 8bit, so we need extra 4bit shift */ -#define PCIE_BDF(dev) (dev << 4) +#define PCIE_BDF(b, d, f) (PCI_BDF(b, d, f) << 4) #define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20) #define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15) #define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12) @@ -188,13 +190,17 @@ * first_busno stores the bus number of the PCIe root-port * number which may vary depending on the PCIe setup * (PEX switches etc). + * @sec_busno: sec_busno stores the bus number for the device behind + * the PCIe root-port * @device: The pointer to PCI uclass device. */ struct pcie_advk { void *base; int first_busno; + int sec_busno; struct udevice *dev; struct gpio_desc reset_gpio; + u32 cfgcache[0x34 - 0x10]; }; static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg) @@ -210,22 +216,30 @@ static inline uint advk_readl(struct pcie_advk *pcie, uint reg) /** * pcie_advk_addr_valid() - Check for valid bus address * + * @pcie: Pointer to the PCI bus + * @busno: Bus number of PCI device + * @dev: Device number of PCI device + * @func: Function number of PCI device * @bdf: The PCI device to access - * @first_busno: Bus number of the PCIe controller root complex * - * Return: 1 on valid, 0 on invalid + * Return: true on valid, false on invalid */ -static int pcie_advk_addr_valid(pci_dev_t bdf, int first_busno) +static bool pcie_advk_addr_valid(struct pcie_advk *pcie, + int busno, u8 dev, u8 func) { - /* - * In PCIE-E only a single device (0) can exist - * on the local bus. Beyound the local bus, there might be - * a Switch and everything is possible. - */ - if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0)) - return 0; + /* On the primary (local) bus there is only one PCI Bridge */ + if (busno == pcie->first_busno && (dev != 0 || func != 0)) + return false; - return 1; + /* + * In PCI-E only a single device (0) can exist on the secondary bus. + * Beyond the secondary bus, there might be a Switch and anything is + * possible. + */ + if (busno == pcie->sec_busno && dev != 0) + return false; + + return true; } /** @@ -355,20 +369,55 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, enum pci_size_t size) { struct pcie_advk *pcie = dev_get_priv(bus); + int busno = PCI_BUS(bdf) - dev_seq(bus); int retry_count; bool allow_crs; + ulong data; uint reg; int ret; dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ", PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { dev_dbg(pcie->dev, "- out of range\n"); *valuep = pci_get_ff(size); return 0; } + /* + * The configuration space of the PCI Bridge on primary (local) bus is + * not accessible via PIO transfers like all other PCIe devices. PCI + * Bridge config registers are available directly in Aardvark memory + * space starting at offset zero. Moreover PCI Bridge registers in the + * range 0x10 - 0x34 are not available and register 0x38 (Expansion ROM + * Base Address) is at offset 0x30. + * We therefore read configuration space content of the primary PCI + * Bridge from our virtual cache. + */ + if (busno == pcie->first_busno) { + if (offset >= 0x10 && offset < 0x34) + data = pcie->cfgcache[(offset - 0x10) / 4]; + else if ((offset & ~3) == PCI_ROM_ADDRESS1) + data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG); + else + data = advk_readl(pcie, offset & ~3); + + if ((offset & ~3) == (PCI_HEADER_TYPE & ~3)) { + /* + * Change Header Type of PCI Bridge device to Type 1 + * (0x01, used by PCI Bridges) because hardwired value + * is Type 0 (0x00, used by Endpoint devices). + */ + data &= ~0x007f0000; + data |= PCI_HEADER_TYPE_BRIDGE << 16; + } + + *valuep = pci_conv_32_to_size(data, offset, size); + + return 0; + } + /* * Returning fabricated CRS value (0xFFFF0001) by PCIe Root Complex to * OS is allowed only for 4-byte PCI_VENDOR_ID config read request and @@ -396,14 +445,14 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (PCI_BUS(bdf) == pcie->first_busno) + if (busno == pcie->sec_busno) reg |= PCIE_CONFIG_RD_TYPE0; else reg |= PCIE_CONFIG_RD_TYPE1; advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); @@ -491,7 +540,9 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, enum pci_size_t size) { struct pcie_advk *pcie = dev_get_priv(bus); + int busno = PCI_BUS(bdf) - dev_seq(bus); int retry_count; + ulong data; uint reg; int ret; @@ -500,11 +551,41 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value); - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { dev_dbg(pcie->dev, "- out of range\n"); return 0; } + /* + * As explained in pcie_advk_read_config(), for the configuration + * space of the primary PCI Bridge, we write the content into virtual + * cache. + */ + if (busno == pcie->first_busno) { + if (offset >= 0x10 && offset < 0x34) { + data = pcie->cfgcache[(offset - 0x10) / 4]; + data = pci_conv_size_to_32(data, value, offset, size); + pcie->cfgcache[(offset - 0x10) / 4] = data; + } else if ((offset & ~3) == PCI_ROM_ADDRESS1) { + data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG); + data = pci_conv_size_to_32(data, value, offset, size); + advk_writel(pcie, data, PCIE_CORE_EXP_ROM_BAR_REG); + } else { + data = advk_readl(pcie, offset & ~3); + data = pci_conv_size_to_32(data, value, offset, size); + advk_writel(pcie, data, offset & ~3); + } + + if (offset == PCI_PRIMARY_BUS) + pcie->first_busno = data & 0xff; + + if (offset == PCI_SECONDARY_BUS || + (offset == PCI_PRIMARY_BUS && size != PCI_SIZE_8)) + pcie->sec_busno = (data >> 8) & 0xff; + + return 0; + } + if (advk_readl(pcie, PIO_START)) { dev_err(pcie->dev, "Previous PIO read/write transfer is still running\n"); @@ -514,14 +595,14 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (PCI_BUS(bdf) == pcie->first_busno) + if (busno == pcie->sec_busno) reg |= PCIE_CONFIG_WR_TYPE0; else reg |= PCIE_CONFIG_WR_TYPE1; advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg); @@ -590,14 +671,14 @@ static int pcie_advk_wait_for_link(struct pcie_advk *pcie) /* check if the link is up or not */ for (retries = 0; retries < LINK_MAX_RETRIES; retries++) { if (pcie_advk_link_up(pcie)) { - printf("PCIE-%d: Link up\n", pcie->first_busno); + printf("PCIe: Link up\n"); return 0; } udelay(LINK_WAIT_TIMEOUT); } - printf("PCIE-%d: Link down\n", pcie->first_busno); + printf("PCIe: Link down\n"); return -ETIMEDOUT; } @@ -716,6 +797,25 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) */ advk_writel(pcie, 0x11ab11ab, VENDOR_ID_REG); + /* + * Change Class Code of PCI Bridge device to PCI Bridge (0x600400), + * because default value is Mass Storage Controller (0x010400), causing + * U-Boot to fail to recognize it as P2P Bridge. + * + * Note that this Aardvark PCI Bridge does not have a compliant Type 1 + * Configuration Space and it even cannot be accessed via Aardvark's + * PCI config space access method. Something like config space is + * available in internal Aardvark registers starting at offset 0x0 + * and is reported as Type 0. In range 0x10 - 0x34 it has totally + * different registers. So our driver reports Header Type as Type 1 and + * for the above mentioned range redirects access to the virtual + * cfgcache[] buffer, which avoids changing internal Aardvark registers. + */ + reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG); + reg &= ~0xffffff00; + reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; + advk_writel(pcie, reg, PCIE_CORE_DEV_REV_REG); + /* Set Advanced Error Capabilities and Control PF0 register */ reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX | PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN | @@ -857,9 +957,14 @@ static int pcie_advk_probe(struct udevice *dev) dev_warn(dev, "PCIE Reset on GPIO support is missing\n"); } - pcie->first_busno = dev_seq(dev); pcie->dev = pci_get_controller(dev); + /* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */ + pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] = + PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8); + pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] = + PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16); + return pcie_advk_setup_hw(pcie); } From 95e101e86ae9d4dbc29ab82bcf1cfa8820a7ba4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 26 Sep 2021 00:54:43 +0200 Subject: [PATCH 16/23] arm: a37xx: pci: Do not automatically enable bus mastering on PCI Bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that PCI Bridge is working for the PCIe Root Port, U-Boot's PCI_PNP code automatically enables memory access and bus mastering when needed. We do not need to enable it when setting the HW up. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- drivers/pci/pci-aardvark.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 082fdc3b74..2481cbea52 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -910,12 +910,6 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) if (pcie_advk_wait_for_link(pcie)) return -ENXIO; - reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG); - reg |= PCIE_CORE_CMD_MEM_ACCESS_EN | - PCIE_CORE_CMD_IO_ACCESS_EN | - PCIE_CORE_CMD_MEM_IO_REQ_EN; - advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG); - return 0; } From 1d7ad68559e2238d42730c7de0a3d5e159d72cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 26 Sep 2021 00:54:44 +0200 Subject: [PATCH 17/23] arm: a37xx: pci: Handle propagation of CRSSVE bit from PCIe Root Port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that PCI Bridge (PCIe Root Port) for Aardvark is emulated in U-Boot, add support for handling and propagation of CRSSVE bit. When CRSSVE bit is unset (default), driver has to reissue config read/write request on CRS response. CRSSVE bit is supported only when CRSVIS bit is provided in read-only Root Capabilities register. So manually inject this CRSVIS bit into read response for that register. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- drivers/pci/pci-aardvark.c | 26 ++++++++++++++++++++++---- include/pci.h | 4 ++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 2481cbea52..591bc8b48c 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -41,6 +41,7 @@ #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) #define PCIE_CORE_DEV_REV_REG 0x8 #define PCIE_CORE_EXP_ROM_BAR_REG 0x30 +#define PCIE_CORE_PCIEXP_CAP_OFF 0xc0 #define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 #define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) @@ -201,6 +202,7 @@ struct pcie_advk { struct udevice *dev; struct gpio_desc reset_gpio; u32 cfgcache[0x34 - 0x10]; + bool cfgcrssve; }; static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg) @@ -413,6 +415,18 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, data |= PCI_HEADER_TYPE_BRIDGE << 16; } + if ((offset & ~3) == PCIE_CORE_PCIEXP_CAP_OFF + PCI_EXP_RTCTL) { + /* CRSSVE bit is stored only in cache */ + if (pcie->cfgcrssve) + data |= PCI_EXP_RTCTL_CRSSVE; + } + + if ((offset & ~3) == PCIE_CORE_PCIEXP_CAP_OFF + + (PCI_EXP_RTCAP & ~3)) { + /* CRS is emulated below, so set CRSVIS capability */ + data |= PCI_EXP_RTCAP_CRSVIS << 16; + } + *valuep = pci_conv_32_to_size(data, offset, size); return 0; @@ -423,13 +437,14 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, * OS is allowed only for 4-byte PCI_VENDOR_ID config read request and * only when CRSSVE bit in Root Port PCIe device is enabled. In all * other error PCIe Root Complex must return all-ones. - * Aardvark HW does not have Root Port PCIe device and U-Boot does not - * implement emulation of this device. + * * U-Boot currently does not support handling of CRS return value for * PCI_VENDOR_ID config read request and also does not set CRSSVE bit. - * Therefore disable returning CRS response for now. + * So it means that pcie->cfgcrssve is false. But the code is prepared + * for returning CRS, so that if U-Boot does support CRS in the future, + * it will work for Aardvark. */ - allow_crs = false; + allow_crs = pcie->cfgcrssve; if (advk_readl(pcie, PIO_START)) { dev_err(pcie->dev, @@ -583,6 +598,9 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, (offset == PCI_PRIMARY_BUS && size != PCI_SIZE_8)) pcie->sec_busno = (data >> 8) & 0xff; + if ((offset & ~3) == PCIE_CORE_PCIEXP_CAP_OFF + PCI_EXP_RTCTL) + pcie->cfgcrssve = data & PCI_EXP_RTCTL_CRSSVE; + return 0; } diff --git a/include/pci.h b/include/pci.h index 11009a2f78..797f224e2f 100644 --- a/include/pci.h +++ b/include/pci.h @@ -495,6 +495,10 @@ #define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ +#define PCI_EXP_RTCTL 28 /* Root Control */ +#define PCI_EXP_RTCTL_CRSSVE 0x0010 /* CRS Software Visibility Enable */ +#define PCI_EXP_RTCAP 30 /* Root Capabilities */ +#define PCI_EXP_RTCAP_CRSVIS 0x0001 /* CRS Software Visibility capability */ #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ #define PCI_EXP_DEVCAP2_ARI 0x00000020 /* ARI Forwarding Supported */ #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ From 96a3c989dc936d51bfd825fa4396a12600dacaa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 26 Sep 2021 00:54:45 +0200 Subject: [PATCH 18/23] arm: a37xx: pci: Cosmetic change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update indentation in driver's private structure. Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- drivers/pci/pci-aardvark.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 591bc8b48c..3f714cd564 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -196,13 +196,13 @@ * @device: The pointer to PCI uclass device. */ struct pcie_advk { - void *base; - int first_busno; - int sec_busno; - struct udevice *dev; - struct gpio_desc reset_gpio; - u32 cfgcache[0x34 - 0x10]; - bool cfgcrssve; + void *base; + int first_busno; + int sec_busno; + struct udevice *dev; + struct gpio_desc reset_gpio; + u32 cfgcache[0x34 - 0x10]; + bool cfgcrssve; }; static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg) From 8247c90e92377afbc4c6366848e56ff8c9295ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 26 Sep 2021 00:54:46 +0200 Subject: [PATCH 19/23] arm: a37xx: pci: Update private structure documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were several changes for this structure but the documentation was not changed at the time. Fix this. Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- drivers/pci/pci-aardvark.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 3f714cd564..38eff495ab 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -186,14 +186,15 @@ /** * struct pcie_advk - Advk PCIe controller state * - * @reg_base: The base address of the register space. - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup - * (PEX switches etc). - * @sec_busno: sec_busno stores the bus number for the device behind - * the PCIe root-port - * @device: The pointer to PCI uclass device. + * @base: The base address of the register space. + * @first_busno: Bus number of the PCIe root-port. + * This may vary depending on the PCIe setup. + * @sec_busno: Bus number for the device behind the PCIe root-port. + * @dev: The pointer to PCI uclass device. + * @reset_gpio: GPIO descriptor for PERST. + * @cfgcache: Buffer for emulation of PCIe Root Port's PCI Bridge registers + * that are not available on Aardvark. + * @cfgcrssve: For CRSSVE emulation. */ struct pcie_advk { void *base; From cf47a8cf8f7e53018bff9952183b7cbf45b07c30 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Sun, 3 Oct 2021 11:53:45 +0200 Subject: [PATCH 20/23] arm: mvebu: Select SPL_SKIP_LOWLEVEL_INIT on ARMADA_32BIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Select SPL_SKIP_LOWLEVEL_INIT on 32bit Armada platforms via Kconfig, as this was removed from mach/config.h in a2ac2b96 ("Convert CONFIG_SKIP_LOWLEVEL_INIT et al to Kconfig"). Signed-off-by: Stefan Roese Fixes: a2ac2b96 ("Convert CONFIG_SKIP_LOWLEVEL_INIT et al to Kconfig") Cc: Tom Rini Cc: Marek Behún Cc: Pali Rohár Tested-by: Pali Rohár --- arch/arm/mach-mvebu/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 087643725e..54dff9986b 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -11,6 +11,7 @@ config ARMADA_32BIT select SPL_DM if SPL select SPL_DM_SEQ_ALIAS if SPL select SPL_OF_CONTROL if SPL + select SPL_SKIP_LOWLEVEL_INIT select SPL_SIMPLE_BUS if SPL select SUPPORT_SPL select TRANSLATION_OFFSET From cfb7102d8d901e9bdc7a6c109b341de7ae84256d Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 4 Oct 2021 15:12:53 +0200 Subject: [PATCH 21/23] arm: mvebu: dts: m801: correct CP1 pinctrl Current CP1 pinctrl that is set on the Puzzle M801 is incorrect. CP1 pins are only used for the SMI bus and the MSS I2C, all other pins are just GPIO-s. Due to this being set completely wrong, the pinctrl was actually ended up being hardcoded in the board_early_init_f() step so that SMI would work. That is obviously not the right thing to do, so convert the register hex values that were being written to individual pin modes and set it in the DTS. Add the SMI pins to the CP1 MDIO node as otherwise CP1 pinctrl does not get probed without an consumer. Fixes: 2ae2b8a2 ("arm: mvebu: Initial iEi Puzzle-M801 support") Signed-off-by: Robert Marko Reviewed-by: Stefan Roese --- arch/arm/dts/armada-8040-puzzle-m801.dts | 36 ++++++++++-------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/arch/arm/dts/armada-8040-puzzle-m801.dts b/arch/arm/dts/armada-8040-puzzle-m801.dts index 510fb84d5a..9e714c33e9 100644 --- a/arch/arm/dts/armada-8040-puzzle-m801.dts +++ b/arch/arm/dts/armada-8040-puzzle-m801.dts @@ -243,6 +243,9 @@ &cp1_mdio { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cp1_smi_pins>; + cp1_ge_phy0: ethernet-phy@3 { reg = <1>; }; @@ -292,33 +295,24 @@ /* * MPP Bus: * [0-5] TDM - * [6,7] CP1_UART 0 - * [8] CP1 10G SFP LOS - * [9] CP1 10G PHY RESET - * [10] CP1 10G SFP TX Disable - * [11] CP1 10G SFP Mode - * [12] SPI1 CS1n - * [13] SPI1 MISO (TDM and SPI ROM shared) - * [14] SPI1 CS0n - * [15] SPI1 MOSI (TDM and SPI ROM shared) - * [16] SPI1 CLK (TDM and SPI ROM shared) - * [24] CP1 2.5G SFP TX Disable - * [26] CP0 10G SFP TX Fault - * [27] CP0 10G SFP Mode - * [28] CP0 10G SFP LOS - * [29] CP0 10G SFP TX Disable - * [30] USB Over current indication - * [31] 10G Port 0 phy reset + * [27-28] SMI + * [29-30] CP1 MSS I2C + * [6-26, 31] GPIO * [32-62] = 0xff: Keep default CP1_shared_pins: */ /* 0 1 2 3 4 5 6 7 8 9 */ - pin-func = < 0x4 0x4 0x4 0x4 0x4 0x4 0x8 0x8 0x0 0x0 - 0x0 0x0 0x3 0x3 0x3 0x3 0x3 0xff 0xff 0xff - 0xff 0xff 0xff 0xff 0x0 0xff 0x0 0x0 0x0 0x0 - 0x0 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + pin-func = < 0x4 0x4 0x4 0x4 0x4 0x4 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x8 0x8 0x8 + 0x8 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + + cp1_smi_pins: cp1-smi-pins { + marvell,pins = < 27 28 >; + marvell,function = <8>; + }; }; &ap_spi0 { From bdce2124aceca9857518220704069d97210ba939 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Mon, 4 Oct 2021 15:12:54 +0200 Subject: [PATCH 22/23] arm: mvebu: mvebu_armada-8k: drop Puzzle M801 early init code Since the CP1 pinctrl is not properly set in the DTS, there is no need for setting the pinctrl by writing hardcoded values to the MPP registers. So, drop the code relating to that. Fixes: 87c220d0 ("arm: mvebu: mvebu_armada-8k: Add support for initializing iEi Puzzle-M801 networking") Signed-off-by: Robert Marko Reviewed-by: Stefan Roese --- board/Marvell/mvebu_armada-8k/board.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/board/Marvell/mvebu_armada-8k/board.c b/board/Marvell/mvebu_armada-8k/board.c index 7da5d9f96b..77c7dd7ab0 100644 --- a/board/Marvell/mvebu_armada-8k/board.c +++ b/board/Marvell/mvebu_armada-8k/board.c @@ -35,17 +35,6 @@ DECLARE_GLOBAL_DATA_PTR; #define I2C_IO_REG_CL ((1 << I2C_IO_REG_0_USB_H0_CL) | \ (1 << I2C_IO_REG_0_USB_H1_CL)) -/* - * Information specific to the iEi Puzzle-M801 board. - */ - -/* Internal configuration registers */ -#define CP1_CONF_REG_BASE 0xf4440000 -#define CONF_REG_MPP0 0x0 -#define CONF_REG_MPP1 0x4 -#define CONF_REG_MPP2 0x8 -#define CONF_REG_MPP3 0xC - static int usb_enabled = 0; /* Board specific xHCI dis-/enable code */ @@ -153,14 +142,7 @@ int board_xhci_enable(fdt_addr_t base) int board_early_init_f(void) { - /* Initialize some platform specific memory locations */ - if (of_machine_is_compatible("marvell,armada8040-puzzle-m801")) { - /* MPP setup */ - writel(0x00444444, CP1_CONF_REG_BASE + CONF_REG_MPP0); - writel(0x00000000, CP1_CONF_REG_BASE + CONF_REG_MPP1); - writel(0x00000000, CP1_CONF_REG_BASE + CONF_REG_MPP2); - writel(0x08888000, CP1_CONF_REG_BASE + CONF_REG_MPP3); - } + /* Nothing to do yet */ return 0; } From 1ead6c20bd5fb8ea2f6afffb81dde91ea54bf54a Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 7 Oct 2021 21:39:23 +1300 Subject: [PATCH 23/23] ARM: mvebu: x530: Remove custom kwbimage.cfg Commit ca1a4c863232 ("mvebu: select boot device at SoC level") made it unnecessary for the A385 boards to have their own kwbimage.cfg but as the x530 was in flight at the time it was added with it's own kwbimage.cfg. Remove the custom kwbimage.cfg as the SoC level file is suitable. Signed-off-by: Chris Packham Reviewed-by: Stefan Roese --- board/alliedtelesis/x530/kwbimage.cfg | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 board/alliedtelesis/x530/kwbimage.cfg diff --git a/board/alliedtelesis/x530/kwbimage.cfg b/board/alliedtelesis/x530/kwbimage.cfg deleted file mode 100644 index f58d388825..0000000000 --- a/board/alliedtelesis/x530/kwbimage.cfg +++ /dev/null @@ -1,12 +0,0 @@ -# -# Copyright (C) 2017 Allied Telesis Labs -# - -# Armada XP uses version 1 image format -VERSION 1 - -# Boot Media configurations -BOOT_FROM spi - -# Binary Header (bin_hdr) with DDR3 training code -BINARY spl/u-boot-spl-dtb.bin 0000005b 00000068