[U-Boot] [PATCHv4 00/12] pci: Add PCIe Gen4 controller driver for NXP Layerscape SoCs

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
Add PCIe Gen4 driver for the NXP Layerscape series SoCs.
Hou Zhiqiang (12): armv8: fsl-layerscpae: correct the PCIe controllers' region size armv8: lx2160a: add MMU table entries for PCIe pci: Add PCIe Gen4 controller driver for NXP Layerscape SoCs kconfig: add dependency PCIE_LAYERSCAPE_GEN4 for FSL_PCIE_COMPAT pci: ls_pcie_g4: add device tree fixups for PCI Stream IDs armv8: lx2160a: add PCIe controller DT nodes armv8: lx2160a: enable PCIe support pci: ls_pcie_g4: add Workaround for A-011577 dm: pci: add APIs for capability accessors dm: pci: add APIs for MPS and MRRS accessors pci: ls_pcie_g4: Add Workaround for A-011451 pci: ls_pcie_g4: add Workaround for A-011452
arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 2 +- arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 12 + arch/arm/dts/fsl-lx2160a.dtsi | 85 +++ .../arm/include/asm/arch-fsl-layerscape/cpu.h | 9 + .../asm/arch-fsl-layerscape/immap_lsch3.h | 14 +- configs/lx2160aqds_tfa_SECURE_BOOT_defconfig | 5 + configs/lx2160aqds_tfa_defconfig | 6 + configs/lx2160ardb_tfa_SECURE_BOOT_defconfig | 5 + configs/lx2160ardb_tfa_defconfig | 6 + drivers/pci/Kconfig | 8 + drivers/pci/Makefile | 2 + drivers/pci/pci-uclass.c | 245 ++++++++ drivers/pci/pci_auto.c | 35 ++ drivers/pci/pcie_layerscape_gen4.c | 593 ++++++++++++++++++ drivers/pci/pcie_layerscape_gen4.h | 273 ++++++++ drivers/pci/pcie_layerscape_gen4_fixup.c | 249 ++++++++ include/pci.h | 33 + include/pci_ids.h | 1 + 18 files changed, 1581 insertions(+), 2 deletions(-) create mode 100644 drivers/pci/pcie_layerscape_gen4.c create mode 100644 drivers/pci/pcie_layerscape_gen4.h create mode 100644 drivers/pci/pcie_layerscape_gen4_fixup.c

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
The LS2080A has 8GB region for each PCIe controller, while the other platforms have 32GB.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - No change
arch/arm/include/asm/arch-fsl-layerscape/cpu.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h index d62754e045..89124cdb0e 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h @@ -34,10 +34,17 @@ #define CONFIG_SYS_FSL_QBMAN_BASE 0x818000000 #define CONFIG_SYS_FSL_QBMAN_SIZE 0x8000000 #define CONFIG_SYS_FSL_QBMAN_SIZE_1 0x4000000 +#ifdef CONFIG_ARCH_LS2080A #define CONFIG_SYS_PCIE1_PHYS_SIZE 0x200000000 #define CONFIG_SYS_PCIE2_PHYS_SIZE 0x200000000 #define CONFIG_SYS_PCIE3_PHYS_SIZE 0x200000000 #define CONFIG_SYS_PCIE4_PHYS_SIZE 0x200000000 +#else +#define CONFIG_SYS_PCIE1_PHYS_SIZE 0x800000000 +#define CONFIG_SYS_PCIE2_PHYS_SIZE 0x800000000 +#define CONFIG_SYS_PCIE3_PHYS_SIZE 0x800000000 +#define CONFIG_SYS_PCIE4_PHYS_SIZE 0x800000000 +#endif #define CONFIG_SYS_FSL_WRIOP1_BASE 0x4300000000 #define CONFIG_SYS_FSL_WRIOP1_SIZE 0x100000000 #define CONFIG_SYS_FSL_AIOP1_BASE 0x4b00000000

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
The lx2160a have up to 6 PCIe controllers and have different address and size of PCIe region.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - No change
arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 12 ++++++++++++ arch/arm/include/asm/arch-fsl-layerscape/cpu.h | 2 ++ .../include/asm/arch-fsl-layerscape/immap_lsch3.h | 14 +++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c index 978d46b32f..2805e5f6f2 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -257,6 +257,18 @@ static struct mm_region final_map[] = { PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN }, +#endif +#ifdef CONFIG_ARCH_LX2160A + { SYS_PCIE5_PHYS_ADDR, SYS_PCIE5_PHYS_ADDR, + SYS_PCIE5_PHYS_SIZE, + PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, + { SYS_PCIE6_PHYS_ADDR, SYS_PCIE6_PHYS_ADDR, + SYS_PCIE6_PHYS_SIZE, + PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, #endif { CONFIG_SYS_FSL_WRIOP1_BASE, CONFIG_SYS_FSL_WRIOP1_BASE, CONFIG_SYS_FSL_WRIOP1_SIZE, diff --git a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h index 89124cdb0e..bdeb62576c 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/cpu.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/cpu.h @@ -44,6 +44,8 @@ #define CONFIG_SYS_PCIE2_PHYS_SIZE 0x800000000 #define CONFIG_SYS_PCIE3_PHYS_SIZE 0x800000000 #define CONFIG_SYS_PCIE4_PHYS_SIZE 0x800000000 +#define SYS_PCIE5_PHYS_SIZE 0x800000000 +#define SYS_PCIE6_PHYS_SIZE 0x800000000 #endif #define CONFIG_SYS_FSL_WRIOP1_BASE 0x4300000000 #define CONFIG_SYS_FSL_WRIOP1_SIZE 0x100000000 diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h index 9fab88ab2f..c9aa0cad71 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h @@ -167,7 +167,19 @@ #define CONFIG_SYS_PCIE2_ADDR (CONFIG_SYS_IMMR + 0x2500000) #define CONFIG_SYS_PCIE3_ADDR (CONFIG_SYS_IMMR + 0x2600000) #define CONFIG_SYS_PCIE4_ADDR (CONFIG_SYS_IMMR + 0x2700000) -#ifdef CONFIG_ARCH_LS1088A +#ifdef CONFIG_ARCH_LX2160A +#define SYS_PCIE5_ADDR (CONFIG_SYS_IMMR + 0x2800000) +#define SYS_PCIE6_ADDR (CONFIG_SYS_IMMR + 0x2900000) +#endif + +#ifdef CONFIG_ARCH_LX2160A +#define CONFIG_SYS_PCIE1_PHYS_ADDR 0x8000000000ULL +#define CONFIG_SYS_PCIE2_PHYS_ADDR 0x8800000000ULL +#define CONFIG_SYS_PCIE3_PHYS_ADDR 0x9000000000ULL +#define CONFIG_SYS_PCIE4_PHYS_ADDR 0x9800000000ULL +#define SYS_PCIE5_PHYS_ADDR 0xa000000000ULL +#define SYS_PCIE6_PHYS_ADDR 0xa800000000ULL +#elif CONFIG_ARCH_LS1088A #define CONFIG_SYS_PCIE1_PHYS_ADDR 0x2000000000ULL #define CONFIG_SYS_PCIE2_PHYS_ADDR 0x2800000000ULL #define CONFIG_SYS_PCIE3_PHYS_ADDR 0x3000000000ULL

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
Add PCIe Gen4 driver for the NXP Layerscape SoCs. This PCIe controller is based on the Mobiveil IP, which is compatible with the PCI Express™ Base Specification, Revision 4.0.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com Signed-off-by: Bao Xiaowei Xiaowei.Bao@nxp.com --- V4: - No change
drivers/pci/Kconfig | 8 + drivers/pci/Makefile | 1 + drivers/pci/pcie_layerscape_gen4.c | 577 +++++++++++++++++++++++++++++ drivers/pci/pcie_layerscape_gen4.h | 264 +++++++++++++ 4 files changed, 850 insertions(+) create mode 100644 drivers/pci/pcie_layerscape_gen4.c create mode 100644 drivers/pci/pcie_layerscape_gen4.h
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 1521885bde..2638a5a72d 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -69,6 +69,14 @@ config PCI_RCAR_GEN2 Renesas RCar Gen2 SoCs. The PCIe controller on RCar Gen2 is also used to access EHCI USB controller on the SoC.
+config PCIE_LAYERSCAPE_GEN4 + bool "Layerscape Gen4 PCIe support" + depends on DM_PCI + help + Support PCIe Gen4 on NXP Layerscape SoCs, which may have one or + several PCIe controllers. The PCIe controller can work in RC or + EP mode according to RCW[HOST_AGT_PEX] setting. + config PCI_SANDBOX bool "Sandbox PCI support" depends on SANDBOX && DM_PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 4923641895..7f585aad55 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -32,5 +32,6 @@ obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o +obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c new file mode 100644 index 0000000000..fbe7d35911 --- /dev/null +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -0,0 +1,577 @@ +// SPDX-License-Identifier: GPL-2.0+ OR X11 +/* + * Copyright 2018 NXP + * + * PCIe Gen4 driver for NXP Layerscape SoCs + * Author: Hou Zhiqiang Minder.Hou@gmail.com + */ + +#include <common.h> +#include <asm/arch/fsl_serdes.h> +#include <pci.h> +#include <asm/io.h> +#include <errno.h> +#include <malloc.h> +#include <dm.h> +#include <linux/sizes.h> + +#include "pcie_layerscape_gen4.h" + +DECLARE_GLOBAL_DATA_PTR; + +LIST_HEAD(ls_pcie_g4_list); + +static u64 bar_size[4] = { + PCIE_BAR0_SIZE, + PCIE_BAR1_SIZE, + PCIE_BAR2_SIZE, + PCIE_BAR4_SIZE +}; + +static int ls_pcie_g4_ltssm(struct ls_pcie_g4 *pcie) +{ + u32 state; + + state = pf_ctrl_readl(pcie, PCIE_LTSSM_STA) & LTSSM_STATE_MASK; + + return state; +} + +static int ls_pcie_g4_link_up(struct ls_pcie_g4 *pcie) +{ + int ltssm; + + ltssm = ls_pcie_g4_ltssm(pcie); + if (ltssm != LTSSM_PCIE_L0) + return 0; + + return 1; +} + +static void ls_pcie_g4_ep_enable_cfg(struct ls_pcie_g4 *pcie) +{ + ccsr_writel(pcie, GPEX_CFG_READY, PCIE_CONFIG_READY); +} + +static void ls_pcie_g4_cfg_set_target(struct ls_pcie_g4 *pcie, u32 target) +{ + ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(0), target); + ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(0), 0); +} + +static int ls_pcie_g4_outbound_win_set(struct ls_pcie_g4 *pcie, int idx, + int type, u64 phys, u64 bus_addr, + pci_size_t size) +{ + u32 val; + u32 size_h, size_l; + + if (idx >= PAB_WINS_NUM) + return -EINVAL; + + size_h = upper_32_bits(~(size - 1)); + size_l = lower_32_bits(~(size - 1)); + + val = ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(idx)); + val &= ~((AXI_AMAP_CTRL_TYPE_MASK << AXI_AMAP_CTRL_TYPE_SHIFT) | + (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT) | + AXI_AMAP_CTRL_EN); + val |= ((type & AXI_AMAP_CTRL_TYPE_MASK) << AXI_AMAP_CTRL_TYPE_SHIFT) | + ((size_l >> AXI_AMAP_CTRL_SIZE_SHIFT) << + AXI_AMAP_CTRL_SIZE_SHIFT) | AXI_AMAP_CTRL_EN; + + ccsr_writel(pcie, PAB_AXI_AMAP_CTRL(idx), val); + + ccsr_writel(pcie, PAB_AXI_AMAP_AXI_WIN(idx), lower_32_bits(phys)); + ccsr_writel(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(idx), upper_32_bits(phys)); + ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr)); + ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr)); + ccsr_writel(pcie, PAB_EXT_AXI_AMAP_SIZE(idx), size_h); + + return 0; +} + +static int ls_pcie_g4_rc_inbound_win_set(struct ls_pcie_g4 *pcie, int idx, + int type, u64 phys, u64 bus_addr, + pci_size_t size) +{ + u32 val; + pci_size_t win_size = ~(size - 1); + + val = ccsr_readl(pcie, PAB_PEX_AMAP_CTRL(idx)); + + val &= ~(PEX_AMAP_CTRL_TYPE_MASK << PEX_AMAP_CTRL_TYPE_SHIFT); + val &= ~(PEX_AMAP_CTRL_EN_MASK << PEX_AMAP_CTRL_EN_SHIFT); + val = (val | (type << PEX_AMAP_CTRL_TYPE_SHIFT)); + val = (val | (1 << PEX_AMAP_CTRL_EN_SHIFT)); + + ccsr_writel(pcie, PAB_PEX_AMAP_CTRL(idx), + val | lower_32_bits(win_size)); + + ccsr_writel(pcie, PAB_EXT_PEX_AMAP_SIZE(idx), upper_32_bits(win_size)); + ccsr_writel(pcie, PAB_PEX_AMAP_AXI_WIN(idx), lower_32_bits(phys)); + ccsr_writel(pcie, PAB_EXT_PEX_AMAP_AXI_WIN(idx), upper_32_bits(phys)); + ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr)); + ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr)); + + return 0; +} + +static void ls_pcie_g4_dump_wins(struct ls_pcie_g4 *pcie, int wins) +{ + int i; + + for (i = 0; i < wins; i++) { + debug("APIO Win%d:\n", i); + debug("\tLOWER PHYS: 0x%08x\n", + ccsr_readl(pcie, PAB_AXI_AMAP_AXI_WIN(i))); + debug("\tUPPER PHYS: 0x%08x\n", + ccsr_readl(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(i))); + debug("\tLOWER BUS: 0x%08x\n", + ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_L(i))); + debug("\tUPPER BUS: 0x%08x\n", + ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_H(i))); + debug("\tSIZE: 0x%08x\n", + ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i)) & + (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT)); + debug("\tEXT_SIZE: 0x%08x\n", + ccsr_readl(pcie, PAB_EXT_AXI_AMAP_SIZE(i))); + debug("\tPARAM: 0x%08x\n", + ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(i))); + debug("\tCTRL: 0x%08x\n", + ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i))); + } +} + +static void ls_pcie_g4_setup_wins(struct ls_pcie_g4 *pcie) +{ + struct pci_region *io, *mem, *pref; + int idx = 1; + + /* INBOUND WIN */ + ls_pcie_g4_rc_inbound_win_set(pcie, 0, IB_TYPE_MEM_F, 0, 0, SIZE_1T); + + /* OUTBOUND WIN 0: CFG */ + ls_pcie_g4_outbound_win_set(pcie, 0, PAB_AXI_TYPE_CFG, + pcie->cfg_res.start, 0, + fdt_resource_size(&pcie->cfg_res)); + + pci_get_regions(pcie->bus, &io, &mem, &pref); + + if (io) + /* OUTBOUND WIN: IO */ + ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_IO, + io->phys_start, io->bus_start, + io->size); + + if (mem) + /* OUTBOUND WIN: MEM */ + ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM, + mem->phys_start, mem->bus_start, + mem->size); + + if (pref) + /* OUTBOUND WIN: perf MEM */ + ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM, + pref->phys_start, pref->bus_start, + pref->size); + + ls_pcie_g4_dump_wins(pcie, idx); +} + +/* Return 0 if the address is valid, -errno if not valid */ +static int ls_pcie_g4_addr_valid(struct ls_pcie_g4 *pcie, pci_dev_t bdf) +{ + struct udevice *bus = pcie->bus; + + if (pcie->mode == PCI_HEADER_TYPE_NORMAL) + return -ENODEV; + + if (!pcie->enabled) + return -ENXIO; + + if (PCI_BUS(bdf) < bus->seq) + return -EINVAL; + + if ((PCI_BUS(bdf) > bus->seq) && (!ls_pcie_g4_link_up(pcie))) + return -EINVAL; + + if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0)) + return -EINVAL; + + return 0; +} + +void *ls_pcie_g4_conf_address(struct ls_pcie_g4 *pcie, pci_dev_t bdf, + int offset) +{ + struct udevice *bus = pcie->bus; + u32 target; + + if (PCI_BUS(bdf) == bus->seq) { + if (offset < INDIRECT_ADDR_BNDRY) { + ccsr_set_page(pcie, 0); + return pcie->ccsr + offset; + } + + ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset)); + return pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset); + } + + target = PAB_TARGET_BUS(PCI_BUS(bdf) - bus->seq) | + PAB_TARGET_DEV(PCI_DEV(bdf)) | + PAB_TARGET_FUNC(PCI_FUNC(bdf)); + + ls_pcie_g4_cfg_set_target(pcie, target); + + return pcie->cfg + offset; +} + +static int ls_pcie_g4_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct ls_pcie_g4 *pcie = dev_get_priv(bus); + void *address; + int ret = 0; + + if (ls_pcie_g4_addr_valid(pcie, bdf)) { + *valuep = pci_get_ff(size); + return 0; + } + + address = ls_pcie_g4_conf_address(pcie, bdf, offset); + + switch (size) { + case PCI_SIZE_8: + *valuep = readb(address); + break; + case PCI_SIZE_16: + *valuep = readw(address); + break; + case PCI_SIZE_32: + *valuep = readl(address); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ls_pcie_g4_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct ls_pcie_g4 *pcie = dev_get_priv(bus); + void *address; + + if (ls_pcie_g4_addr_valid(pcie, bdf)) + return 0; + + address = ls_pcie_g4_conf_address(pcie, bdf, offset); + + switch (size) { + case PCI_SIZE_8: + writeb(value, address); + return 0; + case PCI_SIZE_16: + writew(value, address); + return 0; + case PCI_SIZE_32: + writel(value, address); + return 0; + default: + return -EINVAL; + } +} + +static void ls_pcie_g4_setup_ctrl(struct ls_pcie_g4 *pcie) +{ + u32 val; + + /* Fix class code */ + val = ccsr_readl(pcie, GPEX_CLASSCODE); + val &= ~(GPEX_CLASSCODE_MASK << GPEX_CLASSCODE_SHIFT); + val |= PCI_CLASS_BRIDGE_PCI << GPEX_CLASSCODE_SHIFT; + ccsr_writel(pcie, GPEX_CLASSCODE, val); + + /* Enable APIO and Memory/IO/CFG Wins */ + val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0)); + val |= APIO_EN | MEM_WIN_EN | IO_WIN_EN | CFG_WIN_EN; + ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val); + + ls_pcie_g4_setup_wins(pcie); + + pcie->stream_id_cur = 0; +} + +static void ls_pcie_g4_ep_inbound_win_set(struct ls_pcie_g4 *pcie, int pf, + int bar, u64 phys) +{ + u32 val; + + /* PF BAR1 is for MSI-X and only need to enable */ + if (bar == 1) { + ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), BAR_AMAP_EN); + return; + } + + val = upper_32_bits(phys); + ccsr_writel(pcie, PAB_EXT_PEX_BAR_AMAP(pf, bar), val); + val = lower_32_bits(phys) | BAR_AMAP_EN; + ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), val); +} + +static void ls_pcie_g4_ep_setup_wins(struct ls_pcie_g4 *pcie, int pf) +{ + u64 phys; + int bar; + u32 val; + + if ((!pcie->sriov_support && pf > LS_G4_PF0) || pf > LS_G4_PF1) + return; + + phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR_SIZE * 4 * pf; + for (bar = 0; bar < PF_BAR_NUM; bar++) { + ls_pcie_g4_ep_inbound_win_set(pcie, pf, bar, phys); + phys += PCIE_BAR_SIZE; + } + + /* OUTBOUND: map MEM */ + ls_pcie_g4_outbound_win_set(pcie, pf, PAB_AXI_TYPE_MEM, + pcie->cfg_res.start + + CONFIG_SYS_PCI_MEMORY_SIZE * pf, 0x0, + CONFIG_SYS_PCI_MEMORY_SIZE); + + val = ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf)); + val &= ~FUNC_NUM_PCIE_MASK; + val |= pf; + ccsr_writel(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf), val); +} + +static void ls_pcie_g4_ep_enable_bar(struct ls_pcie_g4 *pcie, int pf, + int bar, bool vf_bar, bool enable) +{ + u32 val; + u32 bar_pos = BAR_POS(bar, pf, vf_bar); + + val = ccsr_readl(pcie, GPEX_BAR_ENABLE); + if (enable) + val |= 1 << bar_pos; + else + val &= ~(1 << bar_pos); + ccsr_writel(pcie, GPEX_BAR_ENABLE, val); +} + +static void ls_pcie_g4_ep_set_bar_size(struct ls_pcie_g4 *pcie, int pf, + int bar, bool vf_bar, u64 size) +{ + u32 bar_pos = BAR_POS(bar, pf, vf_bar); + u32 mask_l = lower_32_bits(~(size - 1)); + u32 mask_h = upper_32_bits(~(size - 1)); + + ccsr_writel(pcie, GPEX_BAR_SELECT, bar_pos); + ccsr_writel(pcie, GPEX_BAR_SIZE_LDW, mask_l); + ccsr_writel(pcie, GPEX_BAR_SIZE_UDW, mask_h); +} + +static void ls_pcie_g4_ep_setup_bar(struct ls_pcie_g4 *pcie, int pf, + int bar, bool vf_bar, u64 size) +{ + bool en = size ? true : false; + + ls_pcie_g4_ep_enable_bar(pcie, pf, bar, vf_bar, en); + ls_pcie_g4_ep_set_bar_size(pcie, pf, bar, vf_bar, size); +} + +static void ls_pcie_g4_ep_setup_bars(struct ls_pcie_g4 *pcie, int pf) +{ + int bar; + + /* Setup PF BARs */ + for (bar = 0; bar < PF_BAR_NUM; bar++) + ls_pcie_g4_ep_setup_bar(pcie, pf, bar, false, bar_size[bar]); + + if (!pcie->sriov_support) + return; + + /* Setup VF BARs */ + for (bar = 0; bar < VF_BAR_NUM; bar++) + ls_pcie_g4_ep_setup_bar(pcie, pf, bar, true, bar_size[bar]); +} + +static void ls_pcie_g4_set_sriov(struct ls_pcie_g4 *pcie, int pf) +{ + unsigned int val; + + val = ccsr_readl(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf)); + val &= ~(TTL_VF_MASK << TTL_VF_SHIFT); + val |= PCIE_VF_NUM << TTL_VF_SHIFT; + val &= ~(INI_VF_MASK << INI_VF_SHIFT); + val |= PCIE_VF_NUM << INI_VF_SHIFT; + ccsr_writel(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf), val); + + val = ccsr_readl(pcie, PCIE_SRIOV_VF_OFFSET_STRIDE); + val += PCIE_VF_NUM * pf - pf; + ccsr_writel(pcie, GPEX_SRIOV_VF_OFFSET_STRIDE(pf), val); +} + +static void ls_pcie_g4_setup_ep(struct ls_pcie_g4 *pcie) +{ + u32 pf, sriov; + u32 val; + int i; + + /* Enable APIO and Memory Win */ + val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0)); + val |= APIO_EN | MEM_WIN_EN; + ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val); + + sriov = ccsr_readl(pcie, PCIE_SRIOV_CAPABILITY); + if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) + pcie->sriov_support = 1; + + pf = pcie->sriov_support ? PCIE_PF_NUM : 1; + + for (i = 0; i < pf; i++) { + ls_pcie_g4_ep_setup_bars(pcie, i); + ls_pcie_g4_ep_setup_wins(pcie, i); + if (pcie->sriov_support) + ls_pcie_g4_set_sriov(pcie, i); + } + + ls_pcie_g4_ep_enable_cfg(pcie); + ls_pcie_g4_dump_wins(pcie, pf); +} + +static int ls_pcie_g4_probe(struct udevice *dev) +{ + struct ls_pcie_g4 *pcie = dev_get_priv(dev); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + u32 link_ctrl_sta; + u32 val; + int ret; + + pcie->bus = dev; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "ccsr", &pcie->ccsr_res); + if (ret) { + printf("ls-pcie-g4: resource "ccsr" not found\n"); + return ret; + } + + pcie->idx = (pcie->ccsr_res.start - PCIE_SYS_BASE_ADDR) / + PCIE_CCSR_SIZE; + + list_add(&pcie->list, &ls_pcie_g4_list); + + pcie->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx)); + if (!pcie->enabled) { + printf("PCIe%d: %s disabled\n", pcie->idx, dev->name); + return 0; + } + + pcie->ccsr = map_physmem(pcie->ccsr_res.start, + fdt_resource_size(&pcie->ccsr_res), + MAP_NOCACHE); + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "config", &pcie->cfg_res); + if (ret) { + printf("%s: resource "config" not found\n", dev->name); + return ret; + } + + pcie->cfg = map_physmem(pcie->cfg_res.start, + fdt_resource_size(&pcie->cfg_res), + MAP_NOCACHE); + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "lut", &pcie->lut_res); + if (ret) { + printf("ls-pcie-g4: resource "lut" not found\n"); + return ret; + } + + pcie->lut = map_physmem(pcie->lut_res.start, + fdt_resource_size(&pcie->lut_res), + MAP_NOCACHE); + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "pf_ctrl", &pcie->pf_ctrl_res); + if (ret) { + printf("ls-pcie-g4: resource "pf_ctrl" not found\n"); + return ret; + } + + pcie->pf_ctrl = map_physmem(pcie->pf_ctrl_res.start, + fdt_resource_size(&pcie->pf_ctrl_res), + MAP_NOCACHE); + + pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian"); + + debug("%s ccsr:%lx, cfg:0x%lx, big-endian:%d\n", + dev->name, (unsigned long)pcie->ccsr, (unsigned long)pcie->cfg, + pcie->big_endian); + + pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f; + + if (pcie->mode == PCI_HEADER_TYPE_NORMAL) { + printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint"); + ls_pcie_g4_setup_ep(pcie); + } else { + printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex"); + ls_pcie_g4_setup_ctrl(pcie); + } + + /* Enable Amba & PEX PIO */ + val = ccsr_readl(pcie, PAB_CTRL); + val |= PAB_CTRL_APIO_EN | PAB_CTRL_PPIO_EN; + ccsr_writel(pcie, PAB_CTRL, val); + + val = ccsr_readl(pcie, PAB_PEX_PIO_CTRL(0)); + val |= PPIO_EN; + ccsr_writel(pcie, PAB_PEX_PIO_CTRL(0), val); + + if (!ls_pcie_g4_link_up(pcie)) { + /* Let the user know there's no PCIe link */ + printf(": no link\n"); + return 0; + } + + /* Print the negotiated PCIe link width */ + link_ctrl_sta = ccsr_readl(pcie, PCIE_LINK_CTRL_STA); + printf(": x%d gen%d\n", + (link_ctrl_sta >> PCIE_LINK_WIDTH_SHIFT & PCIE_LINK_WIDTH_MASK), + (link_ctrl_sta >> PCIE_LINK_SPEED_SHIFT) & PCIE_LINK_SPEED_MASK); + + return 0; +} + +static const struct dm_pci_ops ls_pcie_g4_ops = { + .read_config = ls_pcie_g4_read_config, + .write_config = ls_pcie_g4_write_config, +}; + +static const struct udevice_id ls_pcie_g4_ids[] = { + { .compatible = "fsl,lx2160a-pcie" }, + { } +}; + +U_BOOT_DRIVER(pcie_layerscape_gen4) = { + .name = "pcie_layerscape_gen4", + .id = UCLASS_PCI, + .of_match = ls_pcie_g4_ids, + .ops = &ls_pcie_g4_ops, + .probe = ls_pcie_g4_probe, + .priv_auto_alloc_size = sizeof(struct ls_pcie_g4), +}; + +/* No any fixup so far */ +void ft_pci_setup(void *blob, bd_t *bd) +{ +} diff --git a/drivers/pci/pcie_layerscape_gen4.h b/drivers/pci/pcie_layerscape_gen4.h new file mode 100644 index 0000000000..356b49f9ce --- /dev/null +++ b/drivers/pci/pcie_layerscape_gen4.h @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2018 NXP + * + * PCIe Gen4 driver for NXP Layerscape SoCs + * Author: Hou Zhiqiang Minder.Hou@gmail.com + */ + +#ifndef _PCIE_LAYERSCAPE_GEN4_H_ +#define _PCIE_LAYERSCAPE_GEN4_H_ +#include <pci.h> +#include <dm.h> + +#ifndef CONFIG_SYS_PCI_MEMORY_SIZE +#define CONFIG_SYS_PCI_MEMORY_SIZE (4 * 1024 * 1024 * 1024ULL) +#endif + +#ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE +#define CONFIG_SYS_PCI_EP_MEMORY_BASE CONFIG_SYS_LOAD_ADDR +#endif + +#define PCIE_PF_NUM 2 +#define PCIE_VF_NUM 32 + +#define LS_G4_PF0 0 +#define LS_G4_PF1 1 +#define PF_BAR_NUM 4 +#define VF_BAR_NUM 4 +#define PCIE_BAR_SIZE (8 * 1024) /* 8K */ +#define PCIE_BAR0_SIZE PCIE_BAR_SIZE +#define PCIE_BAR1_SIZE PCIE_BAR_SIZE +#define PCIE_BAR2_SIZE PCIE_BAR_SIZE +#define PCIE_BAR4_SIZE PCIE_BAR_SIZE +#define SIZE_1T (1024 * 1024 * 1024 * 1024ULL) + +/* GPEX CSR */ +#define GPEX_CLASSCODE 0x474 +#define GPEX_CLASSCODE_SHIFT 16 +#define GPEX_CLASSCODE_MASK 0xffff + +#define GPEX_CFG_READY 0x4b0 +#define PCIE_CONFIG_READY BIT(0) + +#define GPEX_BAR_ENABLE 0x4d4 +#define GPEX_BAR_SIZE_LDW 0x4d8 +#define GPEX_BAR_SIZE_UDW 0x4dC +#define GPEX_BAR_SELECT 0x4e0 + +#define BAR_POS(bar, pf, vf_bar) \ + ((bar) + (pf) * PF_BAR_NUM + (vf_bar) * PCIE_PF_NUM * PF_BAR_NUM) + +#define GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf) (0x644 + (pf) * 4) +#define TTL_VF_MASK 0xffff +#define TTL_VF_SHIFT 16 +#define INI_VF_MASK 0xffff +#define INI_VF_SHIFT 0 +#define GPEX_SRIOV_VF_OFFSET_STRIDE(pf) (0x704 + (pf) * 4) + +/* PAB CSR */ +#define PAB_CTRL 0x808 +#define PAB_CTRL_APIO_EN BIT(0) +#define PAB_CTRL_PPIO_EN BIT(1) +#define PAB_CTRL_MAX_BRST_LEN_SHIFT 4 +#define PAB_CTRL_MAX_BRST_LEN_MASK 0x3 +#define PAB_CTRL_PAGE_SEL_SHIFT 13 +#define PAB_CTRL_PAGE_SEL_MASK 0x3f +#define PAB_CTRL_FUNC_SEL_SHIFT 19 +#define PAB_CTRL_FUNC_SEL_MASK 0x1ff + +#define PAB_RST_CTRL 0x820 +#define PAB_BR_STAT 0x80c + +/* AXI PIO Engines */ +#define PAB_AXI_PIO_CTRL(idx) (0x840 + 0x10 * (idx)) +#define APIO_EN BIT(0) +#define MEM_WIN_EN BIT(1) +#define IO_WIN_EN BIT(2) +#define CFG_WIN_EN BIT(3) +#define PAB_AXI_PIO_STAT(idx) (0x844 + 0x10 * (idx)) +#define PAB_AXI_PIO_SL_CMD_STAT(idx) (0x848 + 0x10 * (idx)) +#define PAB_AXI_PIO_SL_ADDR_STAT(idx) (0x84c + 0x10 * (idx)) +#define PAB_AXI_PIO_SL_EXT_ADDR_STAT(idx) (0xb8a0 + 0x4 * (idx)) + +/* PEX PIO Engines */ +#define PAB_PEX_PIO_CTRL(idx) (0x8c0 + 0x10 * (idx)) +#define PPIO_EN BIT(0) +#define PAB_PEX_PIO_STAT(idx) (0x8c4 + 0x10 * (idx)) +#define PAB_PEX_PIO_MT_STAT(idx) (0x8c8 + 0x10 * (idx)) + +#define INDIRECT_ADDR_BNDRY 0xc00 +#define PAGE_IDX_SHIFT 10 +#define PAGE_ADDR_MASK 0x3ff + +#define OFFSET_TO_PAGE_IDX(off) \ + (((off) >> PAGE_IDX_SHIFT) & PAB_CTRL_PAGE_SEL_MASK) + +#define OFFSET_TO_PAGE_ADDR(off) \ + (((off) & PAGE_ADDR_MASK) | INDIRECT_ADDR_BNDRY) + +/* APIO WINs */ +#define PAB_AXI_AMAP_CTRL(idx) (0xba0 + 0x10 * (idx)) +#define PAB_EXT_AXI_AMAP_SIZE(idx) (0xbaf0 + 0x4 * (idx)) +#define PAB_AXI_AMAP_AXI_WIN(idx) (0xba4 + 0x10 * (idx)) +#define PAB_EXT_AXI_AMAP_AXI_WIN(idx) (0x80a0 + 0x4 * (idx)) +#define PAB_AXI_AMAP_PEX_WIN_L(idx) (0xba8 + 0x10 * (idx)) +#define PAB_AXI_AMAP_PEX_WIN_H(idx) (0xbac + 0x10 * (idx)) +#define PAB_AXI_AMAP_PCI_HDR_PARAM(idx) (0x5ba0 + 0x4 * (idx)) +#define FUNC_NUM_PCIE_MASK GENMASK(7, 0) + +#define AXI_AMAP_CTRL_EN BIT(0) +#define AXI_AMAP_CTRL_TYPE_SHIFT 1 +#define AXI_AMAP_CTRL_TYPE_MASK 0x3 +#define AXI_AMAP_CTRL_SIZE_SHIFT 10 +#define AXI_AMAP_CTRL_SIZE_MASK 0x3fffff + +#define PAB_TARGET_BUS(x) (((x) & 0xff) << 24) +#define PAB_TARGET_DEV(x) (((x) & 0x1f) << 19) +#define PAB_TARGET_FUNC(x) (((x) & 0x7) << 16) + +#define PAB_AXI_TYPE_CFG 0x00 +#define PAB_AXI_TYPE_IO 0x01 +#define PAB_AXI_TYPE_MEM 0x02 +#define PAB_AXI_TYPE_ATOM 0x03 + +#define PAB_WINS_NUM 256 + +/* PPIO WINs RC mode */ +#define PAB_PEX_AMAP_CTRL(idx) (0x4ba0 + 0x10 * (idx)) +#define PAB_EXT_PEX_AMAP_SIZE(idx) (0xbef0 + 0x04 * (idx)) +#define PAB_PEX_AMAP_AXI_WIN(idx) (0x4ba4 + 0x10 * (idx)) +#define PAB_EXT_PEX_AMAP_AXI_WIN(idx) (0xb4a0 + 0x04 * (idx)) +#define PAB_PEX_AMAP_PEX_WIN_L(idx) (0x4ba8 + 0x10 * (idx)) +#define PAB_PEX_AMAP_PEX_WIN_H(idx) (0x4bac + 0x10 * (idx)) + +#define IB_TYPE_MEM_F 0x2 +#define IB_TYPE_MEM_NF 0x3 + +#define PEX_AMAP_CTRL_TYPE_SHIFT 0x1 +#define PEX_AMAP_CTRL_EN_SHIFT 0x0 +#define PEX_AMAP_CTRL_TYPE_MASK 0x3 +#define PEX_AMAP_CTRL_EN_MASK 0x1 + +/* PPIO WINs EP mode */ +#define PAB_PEX_BAR_AMAP(pf, bar) \ + (0x1ba0 + 0x20 * (pf) + 4 * (bar)) +#define BAR_AMAP_EN BIT(0) +#define PAB_EXT_PEX_BAR_AMAP(pf, bar) \ + (0x84a0 + 0x20 * (pf) + 4 * (bar)) + +/* CCSR registers */ +#define PCIE_LINK_CTRL_STA 0x5c +#define PCIE_LINK_SPEED_SHIFT 16 +#define PCIE_LINK_SPEED_MASK 0x0f +#define PCIE_LINK_WIDTH_SHIFT 20 +#define PCIE_LINK_WIDTH_MASK 0x3f +#define PCIE_SRIOV_CAPABILITY 0x2a0 +#define PCIE_SRIOV_VF_OFFSET_STRIDE 0x2b4 + +/* LUT registers */ +#define PCIE_LUT_UDR(n) (0x800 + (n) * 8) +#define PCIE_LUT_LDR(n) (0x804 + (n) * 8) +#define PCIE_LUT_ENABLE BIT(31) +#define PCIE_LUT_ENTRY_COUNT 32 + +/* PF control registers */ +#define PCIE_LTSSM_STA 0x7fc +#define LTSSM_STATE_MASK 0x7f +#define LTSSM_PCIE_L0 0x2d /* L0 state */ + +#define PCIE_SRDS_PRTCL(idx) (PCIE1 + (idx)) +#define PCIE_SYS_BASE_ADDR 0x3400000 +#define PCIE_CCSR_SIZE 0x0100000 + +struct ls_pcie_g4 { + int idx; + struct list_head list; + struct udevice *bus; + struct fdt_resource ccsr_res; + struct fdt_resource cfg_res; + struct fdt_resource lut_res; + struct fdt_resource pf_ctrl_res; + void __iomem *ccsr; + void __iomem *cfg; + void __iomem *lut; + void __iomem *pf_ctrl; + bool big_endian; + bool enabled; + int next_lut_index; + struct pci_controller hose; + int stream_id_cur; + int mode; + int sriov_support; +}; + +extern struct list_head ls_pcie_g4_list; + +static inline void lut_writel(struct ls_pcie_g4 *pcie, unsigned int value, + unsigned int offset) +{ + if (pcie->big_endian) + out_be32(pcie->lut + offset, value); + else + out_le32(pcie->lut + offset, value); +} + +static inline u32 lut_readl(struct ls_pcie_g4 *pcie, unsigned int offset) +{ + if (pcie->big_endian) + return in_be32(pcie->lut + offset); + else + return in_le32(pcie->lut + offset); +} + +static inline void ccsr_set_page(struct ls_pcie_g4 *pcie, u8 pg_idx) +{ + u32 val; + + val = in_le32(pcie->ccsr + PAB_CTRL); + val &= ~(PAB_CTRL_PAGE_SEL_MASK << PAB_CTRL_PAGE_SEL_SHIFT); + val |= (pg_idx & PAB_CTRL_PAGE_SEL_MASK) << PAB_CTRL_PAGE_SEL_SHIFT; + + out_le32(pcie->ccsr + PAB_CTRL, val); +} + +static inline unsigned int ccsr_readl(struct ls_pcie_g4 *pcie, u32 offset) +{ + if (offset < INDIRECT_ADDR_BNDRY) { + ccsr_set_page(pcie, 0); + return in_le32(pcie->ccsr + offset); + } + + ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset)); + return in_le32(pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset)); +} + +static inline void ccsr_writel(struct ls_pcie_g4 *pcie, u32 offset, u32 value) +{ + if (offset < INDIRECT_ADDR_BNDRY) { + ccsr_set_page(pcie, 0); + out_le32(pcie->ccsr + offset, value); + } else { + ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset)); + out_le32(pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset), value); + } +} + +static inline unsigned int pf_ctrl_readl(struct ls_pcie_g4 *pcie, u32 offset) +{ + if (pcie->big_endian) + return in_be32(pcie->pf_ctrl + offset); + else + return in_le32(pcie->pf_ctrl + offset); +} + +static inline void pf_ctrl_writel(struct ls_pcie_g4 *pcie, u32 offset, + u32 value) +{ + if (pcie->big_endian) + out_be32(pcie->pf_ctrl + offset, value); + else + out_le32(pcie->pf_ctrl + offset, value); +} + +#endif /* _PCIE_LAYERSCAPE_GEN4_H_ */

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
The LX2160A PCIe is using driver PCIE_LAYERSCAPE_GEN4 instead of PCIE_LAYERSCAPE.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - No change
arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index f48481f465..d37e3678e7 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -242,7 +242,7 @@ config FSL_LAYERSCAPE
config FSL_PCIE_COMPAT string "PCIe compatible of Kernel DT" - depends on PCIE_LAYERSCAPE + depends on PCIE_LAYERSCAPE || PCIE_LAYERSCAPE_GEN4 default "fsl,ls1012a-pcie" if ARCH_LS1012A default "fsl,ls1043a-pcie" if ARCH_LS1043A default "fsl,ls1046a-pcie" if ARCH_LS1046A

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
Add the infrastructure for Layerscape SoCs PCIe Gen4 controller to update device tree nodes to convey SMMU stream IDs in the device tree.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - No change
drivers/pci/Makefile | 3 +- drivers/pci/pcie_layerscape_gen4.c | 5 - drivers/pci/pcie_layerscape_gen4_fixup.c | 249 +++++++++++++++++++++++ 3 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 drivers/pci/pcie_layerscape_gen4_fixup.c
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 7f585aad55..8ee828af6d 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o -obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o +obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ + pcie_layerscape_gen4_fixup.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c index fbe7d35911..4e0d5b168e 100644 --- a/drivers/pci/pcie_layerscape_gen4.c +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -570,8 +570,3 @@ U_BOOT_DRIVER(pcie_layerscape_gen4) = { .probe = ls_pcie_g4_probe, .priv_auto_alloc_size = sizeof(struct ls_pcie_g4), }; - -/* No any fixup so far */ -void ft_pci_setup(void *blob, bd_t *bd) -{ -} diff --git a/drivers/pci/pcie_layerscape_gen4_fixup.c b/drivers/pci/pcie_layerscape_gen4_fixup.c new file mode 100644 index 0000000000..ceeea17f19 --- /dev/null +++ b/drivers/pci/pcie_layerscape_gen4_fixup.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0+ OR X11 +/* + * Copyright 2018 NXP + * + * PCIe Gen4 driver for NXP Layerscape SoCs + * Author: Hou Zhiqiang Minder.Hou@gmail.com + * + */ + +#include <common.h> +#include <pci.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/io.h> +#include <errno.h> +#ifdef CONFIG_OF_BOARD_SETUP +#include <linux/libfdt.h> +#include <fdt_support.h> +#ifdef CONFIG_ARM +#include <asm/arch/clock.h> +#endif +#include "pcie_layerscape_gen4.h" + +#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) +/* + * Return next available LUT index. + */ +static int ls_pcie_g4_next_lut_index(struct ls_pcie_g4 *pcie) +{ + if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT) + return pcie->next_lut_index++; + + return -ENOSPC; /* LUT is full */ +} + +/* returns the next available streamid for pcie, -errno if failed */ +static int ls_pcie_g4_next_streamid(struct ls_pcie_g4 *pcie) +{ + int stream_id = pcie->stream_id_cur; + + if (stream_id > FSL_PEX_STREAM_ID_NUM) + return -EINVAL; + + pcie->stream_id_cur++; + + return stream_id | ((pcie->idx + 1) << 11); +} + +/* + * Program a single LUT entry + */ +static void ls_pcie_g4_lut_set_mapping(struct ls_pcie_g4 *pcie, int index, + u32 devid, u32 streamid) +{ + /* leave mask as all zeroes, want to match all bits */ + lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index)); + lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index)); +} + +/* + * An msi-map is a property to be added to the pci controller + * node. It is a table, where each entry consists of 4 fields + * e.g.: + * + * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count] + * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>; + */ +static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie_g4 *pcie, + u32 devid, u32 streamid) +{ + u32 *prop; + u32 phandle; + int nodeoff; + +#ifdef CONFIG_FSL_PCIE_COMPAT + nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT, + pcie->ccsr_res.start); +#else +#error "No CONFIG_FSL_PCIE_COMPAT defined" +#endif + if (nodeoff < 0) { + debug("%s: ERROR: failed to find pcie compatiable\n", __func__); + return; + } + + /* get phandle to MSI controller */ + prop = (u32 *)fdt_getprop(blob, nodeoff, "msi-parent", 0); + if (!prop) { + debug("\n%s: ERROR: missing msi-parent: PCIe%d\n", + __func__, pcie->idx); + return; + } + phandle = fdt32_to_cpu(*prop); + + /* set one msi-map row */ + fdt_appendprop_u32(blob, nodeoff, "msi-map", devid); + fdt_appendprop_u32(blob, nodeoff, "msi-map", phandle); + fdt_appendprop_u32(blob, nodeoff, "msi-map", streamid); + fdt_appendprop_u32(blob, nodeoff, "msi-map", 1); +} + +/* + * An iommu-map is a property to be added to the pci controller + * node. It is a table, where each entry consists of 4 fields + * e.g.: + * + * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count] + * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>; + */ +static void fdt_pcie_set_iommu_map_entry(void *blob, struct ls_pcie_g4 *pcie, + u32 devid, u32 streamid) +{ + u32 *prop; + u32 iommu_map[4]; + int nodeoff; + int lenp; + +#ifdef CONFIG_FSL_PCIE_COMPAT + nodeoff = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT, + pcie->ccsr_res.start); +#else +#error "No CONFIG_FSL_PCIE_COMPAT defined" +#endif + if (nodeoff < 0) { + debug("%s: ERROR: failed to find pcie compatiable\n", __func__); + return; + } + + /* get phandle to iommu controller */ + prop = fdt_getprop_w(blob, nodeoff, "iommu-map", &lenp); + if (!prop) { + debug("\n%s: ERROR: missing iommu-map: PCIe%d\n", + __func__, pcie->idx); + return; + } + + /* set iommu-map row */ + iommu_map[0] = cpu_to_fdt32(devid); + iommu_map[1] = *++prop; + iommu_map[2] = cpu_to_fdt32(streamid); + iommu_map[3] = cpu_to_fdt32(1); + + if (devid == 0) + fdt_setprop_inplace(blob, nodeoff, "iommu-map", iommu_map, 16); + else + fdt_appendprop(blob, nodeoff, "iommu-map", iommu_map, 16); +} + +static void fdt_fixup_pcie(void *blob) +{ + struct udevice *dev, *bus; + struct ls_pcie_g4 *pcie; + int streamid; + int index; + pci_dev_t bdf; + + /* Scan all known buses */ + for (pci_find_first_device(&dev); dev; pci_find_next_device(&dev)) { + for (bus = dev; device_is_on_pci_bus(bus);) + bus = bus->parent; + pcie = dev_get_priv(bus); + + streamid = ls_pcie_g4_next_streamid(pcie); + if (streamid < 0) { + debug("ERROR: no stream ids free\n"); + continue; + } + + index = ls_pcie_g4_next_lut_index(pcie); + if (index < 0) { + debug("ERROR: no LUT indexes free\n"); + continue; + } + + /* the DT fixup must be relative to the hose first_busno */ + bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0); + /* map PCI b.d.f to streamID in LUT */ + ls_pcie_g4_lut_set_mapping(pcie, index, bdf >> 8, streamid); + /* update msi-map in device tree */ + fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8, streamid); + /* update iommu-map in device tree */ + fdt_pcie_set_iommu_map_entry(blob, pcie, bdf >> 8, streamid); + } +} +#endif + +static void ft_pcie_ep_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie) +{ + int off; + + off = fdt_node_offset_by_compat_reg(blob, "fsl,lx2160a-pcie-ep", + pcie->ccsr_res.start); + + if (off < 0) { + debug("%s: ERROR: failed to find pcie compatiable\n", + __func__); + return; + } + + if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL) + fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0); + else + fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); +} + +static void ft_pcie_rc_layerscape_gen4_fix(void *blob, struct ls_pcie_g4 *pcie) +{ + int off; + +#ifdef CONFIG_FSL_PCIE_COMPAT + off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_COMPAT, + pcie->ccsr_res.start); +#else +#error "No CONFIG_FSL_PCIE_COMPAT defined" +#endif + if (off < 0) { + debug("%s: ERROR: failed to find pcie compatiable\n", __func__); + return; + } + + if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE) + fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0); + else + fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); +} + +static void ft_pcie_layerscape_gen4_setup(void *blob, struct ls_pcie_g4 *pcie) +{ + ft_pcie_rc_layerscape_gen4_fix(blob, pcie); + ft_pcie_ep_layerscape_gen4_fix(blob, pcie); +} + +/* Fixup Kernel DT for PCIe */ +void ft_pci_setup(void *blob, bd_t *bd) +{ + struct ls_pcie_g4 *pcie; + + list_for_each_entry(pcie, &ls_pcie_g4_list, list) + ft_pcie_layerscape_gen4_setup(blob, pcie); + +#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) + fdt_fixup_pcie(blob); +#endif +} + +#else /* !CONFIG_OF_BOARD_SETUP */ +void ft_pci_setup(void *blob, bd_t *bd) +{ +} +#endif

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
The LX2160A integrated 6 PCIe Gen4 controllers.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - No change
arch/arm/dts/fsl-lx2160a.dtsi | 85 +++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+)
diff --git a/arch/arm/dts/fsl-lx2160a.dtsi b/arch/arm/dts/fsl-lx2160a.dtsi index 510b070582..cac3207985 100644 --- a/arch/arm/dts/fsl-lx2160a.dtsi +++ b/arch/arm/dts/fsl-lx2160a.dtsi @@ -176,4 +176,89 @@ status = "disabled";
}; + + pcie@3400000 { + compatible = "fsl,lx2160a-pcie"; + reg = <0x00 0x03400000 0x0 0x80000 /* PAB registers */ + 0x00 0x03480000 0x0 0x40000 /* LUT registers */ + 0x00 0x034c0000 0x0 0x40000 /* PF control registers */ + 0x80 0x00000000 0x0 0x1000>; /* configuration space */ + reg-names = "ccsr", "lut", "pf_ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x40000000 0x80 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + }; + + pcie@3500000 { + compatible = "fsl,lx2160a-pcie"; + reg = <0x00 0x03500000 0x0 0x80000 /* PAB registers */ + 0x00 0x03580000 0x0 0x40000 /* LUT registers */ + 0x00 0x035c0000 0x0 0x40000 /* PF control registers */ + 0x88 0x00000000 0x0 0x1000>; /* configuration space */ + reg-names = "ccsr", "lut", "pf_ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + num-lanes = <2>; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x40000000 0x88 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + }; + + pcie@3600000 { + compatible = "fsl,lx2160a-pcie"; + reg = <0x00 0x03600000 0x0 0x80000 /* PAB registers */ + 0x00 0x03680000 0x0 0x40000 /* LUT registers */ + 0x00 0x036c0000 0x0 0x40000 /* PF control registers */ + 0x90 0x00000000 0x0 0x1000>; /* configuration space */ + reg-names = "ccsr", "lut", "pf_ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x40000000 0x90 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + }; + + pcie@3700000 { + compatible = "fsl,lx2160a-pcie"; + reg = <0x00 0x03700000 0x0 0x80000 /* PAB registers */ + 0x00 0x03780000 0x0 0x40000 /* LUT registers */ + 0x00 0x037c0000 0x0 0x40000 /* PF control registers */ + 0x98 0x00000000 0x0 0x1000>; /* configuration space */ + reg-names = "ccsr", "lut", "pf_ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x40000000 0x98 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + }; + + pcie@3800000 { + compatible = "fsl,lx2160a-pcie"; + reg = <0x00 0x03800000 0x0 0x80000 /* PAB registers */ + 0x00 0x03880000 0x0 0x40000 /* LUT registers */ + 0x00 0x038c0000 0x0 0x40000 /* PF control registers */ + 0xa0 0x00000000 0x0 0x1000>; /* configuration space */ + reg-names = "ccsr", "lut", "pf_ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x40000000 0xa0 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + }; + + pcie@3900000 { + compatible = "fsl,lx2160a-pcie"; + reg = <0x00 0x03900000 0x0 0x80000 /* PAB registers */ + 0x00 0x03980000 0x0 0x40000 /* LUT registers */ + 0x00 0x039c0000 0x0 0x40000 /* PF control registers */ + 0xa8 0x00000000 0x0 0x1000>; /* configuration space */ + reg-names = "ccsr", "lut", "pf_ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x40000000 0xa8 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + }; };

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
Enable the PCIe Gen4 controller driver and e1000 for LX2160ARDB and LX2160AQDS boards.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - Add PCI command support - Enable PCIe in more LX2160A defconfigs
configs/lx2160aqds_tfa_SECURE_BOOT_defconfig | 5 +++++ configs/lx2160aqds_tfa_defconfig | 6 ++++++ configs/lx2160ardb_tfa_SECURE_BOOT_defconfig | 5 +++++ configs/lx2160ardb_tfa_defconfig | 6 ++++++ 4 files changed, 22 insertions(+)
diff --git a/configs/lx2160aqds_tfa_SECURE_BOOT_defconfig b/configs/lx2160aqds_tfa_SECURE_BOOT_defconfig index 58841053ec..367502da37 100644 --- a/configs/lx2160aqds_tfa_SECURE_BOOT_defconfig +++ b/configs/lx2160aqds_tfa_SECURE_BOOT_defconfig @@ -56,3 +56,8 @@ CONFIG_RSA=y CONFIG_SPL_RSA=y CONFIG_RSA_SOFTWARE_EXP=y CONFIG_EFI_LOADER_BOUNCE_BUFFER=y +CONFIG_CMD_PCI=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCIE_LAYERSCAPE_GEN4=y diff --git a/configs/lx2160aqds_tfa_defconfig b/configs/lx2160aqds_tfa_defconfig index a0b86ae142..06ef830acd 100644 --- a/configs/lx2160aqds_tfa_defconfig +++ b/configs/lx2160aqds_tfa_defconfig @@ -51,3 +51,9 @@ CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_EFI_LOADER_BOUNCE_BUFFER=y +CONFIG_CMD_PCI=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCIE_LAYERSCAPE_GEN4=y +CONFIG_E1000=y diff --git a/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig b/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig index f66882d6fa..4e972cc721 100644 --- a/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig +++ b/configs/lx2160ardb_tfa_SECURE_BOOT_defconfig @@ -53,3 +53,8 @@ CONFIG_RSA=y CONFIG_SPL_RSA=y CONFIG_RSA_SOFTWARE_EXP=y CONFIG_EFI_LOADER_BOUNCE_BUFFER=y +CONFIG_CMD_PCI=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCIE_LAYERSCAPE_GEN4=y diff --git a/configs/lx2160ardb_tfa_defconfig b/configs/lx2160ardb_tfa_defconfig index 2dc49c7f5d..73b3b91034 100644 --- a/configs/lx2160ardb_tfa_defconfig +++ b/configs/lx2160ardb_tfa_defconfig @@ -51,3 +51,9 @@ CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_EFI_LOADER_BOUNCE_BUFFER=y +CONFIG_CMD_PCI=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCIE_LAYERSCAPE_GEN4=y +CONFIG_E1000=y

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
PCIe configuration access to non-existent function triggered SERROR interrupt exception.
Workaround: Disable error reporting on AXI bus during the Vendor ID read transactions in enumeration.
This ERRATA is only for LX2160A Rev1.0 and will be fixed in Rev2.0.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - No change
drivers/pci/pcie_layerscape_gen4.c | 8 ++++++++ drivers/pci/pcie_layerscape_gen4.h | 5 +++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c index 4e0d5b168e..799da2f7df 100644 --- a/drivers/pci/pcie_layerscape_gen4.c +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -242,6 +242,9 @@ static int ls_pcie_g4_read_config(struct udevice *bus, pci_dev_t bdf,
address = ls_pcie_g4_conf_address(pcie, bdf, offset);
+ if (pcie->rev == REV_1_0 && offset == PCI_VENDOR_ID) + lut_writel(pcie, 0x0 << PCIE_LUT_GCR_RRE, PCIE_LUT_GCR); + switch (size) { case PCI_SIZE_8: *valuep = readb(address); @@ -257,6 +260,9 @@ static int ls_pcie_g4_read_config(struct udevice *bus, pci_dev_t bdf, break; }
+ if (pcie->rev == REV_1_0 && offset == PCI_VENDOR_ID) + lut_writel(pcie, 0x1 << PCIE_LUT_GCR_RRE, PCIE_LUT_GCR); + return ret; }
@@ -518,6 +524,8 @@ static int ls_pcie_g4_probe(struct udevice *dev) dev->name, (unsigned long)pcie->ccsr, (unsigned long)pcie->cfg, pcie->big_endian);
+ pcie->rev = readb(pcie->ccsr + PCI_REVISION_ID); + pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f;
if (pcie->mode == PCI_HEADER_TYPE_NORMAL) { diff --git a/drivers/pci/pcie_layerscape_gen4.h b/drivers/pci/pcie_layerscape_gen4.h index 356b49f9ce..137768cae7 100644 --- a/drivers/pci/pcie_layerscape_gen4.h +++ b/drivers/pci/pcie_layerscape_gen4.h @@ -11,6 +11,8 @@ #include <pci.h> #include <dm.h>
+#define REV_1_0 (0x10) + #ifndef CONFIG_SYS_PCI_MEMORY_SIZE #define CONFIG_SYS_PCI_MEMORY_SIZE (4 * 1024 * 1024 * 1024ULL) #endif @@ -161,6 +163,8 @@ #define PCIE_LUT_LDR(n) (0x804 + (n) * 8) #define PCIE_LUT_ENABLE BIT(31) #define PCIE_LUT_ENTRY_COUNT 32 +#define PCIE_LUT_GCR (0x28) +#define PCIE_LUT_GCR_RRE (0)
/* PF control registers */ #define PCIE_LTSSM_STA 0x7fc @@ -190,6 +194,7 @@ struct ls_pcie_g4 { int stream_id_cur; int mode; int sriov_support; + u8 rev; };
extern struct list_head ls_pcie_g4_list;

Hi All,
Please ignore this patch, rev1.0 will not be production.
Thanks, Zhiqiang
-----Original Message----- From: Z.q. Hou Sent: 2019年3月11日 10:58 To: u-boot@lists.denx.de; bmeng.cn@gmail.com; albert.u.boot@aribaud.net; Priyanka Jain priyanka.jain@nxp.com; York Sun york.sun@nxp.com; sriram.dash@nxp.com; yamada.masahiro@socionext.com; Prabhakar Kushwaha prabhakar.kushwaha@nxp.com; Mingkai Hu mingkai.hu@nxp.com; M.h. Lian minghuan.lian@nxp.com Cc: Z.q. Hou zhiqiang.hou@nxp.com Subject: [PATCHv4 08/12] pci: ls_pcie_g4: add Workaround for A-011577
From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
PCIe configuration access to non-existent function triggered SERROR interrupt exception.
Workaround: Disable error reporting on AXI bus during the Vendor ID read transactions in enumeration.
This ERRATA is only for LX2160A Rev1.0 and will be fixed in Rev2.0.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com
V4:
- No change
drivers/pci/pcie_layerscape_gen4.c | 8 ++++++++ drivers/pci/pcie_layerscape_gen4.h | 5 +++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c index 4e0d5b168e..799da2f7df 100644 --- a/drivers/pci/pcie_layerscape_gen4.c +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -242,6 +242,9 @@ static int ls_pcie_g4_read_config(struct udevice *bus, pci_dev_t bdf,
address = ls_pcie_g4_conf_address(pcie, bdf, offset);
- if (pcie->rev == REV_1_0 && offset == PCI_VENDOR_ID)
lut_writel(pcie, 0x0 << PCIE_LUT_GCR_RRE, PCIE_LUT_GCR);
- switch (size) { case PCI_SIZE_8: *valuep = readb(address);
@@ -257,6 +260,9 @@ static int ls_pcie_g4_read_config(struct udevice *bus, pci_dev_t bdf, break; }
- if (pcie->rev == REV_1_0 && offset == PCI_VENDOR_ID)
lut_writel(pcie, 0x1 << PCIE_LUT_GCR_RRE, PCIE_LUT_GCR);
- return ret;
}
@@ -518,6 +524,8 @@ static int ls_pcie_g4_probe(struct udevice *dev) dev->name, (unsigned long)pcie->ccsr, (unsigned long)pcie->cfg, pcie->big_endian);
pcie->rev = readb(pcie->ccsr + PCI_REVISION_ID);
pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f;
if (pcie->mode == PCI_HEADER_TYPE_NORMAL) { diff --git
a/drivers/pci/pcie_layerscape_gen4.h b/drivers/pci/pcie_layerscape_gen4.h index 356b49f9ce..137768cae7 100644 --- a/drivers/pci/pcie_layerscape_gen4.h +++ b/drivers/pci/pcie_layerscape_gen4.h @@ -11,6 +11,8 @@ #include <pci.h> #include <dm.h>
+#define REV_1_0 (0x10)
#ifndef CONFIG_SYS_PCI_MEMORY_SIZE #define CONFIG_SYS_PCI_MEMORY_SIZE (4 * 1024 * 1024 * 1024ULL) #endif @@ -161,6 +163,8 @@ #define PCIE_LUT_LDR(n) (0x804 + (n) * 8) #define PCIE_LUT_ENABLE BIT(31) #define PCIE_LUT_ENTRY_COUNT 32 +#define PCIE_LUT_GCR (0x28) +#define PCIE_LUT_GCR_RRE (0)
/* PF control registers */ #define PCIE_LTSSM_STA 0x7fc @@ -190,6 +194,7 @@ struct ls_pcie_g4 { int stream_id_cur; int mode; int sriov_support;
- u8 rev;
};
extern struct list_head ls_pcie_g4_list;
2.17.1

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
This patch introduce a set of PCI/PCIe capability accessors, including 16-bit and 32-bit read, write and clear_and_set operations.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - New patch
drivers/pci/pci-uclass.c | 153 +++++++++++++++++++++++++++++++++++++++ include/pci.h | 20 +++++ 2 files changed, 173 insertions(+)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 824fa11907..4bb30f5d2b 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -1443,6 +1443,159 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap) return dm_pci_find_next_ext_capability(dev, 0, cap); }
+/** + * dm_pci_capability_read() - PCI capability register read + * + * @dev: PCI device to read + * @cap: capability code + * @pos: register offset + * @val: pointer to keep the read value + * @size: register width + * + * Returns 0 if OK or appropriate error value. + */ +int dm_pci_capability_read(struct udevice *dev, int cap, int pos, + ulong *val, enum pci_size_t size) +{ + u32 off; + + switch (size) { + case PCI_SIZE_16: + if (pos & 1) + return -EINVAL; + break; + case PCI_SIZE_32: + if (pos & 3) + return -EINVAL; + break; + default: + return -EINVAL; + } + + off = dm_pci_find_capability(dev, cap); + if (off) + return dm_pci_read_config(dev, off + pos, val, size); + + return -EINVAL; +} + +/** + * dm_pci_capability_write() - PCI capability register write + * + * @dev: PCI device to write + * @cap: capability code + * @pos: register offset + * @val: value to write + * @size: register width + * + * Returns 0 if OK or appropriate error value. + */ +int dm_pci_capability_write(struct udevice *dev, int cap, int pos, + ulong val, enum pci_size_t size) +{ + u32 off; + + switch (size) { + case PCI_SIZE_16: + if (pos & 1) + return -EINVAL; + break; + case PCI_SIZE_32: + if (pos & 3) + return -EINVAL; + break; + default: + return -EINVAL; + } + + off = dm_pci_find_capability(dev, cap); + if (off) + return dm_pci_write_config(dev, off + pos, val, size); + + return -EINVAL; +} + +int dm_pci_capability_read_word(struct udevice *dev, int cap, int pos, u16 *val) +{ + ulong value; + int ret; + + ret = dm_pci_capability_read(dev, cap, pos, &value, PCI_SIZE_16); + if (ret) + return ret; + *val = value; + + return 0; +} + +int dm_pci_capability_write_word(struct udevice *dev, int cap, int pos, u16 val) +{ + return dm_pci_capability_write(dev, cap, pos, val, PCI_SIZE_16); +} + +int dm_pci_capability_read_dword(struct udevice *dev, int cap, + int pos, u32 *val) +{ + ulong value; + int ret; + + return dm_pci_capability_read(dev, cap, pos, &value, PCI_SIZE_32); + if (ret) + return ret; + *val = value; + + return 0; +} + +int dm_pci_capability_write_dword(struct udevice *dev, int cap, + int pos, u32 val) +{ + return dm_pci_capability_write(dev, cap, pos, val, PCI_SIZE_32); +} + +/** + * dm_pci_capability_clear_and_set() - PCI capability register update + * + * @dev: PCI device to update + * @cap: capability code + * @pos: register offset + * @clear: bits to clear + * @set: bits to set + * @size: register width + * + * Returns 0 if OK or appropriate error value. + */ +int dm_pci_capability_clear_and_set(struct udevice *dev, int cap, int pos, + ulong clear, ulong set, + enum pci_size_t size) +{ + int ret; + ulong val; + + ret = dm_pci_capability_read(dev, cap, pos, &val, size); + if (!ret) { + val &= ~clear; + val |= set; + ret = dm_pci_capability_write(dev, cap, pos, val, size); + } + + return ret; +} + +int dm_pci_capability_clear_and_set_word(struct udevice *dev, int cap, + int pos, u16 clear, u16 set) +{ + return dm_pci_capability_clear_and_set(dev, cap, pos, clear, + set, PCI_SIZE_16); +} + +int dm_pci_capability_clear_and_set_dword(struct udevice *dev, int cap, + int pos, u32 clear, u32 set) +{ + return dm_pci_capability_clear_and_set(dev, cap, pos, clear, + set, PCI_SIZE_32); +} + UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", diff --git a/include/pci.h b/include/pci.h index 041f8e3747..d7b6d9f4ff 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1405,6 +1405,26 @@ int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap); */ int dm_pci_find_ext_capability(struct udevice *dev, int cap);
+int dm_pci_capability_read(struct udevice *dev, int cap, int pos, + ulong *val, enum pci_size_t size); +int dm_pci_capability_write(struct udevice *dev, int cap, int pos, + ulong val, enum pci_size_t size); +int dm_pci_capability_read_word(struct udevice *dev, int cap, + int pos, u16 *val); +int dm_pci_capability_write_word(struct udevice *dev, int cap, + int pos, u16 val); +int dm_pci_capability_read_dword(struct udevice *dev, int cap, + int pos, u32 *val); +int dm_pci_capability_write_dword(struct udevice *dev, int cap, + int pos, u32 val); +int dm_pci_capability_clear_and_set(struct udevice *dev, int cap, int pos, + ulong clear, ulong set, + enum pci_size_t size); +int dm_pci_capability_clear_and_set_word(struct udevice *dev, int cap, + int pos, u16 clear, u16 set); +int dm_pci_capability_clear_and_set_dword(struct udevice *dev, int cap, + int pos, u32 clear, u32 set); + #define dm_pci_virt_to_bus(dev, addr, flags) \ dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags)) #define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
This patch introduce APIs for getting and updating the MPS and MRRS fields of Device capability Device control register.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - New patch
drivers/pci/pci-uclass.c | 92 ++++++++++++++++++++++++++++++++++++++++ include/pci.h | 13 ++++++ 2 files changed, 105 insertions(+)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4bb30f5d2b..b2d295435a 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -7,6 +7,7 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <linux/log2.h> #include <pci.h> #include <asm/io.h> #include <dm/device-internal.h> @@ -1596,6 +1597,97 @@ int dm_pci_capability_clear_and_set_dword(struct udevice *dev, int cap, set, PCI_SIZE_32); }
+/** + * dm_pci_get_readrq - get PCI Express read request size + * @dev: PCI device to query + * + * Returns maximum memory read request in bytes + * or appropriate error value. + */ +int dm_pci_get_readrq(struct udevice *dev) +{ + u16 ctl; + int ret; + + ret = dm_pci_capability_read_word(dev, PCI_CAP_ID_EXP, + PCI_EXP_DEVCTL, &ctl); + if (ret) + return ret; + + return 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12); +} + +/** + * dm_pci_set_readrq - set PCI Express maximum memory read request + * @dev: PCI device to query + * @rq: maximum memory read count in bytes + * valid values are 128, 256, 512, 1024, 2048, 4096 + */ +int dm_pci_set_readrq(struct udevice *dev, int rq) +{ + u16 val; + + if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) + return -EINVAL; + + val = (ffs(rq) - 8) << 12; + + return dm_pci_capability_clear_and_set_word(dev, PCI_CAP_ID_EXP, + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_READRQ, + val); +} + +/** + * dm_pci_get_mps - get PCI Express maximum payload size + * @dev: PCI device to query + * + * Returns maximum payload size in bytes + */ +int dm_pci_get_mps(struct udevice *dev) +{ + u16 ctl; + int ret; + + ret = dm_pci_capability_read_word(dev, PCI_CAP_ID_EXP, + PCI_EXP_DEVCTL, &ctl); + if (ret) + return ret; + + return 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); +} + +/** + * dm_pci_set_mps - set PCI Express maximum payload size + * @dev: PCI device to query + * @mps: maximum payload size in bytes + * valid values are 128, 256, 512, 1024, 2048, 4096 + */ +int dm_pci_set_mps(struct udevice *dev, int mps) +{ + u16 val, cap; + int ret; + + if (mps < 128 || mps > 4096 || !is_power_of_2(mps)) + return -EINVAL; + + ret = dm_pci_capability_read_word(dev, PCI_CAP_ID_EXP, + PCI_EXP_DEVCAP, &cap); + if (ret) + return ret; + + val = ffs(mps) - 8; + if (val > (cap & PCI_EXP_DEVCAP_PAYLOAD)) + return -EINVAL; + + val <<= 5; + + return dm_pci_capability_clear_and_set_word(dev, PCI_CAP_ID_EXP, + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_PAYLOAD, + val); +} + UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", diff --git a/include/pci.h b/include/pci.h index d7b6d9f4ff..b48df8a363 100644 --- a/include/pci.h +++ b/include/pci.h @@ -414,6 +414,14 @@ #define PCI_MAX_PCI_DEVICES 32 #define PCI_MAX_PCI_FUNCTIONS 8
+/* PCI Express capability registers */ +#define PCI_EXP_DEVCAP 4 /* Device capabilities */ +#define PCI_EXP_DEVCAP_PAYLOAD 0x0007 /* Max_Payload_Size */ + +#define PCI_EXP_DEVCTL 8 /* Device Control */ +#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ +#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ + #define PCI_FIND_CAP_TTL 0x48 #define CAP_START_POS 0x40
@@ -1425,6 +1433,11 @@ int dm_pci_capability_clear_and_set_word(struct udevice *dev, int cap, int dm_pci_capability_clear_and_set_dword(struct udevice *dev, int cap, int pos, u32 clear, u32 set);
+int dm_pci_get_readrq(struct udevice *dev); +int dm_pci_set_readrq(struct udevice *dev, int rq); +int dm_pci_get_mps(struct udevice *dev); +int dm_pci_set_mps(struct udevice *dev, int mps); + #define dm_pci_virt_to_bus(dev, addr, flags) \ dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags)) #define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
When LAYERSCAPE Gen4 PCIe controller is sending multiple split completions and ACK latency expires indicating that ACK should be send at priority. But because of large number of split completions and FC update DLLP, the controller does not give priority to ACK transmission. This results into ACK latency timer timeout error at the link partner and the pending TLPs are replayed by the link partner again.
Workaround: 1. Reduce the ACK latency timeout value to a very small value. 2. Restrict the number of completions from the PCIe controller to 1, by changing the Max Read Request Size (MRRS) of link partner to the same value as Max Packet size (MPS).
This ERRATA is only for LX2160A Rev1.0 and will be fixed in Rev2.0.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - V3 patch find root port wrongly, fix it in V4. - Change to use the MPS and MRRS accessors.
drivers/pci/pci_auto.c | 35 ++++++++++++++++++++++++++++++ drivers/pci/pcie_layerscape_gen4.c | 8 +++++++ drivers/pci/pcie_layerscape_gen4.h | 4 ++++ include/pci_ids.h | 1 + 4 files changed, 48 insertions(+)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index d7237f6eee..611462d1d4 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -22,6 +22,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, struct pci_region *prefetch, struct pci_region *io, bool enum_only) { + struct udevice *ctrl = pci_get_controller(dev); + struct udevice *rp; u32 bar_response; pci_size_t bar_size; u16 cmdstat = 0; @@ -32,6 +34,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, struct pci_region *bar_res = NULL; int found_mem64 = 0; u16 class; + u16 vendor, dev_id; + u8 rev;
dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat); cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | @@ -161,6 +165,37 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, dm_pci_write_config8(dev, PCI_CACHE_LINE_SIZE, CONFIG_SYS_PCI_CACHE_LINE_SIZE); dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80); + + /* + * When NXP LAYERSCAPE Gen4 PCIe controller is sending multiple split + * completions and ACK latency expires indicating that ACK should be + * send at priority. But because of large number of split completions + * and FC update DLLP, the controller does not give priority to ACK + * transmission. This results into ACK latency timer timeout error at + * the link partner and the pending TLPs are replayed by the link + * partner again. + * + * The workaround: + * Restrict the number of completions from the PCIe controller to 1, + * by changing the Max Read Request Size (MRRS) of link partner to the + * same value as Max Packet size (MPS). + * + * So, set both the MPS and MRRS to the minimum 128B. + */ + device_find_first_child(ctrl, &rp); + if (!rp) { + debug("%s: Host: %s, RP is NULL\n", __func__, ctrl->name); + return; + } + + dm_pci_read_config16(rp, PCI_VENDOR_ID, &vendor); + dm_pci_read_config16(rp, PCI_DEVICE_ID, &dev_id); + dm_pci_read_config8(rp, PCI_REVISION_ID, &rev); + if (vendor == PCI_VENDOR_ID_FREESCALE && + dev_id == PCI_DEVICE_ID_LX2160A && rev == 0x10) { + dm_pci_set_mps(dev, 128); + dm_pci_set_readrq(dev, 128); + } }
void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c index 799da2f7df..b530a9979c 100644 --- a/drivers/pci/pcie_layerscape_gen4.c +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -526,6 +526,14 @@ static int ls_pcie_g4_probe(struct udevice *dev)
pcie->rev = readb(pcie->ccsr + PCI_REVISION_ID);
+ /* Set ACK latency timeout */ + if (pcie->rev == REV_1_0) { + val = ccsr_readl(pcie, GPEX_ACK_REPLAY_TO); + val &= ~(ACK_LAT_TO_VAL_MASK << ACK_LAT_TO_VAL_SHIFT); + val |= (4 << ACK_LAT_TO_VAL_SHIFT); + ccsr_writel(pcie, GPEX_ACK_REPLAY_TO, val); + } + pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f;
if (pcie->mode == PCI_HEADER_TYPE_NORMAL) { diff --git a/drivers/pci/pcie_layerscape_gen4.h b/drivers/pci/pcie_layerscape_gen4.h index 137768cae7..ebde52e49a 100644 --- a/drivers/pci/pcie_layerscape_gen4.h +++ b/drivers/pci/pcie_layerscape_gen4.h @@ -58,6 +58,10 @@ #define INI_VF_SHIFT 0 #define GPEX_SRIOV_VF_OFFSET_STRIDE(pf) (0x704 + (pf) * 4)
+#define GPEX_ACK_REPLAY_TO 0x438 +#define ACK_LAT_TO_VAL_SHIFT 0 +#define ACK_LAT_TO_VAL_MASK 0x1fff + /* PAB CSR */ #define PAB_CTRL 0x808 #define PAB_CTRL_APIO_EN BIT(0) diff --git a/include/pci_ids.h b/include/pci_ids.h index fdda679cc0..92a4339e3e 100644 --- a/include/pci_ids.h +++ b/include/pci_ids.h @@ -2481,6 +2481,7 @@ #define PCI_DEVICE_ID_MPC8641 0x7010 #define PCI_DEVICE_ID_MPC8641D 0x7011 #define PCI_DEVICE_ID_MPC8610 0x7018 +#define PCI_DEVICE_ID_LX2160A 0x8D80
#define PCI_VENDOR_ID_PASEMI 0x1959

Hi All,
Please ignore this patch, rev1.0 will not be production.
Thanks, Zhiqiang
-----Original Message----- From: Z.q. Hou Sent: 2019年3月11日 10:59 To: u-boot@lists.denx.de; bmeng.cn@gmail.com; albert.u.boot@aribaud.net; Priyanka Jain priyanka.jain@nxp.com; York Sun york.sun@nxp.com; sriram.dash@nxp.com; yamada.masahiro@socionext.com; Prabhakar Kushwaha prabhakar.kushwaha@nxp.com; Mingkai Hu mingkai.hu@nxp.com; M.h. Lian minghuan.lian@nxp.com Cc: Z.q. Hou zhiqiang.hou@nxp.com Subject: [PATCHv4 11/12] pci: ls_pcie_g4: Add Workaround for A-011451
From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
When LAYERSCAPE Gen4 PCIe controller is sending multiple split completions and ACK latency expires indicating that ACK should be send at priority. But because of large number of split completions and FC update DLLP, the controller does not give priority to ACK transmission. This results into ACK latency timer timeout error at the link partner and the pending TLPs are replayed by the link partner again.
Workaround:
- Reduce the ACK latency timeout value to a very small value.
- Restrict the number of completions from the PCIe controller to 1, by changing the Max Read Request Size (MRRS) of link partner to the same value as Max Packet size (MPS).
This ERRATA is only for LX2160A Rev1.0 and will be fixed in Rev2.0.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com
V4:
- V3 patch find root port wrongly, fix it in V4.
- Change to use the MPS and MRRS accessors.
drivers/pci/pci_auto.c | 35 ++++++++++++++++++++++++++++++ drivers/pci/pcie_layerscape_gen4.c | 8 +++++++ drivers/pci/pcie_layerscape_gen4.h | 4 ++++ include/pci_ids.h | 1 + 4 files changed, 48 insertions(+)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index d7237f6eee..611462d1d4 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -22,6 +22,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, struct pci_region *prefetch, struct pci_region *io, bool enum_only) {
- struct udevice *ctrl = pci_get_controller(dev);
- struct udevice *rp; u32 bar_response; pci_size_t bar_size; u16 cmdstat = 0;
@@ -32,6 +34,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, struct pci_region *bar_res = NULL; int found_mem64 = 0; u16 class;
u16 vendor, dev_id;
u8 rev;
dm_pci_read_config16(dev, PCI_COMMAND, &cmdstat); cmdstat = (cmdstat & ~(PCI_COMMAND_IO |
PCI_COMMAND_MEMORY)) | @@ -161,6 +165,37 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, dm_pci_write_config8(dev, PCI_CACHE_LINE_SIZE, CONFIG_SYS_PCI_CACHE_LINE_SIZE); dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80);
- /*
* When NXP LAYERSCAPE Gen4 PCIe controller is sending multiple split
* completions and ACK latency expires indicating that ACK should be
* send at priority. But because of large number of split completions
* and FC update DLLP, the controller does not give priority to ACK
* transmission. This results into ACK latency timer timeout error at
* the link partner and the pending TLPs are replayed by the link
* partner again.
*
* The workaround:
* Restrict the number of completions from the PCIe controller to 1,
* by changing the Max Read Request Size (MRRS) of link partner to the
* same value as Max Packet size (MPS).
*
* So, set both the MPS and MRRS to the minimum 128B.
*/
- device_find_first_child(ctrl, &rp);
- if (!rp) {
debug("%s: Host: %s, RP is NULL\n", __func__, ctrl->name);
return;
- }
- dm_pci_read_config16(rp, PCI_VENDOR_ID, &vendor);
- dm_pci_read_config16(rp, PCI_DEVICE_ID, &dev_id);
- dm_pci_read_config8(rp, PCI_REVISION_ID, &rev);
- if (vendor == PCI_VENDOR_ID_FREESCALE &&
dev_id == PCI_DEVICE_ID_LX2160A && rev == 0x10) {
dm_pci_set_mps(dev, 128);
dm_pci_set_readrq(dev, 128);
- }
}
void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus) diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c index 799da2f7df..b530a9979c 100644 --- a/drivers/pci/pcie_layerscape_gen4.c +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -526,6 +526,14 @@ static int ls_pcie_g4_probe(struct udevice *dev)
pcie->rev = readb(pcie->ccsr + PCI_REVISION_ID);
/* Set ACK latency timeout */
if (pcie->rev == REV_1_0) {
val = ccsr_readl(pcie, GPEX_ACK_REPLAY_TO);
val &= ~(ACK_LAT_TO_VAL_MASK << ACK_LAT_TO_VAL_SHIFT);
val |= (4 << ACK_LAT_TO_VAL_SHIFT);
ccsr_writel(pcie, GPEX_ACK_REPLAY_TO, val);
}
pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f;
if (pcie->mode == PCI_HEADER_TYPE_NORMAL) { diff --git
a/drivers/pci/pcie_layerscape_gen4.h b/drivers/pci/pcie_layerscape_gen4.h index 137768cae7..ebde52e49a 100644 --- a/drivers/pci/pcie_layerscape_gen4.h +++ b/drivers/pci/pcie_layerscape_gen4.h @@ -58,6 +58,10 @@ #define INI_VF_SHIFT 0 #define GPEX_SRIOV_VF_OFFSET_STRIDE(pf) (0x704 + (pf) * 4)
+#define GPEX_ACK_REPLAY_TO 0x438 +#define ACK_LAT_TO_VAL_SHIFT 0 +#define ACK_LAT_TO_VAL_MASK 0x1fff
/* PAB CSR */ #define PAB_CTRL 0x808 #define PAB_CTRL_APIO_EN BIT(0) diff --git a/include/pci_ids.h b/include/pci_ids.h index fdda679cc0..92a4339e3e 100644 --- a/include/pci_ids.h +++ b/include/pci_ids.h @@ -2481,6 +2481,7 @@ #define PCI_DEVICE_ID_MPC8641 0x7010 #define PCI_DEVICE_ID_MPC8641D 0x7011 #define PCI_DEVICE_ID_MPC8610 0x7018 +#define PCI_DEVICE_ID_LX2160A 0x8D80
#define PCI_VENDOR_ID_PASEMI 0x1959
-- 2.17.1

Hi Zhiqiang,
On Wed, Mar 13, 2019 at 10:54 PM Z.q. Hou zhiqiang.hou@nxp.com wrote:
Hi All,
Please ignore this patch, rev1.0 will not be production.
OK, thanks for the update.
So let's not touch the generic PCI codes this time.
Regards, Bin

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
For PCIe controllers with SRIOV, MSIx table entries of all the VFs are not accessible if BAR size is set to less than 8MB.
This ERRATA is only for LX2160A Rev1.0 and will be fixed in Rev2.0.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- V4: - No change
drivers/pci/pcie_layerscape_gen4.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c index b530a9979c..3792dbdf55 100644 --- a/drivers/pci/pcie_layerscape_gen4.c +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -378,6 +378,11 @@ static void ls_pcie_g4_ep_set_bar_size(struct ls_pcie_g4 *pcie, int pf, u32 mask_l = lower_32_bits(~(size - 1)); u32 mask_h = upper_32_bits(~(size - 1));
+ /* A-011452 workaround: set the VF BAR1 to 8MB */ + if (pcie->rev == REV_1_0 && vf_bar && bar == 1) { + mask_l = lower_32_bits(~(SZ_8M - 1)); + mask_h = upper_32_bits(~(SZ_8M - 1)); + } ccsr_writel(pcie, GPEX_BAR_SELECT, bar_pos); ccsr_writel(pcie, GPEX_BAR_SIZE_LDW, mask_l); ccsr_writel(pcie, GPEX_BAR_SIZE_UDW, mask_h);

Hi All,
Please ignore this patch, rev1.0 will not be production.
Thanks, Zhiqiang
-----Original Message----- From: Z.q. Hou Sent: 2019年3月11日 10:59 To: u-boot@lists.denx.de; bmeng.cn@gmail.com; albert.u.boot@aribaud.net; Priyanka Jain priyanka.jain@nxp.com; York Sun york.sun@nxp.com; sriram.dash@nxp.com; yamada.masahiro@socionext.com; Prabhakar Kushwaha prabhakar.kushwaha@nxp.com; Mingkai Hu mingkai.hu@nxp.com; M.h. Lian minghuan.lian@nxp.com Cc: Z.q. Hou zhiqiang.hou@nxp.com Subject: [PATCHv4 12/12] pci: ls_pcie_g4: add Workaround for A-011452
From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
For PCIe controllers with SRIOV, MSIx table entries of all the VFs are not accessible if BAR size is set to less than 8MB.
This ERRATA is only for LX2160A Rev1.0 and will be fixed in Rev2.0.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com
V4:
- No change
drivers/pci/pcie_layerscape_gen4.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/pci/pcie_layerscape_gen4.c b/drivers/pci/pcie_layerscape_gen4.c index b530a9979c..3792dbdf55 100644 --- a/drivers/pci/pcie_layerscape_gen4.c +++ b/drivers/pci/pcie_layerscape_gen4.c @@ -378,6 +378,11 @@ static void ls_pcie_g4_ep_set_bar_size(struct ls_pcie_g4 *pcie, int pf, u32 mask_l = lower_32_bits(~(size - 1)); u32 mask_h = upper_32_bits(~(size - 1));
- /* A-011452 workaround: set the VF BAR1 to 8MB */
- if (pcie->rev == REV_1_0 && vf_bar && bar == 1) {
mask_l = lower_32_bits(~(SZ_8M - 1));
mask_h = upper_32_bits(~(SZ_8M - 1));
- } ccsr_writel(pcie, GPEX_BAR_SELECT, bar_pos); ccsr_writel(pcie, GPEX_BAR_SIZE_LDW, mask_l); ccsr_writel(pcie, GPEX_BAR_SIZE_UDW, mask_h);
-- 2.17.1

-----Original Message----- From: Z.q. Hou Sent: Wednesday, March 13, 2019 8:25 PM To: u-boot@lists.denx.de; bmeng.cn@gmail.com; albert.u.boot@aribaud.net; Priyanka Jain priyanka.jain@nxp.com; York Sun york.sun@nxp.com; sriram.dash@nxp.com; yamada.masahiro@socionext.com; Prabhakar Kushwaha prabhakar.kushwaha@nxp.com; Mingkai Hu mingkai.hu@nxp.com; M.h. Lian minghuan.lian@nxp.com Subject: RE: [PATCHv4 12/12] pci: ls_pcie_g4: add Workaround for A-011452
Hi All,
Please ignore this patch, rev1.0 will not be production.
I request you to resend your patch-set with the patches which you want to reviewed and accepted. Please use [RESEND] in subject.
--pk

Hi Prabhakar,
Thanks a lot for your comments!
-----Original Message----- From: Prabhakar Kushwaha Sent: 2019年3月17日 11:28 To: Z.q. Hou zhiqiang.hou@nxp.com; u-boot@lists.denx.de; bmeng.cn@gmail.com; albert.u.boot@aribaud.net; Priyanka Jain priyanka.jain@nxp.com; York Sun york.sun@nxp.com; sriram.dash@nxp.com; yamada.masahiro@socionext.com; Mingkai Hu mingkai.hu@nxp.com; M.h. Lian minghuan.lian@nxp.com Subject: RE: [PATCHv4 12/12] pci: ls_pcie_g4: add Workaround for A-011452
-----Original Message----- From: Z.q. Hou Sent: Wednesday, March 13, 2019 8:25 PM To: u-boot@lists.denx.de; bmeng.cn@gmail.com; albert.u.boot@aribaud.net; Priyanka Jain priyanka.jain@nxp.com; York Sun york.sun@nxp.com; sriram.dash@nxp.com; yamada.masahiro@socionext.com; Prabhakar Kushwaha prabhakar.kushwaha@nxp.com; Mingkai Hu mingkai.hu@nxp.com;
M.h.
Lian minghuan.lian@nxp.com Subject: RE: [PATCHv4 12/12] pci: ls_pcie_g4: add Workaround for A-011452
Hi All,
Please ignore this patch, rev1.0 will not be production.
I request you to resend your patch-set with the patches which you want to reviewed and accepted. Please use [RESEND] in subject.
Resent the patch set with the workaround patches removed. Thanks, Zhiqiang
participants (3)
-
Bin Meng
-
Prabhakar Kushwaha
-
Z.q. Hou