[U-Boot] [PATCH 0/8] pci: Add pcie controller driver for NXP LX SoCs

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
Add PCIe driver for the NXP LX series SoCs.
Hou Zhiqiang (8): armv8: fsl-layerscpae: correct the PCIe controllers' region size armv8: lx2160a: add MMU table entries for PCIe pci: Add pcie controller driver for NXP LX SoCs kconfig: add dependency PCIE_LX for FSL_PCIE_COMPAT pci: pcie_lx: add device tree fixups for PCI Stream IDs armv8: lx2160a: add pcie DT nodes armv8: lx2160a: enable pcie support on RDB defconfig armv8: lx2160a: enable the pci command
Depends on the following patches: https://patchwork.ozlabs.org/patch/990088/ https://patchwork.ozlabs.org/patch/990093/ https://patchwork.ozlabs.org/patch/990097/ https://patchwork.ozlabs.org/patch/990098/ 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/lx2160ardb_tfa_defconfig | 5 + drivers/pci/Kconfig | 8 + drivers/pci/Makefile | 1 + drivers/pci/pcie_lx.c | 607 ++++++++++++++++++ drivers/pci/pcie_lx.h | 258 ++++++++ drivers/pci/pcie_lx_fixup.c | 234 +++++++ include/configs/lx2160a_common.h | 1 + 12 files changed, 1234 insertions(+), 2 deletions(-) create mode 100644 drivers/pci/pcie_lx.c create mode 100644 drivers/pci/pcie_lx.h create mode 100644 drivers/pci/pcie_lx_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 --- 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 eaa9ed251e..b4bd2c604a 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

On Tue, Oct 30, 2018 at 10:21 PM Z.q. Hou zhiqiang.hou@nxp.com wrote:
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
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 eaa9ed251e..b4bd2c604a 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
Shouldn't these sizes be encoded in the ranges property of the PCIe node in DTS files?
#define CONFIG_SYS_FSL_WRIOP1_BASE 0x4300000000 #define CONFIG_SYS_FSL_WRIOP1_SIZE 0x100000000
#define CONFIG_SYS_FSL_AIOP1_BASE 0x4b00000000
Regards, Bin

Hi Bin,
Thanks a lot for your comments!
-----Original Message----- From: Bin Meng bmeng.cn@gmail.com Sent: 2019年2月12日 11:33 To: Z.q. Hou zhiqiang.hou@nxp.com Cc: u-boot@lists.denx.de; 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: [U-Boot] [PATCH 1/8] armv8: fsl-layerscpae: correct the PCIe controllers' region size
On Tue, Oct 30, 2018 at 10:21 PM Z.q. Hou zhiqiang.hou@nxp.com wrote:
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
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 eaa9ed251e..b4bd2c604a 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
Shouldn't these sizes be encoded in the ranges property of the PCIe node in DTS files?
No, these macros are used to setup the MMU tables for the address space assigned to PCIe controllers.
#define CONFIG_SYS_FSL_WRIOP1_BASE 0x4300000000 #define CONFIG_SYS_FSL_WRIOP1_SIZE 0x100000000
#define CONFIG_SYS_FSL_AIOP1_BASE 0x4b00000000
Regards, Bin
Thanks, Zhiqiang

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 --- 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 a35958a9ee..bfde3934aa 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c @@ -255,6 +255,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 b4bd2c604a..678ffe5e7a 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 2ed6b99fad..0662745962 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 driver for the NXP LX series 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 --- drivers/pci/Kconfig | 8 + drivers/pci/Makefile | 1 + drivers/pci/pcie_lx.c | 612 ++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pcie_lx.h | 258 ++++++++++++++++++ 4 files changed, 879 insertions(+) create mode 100644 drivers/pci/pcie_lx.c create mode 100644 drivers/pci/pcie_lx.h
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index f59803dbd6..f0db158ccf 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_LX + bool "LX PCIe support" + depends on DM_PCI + help + Support PCIe on NXP LX series SoCs, which may have one or several + PCIe controllers. The PCIe may works 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..bb125c7adc 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_LX) += pcie_lx.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o diff --git a/drivers/pci/pcie_lx.c b/drivers/pci/pcie_lx.c new file mode 100644 index 0000000000..1ba1721e38 --- /dev/null +++ b/drivers/pci/pcie_lx.c @@ -0,0 +1,612 @@ +// SPDX-License-Identifier: GPL-2.0+ OR X11 +/* + * Copyright 2018 NXP + * + * PCIe driver for NXP LX 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 "pcie_lx.h" + +DECLARE_GLOBAL_DATA_PTR; + +LIST_HEAD(lx_pcie_list); + +static u64 bar_size[4] = { + PCIE_BAR0_SIZE, + PCIE_BAR1_SIZE, + PCIE_BAR2_SIZE, + PCIE_BAR4_SIZE +}; + +static int lx_pcie_ltssm(struct lx_pcie *pcie) +{ + u32 state; + + state = pf_ctrl_readl(pcie, PCIE_LTSSM_STA) & LTSSM_STATE_MASK; + + return state; +} + +static int lx_pcie_link_up(struct lx_pcie *pcie) +{ + int ltssm; + + ltssm = lx_pcie_ltssm(pcie); + if (ltssm != LTSSM_PCIE_L0) + return 0; + + return 1; +} + +static void lx_pcie_ep_enable_cfg(struct lx_pcie *pcie) +{ + ccsr_writel(pcie, GPEX_CFG_READY, PCIE_CONFIG_READY); +} + +static void lx_pcie_cfg_set_target(struct lx_pcie *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 lx_pcie_outbound_win_set(struct lx_pcie *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 lx_pcie_inbound_win_set_rc(struct lx_pcie *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 lx_pcie_dump_wins(struct lx_pcie *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 lx_pcie_setup_wins(struct lx_pcie *pcie) +{ + struct pci_region *io, *mem, *pref; + int idx = 1; + + /* INBOUND WIN */ + lx_pcie_inbound_win_set_rc(pcie, 0, IB_TYPE_MEM_F, 0, 0, SIZE_1T); + + /* OUTBOUND WIN 0: CFG */ + lx_pcie_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 */ + lx_pcie_outbound_win_set(pcie, idx++, + PAB_AXI_TYPE_IO, + io->phys_start, + io->bus_start, + io->size); + + if (mem) + /* OUTBOUND WIN: MEM */ + lx_pcie_outbound_win_set(pcie, idx++, + PAB_AXI_TYPE_MEM, + mem->phys_start, + mem->bus_start, + mem->size); + + if (pref) + /* OUTBOUND WIN: perf MEM */ + lx_pcie_outbound_win_set(pcie, idx++, + PAB_AXI_TYPE_MEM, + pref->phys_start, + pref->bus_start, + pref->size); + + lx_pcie_dump_wins(pcie, idx); +} + +/* Return 0 if the address is valid, -errno if not valid */ +static int lx_pcie_addr_valid(struct lx_pcie *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) && (!lx_pcie_link_up(pcie))) + return -EINVAL; + + if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0)) + return -EINVAL; + + return 0; +} + +void *lx_pcie_conf_address(struct lx_pcie *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)); + + lx_pcie_cfg_set_target(pcie, target); + + return pcie->cfg + offset; +} + +static int lx_pcie_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct lx_pcie *pcie = dev_get_priv(bus); + void *address; + int ret = 0; + + if (lx_pcie_addr_valid(pcie, bdf)) { + *valuep = pci_get_ff(size); + return 0; + } + + address = lx_pcie_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 lx_pcie_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct lx_pcie *pcie = dev_get_priv(bus); + void *address; + + if (lx_pcie_addr_valid(pcie, bdf)) + return 0; + + address = lx_pcie_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 lx_pcie_setup_ctrl(struct lx_pcie *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); + + lx_pcie_setup_wins(pcie); + + pcie->stream_id_cur = 0; +} + +static void lx_pcie_ep_inbound_win_set(struct lx_pcie *pcie, int func, + int bar, u64 phys) +{ + ccsr_writel(pcie, PAB_EXT_PEX_BAR_AMAP(func, bar), upper_32_bits(phys)); + ccsr_writel(pcie, PAB_PEX_BAR_AMAP(func, bar), lower_32_bits(phys) | 1); +} + +static void lx_pcie_ep_setup_wins(struct lx_pcie *pcie, int pf) +{ + u64 phys; + int bar, bar_num; + u32 val; + + if (pcie->sriov_enabled) { + bar_num = 8; + if (pf == 1) + phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + + PCIE_BAR_SIZE * 4; + else + phys = CONFIG_SYS_PCI_EP_MEMORY_BASE; + } else { + bar_num = 4; + phys = CONFIG_SYS_PCI_EP_MEMORY_BASE; + } + + for (bar = 0; bar < bar_num; bar++) { + if (bar == 1 || bar == 5) + ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), 1); + else + if (bar < 4) { + lx_pcie_ep_inbound_win_set(pcie, pf, bar, phys); + phys += PCIE_BAR_SIZE; + } + } + + /* WIN 0 : OUTBOUND : map MEM */ + if (pf == 1) { + lx_pcie_outbound_win_set(pcie, 1, PAB_AXI_TYPE_MEM, + pcie->cfg_res.start + + CONFIG_SYS_PCI_MEMORY_SIZE, + 0x00000000, + CONFIG_SYS_PCI_MEMORY_SIZE); + val = ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(1)); + ccsr_writel(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(1), val | 1); + } else if (pf == 0) { + lx_pcie_outbound_win_set(pcie, 0, PAB_AXI_TYPE_MEM, + pcie->cfg_res.start, 0x00000000, + CONFIG_SYS_PCI_MEMORY_SIZE); + } +} + +static void lx_pcie_ep_enable_bar(struct lx_pcie *pcie, int bar) +{ + u32 val; + + val = ccsr_readl(pcie, GPEX_BAR_ENABLE); + val |= 1 << bar; + ccsr_writel(pcie, GPEX_BAR_ENABLE, val); +} + +static void lx_pcie_ep_disable_bar(struct lx_pcie *pcie, int bar) +{ + u32 val; + + val = ccsr_readl(pcie, GPEX_BAR_ENABLE); + val &= ~(1 << bar); + ccsr_writel(pcie, GPEX_BAR_ENABLE, val); +} + +static void lx_pcie_ep_set_bar_size(struct lx_pcie *pcie, int bar, u64 size) +{ + u32 mask_l = lower_32_bits(~(size - 1)); + u32 mask_h = upper_32_bits(~(size - 1)); + + ccsr_writel(pcie, GPEX_BAR_SELECT, bar); + ccsr_writel(pcie, GPEX_BAR_SIZE_LDW, mask_l); + ccsr_writel(pcie, GPEX_BAR_SIZE_UDW, mask_h); +} + +static void lx_pcie_ep_setup_bar_vf(struct lx_pcie *pcie, + int pf, int bar, u64 size) +{ + if (pf == LX_PF1) + bar += PF1_VF_BAR_OFFSET; + else + bar += PF0_VF_BAR_OFFSET; + + if (size == 0) + lx_pcie_ep_disable_bar(pcie, bar); + else + lx_pcie_ep_enable_bar(pcie, bar); + + lx_pcie_ep_set_bar_size(pcie, bar, size); +} + +static void lx_pcie_ep_setup_bar_pf(struct lx_pcie *pcie, + int pf, int bar, u64 size) +{ + if (pf == LX_PF1) + bar += PF1_BAR_OFFSET; + + if (size == 0) + lx_pcie_ep_disable_bar(pcie, bar); + else + lx_pcie_ep_enable_bar(pcie, bar); + + lx_pcie_ep_set_bar_size(pcie, bar, size); +} + +static void lx_pcie_ep_setup_bars(struct lx_pcie *pcie, int pf) +{ + int bar; + + for (bar = 0; bar < BAR_NUM; bar++) + lx_pcie_ep_setup_bar_pf(pcie, pf, bar, bar_size[bar]); + if (pcie->sriov_enabled) { + for (bar = 0; bar < BAR_NUM; bar++) + lx_pcie_ep_setup_bar_vf(pcie, pf, bar, bar_size[bar]); + } +} + +static void lx_pcie_set_sriov(struct lx_pcie *pcie, int func) +{ + unsigned int val; + + val = ccsr_readl(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(func)); + 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(func), val); + + if (func == 1) { + val = ccsr_readl(pcie, PCIE_SRIOV_VF_OFFSET_STRIDE); + val += PCIE_VF_NUM - 1; + ccsr_writel(pcie, GPEX_SRIOV_VF_OFFSET_STRIDE(func), val); + } +} + +static void lx_pcie_setup_ep(struct lx_pcie *pcie) +{ + u32 pf; + u32 sriov; + u32 val; + + /* 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_enabled = 1; + + for (pf = 0; pf < PCIE_PF_NUM; pf++) { + lx_pcie_ep_setup_bars(pcie, pf); + lx_pcie_ep_setup_wins(pcie, pf); + lx_pcie_set_sriov(pcie, pf); + } + } else { + pcie->sriov_enabled = 0; + + lx_pcie_ep_setup_bars(pcie, 0); + lx_pcie_ep_setup_wins(pcie, 0); + } + + lx_pcie_ep_enable_cfg(pcie); + lx_pcie_dump_wins(pcie, 2); +} + +static int lx_pcie_probe(struct udevice *dev) +{ + struct lx_pcie *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("lx-pcie: resource "ccsr" not found\n"); + return ret; + } + + pcie->idx = (pcie->ccsr_res.start - PCIE_SYS_BASE_ADDR) / + PCIE_CCSR_SIZE; + + list_add(&pcie->list, &lx_pcie_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("lx-pcie: 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("lx-pcie: 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"); + lx_pcie_setup_ep(pcie); + } else { + printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex"); + lx_pcie_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 (!lx_pcie_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 lx_pcie_ops = { + .read_config = lx_pcie_read_config, + .write_config = lx_pcie_write_config, +}; + +static const struct udevice_id lx_pcie_ids[] = { + { .compatible = "fsl,lx2160a-pcie" }, + { } +}; + +U_BOOT_DRIVER(pcie_lx) = { + .name = "pcie_lx", + .id = UCLASS_PCI, + .of_match = lx_pcie_ids, + .ops = &lx_pcie_ops, + .probe = lx_pcie_probe, + .priv_auto_alloc_size = sizeof(struct lx_pcie), +}; + +/* No any fixup so far */ +void ft_pci_setup(void *blob, bd_t *bd) +{ +} diff --git a/drivers/pci/pcie_lx.h b/drivers/pci/pcie_lx.h new file mode 100644 index 0000000000..4deb52ffff --- /dev/null +++ b/drivers/pci/pcie_lx.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2018 NXP + * + * PCIe driver for NXP LX SoCs + * Author: Hou Zhiqiang Minder.Hou@gmail.com + */ + +#ifndef _PCIE_LX_H_ +#define _PCIE_LX_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 PCIE_SRIOV_CAPABILITY 0x2a0 +#define PCI_EXT_CAP_ID_SRIOV 0x10 +#define PCIE_SRIOV_VF_OFFSET_STRIDE 0x2b4 + +#define LX_PF1 1 +#define BAR_NUM 4 +#define PF1_BAR_OFFSET 4 +#define PF0_VF_BAR_OFFSET 8 +#define PF1_VF_BAR_OFFSET 12 +#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) +#define SIZE_1M (1024 * 1024) + +/* 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 + +/* 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 GPEX_SRIOV_INIT_VFS_TOTAL_VF(func) (0x644 + (func) * 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(func) (0x704 + (func) * 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 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(func, bar) \ + (0x1ba0 + 0x20 * (func) + 4 * (bar)) +#define PAB_EXT_PEX_BAR_AMAP(func, bar) \ + (0x84a0 + 0x20 * (func) + 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 + +/* 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 lx_pcie { + 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_enabled; +}; + +extern struct list_head lx_pcie_list; + +static inline void lut_writel(struct lx_pcie *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 lx_pcie *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 lx_pcie *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 lx_pcie *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 lx_pcie *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 lx_pcie *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 lx_pcie *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_LX_H_ */

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
The CONFIG of LX2160A PCIe driver is PCIE_LX instead of PCIE_LAYERSCAPE.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- 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 2b086da79b..e102a2ace1 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -232,7 +232,7 @@ menu "Layerscape architecture"
config FSL_PCIE_COMPAT string "PCIe compatible of Kernel DT" - depends on PCIE_LAYERSCAPE + depends on PCIE_LAYERSCAPE || PCIE_LX 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 LX SoCs PCIe controller to update device tree nodes to convey SMMU stream IDs in the device tree.
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- drivers/pci/Makefile | 2 +- drivers/pci/pcie_lx.c | 5 - drivers/pci/pcie_lx_fixup.c | 234 ++++++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+), 6 deletions(-) create mode 100644 drivers/pci/pcie_lx_fixup.c
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index bb125c7adc..32244f23fc 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -32,6 +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_LX) += pcie_lx.o +obj-$(CONFIG_PCIE_LX) += pcie_lx.o pcie_lx_fixup.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o diff --git a/drivers/pci/pcie_lx.c b/drivers/pci/pcie_lx.c index 1ba1721e38..84311e3d5a 100644 --- a/drivers/pci/pcie_lx.c +++ b/drivers/pci/pcie_lx.c @@ -605,8 +605,3 @@ U_BOOT_DRIVER(pcie_lx) = { .probe = lx_pcie_probe, .priv_auto_alloc_size = sizeof(struct lx_pcie), }; - -/* No any fixup so far */ -void ft_pci_setup(void *blob, bd_t *bd) -{ -} diff --git a/drivers/pci/pcie_lx_fixup.c b/drivers/pci/pcie_lx_fixup.c new file mode 100644 index 0000000000..c658646ac4 --- /dev/null +++ b/drivers/pci/pcie_lx_fixup.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0+ OR X11 +/* + * Copyright 2018 NXP + * + * PCIe driver for NXP LX 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_lx.h" + +#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) +/* + * Return next available LUT index. + */ +static int lx_pcie_next_lut_index(struct lx_pcie *pcie) +{ + if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT) + return pcie->next_lut_index++; + else + return -ENOSPC; /* LUT is full */ +} + +/* returns the next available streamid for pcie, -errno if failed */ +static int lx_pcie_next_streamid(struct lx_pcie *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 lx_pcie_lut_set_mapping(struct lx_pcie *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 lx_pcie *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 lx_pcie *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 lx_pcie *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 = lx_pcie_next_streamid(pcie); + if (streamid < 0) { + debug("ERROR: no stream ids free\n"); + continue; + } + + index = lx_pcie_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 */ + lx_pcie_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_lx_setup(void *blob, struct lx_pcie *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) + fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0); + else + fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); +} + +/* Fixup Kernel DT for PCIe */ +void ft_pci_setup(void *blob, bd_t *bd) +{ + struct lx_pcie *pcie; + + list_for_each_entry(pcie, &lx_pcie_list, list) + ft_pcie_lx_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
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- 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 b407dc6e13..9654fb46a1 100644 --- a/arch/arm/dts/fsl-lx2160a.dtsi +++ b/arch/arm/dts/fsl-lx2160a.dtsi @@ -115,4 +115,89 @@ interrupts = <0 81 0x4>; /* Level high type */ dr_mode = "host"; }; + + 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
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- configs/lx2160ardb_tfa_defconfig | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/configs/lx2160ardb_tfa_defconfig b/configs/lx2160ardb_tfa_defconfig index fb1102ec64..64cc31d475 100644 --- a/configs/lx2160ardb_tfa_defconfig +++ b/configs/lx2160ardb_tfa_defconfig @@ -51,6 +51,11 @@ CONFIG_CMD_MII=y CONFIG_CMD_DHCP=y CONFIG_CMD_FAT=y CONFIG_CMD_EXT2=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCIE_LX=y +CONFIG_E1000=y CONFIG_NET=y CONFIG_USB=y CONFIG_DM_USB=y

From: Hou Zhiqiang Zhiqiang.Hou@nxp.com
Signed-off-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com --- include/configs/lx2160a_common.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/configs/lx2160a_common.h b/include/configs/lx2160a_common.h index 41931e5b53..19053b43a1 100644 --- a/include/configs/lx2160a_common.h +++ b/include/configs/lx2160a_common.h @@ -129,6 +129,7 @@ #ifdef CONFIG_PCI #define CONFIG_SYS_PCI_64BIT #define CONFIG_PCI_SCAN_SHOW +#define CONFIG_CMD_PCI #endif
/* MMC */
participants (2)
-
Bin Meng
-
Z.q. Hou