[PATCH 1/9] pci: layerscape: Split the EP and RC driver

Split the RC and EP driver, and reimplement the EP driver base on the EP framework.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- drivers/pci/Makefile | 2 +- drivers/pci/pcie_layerscape.c | 492 +++--------------------------------- drivers/pci/pcie_layerscape.h | 44 +++- drivers/pci/pcie_layerscape_ep.c | 240 ++++++++++++++++++ drivers/pci/pcie_layerscape_fixup.c | 79 +++--- drivers/pci/pcie_layerscape_rc.c | 378 +++++++++++++++++++++++++++ 6 files changed, 734 insertions(+), 501 deletions(-) create mode 100644 drivers/pci/pcie_layerscape_ep.c create mode 100644 drivers/pci/pcie_layerscape_rc.c
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index c051ecc..440b5af 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o obj-$(CONFIG_PCIE_FSL) += pcie_fsl.o pcie_fsl_fixup.o -obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o +obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o pcie_layerscape_rc.o pcie_layerscape_ep.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o pcie_layerscape_fixup_common.o obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_gen4_fixup.o \ diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 2ab67d1..3ca75c5 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -1,39 +1,32 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2017-2019 NXP + * Copyright 2017-2020 NXP * Copyright 2014-2015 Freescale Semiconductor, Inc. * Layerscape PCIe driver */
#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> -#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \ - defined(CONFIG_ARM) -#include <asm/arch/clock.h> -#endif #include "pcie_layerscape.h"
DECLARE_GLOBAL_DATA_PTR;
LIST_HEAD(ls_pcie_list);
-static unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset) +unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset) { return in_le32(pcie->dbi + offset); }
-static void dbi_writel(struct ls_pcie *pcie, unsigned int value, - unsigned int offset) +void dbi_writel(struct ls_pcie *pcie, unsigned int value, + unsigned int offset) { out_le32(pcie->dbi + offset, value); }
-static unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) +unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) { if (pcie->big_endian) return in_be32(pcie->ctrl + offset); @@ -41,8 +34,8 @@ static unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) return in_le32(pcie->ctrl + offset); }
-static void ctrl_writel(struct ls_pcie *pcie, unsigned int value, - unsigned int offset) +void ctrl_writel(struct ls_pcie *pcie, unsigned int value, + unsigned int offset) { if (pcie->big_endian) out_be32(pcie->ctrl + offset, value); @@ -50,6 +43,26 @@ static void ctrl_writel(struct ls_pcie *pcie, unsigned int value, out_le32(pcie->ctrl + offset, value); }
+void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie) +{ + u32 reg, val; + + reg = PCIE_MISC_CONTROL_1_OFF; + val = dbi_readl(pcie, reg); + val |= PCIE_DBI_RO_WR_EN; + dbi_writel(pcie, val, reg); +} + +void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie) +{ + u32 reg, val; + + reg = PCIE_MISC_CONTROL_1_OFF; + val = dbi_readl(pcie, reg); + val &= ~PCIE_DBI_RO_WR_EN; + dbi_writel(pcie, val, reg); +} + static int ls_pcie_ltssm(struct ls_pcie *pcie) { u32 state; @@ -66,7 +79,7 @@ static int ls_pcie_ltssm(struct ls_pcie *pcie) return state; }
-static int ls_pcie_link_up(struct ls_pcie *pcie) +int ls_pcie_link_up(struct ls_pcie *pcie) { int ltssm;
@@ -77,22 +90,8 @@ static int ls_pcie_link_up(struct ls_pcie *pcie) return 1; }
-static void ls_pcie_cfg0_set_busdev(struct ls_pcie *pcie, u32 busdev) -{ - dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, - PCIE_ATU_VIEWPORT); - dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); -} - -static void ls_pcie_cfg1_set_busdev(struct ls_pcie *pcie, u32 busdev) -{ - dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, - PCIE_ATU_VIEWPORT); - dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); -} - -static void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, - u64 phys, u64 bus_addr, pci_size_t size) +void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, + u64 phys, u64 bus_addr, pci_size_t size) { dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_BASE); @@ -105,18 +104,18 @@ static void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, }
/* Use bar match mode and MEM type as default */ -static void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, - int bar, u64 phys) +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type, + int bar, u64 phys) { dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET); dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET); - dbi_writel(pcie, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); + dbi_writel(pcie, type, PCIE_ATU_CR1); dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); }
-static void ls_pcie_dump_atu(struct ls_pcie *pcie) +void ls_pcie_dump_atu(struct ls_pcie *pcie) { int i;
@@ -133,431 +132,10 @@ static void ls_pcie_dump_atu(struct ls_pcie *pcie) debug("\tUPPER BUS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_UPPER_TARGET)); debug("\tLIMIT 0x%08x\n", - readl(pcie->dbi + PCIE_ATU_LIMIT)); + dbi_readl(pcie, PCIE_ATU_LIMIT)); debug("\tCR1 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR1)); debug("\tCR2 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR2)); } } - -static void ls_pcie_setup_atu(struct ls_pcie *pcie) -{ - struct pci_region *io, *mem, *pref; - unsigned long long offset = 0; - int idx = 0; - uint svr; - - svr = get_svr(); - if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) == SVR_LS102XA) { - offset = LS1021_PCIE_SPACE_OFFSET + - LS1021_PCIE_SPACE_SIZE * pcie->idx; - } - - /* ATU 0 : OUTBOUND : CFG0 */ - ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0, - PCIE_ATU_TYPE_CFG0, - pcie->cfg_res.start + offset, - 0, - fdt_resource_size(&pcie->cfg_res) / 2); - /* ATU 1 : OUTBOUND : CFG1 */ - ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_CFG1, - pcie->cfg_res.start + offset + - fdt_resource_size(&pcie->cfg_res) / 2, - 0, - fdt_resource_size(&pcie->cfg_res) / 2); - - pci_get_regions(pcie->bus, &io, &mem, &pref); - idx = PCIE_ATU_REGION_INDEX1 + 1; - - /* Fix the pcie memory map for LS2088A series SoCs */ - svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; - if (svr == SVR_LS2088A || svr == SVR_LS2084A || - svr == SVR_LS2048A || svr == SVR_LS2044A || - svr == SVR_LS2081A || svr == SVR_LS2041A) { - if (io) - io->phys_start = (io->phys_start & - (PCIE_PHYS_SIZE - 1)) + - LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - if (mem) - mem->phys_start = (mem->phys_start & - (PCIE_PHYS_SIZE - 1)) + - LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - if (pref) - pref->phys_start = (pref->phys_start & - (PCIE_PHYS_SIZE - 1)) + - LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - } - - if (io) - /* ATU : OUTBOUND : IO */ - ls_pcie_atu_outbound_set(pcie, idx++, - PCIE_ATU_TYPE_IO, - io->phys_start + offset, - io->bus_start, - io->size); - - if (mem) - /* ATU : OUTBOUND : MEM */ - ls_pcie_atu_outbound_set(pcie, idx++, - PCIE_ATU_TYPE_MEM, - mem->phys_start + offset, - mem->bus_start, - mem->size); - - if (pref) - /* ATU : OUTBOUND : pref */ - ls_pcie_atu_outbound_set(pcie, idx++, - PCIE_ATU_TYPE_MEM, - pref->phys_start + offset, - pref->bus_start, - pref->size); - - ls_pcie_dump_atu(pcie); -} - -/* Return 0 if the address is valid, -errno if not valid */ -static int ls_pcie_addr_valid(struct ls_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) && (!ls_pcie_link_up(pcie))) - return -EINVAL; - - if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0)) - return -EINVAL; - - return 0; -} - -int ls_pcie_conf_address(struct udevice *bus, pci_dev_t bdf, - uint offset, void **paddress) -{ - struct ls_pcie *pcie = dev_get_priv(bus); - u32 busdev; - - if (ls_pcie_addr_valid(pcie, bdf)) - return -EINVAL; - - if (PCI_BUS(bdf) == bus->seq) { - *paddress = pcie->dbi + offset; - return 0; - } - - busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - bus->seq) | - PCIE_ATU_DEV(PCI_DEV(bdf)) | - PCIE_ATU_FUNC(PCI_FUNC(bdf)); - - if (PCI_BUS(bdf) == bus->seq + 1) { - ls_pcie_cfg0_set_busdev(pcie, busdev); - *paddress = pcie->cfg0 + offset; - } else { - ls_pcie_cfg1_set_busdev(pcie, busdev); - *paddress = pcie->cfg1 + offset; - } - return 0; -} - -static int ls_pcie_read_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - return pci_generic_mmap_read_config(bus, ls_pcie_conf_address, - bdf, offset, valuep, size); -} - -static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - return pci_generic_mmap_write_config(bus, ls_pcie_conf_address, - bdf, offset, value, size); -} - -/* Clear multi-function bit */ -static void ls_pcie_clear_multifunction(struct ls_pcie *pcie) -{ - writeb(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE); -} - -/* Fix class value */ -static void ls_pcie_fix_class(struct ls_pcie *pcie) -{ - writew(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE); -} - -/* Drop MSG TLP except for Vendor MSG */ -static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) -{ - u32 val; - - val = dbi_readl(pcie, PCIE_STRFMR1); - val &= 0xDFFFFFFF; - dbi_writel(pcie, val, PCIE_STRFMR1); -} - -/* Disable all bars in RC mode */ -static void ls_pcie_disable_bars(struct ls_pcie *pcie) -{ - dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_0); - dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_1); - dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1); -} - -static void ls_pcie_setup_ctrl(struct ls_pcie *pcie) -{ - ls_pcie_setup_atu(pcie); - - dbi_writel(pcie, 1, PCIE_DBI_RO_WR_EN); - ls_pcie_fix_class(pcie); - ls_pcie_clear_multifunction(pcie); - ls_pcie_drop_msg_tlp(pcie); - dbi_writel(pcie, 0, PCIE_DBI_RO_WR_EN); - - ls_pcie_disable_bars(pcie); - pcie->stream_id_cur = 0; -} - -static void ls_pcie_ep_setup_atu(struct ls_pcie *pcie) -{ - u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE; - - /* ATU 0 : INBOUND : map BAR0 */ - ls_pcie_atu_inbound_set(pcie, 0, 0, phys); - /* ATU 1 : INBOUND : map BAR1 */ - phys += PCIE_BAR1_SIZE; - ls_pcie_atu_inbound_set(pcie, 1, 1, phys); - /* ATU 2 : INBOUND : map BAR2 */ - phys += PCIE_BAR2_SIZE; - ls_pcie_atu_inbound_set(pcie, 2, 2, phys); - /* ATU 3 : INBOUND : map BAR4 */ - phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE; - ls_pcie_atu_inbound_set(pcie, 3, 4, phys); - - /* ATU 0 : OUTBOUND : map MEM */ - ls_pcie_atu_outbound_set(pcie, 0, - PCIE_ATU_TYPE_MEM, - pcie->cfg_res.start, - 0, - CONFIG_SYS_PCI_MEMORY_SIZE); -} - -/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ -static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) -{ - /* The least inbound window is 4KiB */ - if (size < 4 * 1024) - return; - - switch (bar) { - case 0: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_0); - break; - case 1: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_1); - break; - case 2: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_2); - writel(0, bar_base + PCI_BASE_ADDRESS_3); - break; - case 4: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_4); - writel(0, bar_base + PCI_BASE_ADDRESS_5); - break; - default: - break; - } -} - -static void ls_pcie_ep_setup_bars(void *bar_base) -{ - /* BAR0 - 32bit - 4K configuration */ - ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); - /* BAR1 - 32bit - 8K MSIX*/ - ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); - /* BAR2 - 64bit - 4K MEM desciptor */ - ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); - /* BAR4 - 64bit - 1M MEM*/ - ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); -} - -static void ls_pcie_ep_enable_cfg(struct ls_pcie *pcie) -{ - u32 config; - - config = ctrl_readl(pcie, PCIE_PF_CONFIG); - config |= PCIE_CONFIG_READY; - ctrl_writel(pcie, config, PCIE_PF_CONFIG); -} - -static void ls_pcie_setup_ep(struct ls_pcie *pcie) -{ - u32 sriov; - - sriov = readl(pcie->dbi + PCIE_SRIOV); - if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) { - int pf, vf; - - for (pf = 0; pf < PCIE_PF_NUM; pf++) { - for (vf = 0; vf <= PCIE_VF_NUM; vf++) { - ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf), - PCIE_PF_VF_CTRL); - - ls_pcie_ep_setup_bars(pcie->dbi); - ls_pcie_ep_setup_atu(pcie); - } - } - /* Disable CFG2 */ - ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL); - } else { - ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE); - ls_pcie_ep_setup_atu(pcie); - } - - ls_pcie_ep_enable_cfg(pcie); -} - -static int ls_pcie_probe(struct udevice *dev) -{ - struct ls_pcie *pcie = dev_get_priv(dev); - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(dev); - u16 link_sta; - uint svr; - int ret; - fdt_size_t cfg_size; - - pcie->bus = dev; - - ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", - "dbi", &pcie->dbi_res); - if (ret) { - printf("ls-pcie: resource "dbi" not found\n"); - return ret; - } - - pcie->idx = (pcie->dbi_res.start - PCIE_SYS_BASE_ADDR) / PCIE_CCSR_SIZE; - - list_add(&pcie->list, &ls_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->dbi = map_physmem(pcie->dbi_res.start, - fdt_resource_size(&pcie->dbi_res), - MAP_NOCACHE); - - ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", - "lut", &pcie->lut_res); - if (!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", - "ctrl", &pcie->ctrl_res); - if (!ret) - pcie->ctrl = map_physmem(pcie->ctrl_res.start, - fdt_resource_size(&pcie->ctrl_res), - MAP_NOCACHE); - if (!pcie->ctrl) - pcie->ctrl = pcie->lut; - - if (!pcie->ctrl) { - printf("%s: NOT find CTRL\n", dev->name); - return -1; - } - - 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; - } - - /* - * Fix the pcie memory map address and PF control registers address - * for LS2088A series SoCs - */ - svr = get_svr(); - svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; - if (svr == SVR_LS2088A || svr == SVR_LS2084A || - svr == SVR_LS2048A || svr == SVR_LS2044A || - svr == SVR_LS2081A || svr == SVR_LS2041A) { - cfg_size = fdt_resource_size(&pcie->cfg_res); - pcie->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - pcie->cfg_res.end = pcie->cfg_res.start + cfg_size; - pcie->ctrl = pcie->lut + 0x40000; - } - - pcie->cfg0 = map_physmem(pcie->cfg_res.start, - fdt_resource_size(&pcie->cfg_res), - MAP_NOCACHE); - pcie->cfg1 = pcie->cfg0 + fdt_resource_size(&pcie->cfg_res) / 2; - - pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian"); - - debug("%s dbi:%lx lut:%lx ctrl:0x%lx cfg0:0x%lx, big-endian:%d\n", - dev->name, (unsigned long)pcie->dbi, (unsigned long)pcie->lut, - (unsigned long)pcie->ctrl, (unsigned long)pcie->cfg0, - pcie->big_endian); - - pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; - - if (pcie->mode == PCI_HEADER_TYPE_NORMAL) { - printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint"); - ls_pcie_setup_ep(pcie); - } else { - printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex"); - ls_pcie_setup_ctrl(pcie); - } - - if (!ls_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_sta = readw(pcie->dbi + PCIE_LINK_STA); - printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4, - link_sta & PCIE_LINK_SPEED_MASK); - - return 0; -} - -static const struct dm_pci_ops ls_pcie_ops = { - .read_config = ls_pcie_read_config, - .write_config = ls_pcie_write_config, -}; - -static const struct udevice_id ls_pcie_ids[] = { - { .compatible = "fsl,ls-pcie" }, - { } -}; - -U_BOOT_DRIVER(pci_layerscape) = { - .name = "pci_layerscape", - .id = UCLASS_PCI, - .of_match = ls_pcie_ids, - .ops = &ls_pcie_ops, - .probe = ls_pcie_probe, - .priv_auto_alloc_size = sizeof(struct ls_pcie), -}; diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 95454bc..217dcda 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright 2017-2019 NXP + * Copyright 2017-2020 NXP * Copyright 2014-2015 Freescale Semiconductor, Inc. * Layerscape PCIe driver */ @@ -60,7 +60,8 @@ /* DBI registers */ #define PCIE_SRIOV 0x178 #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ -#define PCIE_DBI_RO_WR_EN 0x8bc +#define PCIE_DBI_RO_WR_EN BIT(0) +#define PCIE_MISC_CONTROL_1_OFF 0x8BC
#define PCIE_LINK_CAP 0x7c #define PCIE_LINK_SPEED_MASK 0xf @@ -82,7 +83,7 @@ PCIE_LCTRL0_CFG2_ENABLE)
#define PCIE_NO_SRIOV_BAR_BASE 0x1000 - +#define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */ #define PCIE_PF_NUM 2 #define PCIE_VF_NUM 64
@@ -129,25 +130,52 @@ #define LS1021_LTSSM_STATE_SHIFT 20
struct ls_pcie { + void __iomem *dbi; + void __iomem *lut; + void __iomem *ctrl; int idx; + bool big_endian; + int mode; +}; + +struct ls_pcie_rc { + struct ls_pcie *pcie; struct list_head list; struct udevice *bus; struct fdt_resource dbi_res; struct fdt_resource lut_res; struct fdt_resource ctrl_res; struct fdt_resource cfg_res; - void __iomem *dbi; - void __iomem *lut; - void __iomem *ctrl; void __iomem *cfg0; void __iomem *cfg1; - bool big_endian; bool enabled; int next_lut_index; int stream_id_cur; - int mode; +}; + +struct ls_pcie_ep { + struct fdt_resource addr_res; + struct ls_pcie *pcie; + struct udevice *bus; + void __iomem *addr; + u32 num_ib_wins; + u32 num_ob_wins; + u8 max_functions; };
extern struct list_head ls_pcie_list;
+unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset); +void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); +unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset); +void ctrl_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); +void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, + u64 phys, u64 bus_addr, pci_size_t size); +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type, + int bar, u64 phys); +void ls_pcie_dump_atu(struct ls_pcie *pcie); +int ls_pcie_link_up(struct ls_pcie *pcie); +void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); +void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie); + #endif /* _PCIE_LAYERSCAPE_H_ */ diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c new file mode 100644 index 0000000..8d0c99a --- /dev/null +++ b/drivers/pci/pcie_layerscape_ep.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * Layerscape PCIe EP driver + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <pci_ep.h> +#include <asm/io.h> +#include <linux/sizes.h> +#include <linux/log2.h> +#include "pcie_layerscape.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void ls_pcie_ep_enable_cfg(struct ls_pcie_ep *pcie_ep) +{ + struct ls_pcie *pcie = pcie_ep->pcie; + u32 config; + + config = ctrl_readl(pcie, PCIE_PF_CONFIG); + config |= PCIE_CONFIG_READY; + ctrl_writel(pcie, config, PCIE_PF_CONFIG); +} + +static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar) +{ + struct ls_pcie_ep *pcie_ep = dev_get_priv(dev); + struct ls_pcie *pcie = pcie_ep->pcie; + dma_addr_t bar_phys = ep_bar->phys_addr; + enum pci_barno bar = ep_bar->barno; + u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar); + int flags = ep_bar->flags; + int type, idx; + u64 size; + + idx = bar; + /* BAR size is 2^(aperture + 11) */ + size = max_t(size_t, ep_bar->size, FSL_PCIE_EP_MIN_APERTURE); + + if (!(flags & PCI_BASE_ADDRESS_SPACE)) + type = PCIE_ATU_TYPE_MEM; + else + type = PCIE_ATU_TYPE_IO; + + ls_pcie_atu_inbound_set(pcie, idx, bar, bar_phys, type); + + dbi_writel(pcie, lower_32_bits(size - 1), reg + PCIE_NO_SRIOV_BAR_BASE); + dbi_writel(pcie, flags, reg); + + if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) { + dbi_writel(pcie, upper_32_bits(size - 1), + reg + 4 + PCIE_NO_SRIOV_BAR_BASE); + dbi_writel(pcie, 0, reg + 4); + } + + return 0; +} + +static struct pci_ep_ops ls_pcie_ep_ops = { + .set_bar = ls_ep_set_bar, +}; + +static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep) +{ + struct ls_pcie *pcie = pcie_ep->pcie; + u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE; + + /* ATU 0 : INBOUND : map BAR0 */ + ls_pcie_atu_inbound_set(pcie, 0, PCIE_ATU_TYPE_MEM, 0, phys); + /* ATU 1 : INBOUND : map BAR1 */ + phys += PCIE_BAR1_SIZE; + ls_pcie_atu_inbound_set(pcie, 1, PCIE_ATU_TYPE_MEM, 1, phys); + /* ATU 2 : INBOUND : map BAR2 */ + phys += PCIE_BAR2_SIZE; + ls_pcie_atu_inbound_set(pcie, 2, PCIE_ATU_TYPE_MEM, 2, phys); + /* ATU 3 : INBOUND : map BAR4 */ + phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE; + ls_pcie_atu_inbound_set(pcie, 3, PCIE_ATU_TYPE_MEM, 4, phys); + + /* ATU 0 : OUTBOUND : map MEM */ + ls_pcie_atu_outbound_set(pcie, 0, + PCIE_ATU_TYPE_MEM, + pcie_ep->addr_res.start, + 0, + CONFIG_SYS_PCI_MEMORY_SIZE); +} + +/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ +static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) +{ + /* The least inbound window is 4KiB */ + if (size < 4 * 1024) + return; + + switch (bar) { + case 0: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_0); + break; + case 1: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_1); + break; + case 2: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_2); + writel(0, bar_base + PCI_BASE_ADDRESS_3); + break; + case 4: + writel(size - 1, bar_base + PCI_BASE_ADDRESS_4); + writel(0, bar_base + PCI_BASE_ADDRESS_5); + break; + default: + break; + } +} + +static void ls_pcie_ep_setup_bars(void *bar_base) +{ + /* BAR0 - 32bit - 4K configuration */ + ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); + /* BAR1 - 32bit - 8K MSIX */ + ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); + /* BAR2 - 64bit - 4K MEM descriptor */ + ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); + /* BAR4 - 64bit - 1M MEM */ + ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); +} + +static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) +{ + u32 sriov; + struct ls_pcie *pcie = pcie_ep->pcie; + + sriov = readl(pcie->dbi + PCIE_SRIOV); + if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) { + int pf, vf; + + for (pf = 0; pf < PCIE_PF_NUM; pf++) { + for (vf = 0; vf <= PCIE_VF_NUM; vf++) { + ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf), + PCIE_PF_VF_CTRL); + + ls_pcie_ep_setup_bars(pcie->dbi); + ls_pcie_ep_setup_atu(pcie_ep); + } + } + /* Disable CFG2 */ + ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL); + } else { + ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE); + ls_pcie_ep_setup_atu(pcie_ep); + } + + ls_pcie_ep_enable_cfg(pcie_ep); +} + +static int ls_pcie_ep_probe(struct udevice *dev) +{ + struct ls_pcie_ep *pcie_ep = dev_get_priv(dev); + struct ls_pcie *pcie; + u16 link_sta; + int ret; + + pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie_ep->pcie = pcie; + + pcie->dbi = (void __iomem *)devfdt_get_addr_index(dev, 0); + if (!pcie->dbi) + return -ENOMEM; + + pcie->ctrl = (void __iomem *)devfdt_get_addr_index(dev, 1); + if (!pcie->ctrl) + return -ENOMEM; + + ret = fdt_get_named_resource(gd->fdt_blob, dev_of_offset(dev), + "reg", "reg-names", + "addr_space", &pcie_ep->addr_res); + if (ret) { + printf("%s: resource "addr_space" not found\n", dev->name); + return ret; + } + + pcie->idx = ((unsigned long)pcie->dbi - PCIE_SYS_BASE_ADDR) / + PCIE_CCSR_SIZE; + + pcie->big_endian = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), + "big-endian"); + + pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; + if (pcie->mode != PCI_HEADER_TYPE_NORMAL) + return 0; + + pcie_ep->max_functions = fdtdec_get_int(gd->fdt_blob, + dev_of_offset(dev), + "max-functions", 1); + pcie_ep->num_ib_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "num-ib-windows", 8); + pcie_ep->num_ob_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "num-ob-windows", 8); + + printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint"); + ls_pcie_setup_ep(pcie_ep); + + if (!ls_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_sta = readw(pcie->dbi + PCIE_LINK_STA); + printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4, + link_sta & PCIE_LINK_SPEED_MASK); + + return 0; +} + +static int ls_pcie_ep_remove(struct udevice *dev) +{ + return 0; +} + +const struct udevice_id ls_pcie_ep_ids[] = { + { .compatible = "fsl,ls-pcie-ep" }, + { } +}; + +U_BOOT_DRIVER(pci_layerscape_ep) = { + .name = "pci_layerscape_ep", + .id = UCLASS_PCI_EP, + .of_match = ls_pcie_ep_ids, + .ops = &ls_pcie_ep_ops, + .probe = ls_pcie_ep_probe, + .remove = ls_pcie_ep_remove, + .priv_auto_alloc_size = sizeof(struct ls_pcie_ep), +}; diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c index ec6acbb..a981f8c 100644 --- a/drivers/pci/pcie_layerscape_fixup.c +++ b/drivers/pci/pcie_layerscape_fixup.c @@ -23,17 +23,19 @@ /* * Return next available LUT index. */ -static int ls_pcie_next_lut_index(struct ls_pcie *pcie) +static int ls_pcie_next_lut_index(struct ls_pcie_rc *pcie_rc) { - if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT) - return pcie->next_lut_index++; + if (pcie_rc->next_lut_index < PCIE_LUT_ENTRY_COUNT) + return pcie_rc->next_lut_index++; else return -ENOSPC; /* LUT is full */ }
-static void lut_writel(struct ls_pcie *pcie, unsigned int value, +static void lut_writel(struct ls_pcie_rc *pcie_rc, unsigned int value, unsigned int offset) { + struct ls_pcie *pcie = pcie_rc->pcie; + if (pcie->big_endian) out_be32(pcie->lut + offset, value); else @@ -43,12 +45,12 @@ static void lut_writel(struct ls_pcie *pcie, unsigned int value, /* * Program a single LUT entry */ -static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid, - u32 streamid) +static void ls_pcie_lut_set_mapping(struct ls_pcie_rc *pcie_rc, 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)); + lut_writel(pcie_rc, devid << 16, PCIE_LUT_UDR(index)); + lut_writel(pcie_rc, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index)); }
/* @@ -59,7 +61,8 @@ static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid, * 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_ls(void *blob, struct ls_pcie *pcie, +static void fdt_pcie_set_msi_map_entry_ls(void *blob, + struct ls_pcie_rc *pcie_rc, u32 devid, u32 streamid) { u32 *prop; @@ -67,10 +70,11 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, int nodeoffset; uint svr; char *compat = NULL; + struct ls_pcie *pcie = pcie_rc->pcie;
/* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (nodeoffset < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -82,7 +86,7 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, compat = CONFIG_FSL_PCIE_COMPAT; if (compat) nodeoffset = fdt_node_offset_by_compat_reg(blob, - compat, pcie->dbi_res.start); + compat, pcie_rc->dbi_res.start); #endif if (nodeoffset < 0) return; @@ -112,7 +116,8 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, * 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_ls(void *blob, struct ls_pcie *pcie, +static void fdt_pcie_set_iommu_map_entry_ls(void *blob, + struct ls_pcie_rc *pcie_rc, u32 devid, u32 streamid) { u32 *prop; @@ -121,10 +126,11 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, int lenp; uint svr; char *compat = NULL; + struct ls_pcie *pcie = pcie_rc->pcie;
/* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (nodeoffset < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -137,7 +143,7 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie,
if (compat) nodeoffset = fdt_node_offset_by_compat_reg(blob, - compat, pcie->dbi_res.start); + compat, pcie_rc->dbi_res.start); #endif if (nodeoffset < 0) return; @@ -168,7 +174,7 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, static void fdt_fixup_pcie_ls(void *blob) { struct udevice *dev, *bus; - struct ls_pcie *pcie; + struct ls_pcie_rc *pcie_rc; int streamid; int index; pci_dev_t bdf; @@ -179,17 +185,18 @@ static void fdt_fixup_pcie_ls(void *blob) pci_find_next_device(&dev)) { for (bus = dev; device_is_on_pci_bus(bus);) bus = bus->parent; - pcie = dev_get_priv(bus); + pcie_rc = dev_get_priv(bus);
- streamid = pcie_next_streamid(pcie->stream_id_cur, pcie->idx); + streamid = pcie_next_streamid(pcie_rc->stream_id_cur, + pcie_rc->pcie->idx); if (streamid < 0) { debug("ERROR: no stream ids free\n"); continue; } else { - pcie->stream_id_cur++; + pcie_rc->stream_id_cur++; }
- index = ls_pcie_next_lut_index(pcie); + index = ls_pcie_next_lut_index(pcie_rc); if (index < 0) { debug("ERROR: no LUT indexes free\n"); continue; @@ -198,27 +205,28 @@ static void fdt_fixup_pcie_ls(void *blob) /* 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_lut_set_mapping(pcie, index, bdf >> 8, + ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8, streamid); /* update msi-map in device tree */ - fdt_pcie_set_msi_map_entry_ls(blob, pcie, bdf >> 8, + fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid); /* update iommu-map in device tree */ - fdt_pcie_set_iommu_map_entry_ls(blob, pcie, bdf >> 8, + fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid); } pcie_board_fix_fdt(blob); } #endif
-static void ft_pcie_rc_fix(void *blob, struct ls_pcie *pcie) +static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc) { int off; uint svr; char *compat = NULL; + struct ls_pcie *pcie = pcie_rc->pcie;
off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (off < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -230,46 +238,47 @@ static void ft_pcie_rc_fix(void *blob, struct ls_pcie *pcie) compat = CONFIG_FSL_PCIE_COMPAT; if (compat) off = fdt_node_offset_by_compat_reg(blob, - compat, pcie->dbi_res.start); + compat, pcie_rc->dbi_res.start); #endif if (off < 0) return; }
- if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE) + if (pcie_rc->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_ep_fix(void *blob, struct ls_pcie *pcie) +static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc) { int off; + struct ls_pcie *pcie = pcie_rc->pcie;
off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_EP_COMPAT, - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (off < 0) return;
- if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL) + if (pcie_rc->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_ls_setup(void *blob, struct ls_pcie *pcie) +static void ft_pcie_ls_setup(void *blob, struct ls_pcie_rc *pcie_rc) { - ft_pcie_ep_fix(blob, pcie); - ft_pcie_rc_fix(blob, pcie); + ft_pcie_ep_fix(blob, pcie_rc); + ft_pcie_rc_fix(blob, pcie_rc); }
/* Fixup Kernel DT for PCIe */ void ft_pci_setup_ls(void *blob, bd_t *bd) { - struct ls_pcie *pcie; + struct ls_pcie_rc *pcie_rc;
- list_for_each_entry(pcie, &ls_pcie_list, list) - ft_pcie_ls_setup(blob, pcie); + list_for_each_entry(pcie_rc, &ls_pcie_list, list) + ft_pcie_ls_setup(blob, pcie_rc);
#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) fdt_fixup_pcie_ls(blob); diff --git a/drivers/pci/pcie_layerscape_rc.c b/drivers/pci/pcie_layerscape_rc.c new file mode 100644 index 0000000..927722d --- /dev/null +++ b/drivers/pci/pcie_layerscape_rc.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * Layerscape PCIe driver + */ + +#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> +#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \ + defined(CONFIG_ARM) +#include <asm/arch/clock.h> +#endif +#include "pcie_layerscape.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void ls_pcie_cfg0_set_busdev(struct ls_pcie_rc *pcie_rc, u32 busdev) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, + PCIE_ATU_VIEWPORT); + dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); +} + +static void ls_pcie_cfg1_set_busdev(struct ls_pcie_rc *pcie_rc, u32 busdev) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, + PCIE_ATU_VIEWPORT); + dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); +} + +static void ls_pcie_setup_atu(struct ls_pcie_rc *pcie_rc) +{ + struct pci_region *io, *mem, *pref; + unsigned long long offset = 0; + struct ls_pcie *pcie = pcie_rc->pcie; + int idx = 0; + uint svr; + + svr = get_svr(); + if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) == SVR_LS102XA) { + offset = LS1021_PCIE_SPACE_OFFSET + + LS1021_PCIE_SPACE_SIZE * pcie->idx; + } + + /* ATU 0 : OUTBOUND : CFG0 */ + ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_CFG0, + pcie_rc->cfg_res.start + offset, + 0, + fdt_resource_size(&pcie_rc->cfg_res) / 2); + /* ATU 1 : OUTBOUND : CFG1 */ + ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_CFG1, + pcie_rc->cfg_res.start + offset + + fdt_resource_size(&pcie_rc->cfg_res) / 2, + 0, + fdt_resource_size(&pcie_rc->cfg_res) / 2); + + pci_get_regions(pcie_rc->bus, &io, &mem, &pref); + idx = PCIE_ATU_REGION_INDEX1 + 1; + + /* Fix the pcie memory map for LS2088A series SoCs */ + svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; + if (svr == SVR_LS2088A || svr == SVR_LS2084A || + svr == SVR_LS2048A || svr == SVR_LS2044A || + svr == SVR_LS2081A || svr == SVR_LS2041A) { + if (io) + io->phys_start = (io->phys_start & + (PCIE_PHYS_SIZE - 1)) + + LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + if (mem) + mem->phys_start = (mem->phys_start & + (PCIE_PHYS_SIZE - 1)) + + LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + if (pref) + pref->phys_start = (pref->phys_start & + (PCIE_PHYS_SIZE - 1)) + + LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + } + + if (io) + /* ATU : OUTBOUND : IO */ + ls_pcie_atu_outbound_set(pcie, idx++, + PCIE_ATU_TYPE_IO, + io->phys_start + offset, + io->bus_start, + io->size); + + if (mem) + /* ATU : OUTBOUND : MEM */ + ls_pcie_atu_outbound_set(pcie, idx++, + PCIE_ATU_TYPE_MEM, + mem->phys_start + offset, + mem->bus_start, + mem->size); + + if (pref) + /* ATU : OUTBOUND : pref */ + ls_pcie_atu_outbound_set(pcie, idx++, + PCIE_ATU_TYPE_MEM, + pref->phys_start + offset, + pref->bus_start, + pref->size); + + ls_pcie_dump_atu(pcie); +} + +/* Return 0 if the address is valid, -errno if not valid */ +static int ls_pcie_addr_valid(struct ls_pcie_rc *pcie_rc, pci_dev_t bdf) +{ + struct udevice *bus = pcie_rc->bus; + struct ls_pcie *pcie = pcie_rc->pcie; + + if (pcie->mode == PCI_HEADER_TYPE_NORMAL) + return -ENODEV; + + if (!pcie_rc->enabled) + return -ENXIO; + + if (PCI_BUS(bdf) < bus->seq) + return -EINVAL; + + if ((PCI_BUS(bdf) > bus->seq) && (!ls_pcie_link_up(pcie))) + return -EINVAL; + + if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0)) + return -EINVAL; + + return 0; +} + +int ls_pcie_conf_address(struct udevice *bus, pci_dev_t bdf, + uint offset, void **paddress) +{ + struct ls_pcie_rc *pcie_rc = dev_get_priv(bus); + struct ls_pcie *pcie = pcie_rc->pcie; + u32 busdev; + + if (ls_pcie_addr_valid(pcie_rc, bdf)) + return -EINVAL; + + if (PCI_BUS(bdf) == bus->seq) { + *paddress = pcie->dbi + offset; + return 0; + } + + busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - bus->seq) | + PCIE_ATU_DEV(PCI_DEV(bdf)) | + PCIE_ATU_FUNC(PCI_FUNC(bdf)); + + if (PCI_BUS(bdf) == bus->seq + 1) { + ls_pcie_cfg0_set_busdev(pcie_rc, busdev); + *paddress = pcie_rc->cfg0 + offset; + } else { + ls_pcie_cfg1_set_busdev(pcie_rc, busdev); + *paddress = pcie_rc->cfg1 + offset; + } + return 0; +} + +static int ls_pcie_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + return pci_generic_mmap_read_config(bus, ls_pcie_conf_address, + bdf, offset, valuep, size); +} + +static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + return pci_generic_mmap_write_config(bus, ls_pcie_conf_address, + bdf, offset, value, size); +} + +/* Clear multi-function bit */ +static void ls_pcie_clear_multifunction(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + writeb(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE); +} + +/* Fix class value */ +static void ls_pcie_fix_class(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + writew(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE); +} + +/* Drop MSG TLP except for Vendor MSG */ +static void ls_pcie_drop_msg_tlp(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + u32 val; + + val = dbi_readl(pcie, PCIE_STRFMR1); + val &= 0xDFFFFFFF; + dbi_writel(pcie, val, PCIE_STRFMR1); +} + +/* Disable all bars in RC mode */ +static void ls_pcie_disable_bars(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_0); + dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_1); + dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1); +} + +static void ls_pcie_setup_ctrl(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + ls_pcie_setup_atu(pcie_rc); + + ls_pcie_dbi_ro_wr_en(pcie); + ls_pcie_fix_class(pcie_rc); + ls_pcie_clear_multifunction(pcie_rc); + ls_pcie_drop_msg_tlp(pcie_rc); + ls_pcie_dbi_ro_wr_dis(pcie); + + ls_pcie_disable_bars(pcie_rc); + pcie_rc->stream_id_cur = 0; +} + +static int ls_pcie_probe(struct udevice *dev) +{ + struct ls_pcie_rc *pcie_rc = dev_get_priv(dev); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + struct ls_pcie *pcie; + u16 link_sta; + uint svr; + int ret; + fdt_size_t cfg_size; + + pcie_rc->bus = dev; + + pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie_rc->pcie = pcie; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "dbi", &pcie_rc->dbi_res); + if (ret) { + printf("ls-pcie: resource "dbi" not found\n"); + return ret; + } + + pcie->idx = (pcie_rc->dbi_res.start - PCIE_SYS_BASE_ADDR) / + PCIE_CCSR_SIZE; + + list_add(&pcie_rc->list, &ls_pcie_list); + + pcie_rc->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx)); + if (!pcie_rc->enabled) { + printf("PCIe%d: %s disabled\n", pcie->idx, dev->name); + return 0; + } + + pcie->dbi = map_physmem(pcie_rc->dbi_res.start, + fdt_resource_size(&pcie_rc->dbi_res), + MAP_NOCACHE); + + pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; + if (pcie->mode == PCI_HEADER_TYPE_NORMAL) + return 0; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "lut", &pcie_rc->lut_res); + if (!ret) + pcie->lut = map_physmem(pcie_rc->lut_res.start, + fdt_resource_size(&pcie_rc->lut_res), + MAP_NOCACHE); + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "ctrl", &pcie_rc->ctrl_res); + if (!ret) + pcie->ctrl = map_physmem(pcie_rc->ctrl_res.start, + fdt_resource_size(&pcie_rc->ctrl_res), + MAP_NOCACHE); + if (!pcie->ctrl) + pcie->ctrl = pcie->lut; + + if (!pcie->ctrl) { + printf("%s: NOT find CTRL\n", dev->name); + return -1; + } + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "config", &pcie_rc->cfg_res); + if (ret) { + printf("%s: resource "config" not found\n", dev->name); + return ret; + } + + /* + * Fix the pcie memory map address and PF control registers address + * for LS2088A series SoCs + */ + svr = get_svr(); + svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; + if (svr == SVR_LS2088A || svr == SVR_LS2084A || + svr == SVR_LS2048A || svr == SVR_LS2044A || + svr == SVR_LS2081A || svr == SVR_LS2041A) { + cfg_size = fdt_resource_size(&pcie_rc->cfg_res); + pcie_rc->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + pcie_rc->cfg_res.end = pcie_rc->cfg_res.start + cfg_size; + pcie->ctrl = pcie->lut + 0x40000; + } + + pcie_rc->cfg0 = map_physmem(pcie_rc->cfg_res.start, + fdt_resource_size(&pcie_rc->cfg_res), + MAP_NOCACHE); + pcie_rc->cfg1 = pcie_rc->cfg0 + + fdt_resource_size(&pcie_rc->cfg_res) / 2; + + pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian"); + + debug("%s dbi:%lx lut:%lx ctrl:0x%lx cfg0:0x%lx, big-endian:%d\n", + dev->name, (unsigned long)pcie->dbi, (unsigned long)pcie->lut, + (unsigned long)pcie->ctrl, (unsigned long)pcie_rc->cfg0, + pcie->big_endian); + + printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex"); + ls_pcie_setup_ctrl(pcie_rc); + + if (!ls_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_sta = readw(pcie->dbi + PCIE_LINK_STA); + printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4, + link_sta & PCIE_LINK_SPEED_MASK); + + return 0; +} + +static const struct dm_pci_ops ls_pcie_ops = { + .read_config = ls_pcie_read_config, + .write_config = ls_pcie_write_config, +}; + +static const struct udevice_id ls_pcie_ids[] = { + { .compatible = "fsl,ls-pcie" }, + { } +}; + +U_BOOT_DRIVER(pci_layerscape) = { + .name = "pci_layerscape", + .id = UCLASS_PCI, + .of_match = ls_pcie_ids, + .ops = &ls_pcie_ops, + .probe = ls_pcie_probe, + .priv_auto_alloc_size = sizeof(struct ls_pcie_rc), +};

Some EP deivces need to initialize before RC scan it, e.g. NXP layerscape platform, so add the init function in pci_ep uclass.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- common/board_r.c | 12 ++++++++++++ drivers/pci_endpoint/pci_ep-uclass.c | 11 +++++++++++ include/init.h | 1 + 3 files changed, 24 insertions(+)
diff --git a/common/board_r.c b/common/board_r.c index 0bbeaa7..856b47f 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -229,6 +229,15 @@ static int initr_unlock_ram_in_cache(void) } #endif
+#ifdef CONFIG_PCI_ENDPOINT +static int initr_pci_ep(void) +{ + pci_ep_init(); + + return 0; +} +#endif + #ifdef CONFIG_PCI static int initr_pci(void) { @@ -839,6 +848,9 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif +#ifdef CONFIG_PCI_ENDPOINT + initr_pci_ep, +#endif #ifdef CONFIG_CMD_NET INIT_FUNC_WATCHDOG_RESET initr_net, diff --git a/drivers/pci_endpoint/pci_ep-uclass.c b/drivers/pci_endpoint/pci_ep-uclass.c index 9f53a9a..38a5f08 100644 --- a/drivers/pci_endpoint/pci_ep-uclass.c +++ b/drivers/pci_endpoint/pci_ep-uclass.c @@ -209,3 +209,14 @@ UCLASS_DRIVER(pci_ep) = { .name = "pci_ep", .flags = DM_UC_FLAG_SEQ_ALIAS, }; + +void pci_ep_init(void) +{ + struct udevice *dev; + + for (uclass_first_device_check(UCLASS_PCI_EP, &dev); + dev; + uclass_next_device_check(&dev)) { + ; + } +} diff --git a/include/init.h b/include/init.h index 2a33a3f..fbc26a8 100644 --- a/include/init.h +++ b/include/init.h @@ -202,6 +202,7 @@ int set_cpu_clk_info(void); int update_flash_size(int flash_size); int arch_early_init_r(void); void pci_init(void); +void pci_ep_init(void); int misc_init_r(void); #if defined(CONFIG_VID) int init_func_vid(void);

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 2/9] pci_ep: Add the init function
Some EP deivces need to initialize before RC scan it, e.g. NXP layerscape platform, so add the init function in pci_ep uclass.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
common/board_r.c | 12 ++++++++++++ drivers/pci_endpoint/pci_ep-uclass.c | 11 +++++++++++ include/init.h | 1 + 3 files changed, 24 insertions(+)
diff --git a/common/board_r.c b/common/board_r.c index 0bbeaa7..856b47f 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -229,6 +229,15 @@ static int initr_unlock_ram_in_cache(void) } #endif
+#ifdef CONFIG_PCI_ENDPOINT +static int initr_pci_ep(void) +{
- pci_ep_init();
- return 0;
+} +#endif
#ifdef CONFIG_PCI static int initr_pci(void) { @@ -839,6 +848,9 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BITBANGMII initr_bbmii, #endif +#ifdef CONFIG_PCI_ENDPOINT
- initr_pci_ep,
+#endif #ifdef CONFIG_CMD_NET INIT_FUNC_WATCHDOG_RESET initr_net, diff --git a/drivers/pci_endpoint/pci_ep-uclass.c b/drivers/pci_endpoint/pci_ep-uclass.c index 9f53a9a..38a5f08 100644 --- a/drivers/pci_endpoint/pci_ep-uclass.c +++ b/drivers/pci_endpoint/pci_ep-uclass.c @@ -209,3 +209,14 @@ UCLASS_DRIVER(pci_ep) = { .name = "pci_ep", .flags = DM_UC_FLAG_SEQ_ALIAS, };
+void pci_ep_init(void) +{
- struct udevice *dev;
- for (uclass_first_device_check(UCLASS_PCI_EP, &dev);
dev;
uclass_next_device_check(&dev)) {
;
- }
+} diff --git a/include/init.h b/include/init.h index 2a33a3f..fbc26a8 100644 --- a/include/init.h +++ b/include/init.h @@ -202,6 +202,7 @@ int set_cpu_clk_info(void); int update_flash_size(int flash_size); int arch_early_init_r(void); void pci_init(void); +void pci_ep_init(void); int misc_init_r(void); #if defined(CONFIG_VID) int init_func_vid(void); -- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

Add the PCIe EP node for ls1046a.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- arch/arm/dts/fsl-ls1046a.dtsi | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/arch/arm/dts/fsl-ls1046a.dtsi b/arch/arm/dts/fsl-ls1046a.dtsi index fdf93fd..e4b4a8e 100644 --- a/arch/arm/dts/fsl-ls1046a.dtsi +++ b/arch/arm/dts/fsl-ls1046a.dtsi @@ -259,6 +259,17 @@ 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ };
+ pcie_ep@3400000 { + compatible = "fsl,ls-pcie-ep"; + reg = <0x00 0x03400000 0x0 0x80000 + 0x00 0x034c0000 0x0 0x40000 + 0x40 0x00000000 0x8 0x00000000>; + reg-names = "regs", "ctrl", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <8>; + big-endian; + }; + pcie@3500000 { compatible = "fsl,ls-pcie", "snps,dw-pcie"; reg = <0x00 0x03500000 0x0 0x80000 /* dbi registers */ @@ -276,6 +287,17 @@ 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ };
+ pcie_ep@3500000 { + compatible = "fsl,ls-pcie-ep"; + reg = <0x00 0x03500000 0x0 0x80000 + 0x00 0x035c0000 0x0 0x40000 + 0x48 0x00000000 0x8 0x00000000>; + reg-names = "regs", "ctrl", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <8>; + big-endian; + }; + pcie@3600000 { compatible = "fsl,ls-pcie", "snps,dw-pcie"; reg = <0x00 0x03600000 0x0 0x80000 /* dbi registers */ @@ -292,6 +314,17 @@ 0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ };
+ pcie_ep@3600000 { + compatible = "fsl,ls-pcie-ep"; + reg = <0x00 0x03600000 0x0 0x80000 + 0x00 0x036c0000 0x0 0x40000 + 0x50 0x00000000 0x8 0x00000000>; + reg-names = "regs", "ctrl", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <8>; + big-endian; + }; + sata: sata@3200000 { compatible = "fsl,ls1046a-ahci"; reg = <0x0 0x3200000 0x0 0x10000 /* ccsr sata base */

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 3/9] armv8: dts: ls1046a: Add the PCIe EP node
Add the PCIe EP node for ls1046a.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
arch/arm/dts/fsl-ls1046a.dtsi | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/arch/arm/dts/fsl-ls1046a.dtsi b/arch/arm/dts/fsl-ls1046a.dtsi index fdf93fd..e4b4a8e 100644 --- a/arch/arm/dts/fsl-ls1046a.dtsi +++ b/arch/arm/dts/fsl-ls1046a.dtsi @@ -259,6 +259,17 @@ 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ };
pcie_ep@3400000 {
compatible = "fsl,ls-pcie-ep";
reg = <0x00 0x03400000 0x0 0x80000
0x00 0x034c0000 0x0 0x40000
0x40 0x00000000 0x8 0x00000000>;
reg-names = "regs", "ctrl", "addr_space";
num-ib-windows = <6>;
num-ob-windows = <8>;
big-endian;
};
- pcie@3500000 { compatible = "fsl,ls-pcie", "snps,dw-pcie"; reg = <0x00 0x03500000 0x0 0x80000 /* dbi registers */
@@ -276,6 +287,17 @@ 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ };
pcie_ep@3500000 {
compatible = "fsl,ls-pcie-ep";
reg = <0x00 0x03500000 0x0 0x80000
0x00 0x035c0000 0x0 0x40000
0x48 0x00000000 0x8 0x00000000>;
reg-names = "regs", "ctrl", "addr_space";
num-ib-windows = <6>;
num-ob-windows = <8>;
big-endian;
};
- pcie@3600000 { compatible = "fsl,ls-pcie", "snps,dw-pcie"; reg = <0x00 0x03600000 0x0 0x80000 /* dbi registers */
@@ -292,6 +314,17 @@ 0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ };
pcie_ep@3600000 {
compatible = "fsl,ls-pcie-ep";
reg = <0x00 0x03600000 0x0 0x80000
0x00 0x036c0000 0x0 0x40000
0x50 0x00000000 0x8 0x00000000>;
reg-names = "regs", "ctrl", "addr_space";
num-ib-windows = <6>;
num-ob-windows = <8>;
big-endian;
};
- sata: sata@3200000 { compatible = "fsl,ls1046a-ahci"; reg = <0x0 0x3200000 0x0 0x10000 /* ccsr sata base */
-- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

Add the multiple function support for Layerscape platform, some PEXs of Layerscaple platform have more than one PF.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- drivers/pci/pcie_layerscape.c | 6 +- drivers/pci/pcie_layerscape.h | 21 +++++-- drivers/pci/pcie_layerscape_ep.c | 119 ++++++++++++++++++++++++++------------- 3 files changed, 98 insertions(+), 48 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 3ca75c5..88a0e8a 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -104,13 +104,13 @@ void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, }
/* Use bar match mode and MEM type as default */ -void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type, - int bar, u64 phys) +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type, + int idx, int bar, u64 phys) { dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET); dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET); - dbi_writel(pcie, type, PCIE_ATU_CR1); + dbi_writel(pcie, type | PCIE_ATU_FUNC_NUM(pf), PCIE_ATU_CR1); dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); } diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 217dcda..dabfff3 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -9,6 +9,7 @@ #define _PCIE_LAYERSCAPE_H_ #include <pci.h> #include <dm.h> +#include <linux/sizes.h>
#ifndef CONFIG_SYS_PCI_MEMORY_BUS #define CONFIG_SYS_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE @@ -44,6 +45,7 @@ #define PCIE_ATU_TYPE_IO (0x2 << 0) #define PCIE_ATU_TYPE_CFG0 (0x4 << 0) #define PCIE_ATU_TYPE_CFG1 (0x5 << 0) +#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20) #define PCIE_ATU_CR2 0x908 #define PCIE_ATU_ENABLE (0x1 << 31) #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) @@ -86,11 +88,16 @@ #define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */ #define PCIE_PF_NUM 2 #define PCIE_VF_NUM 64 +#define BAR_NUM 4
-#define PCIE_BAR0_SIZE (4 * 1024) /* 4K */ -#define PCIE_BAR1_SIZE (8 * 1024) /* 8K for MSIX */ -#define PCIE_BAR2_SIZE (4 * 1024) /* 4K */ -#define PCIE_BAR4_SIZE (1 * 1024 * 1024) /* 1M */ +#define PCIE_BAR0_SIZE SZ_4K +#define PCIE_BAR1_SIZE SZ_8K +#define PCIE_BAR2_SIZE SZ_4K +#define PCIE_BAR4_SIZE SZ_1M + +#define PCIE_SRIOV_VFBAR0 0x19C + +#define PCIE_MASK_OFFSET(flag, pf) ((flag) ? 0 : (0x1000 + 0x20000 * (pf)))
/* LUT registers */ #define PCIE_LUT_UDR(n) (0x800 + (n) * 8) @@ -158,6 +165,8 @@ struct ls_pcie_ep { struct ls_pcie *pcie; struct udevice *bus; void __iomem *addr; + u32 cfg2_flag; + u32 sriov_flag; u32 num_ib_wins; u32 num_ob_wins; u8 max_functions; @@ -171,8 +180,8 @@ unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset); void ctrl_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, u64 phys, u64 bus_addr, pci_size_t size); -void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type, - int bar, u64 phys); +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type, + int idx, int bar, u64 phys); void ls_pcie_dump_atu(struct ls_pcie *pcie); int ls_pcie_link_up(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index 8d0c99a..bec374b 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -45,7 +45,7 @@ static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar) else type = PCIE_ATU_TYPE_IO;
- ls_pcie_atu_inbound_set(pcie, idx, bar, bar_phys, type); + ls_pcie_atu_inbound_set(pcie, fn, type, idx, bar, bar_phys);
dbi_writel(pcie, lower_32_bits(size - 1), reg + PCIE_NO_SRIOV_BAR_BASE); dbi_writel(pcie, flags, reg); @@ -63,51 +63,61 @@ static struct pci_ep_ops ls_pcie_ep_ops = { .set_bar = ls_ep_set_bar, };
-static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep) +static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep, u32 pf) { struct ls_pcie *pcie = pcie_ep->pcie; - u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE; + u64 phys = 0;
+ phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + pf * SZ_64M; + + phys = ALIGN(phys, PCIE_BAR0_SIZE); /* ATU 0 : INBOUND : map BAR0 */ - ls_pcie_atu_inbound_set(pcie, 0, PCIE_ATU_TYPE_MEM, 0, phys); + ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + 0 + pf * BAR_NUM, 0, phys); /* ATU 1 : INBOUND : map BAR1 */ - phys += PCIE_BAR1_SIZE; - ls_pcie_atu_inbound_set(pcie, 1, PCIE_ATU_TYPE_MEM, 1, phys); + phys = ALIGN(phys + PCIE_BAR0_SIZE, PCIE_BAR1_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + 1 + pf * BAR_NUM, 1, phys); /* ATU 2 : INBOUND : map BAR2 */ - phys += PCIE_BAR2_SIZE; - ls_pcie_atu_inbound_set(pcie, 2, PCIE_ATU_TYPE_MEM, 2, phys); - /* ATU 3 : INBOUND : map BAR4 */ - phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE; - ls_pcie_atu_inbound_set(pcie, 3, PCIE_ATU_TYPE_MEM, 4, phys); - - /* ATU 0 : OUTBOUND : map MEM */ - ls_pcie_atu_outbound_set(pcie, 0, - PCIE_ATU_TYPE_MEM, - pcie_ep->addr_res.start, - 0, - CONFIG_SYS_PCI_MEMORY_SIZE); + phys = ALIGN(phys + PCIE_BAR1_SIZE, PCIE_BAR2_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + 2 + pf * BAR_NUM, 2, phys); + /* ATU 3 : INBOUND : map BAR2 */ + phys = ALIGN(phys + PCIE_BAR2_SIZE, PCIE_BAR4_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + 3 + pf * BAR_NUM, 4, phys); + + /* ATU: OUTBOUND : map MEM */ + ls_pcie_atu_outbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + (u64)pcie_ep->addr_res.start + + pf * CONFIG_SYS_PCI_MEMORY_SIZE, + 0, CONFIG_SYS_PCI_MEMORY_SIZE); }
/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) { + u32 mask; + /* The least inbound window is 4KiB */ - if (size < 4 * 1024) - return; + if (size < SZ_4K) + mask = 0; + else + mask = size - 1;
switch (bar) { case 0: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_0); + writel(mask, bar_base + PCI_BASE_ADDRESS_0); break; case 1: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_1); + writel(mask, bar_base + PCI_BASE_ADDRESS_1); break; case 2: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_2); + writel(mask, bar_base + PCI_BASE_ADDRESS_2); writel(0, bar_base + PCI_BASE_ADDRESS_3); break; case 4: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_4); + writel(mask, bar_base + PCI_BASE_ADDRESS_4); writel(0, bar_base + PCI_BASE_ADDRESS_5); break; default: @@ -117,39 +127,62 @@ static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size)
static void ls_pcie_ep_setup_bars(void *bar_base) { - /* BAR0 - 32bit - 4K configuration */ + /* BAR0 - 32bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); + /* BAR1 - 32bit - MEM*/ + ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); + /* BAR2 - 64bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); + /* BAR4 - 64bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); +} + +static void ls_pcie_ep_setup_vf_bars(void *bar_base) +{ + /* VF BAR0 MASK register at offset 0x19c*/ + bar_base += PCIE_SRIOV_VFBAR0 - PCI_BASE_ADDRESS_0; + + /* VF-BAR0 - 32bit - MEM */ ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); - /* BAR1 - 32bit - 8K MSIX */ + /* VF-BAR1 - 32bit - MEM*/ ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); - /* BAR2 - 64bit - 4K MEM descriptor */ + /* VF-BAR2 - 64bit - MEM */ ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); - /* BAR4 - 64bit - 1M MEM */ + /* VF-BAR4 - 64bit - MEM */ ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); }
static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) { u32 sriov; + u32 pf, vf; + void *bar_base = NULL; struct ls_pcie *pcie = pcie_ep->pcie;
sriov = readl(pcie->dbi + PCIE_SRIOV); if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) { - int pf, vf; - + pcie_ep->sriov_flag = 1; for (pf = 0; pf < PCIE_PF_NUM; pf++) { - for (vf = 0; vf <= PCIE_VF_NUM; vf++) { - ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf), - PCIE_PF_VF_CTRL); - - ls_pcie_ep_setup_bars(pcie->dbi); - ls_pcie_ep_setup_atu(pcie_ep); + if (pcie_ep->cfg2_flag) { + for (vf = 0; vf <= PCIE_VF_NUM; vf++) { + ctrl_writel(pcie, + PCIE_LCTRL0_VAL(pf, vf), + PCIE_PF_VF_CTRL); + } } + bar_base = pcie->dbi + + PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf); + ls_pcie_ep_setup_bars(bar_base); + ls_pcie_ep_setup_vf_bars(bar_base); + + ls_pcie_ep_setup_atu(pcie_ep, pf); } - /* Disable CFG2 */ - ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL); + + if (pcie_ep->cfg2_flag) /* Disable CFG2 */ + ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL); } else { ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE); - ls_pcie_ep_setup_atu(pcie_ep); + ls_pcie_ep_setup_atu(pcie_ep, 0); }
ls_pcie_ep_enable_cfg(pcie_ep); @@ -161,6 +194,7 @@ static int ls_pcie_ep_probe(struct udevice *dev) struct ls_pcie *pcie; u16 link_sta; int ret; + u32 svr;
pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie) @@ -190,6 +224,13 @@ static int ls_pcie_ep_probe(struct udevice *dev) pcie->big_endian = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), "big-endian");
+ svr = SVR_SOC_VER(get_svr()); + + if (svr == SVR_LS2080A || svr == SVR_LS2085A) + pcie_ep->cfg2_flag = 1; + else + pcie_ep->cfg2_flag = 0; + pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; if (pcie->mode != PCI_HEADER_TYPE_NORMAL) return 0;

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 4/9] PCI_EP: layerscape: Add the multiple function supprot
Add the multiple function support for Layerscape platform, some PEXs of Layerscaple platform have more than one PF.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/pcie_layerscape.c | 6 +- drivers/pci/pcie_layerscape.h | 21 +++++-- drivers/pci/pcie_layerscape_ep.c | 119 ++++++++++++++++++++++++++------------- 3 files changed, 98 insertions(+), 48 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 3ca75c5..88a0e8a 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -104,13 +104,13 @@ void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, }
/* Use bar match mode and MEM type as default */ -void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type,
int bar, u64 phys)
+void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type,
int idx, int bar, u64 phys)
{ dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET); dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET);
- dbi_writel(pcie, type, PCIE_ATU_CR1);
- dbi_writel(pcie, type | PCIE_ATU_FUNC_NUM(pf), PCIE_ATU_CR1); dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); } diff --git
a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 217dcda..dabfff3 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -9,6 +9,7 @@ #define _PCIE_LAYERSCAPE_H_ #include <pci.h> #include <dm.h> +#include <linux/sizes.h>
#ifndef CONFIG_SYS_PCI_MEMORY_BUS #define CONFIG_SYS_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE @@ -44,6 +45,7 @@ #define PCIE_ATU_TYPE_IO (0x2 << 0) #define PCIE_ATU_TYPE_CFG0 (0x4 << 0) #define PCIE_ATU_TYPE_CFG1 (0x5 << 0) +#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20) #define PCIE_ATU_CR2 0x908 #define PCIE_ATU_ENABLE (0x1 << 31) #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) @@ -86,11 +88,16 @@ #define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */ #define PCIE_PF_NUM 2 #define PCIE_VF_NUM 64 +#define BAR_NUM 4
-#define PCIE_BAR0_SIZE (4 * 1024) /* 4K */ -#define PCIE_BAR1_SIZE (8 * 1024) /* 8K for MSIX */ -#define PCIE_BAR2_SIZE (4 * 1024) /* 4K */ -#define PCIE_BAR4_SIZE (1 * 1024 * 1024) /* 1M */ +#define PCIE_BAR0_SIZE SZ_4K +#define PCIE_BAR1_SIZE SZ_8K +#define PCIE_BAR2_SIZE SZ_4K +#define PCIE_BAR4_SIZE SZ_1M
+#define PCIE_SRIOV_VFBAR0 0x19C
+#define PCIE_MASK_OFFSET(flag, pf) ((flag) ? 0 : (0x1000 + 0x20000 * +(pf)))
/* LUT registers */ #define PCIE_LUT_UDR(n) (0x800 + (n) * 8) @@ -158,6 +165,8 @@ struct ls_pcie_ep { struct ls_pcie *pcie; struct udevice *bus; void __iomem *addr;
- u32 cfg2_flag;
- u32 sriov_flag; u32 num_ib_wins; u32 num_ob_wins; u8 max_functions;
@@ -171,8 +180,8 @@ unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset); void ctrl_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, u64 phys, u64 bus_addr, pci_size_t size); -void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type,
int bar, u64 phys);
+void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type,
int idx, int bar, u64 phys);
void ls_pcie_dump_atu(struct ls_pcie *pcie); int ls_pcie_link_up(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index 8d0c99a..bec374b 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -45,7 +45,7 @@ static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar) else type = PCIE_ATU_TYPE_IO;
- ls_pcie_atu_inbound_set(pcie, idx, bar, bar_phys, type);
ls_pcie_atu_inbound_set(pcie, fn, type, idx, bar, bar_phys);
dbi_writel(pcie, lower_32_bits(size - 1), reg +
PCIE_NO_SRIOV_BAR_BASE); dbi_writel(pcie, flags, reg); @@ -63,51 +63,61 @@ static struct pci_ep_ops ls_pcie_ep_ops = { .set_bar = ls_ep_set_bar, };
-static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep) +static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep, u32 pf) { struct ls_pcie *pcie = pcie_ep->pcie;
- u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE;
u64 phys = 0;
phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + pf * SZ_64M;
phys = ALIGN(phys, PCIE_BAR0_SIZE); /* ATU 0 : INBOUND : map BAR0 */
- ls_pcie_atu_inbound_set(pcie, 0, PCIE_ATU_TYPE_MEM, 0, phys);
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
/* ATU 1 : INBOUND : map BAR1 */0 + pf * BAR_NUM, 0, phys);
- phys += PCIE_BAR1_SIZE;
- ls_pcie_atu_inbound_set(pcie, 1, PCIE_ATU_TYPE_MEM, 1, phys);
- phys = ALIGN(phys + PCIE_BAR0_SIZE, PCIE_BAR1_SIZE);
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
/* ATU 2 : INBOUND : map BAR2 */1 + pf * BAR_NUM, 1, phys);
- phys += PCIE_BAR2_SIZE;
- ls_pcie_atu_inbound_set(pcie, 2, PCIE_ATU_TYPE_MEM, 2, phys);
- /* ATU 3 : INBOUND : map BAR4 */
- phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE;
- ls_pcie_atu_inbound_set(pcie, 3, PCIE_ATU_TYPE_MEM, 4, phys);
- /* ATU 0 : OUTBOUND : map MEM */
- ls_pcie_atu_outbound_set(pcie, 0,
PCIE_ATU_TYPE_MEM,
pcie_ep->addr_res.start,
0,
CONFIG_SYS_PCI_MEMORY_SIZE);
- phys = ALIGN(phys + PCIE_BAR1_SIZE, PCIE_BAR2_SIZE);
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
2 + pf * BAR_NUM, 2, phys);
- /* ATU 3 : INBOUND : map BAR2 */
- phys = ALIGN(phys + PCIE_BAR2_SIZE, PCIE_BAR4_SIZE);
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
3 + pf * BAR_NUM, 4, phys);
- /* ATU: OUTBOUND : map MEM */
- ls_pcie_atu_outbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
(u64)pcie_ep->addr_res.start +
pf * CONFIG_SYS_PCI_MEMORY_SIZE,
0, CONFIG_SYS_PCI_MEMORY_SIZE);
}
/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) {
- u32 mask;
- /* The least inbound window is 4KiB */
- if (size < 4 * 1024)
return;
if (size < SZ_4K)
mask = 0;
else
mask = size - 1;
switch (bar) { case 0:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_0);
break; case 1:writel(mask, bar_base + PCI_BASE_ADDRESS_0);
writel(size - 1, bar_base + PCI_BASE_ADDRESS_1);
break; case 2:writel(mask, bar_base + PCI_BASE_ADDRESS_1);
writel(size - 1, bar_base + PCI_BASE_ADDRESS_2);
writel(0, bar_base + PCI_BASE_ADDRESS_3); break; case 4:writel(mask, bar_base + PCI_BASE_ADDRESS_2);
writel(size - 1, bar_base + PCI_BASE_ADDRESS_4);
writel(0, bar_base + PCI_BASE_ADDRESS_5); break; default:writel(mask, bar_base + PCI_BASE_ADDRESS_4);
@@ -117,39 +127,62 @@ static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size)
static void ls_pcie_ep_setup_bars(void *bar_base) {
- /* BAR0 - 32bit - 4K configuration */
- /* BAR0 - 32bit - MEM */
- ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE);
- /* BAR1 - 32bit - MEM*/
- ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE);
- /* BAR2 - 64bit - MEM */
- ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE);
- /* BAR4 - 64bit - MEM */
- ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); }
+static void ls_pcie_ep_setup_vf_bars(void *bar_base) {
- /* VF BAR0 MASK register at offset 0x19c*/
- bar_base += PCIE_SRIOV_VFBAR0 - PCI_BASE_ADDRESS_0;
- /* VF-BAR0 - 32bit - MEM */ ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE);
- /* BAR1 - 32bit - 8K MSIX */
- /* VF-BAR1 - 32bit - MEM*/ ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE);
- /* BAR2 - 64bit - 4K MEM descriptor */
- /* VF-BAR2 - 64bit - MEM */ ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE);
- /* BAR4 - 64bit - 1M MEM */
- /* VF-BAR4 - 64bit - MEM */ ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); }
static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) { u32 sriov;
u32 pf, vf;
void *bar_base = NULL; struct ls_pcie *pcie = pcie_ep->pcie;
sriov = readl(pcie->dbi + PCIE_SRIOV); if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) {
int pf, vf;
for (pf = 0; pf < PCIE_PF_NUM; pf++) {pcie_ep->sriov_flag = 1;
for (vf = 0; vf <= PCIE_VF_NUM; vf++) {
ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf),
PCIE_PF_VF_CTRL);
ls_pcie_ep_setup_bars(pcie->dbi);
ls_pcie_ep_setup_atu(pcie_ep);
if (pcie_ep->cfg2_flag) {
for (vf = 0; vf <= PCIE_VF_NUM; vf++) {
ctrl_writel(pcie,
PCIE_LCTRL0_VAL(pf, vf),
PCIE_PF_VF_CTRL);
} }
bar_base = pcie->dbi +
PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf);
ls_pcie_ep_setup_bars(bar_base);
ls_pcie_ep_setup_vf_bars(bar_base);
}ls_pcie_ep_setup_atu(pcie_ep, pf);
/* Disable CFG2 */
ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL);
if (pcie_ep->cfg2_flag) /* Disable CFG2 */
} else { ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE);ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL);
ls_pcie_ep_setup_atu(pcie_ep);
ls_pcie_ep_setup_atu(pcie_ep, 0);
}
ls_pcie_ep_enable_cfg(pcie_ep);
@@ -161,6 +194,7 @@ static int ls_pcie_ep_probe(struct udevice *dev) struct ls_pcie *pcie; u16 link_sta; int ret;
u32 svr;
pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL); if (!pcie)
@@ -190,6 +224,13 @@ static int ls_pcie_ep_probe(struct udevice *dev) pcie->big_endian = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), "big-endian");
- svr = SVR_SOC_VER(get_svr());
- if (svr == SVR_LS2080A || svr == SVR_LS2085A)
pcie_ep->cfg2_flag = 1;
- else
pcie_ep->cfg2_flag = 0;
- pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; if (pcie->mode != PCI_HEADER_TYPE_NORMAL) return 0;
-- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

The VF_BARn_REG register's Prefetchable and Type bit fields are overwritten by a write to VF's BAR Mask register. workaround: Before writing to the VF_BARn_MASK_REG register, write 0b to the PCIE_MISC_CONTROL_1_OFF register.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- drivers/pci/pcie_layerscape_ep.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index bec374b..a2b18ad 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -163,6 +163,15 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) { pcie_ep->sriov_flag = 1; for (pf = 0; pf < PCIE_PF_NUM; pf++) { + /* + * The VF_BARn_REG register's Prefetchable and Type bit + * fields are overwritten by a write to VF's BAR Mask + * register. Before writing to the VF_BARn_MASK_REG + * register, write 0b to the PCIE_MISC_CONTROL_1_OFF + * register. + */ + writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF); + if (pcie_ep->cfg2_flag) { for (vf = 0; vf <= PCIE_VF_NUM; vf++) { ctrl_writel(pcie,

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 5/9] pci_ep: layerscape: Add the workaround for errata A-009460
The VF_BARn_REG register's Prefetchable and Type bit fields are overwritten by a write to VF's BAR Mask register. workaround: Before writing to the VF_BARn_MASK_REG register, write 0b to the PCIE_MISC_CONTROL_1_OFF register.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/pcie_layerscape_ep.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index bec374b..a2b18ad 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -163,6 +163,15 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) { pcie_ep->sriov_flag = 1; for (pf = 0; pf < PCIE_PF_NUM; pf++) {
/*
* The VF_BARn_REG register's Prefetchable and Type bit
* fields are overwritten by a write to VF's BAR Mask
* register. Before writing to the VF_BARn_MASK_REG
* register, write 0b to the PCIE_MISC_CONTROL_1_OFF
* register.
*/
writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF);
if (pcie_ep->cfg2_flag) { for (vf = 0; vf <= PCIE_VF_NUM; vf++) { ctrl_writel(pcie,
-- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

Due to the ls2085a and ls2080a use difference way to set the BAR size, so add the BAR size init code here.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- drivers/pci/pcie_layerscape_ep.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index a2b18ad..cd7ea26 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -172,17 +172,25 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) */ writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF);
+ bar_base = pcie->dbi + + PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf); + if (pcie_ep->cfg2_flag) { - for (vf = 0; vf <= PCIE_VF_NUM; vf++) { + ctrl_writel(pcie, + PCIE_LCTRL0_VAL(pf, 0), + PCIE_PF_VF_CTRL); + ls_pcie_ep_setup_bars(bar_base); + + for (vf = 1; vf <= PCIE_VF_NUM; vf++) { ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf), PCIE_PF_VF_CTRL); + ls_pcie_ep_setup_vf_bars(bar_base); } + } else { + ls_pcie_ep_setup_bars(bar_base); + ls_pcie_ep_setup_vf_bars(bar_base); } - bar_base = pcie->dbi + - PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf); - ls_pcie_ep_setup_bars(bar_base); - ls_pcie_ep_setup_vf_bars(bar_base);
ls_pcie_ep_setup_atu(pcie_ep, pf); }

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 6/9] pci_ep: layerscape: Add Support for ls2085a and ls2080a EP mode
Due to the ls2085a and ls2080a use difference way to set the BAR size, so add the BAR size init code here.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/pcie_layerscape_ep.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index a2b18ad..cd7ea26 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -172,17 +172,25 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) */ writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF);
bar_base = pcie->dbi +
PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf);
if (pcie_ep->cfg2_flag) {
for (vf = 0; vf <= PCIE_VF_NUM; vf++) {
ctrl_writel(pcie,
PCIE_LCTRL0_VAL(pf, 0),
PCIE_PF_VF_CTRL);
ls_pcie_ep_setup_bars(bar_base);
for (vf = 1; vf <= PCIE_VF_NUM; vf++) { ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf), PCIE_PF_VF_CTRL);
ls_pcie_ep_setup_vf_bars(bar_base); }
} else {
ls_pcie_ep_setup_bars(bar_base);
ls_pcie_ep_setup_vf_bars(bar_base); }
bar_base = pcie->dbi +
PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf);
ls_pcie_ep_setup_bars(bar_base);
ls_pcie_ep_setup_vf_bars(bar_base); ls_pcie_ep_setup_atu(pcie_ep, pf);
}
-- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

Add the INBOUND configuration for VFs of PF.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- drivers/pci/pcie_layerscape.c | 8 +++++--- drivers/pci/pcie_layerscape.h | 13 ++++++++----- drivers/pci/pcie_layerscape_ep.c | 34 +++++++++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 88a0e8a..c7a96ed 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -91,7 +91,7 @@ int ls_pcie_link_up(struct ls_pcie *pcie) }
void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, - u64 phys, u64 bus_addr, pci_size_t size) + u64 phys, u64 bus_addr, u64 size) { dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_BASE); @@ -104,14 +104,16 @@ void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, }
/* Use bar match mode and MEM type as default */ -void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type, - int idx, int bar, u64 phys) +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, + int type, int idx, int bar, u64 phys) { dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET); dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET); dbi_writel(pcie, type | PCIE_ATU_FUNC_NUM(pf), PCIE_ATU_CR1); dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | + (vf_flag ? PCIE_ATU_FUNC_NUM_MATCH_EN : 0) | + (vf_flag ? PCIE_ATU_VFBAR_MATCH_MODE_EN : 0) | PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); }
diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index dabfff3..26d0177 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -20,7 +20,7 @@ #endif
#ifndef CONFIG_SYS_PCI_MEMORY_SIZE -#define CONFIG_SYS_PCI_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) /* 2G */ +#define CONFIG_SYS_PCI_MEMORY_SIZE SZ_4G #endif
#ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE @@ -40,6 +40,7 @@ #define PCIE_ATU_REGION_INDEX2 (0x2 << 0) #define PCIE_ATU_REGION_INDEX3 (0x3 << 0) #define PCIE_ATU_REGION_NUM 6 +#define PCIE_ATU_REGION_NUM_SRIOV 24 #define PCIE_ATU_CR1 0x904 #define PCIE_ATU_TYPE_MEM (0x0 << 0) #define PCIE_ATU_TYPE_IO (0x2 << 0) @@ -49,6 +50,8 @@ #define PCIE_ATU_CR2 0x908 #define PCIE_ATU_ENABLE (0x1 << 31) #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) +#define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19) +#define PCIE_ATU_VFBAR_MATCH_MODE_EN BIT(26) #define PCIE_ATU_BAR_NUM(bar) ((bar) << 8) #define PCIE_ATU_LOWER_BASE 0x90C #define PCIE_ATU_UPPER_BASE 0x910 @@ -88,7 +91,7 @@ #define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */ #define PCIE_PF_NUM 2 #define PCIE_VF_NUM 64 -#define BAR_NUM 4 +#define BAR_NUM 8
#define PCIE_BAR0_SIZE SZ_4K #define PCIE_BAR1_SIZE SZ_8K @@ -179,9 +182,9 @@ void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset); void ctrl_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, - u64 phys, u64 bus_addr, pci_size_t size); -void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type, - int idx, int bar, u64 phys); + u64 phys, u64 bus_addr, u64 size); +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, + int type, int idx, int bar, u64 phys); void ls_pcie_dump_atu(struct ls_pcie *pcie); int ls_pcie_link_up(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index cd7ea26..67ce36c 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -45,7 +45,7 @@ static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar) else type = PCIE_ATU_TYPE_IO;
- ls_pcie_atu_inbound_set(pcie, fn, type, idx, bar, bar_phys); + ls_pcie_atu_inbound_set(pcie, fn, 0, type, idx, bar, bar_phys);
dbi_writel(pcie, lower_32_bits(size - 1), reg + PCIE_NO_SRIOV_BAR_BASE); dbi_writel(pcie, flags, reg); @@ -66,27 +66,51 @@ static struct pci_ep_ops ls_pcie_ep_ops = { static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep, u32 pf) { struct ls_pcie *pcie = pcie_ep->pcie; + u32 vf_flag = 0; u64 phys = 0;
phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + pf * SZ_64M;
phys = ALIGN(phys, PCIE_BAR0_SIZE); /* ATU 0 : INBOUND : map BAR0 */ - ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 0 + pf * BAR_NUM, 0, phys); /* ATU 1 : INBOUND : map BAR1 */ phys = ALIGN(phys + PCIE_BAR0_SIZE, PCIE_BAR1_SIZE); - ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 1 + pf * BAR_NUM, 1, phys); /* ATU 2 : INBOUND : map BAR2 */ phys = ALIGN(phys + PCIE_BAR1_SIZE, PCIE_BAR2_SIZE); - ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 2 + pf * BAR_NUM, 2, phys); /* ATU 3 : INBOUND : map BAR2 */ phys = ALIGN(phys + PCIE_BAR2_SIZE, PCIE_BAR4_SIZE); - ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 3 + pf * BAR_NUM, 4, phys);
+ if (pcie_ep->sriov_flag) { + vf_flag = 1; + /* ATU 4 : INBOUND : map BAR0 */ + phys = ALIGN(phys + PCIE_BAR4_SIZE, PCIE_BAR0_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 4 + pf * BAR_NUM, 0, phys); + /* ATU 5 : INBOUND : map BAR1 */ + phys = ALIGN(phys + PCIE_BAR0_SIZE * PCIE_VF_NUM, + PCIE_BAR1_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 5 + pf * BAR_NUM, 1, phys); + /* ATU 6 : INBOUND : map BAR2 */ + phys = ALIGN(phys + PCIE_BAR1_SIZE * PCIE_VF_NUM, + PCIE_BAR2_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 6 + pf * BAR_NUM, 2, phys); + /* ATU 7 : INBOUND : map BAR4 */ + phys = ALIGN(phys + PCIE_BAR2_SIZE * PCIE_VF_NUM, + PCIE_BAR4_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 7 + pf * BAR_NUM, 4, phys); + } + /* ATU: OUTBOUND : map MEM */ ls_pcie_atu_outbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, (u64)pcie_ep->addr_res.start +

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 7/9] pci_ep: layerscape: Add the SRIOV VFs of PF support
Add the INBOUND configuration for VFs of PF.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/pcie_layerscape.c | 8 +++++--- drivers/pci/pcie_layerscape.h | 13 ++++++++----- drivers/pci/pcie_layerscape_ep.c | 34 +++++++++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 88a0e8a..c7a96ed 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -91,7 +91,7 @@ int ls_pcie_link_up(struct ls_pcie *pcie) }
void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
u64 phys, u64 bus_addr, pci_size_t size)
u64 phys, u64 bus_addr, u64 size)
{ dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_BASE); @@ -104,14 +104,16 @@ void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, }
/* Use bar match mode and MEM type as default */ -void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type,
int idx, int bar, u64 phys)
+void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag,
int type, int idx, int bar, u64 phys)
{ dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET); dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET); dbi_writel(pcie, type | PCIE_ATU_FUNC_NUM(pf), PCIE_ATU_CR1); dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE |
(vf_flag ? PCIE_ATU_FUNC_NUM_MATCH_EN : 0) |
PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); }(vf_flag ? PCIE_ATU_VFBAR_MATCH_MODE_EN : 0) |
diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index dabfff3..26d0177 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -20,7 +20,7 @@ #endif
#ifndef CONFIG_SYS_PCI_MEMORY_SIZE -#define CONFIG_SYS_PCI_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) /* 2G */ +#define CONFIG_SYS_PCI_MEMORY_SIZE SZ_4G #endif
#ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE @@ -40,6 +40,7 @@ #define PCIE_ATU_REGION_INDEX2 (0x2 << 0) #define PCIE_ATU_REGION_INDEX3 (0x3 << 0) #define PCIE_ATU_REGION_NUM 6 +#define PCIE_ATU_REGION_NUM_SRIOV 24 #define PCIE_ATU_CR1 0x904 #define PCIE_ATU_TYPE_MEM (0x0 << 0) #define PCIE_ATU_TYPE_IO (0x2 << 0) @@ -49,6 +50,8 @@ #define PCIE_ATU_CR2 0x908 #define PCIE_ATU_ENABLE (0x1 << 31) #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) +#define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19) +#define PCIE_ATU_VFBAR_MATCH_MODE_EN BIT(26) #define PCIE_ATU_BAR_NUM(bar) ((bar) << 8) #define PCIE_ATU_LOWER_BASE 0x90C #define PCIE_ATU_UPPER_BASE 0x910 @@ -88,7 +91,7 @@ #define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */ #define PCIE_PF_NUM 2 #define PCIE_VF_NUM 64 -#define BAR_NUM 4 +#define BAR_NUM 8
#define PCIE_BAR0_SIZE SZ_4K #define PCIE_BAR1_SIZE SZ_8K @@ -179,9 +182,9 @@ void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset); void ctrl_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
u64 phys, u64 bus_addr, pci_size_t size);
-void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, int type,
int idx, int bar, u64 phys);
u64 phys, u64 bus_addr, u64 size); void
+ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag,
int type, int idx, int bar, u64 phys);
void ls_pcie_dump_atu(struct ls_pcie *pcie); int ls_pcie_link_up(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index cd7ea26..67ce36c 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -45,7 +45,7 @@ static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar) else type = PCIE_ATU_TYPE_IO;
- ls_pcie_atu_inbound_set(pcie, fn, type, idx, bar, bar_phys);
ls_pcie_atu_inbound_set(pcie, fn, 0, type, idx, bar, bar_phys);
dbi_writel(pcie, lower_32_bits(size - 1), reg +
PCIE_NO_SRIOV_BAR_BASE); dbi_writel(pcie, flags, reg); @@ -66,27 +66,51 @@ static struct pci_ep_ops ls_pcie_ep_ops = { static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep, u32 pf) { struct ls_pcie *pcie = pcie_ep->pcie;
u32 vf_flag = 0; u64 phys = 0;
phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + pf * SZ_64M;
phys = ALIGN(phys, PCIE_BAR0_SIZE); /* ATU 0 : INBOUND : map BAR0 */
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
- ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 0 + pf * BAR_NUM, 0, phys); /* ATU 1 : INBOUND : map BAR1 */ phys = ALIGN(phys + PCIE_BAR0_SIZE, PCIE_BAR1_SIZE);
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
- ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 1 + pf * BAR_NUM, 1, phys); /* ATU 2 : INBOUND : map BAR2 */ phys = ALIGN(phys + PCIE_BAR1_SIZE, PCIE_BAR2_SIZE);
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
- ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 2 + pf * BAR_NUM, 2, phys); /* ATU 3 : INBOUND : map BAR2 */ phys = ALIGN(phys + PCIE_BAR2_SIZE, PCIE_BAR4_SIZE);
- ls_pcie_atu_inbound_set(pcie, pf, PCIE_ATU_TYPE_MEM,
ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, 3 + pf * BAR_NUM, 4, phys);
if (pcie_ep->sriov_flag) {
vf_flag = 1;
/* ATU 4 : INBOUND : map BAR0 */
phys = ALIGN(phys + PCIE_BAR4_SIZE, PCIE_BAR0_SIZE);
ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
4 + pf * BAR_NUM, 0, phys);
/* ATU 5 : INBOUND : map BAR1 */
phys = ALIGN(phys + PCIE_BAR0_SIZE * PCIE_VF_NUM,
PCIE_BAR1_SIZE);
ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
5 + pf * BAR_NUM, 1, phys);
/* ATU 6 : INBOUND : map BAR2 */
phys = ALIGN(phys + PCIE_BAR1_SIZE * PCIE_VF_NUM,
PCIE_BAR2_SIZE);
ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
6 + pf * BAR_NUM, 2, phys);
/* ATU 7 : INBOUND : map BAR4 */
phys = ALIGN(phys + PCIE_BAR2_SIZE * PCIE_VF_NUM,
PCIE_BAR4_SIZE);
ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM,
7 + pf * BAR_NUM, 4, phys);
}
/* ATU: OUTBOUND : map MEM */ ls_pcie_atu_outbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, (u64)pcie_ep->addr_res.start +
-- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

Modify the ls_pcie_dump_atu function, make it can print the INBOUND windows registers.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- drivers/pci/pcie_layerscape.c | 25 +++++++++++++------------ drivers/pci/pcie_layerscape.h | 2 +- drivers/pci/pcie_layerscape_ep.c | 3 +++ drivers/pci/pcie_layerscape_rc.c | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index c7a96ed..4015a0d 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -117,24 +117,25 @@ void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); }
-void ls_pcie_dump_atu(struct ls_pcie *pcie) +void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type) { - int i; + int win_idx;
- for (i = 0; i < PCIE_ATU_REGION_NUM; i++) { - dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | i, - PCIE_ATU_VIEWPORT); - debug("iATU%d:\n", i); + for (win_idx = 0; win_idx < win_num; win_idx++) { + dbi_writel(pcie, type | win_idx, PCIE_ATU_VIEWPORT); + debug("iATU%d:\n", win_idx); debug("\tLOWER PHYS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_LOWER_BASE)); debug("\tUPPER PHYS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_UPPER_BASE)); - debug("\tLOWER BUS 0x%08x\n", - dbi_readl(pcie, PCIE_ATU_LOWER_TARGET)); - debug("\tUPPER BUS 0x%08x\n", - dbi_readl(pcie, PCIE_ATU_UPPER_TARGET)); - debug("\tLIMIT 0x%08x\n", - dbi_readl(pcie, PCIE_ATU_LIMIT)); + if (type == PCIE_ATU_REGION_OUTBOUND) { + debug("\tLOWER BUS 0x%08x\n", + dbi_readl(pcie, PCIE_ATU_LOWER_TARGET)); + debug("\tUPPER BUS 0x%08x\n", + dbi_readl(pcie, PCIE_ATU_UPPER_TARGET)); + debug("\tLIMIT 0x%08x\n", + dbi_readl(pcie, PCIE_ATU_LIMIT)); + } debug("\tCR1 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR1)); debug("\tCR2 0x%08x\n", diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 26d0177..5f5c51d 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -185,7 +185,7 @@ void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, u64 phys, u64 bus_addr, u64 size); void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, int type, int idx, int bar, u64 phys); -void ls_pcie_dump_atu(struct ls_pcie *pcie); +void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type); int ls_pcie_link_up(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie); diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index 67ce36c..ebf69ee 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -226,6 +226,9 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) ls_pcie_ep_setup_atu(pcie_ep, 0); }
+ ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM_SRIOV, + PCIE_ATU_REGION_INBOUND); + ls_pcie_ep_enable_cfg(pcie_ep); }
diff --git a/drivers/pci/pcie_layerscape_rc.c b/drivers/pci/pcie_layerscape_rc.c index 927722d..b045159 100644 --- a/drivers/pci/pcie_layerscape_rc.c +++ b/drivers/pci/pcie_layerscape_rc.c @@ -114,7 +114,7 @@ static void ls_pcie_setup_atu(struct ls_pcie_rc *pcie_rc) pref->bus_start, pref->size);
- ls_pcie_dump_atu(pcie); + ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM, PCIE_ATU_REGION_OUTBOUND); }
/* Return 0 if the address is valid, -errno if not valid */

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 8/9] pci: layerscaple: Modify the ls_pcie_dump_atu function
Modify the ls_pcie_dump_atu function, make it can print the INBOUND windows registers.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/pcie_layerscape.c | 25 +++++++++++++------------ drivers/pci/pcie_layerscape.h | 2 +- drivers/pci/pcie_layerscape_ep.c | 3 +++ drivers/pci/pcie_layerscape_rc.c | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index c7a96ed..4015a0d 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -117,24 +117,25 @@ void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); }
-void ls_pcie_dump_atu(struct ls_pcie *pcie) +void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type) {
- int i;
- int win_idx;
- for (i = 0; i < PCIE_ATU_REGION_NUM; i++) {
dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | i,
PCIE_ATU_VIEWPORT);
debug("iATU%d:\n", i);
- for (win_idx = 0; win_idx < win_num; win_idx++) {
dbi_writel(pcie, type | win_idx, PCIE_ATU_VIEWPORT);
debug("\tLOWER PHYS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_LOWER_BASE)); debug("\tUPPER PHYS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_UPPER_BASE));debug("iATU%d:\n", win_idx);
debug("\tLOWER BUS 0x%08x\n",
dbi_readl(pcie, PCIE_ATU_LOWER_TARGET));
debug("\tUPPER BUS 0x%08x\n",
dbi_readl(pcie, PCIE_ATU_UPPER_TARGET));
debug("\tLIMIT 0x%08x\n",
dbi_readl(pcie, PCIE_ATU_LIMIT));
if (type == PCIE_ATU_REGION_OUTBOUND) {
debug("\tLOWER BUS 0x%08x\n",
dbi_readl(pcie, PCIE_ATU_LOWER_TARGET));
debug("\tUPPER BUS 0x%08x\n",
dbi_readl(pcie, PCIE_ATU_UPPER_TARGET));
debug("\tLIMIT 0x%08x\n",
dbi_readl(pcie, PCIE_ATU_LIMIT));
debug("\tCR1 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR1)); debug("\tCR2 0x%08x\n",}
diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 26d0177..5f5c51d 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -185,7 +185,7 @@ void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, u64 phys, u64 bus_addr, u64 size); void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, int type, int idx, int bar, u64 phys); -void ls_pcie_dump_atu(struct ls_pcie *pcie); +void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type); int ls_pcie_link_up(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie); diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index 67ce36c..ebf69ee 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -226,6 +226,9 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) ls_pcie_ep_setup_atu(pcie_ep, 0); }
- ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM_SRIOV,
PCIE_ATU_REGION_INBOUND);
- ls_pcie_ep_enable_cfg(pcie_ep);
}
diff --git a/drivers/pci/pcie_layerscape_rc.c b/drivers/pci/pcie_layerscape_rc.c index 927722d..b045159 100644 --- a/drivers/pci/pcie_layerscape_rc.c +++ b/drivers/pci/pcie_layerscape_rc.c @@ -114,7 +114,7 @@ static void ls_pcie_setup_atu(struct ls_pcie_rc *pcie_rc) pref->bus_start, pref->size);
- ls_pcie_dump_atu(pcie);
- ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM,
PCIE_ATU_REGION_OUTBOUND); }
/* Return 0 if the address is valid, -errno if not valid */
2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

Add the PCIe EP mode support for lx2160a-v2 platform.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com --- drivers/pci/pcie_layerscape.h | 9 ++++++++- drivers/pci/pcie_layerscape_ep.c | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 5f5c51d..593798e 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -100,7 +100,7 @@
#define PCIE_SRIOV_VFBAR0 0x19C
-#define PCIE_MASK_OFFSET(flag, pf) ((flag) ? 0 : (0x1000 + 0x20000 * (pf))) +#define PCIE_MASK_OFFSET(flag, pf, off) ((flag) ? 0 : (0x1000 + (off) * (pf)))
/* LUT registers */ #define PCIE_LUT_UDR(n) (0x800 + (n) * 8) @@ -139,6 +139,12 @@ #define LS1021_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) #define LS1021_LTSSM_STATE_SHIFT 20
+/* LX2160a PF1 offset */ +#define LX2160_PCIE_PF1_OFFSET 0x8000 + +/* layerscape PF1 offset */ +#define LS_PCIE_PF1_OFFSET 0x20000 + struct ls_pcie { void __iomem *dbi; void __iomem *lut; @@ -170,6 +176,7 @@ struct ls_pcie_ep { void __iomem *addr; u32 cfg2_flag; u32 sriov_flag; + u32 pf1_offset; u32 num_ib_wins; u32 num_ob_wins; u8 max_functions; diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index ebf69ee..0228863 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -197,7 +197,8 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF);
bar_base = pcie->dbi + - PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf); + PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf, + pcie_ep->pf1_offset);
if (pcie_ep->cfg2_flag) { ctrl_writel(pcie, @@ -270,6 +271,11 @@ static int ls_pcie_ep_probe(struct udevice *dev)
svr = SVR_SOC_VER(get_svr());
+ if (svr == SVR_LX2160A) + pcie_ep->pf1_offset = LX2160_PCIE_PF1_OFFSET; + else + pcie_ep->pf1_offset = LS_PCIE_PF1_OFFSET; + if (svr == SVR_LS2080A || svr == SVR_LS2085A) pcie_ep->cfg2_flag = 1; else

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 9/9] pci_ep: layerscape: Add the PCIe EP mode support for lx2160a-v2
Add the PCIe EP mode support for lx2160a-v2 platform.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/pcie_layerscape.h | 9 ++++++++- drivers/pci/pcie_layerscape_ep.c | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 5f5c51d..593798e 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -100,7 +100,7 @@
#define PCIE_SRIOV_VFBAR0 0x19C
-#define PCIE_MASK_OFFSET(flag, pf) ((flag) ? 0 : (0x1000 + 0x20000 * (pf))) +#define PCIE_MASK_OFFSET(flag, pf, off) ((flag) ? 0 : (0x1000 + (off) * +(pf)))
/* LUT registers */ #define PCIE_LUT_UDR(n) (0x800 + (n) * 8) @@ -139,6 +139,12 @@ #define LS1021_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) #define LS1021_LTSSM_STATE_SHIFT 20
+/* LX2160a PF1 offset */ +#define LX2160_PCIE_PF1_OFFSET 0x8000
+/* layerscape PF1 offset */ +#define LS_PCIE_PF1_OFFSET 0x20000
struct ls_pcie { void __iomem *dbi; void __iomem *lut; @@ -170,6 +176,7 @@ struct ls_pcie_ep { void __iomem *addr; u32 cfg2_flag; u32 sriov_flag;
- u32 pf1_offset; u32 num_ib_wins; u32 num_ob_wins; u8 max_functions;
diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index ebf69ee..0228863 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -197,7 +197,8 @@ static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF);
bar_base = pcie->dbi +
PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf);
PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf,
pcie_ep->pf1_offset); if (pcie_ep->cfg2_flag) { ctrl_writel(pcie,
@@ -270,6 +271,11 @@ static int ls_pcie_ep_probe(struct udevice *dev)
svr = SVR_SOC_VER(get_svr());
- if (svr == SVR_LX2160A)
pcie_ep->pf1_offset = LX2160_PCIE_PF1_OFFSET;
- else
pcie_ep->pf1_offset = LS_PCIE_PF1_OFFSET;
- if (svr == SVR_LS2080A || svr == SVR_LS2085A) pcie_ep->cfg2_flag = 1; else
-- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com

-----Original Message----- From: U-Boot u-boot-bounces@lists.denx.de On Behalf Of Xiaowei Bao Sent: Sunday, March 22, 2020 4:43 PM To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 1/9] pci: layerscape: Split the EP and RC driver
Split the RC and EP driver, and reimplement the EP driver base on the EP framework.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/Makefile | 2 +- drivers/pci/pcie_layerscape.c | 492 +++--------------------------------- drivers/pci/pcie_layerscape.h | 44 +++- drivers/pci/pcie_layerscape_ep.c | 240 ++++++++++++++++++ drivers/pci/pcie_layerscape_fixup.c | 79 +++--- drivers/pci/pcie_layerscape_rc.c | 378 +++++++++++++++++++++++++++ 6 files changed, 734 insertions(+), 501 deletions(-) create mode 100644 drivers/pci/pcie_layerscape_ep.c create mode 100644 drivers/pci/pcie_layerscape_rc.c
Kindly rebase the series on top of tree
Thanks Priyanka

-----Original Message----- From: Xiaowei Bao xiaowei.bao@nxp.com Sent: 2020年3月22日 19:13 To: M.h. Lian minghuan.lian@nxp.com; Z.q. Hou zhiqiang.hou@nxp.com; Mingkai Hu mingkai.hu@nxp.com; bmeng.cn@gmail.com; yamada.masahiro@socionext.com; u-boot@lists.denx.de Cc: Xiaowei Bao xiaowei.bao@nxp.com Subject: [PATCH 1/9] pci: layerscape: Split the EP and RC driver
Split the RC and EP driver, and reimplement the EP driver base on the EP framework.
Signed-off-by: Xiaowei Bao xiaowei.bao@nxp.com
drivers/pci/Makefile | 2 +- drivers/pci/pcie_layerscape.c | 492 +++--------------------------------- drivers/pci/pcie_layerscape.h | 44 +++- drivers/pci/pcie_layerscape_ep.c | 240 ++++++++++++++++++ drivers/pci/pcie_layerscape_fixup.c | 79 +++--- drivers/pci/pcie_layerscape_rc.c | 378 +++++++++++++++++++++++++++ 6 files changed, 734 insertions(+), 501 deletions(-) create mode 100644 drivers/pci/pcie_layerscape_ep.c create mode 100644 drivers/pci/pcie_layerscape_rc.c
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index c051ecc..440b5af 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o obj-$(CONFIG_PCIE_FSL) += pcie_fsl.o pcie_fsl_fixup.o -obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o +obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o pcie_layerscape_rc.o +pcie_layerscape_ep.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o pcie_layerscape_fixup_common.o obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_gen4_fixup.o \ diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 2ab67d1..3ca75c5 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -1,39 +1,32 @@ // SPDX-License-Identifier: GPL-2.0+ /*
- Copyright 2017-2019 NXP
*/
- Copyright 2017-2020 NXP
- Copyright 2014-2015 Freescale Semiconductor, Inc.
- Layerscape PCIe driver
#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> -#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
- defined(CONFIG_ARM)
-#include <asm/arch/clock.h> -#endif #include "pcie_layerscape.h"
DECLARE_GLOBAL_DATA_PTR;
LIST_HEAD(ls_pcie_list);
-static unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset) +unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset) { return in_le32(pcie->dbi + offset); }
-static void dbi_writel(struct ls_pcie *pcie, unsigned int value,
unsigned int offset)
+void dbi_writel(struct ls_pcie *pcie, unsigned int value,
unsigned int offset)
{ out_le32(pcie->dbi + offset, value); }
-static unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) +unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) { if (pcie->big_endian) return in_be32(pcie->ctrl + offset); @@ -41,8 +34,8 @@ static unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) return in_le32(pcie->ctrl + offset); }
-static void ctrl_writel(struct ls_pcie *pcie, unsigned int value,
unsigned int offset)
+void ctrl_writel(struct ls_pcie *pcie, unsigned int value,
unsigned int offset)
{ if (pcie->big_endian) out_be32(pcie->ctrl + offset, value); @@ -50,6 +43,26 @@ static void ctrl_writel(struct ls_pcie *pcie, unsigned int value, out_le32(pcie->ctrl + offset, value); }
+void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie) {
- u32 reg, val;
- reg = PCIE_MISC_CONTROL_1_OFF;
- val = dbi_readl(pcie, reg);
- val |= PCIE_DBI_RO_WR_EN;
- dbi_writel(pcie, val, reg);
+}
+void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie) {
- u32 reg, val;
- reg = PCIE_MISC_CONTROL_1_OFF;
- val = dbi_readl(pcie, reg);
- val &= ~PCIE_DBI_RO_WR_EN;
- dbi_writel(pcie, val, reg);
+}
static int ls_pcie_ltssm(struct ls_pcie *pcie) { u32 state; @@ -66,7 +79,7 @@ static int ls_pcie_ltssm(struct ls_pcie *pcie) return state; }
-static int ls_pcie_link_up(struct ls_pcie *pcie) +int ls_pcie_link_up(struct ls_pcie *pcie) { int ltssm;
@@ -77,22 +90,8 @@ static int ls_pcie_link_up(struct ls_pcie *pcie) return 1; }
-static void ls_pcie_cfg0_set_busdev(struct ls_pcie *pcie, u32 busdev) -{
- dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND |
PCIE_ATU_REGION_INDEX0,
PCIE_ATU_VIEWPORT);
- dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET);
-}
-static void ls_pcie_cfg1_set_busdev(struct ls_pcie *pcie, u32 busdev) -{
- dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND |
PCIE_ATU_REGION_INDEX1,
PCIE_ATU_VIEWPORT);
- dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET);
-}
-static void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
u64 phys, u64 bus_addr, pci_size_t size)
+void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
u64 phys, u64 bus_addr, pci_size_t size)
{ dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_BASE); @@ -105,18 +104,18 @@ static void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, }
/* Use bar match mode and MEM type as default */ -static void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx,
int bar, u64 phys)
+void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type,
int bar, u64 phys)
{ dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET); dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET);
- dbi_writel(pcie, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
- dbi_writel(pcie, type, PCIE_ATU_CR1); dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); }
-static void ls_pcie_dump_atu(struct ls_pcie *pcie) +void ls_pcie_dump_atu(struct ls_pcie *pcie) { int i;
@@ -133,431 +132,10 @@ static void ls_pcie_dump_atu(struct ls_pcie *pcie) debug("\tUPPER BUS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_UPPER_TARGET)); debug("\tLIMIT 0x%08x\n",
readl(pcie->dbi + PCIE_ATU_LIMIT));
debug("\tCR1 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR1)); debug("\tCR2 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR2)); }dbi_readl(pcie, PCIE_ATU_LIMIT));
}
-static void ls_pcie_setup_atu(struct ls_pcie *pcie) -{
- struct pci_region *io, *mem, *pref;
- unsigned long long offset = 0;
- int idx = 0;
- uint svr;
- svr = get_svr();
- if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) ==
SVR_LS102XA) {
offset = LS1021_PCIE_SPACE_OFFSET +
LS1021_PCIE_SPACE_SIZE * pcie->idx;
- }
- /* ATU 0 : OUTBOUND : CFG0 */
- ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_CFG0,
pcie->cfg_res.start + offset,
0,
fdt_resource_size(&pcie->cfg_res) / 2);
- /* ATU 1 : OUTBOUND : CFG1 */
- ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_CFG1,
pcie->cfg_res.start + offset +
fdt_resource_size(&pcie->cfg_res) / 2,
0,
fdt_resource_size(&pcie->cfg_res) / 2);
- pci_get_regions(pcie->bus, &io, &mem, &pref);
- idx = PCIE_ATU_REGION_INDEX1 + 1;
- /* Fix the pcie memory map for LS2088A series SoCs */
- svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
- if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
svr == SVR_LS2048A || svr == SVR_LS2044A ||
svr == SVR_LS2081A || svr == SVR_LS2041A) {
if (io)
io->phys_start = (io->phys_start &
(PCIE_PHYS_SIZE - 1)) +
LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
if (mem)
mem->phys_start = (mem->phys_start &
(PCIE_PHYS_SIZE - 1)) +
LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
if (pref)
pref->phys_start = (pref->phys_start &
(PCIE_PHYS_SIZE - 1)) +
LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
- }
- if (io)
/* ATU : OUTBOUND : IO */
ls_pcie_atu_outbound_set(pcie, idx++,
PCIE_ATU_TYPE_IO,
io->phys_start + offset,
io->bus_start,
io->size);
- if (mem)
/* ATU : OUTBOUND : MEM */
ls_pcie_atu_outbound_set(pcie, idx++,
PCIE_ATU_TYPE_MEM,
mem->phys_start + offset,
mem->bus_start,
mem->size);
- if (pref)
/* ATU : OUTBOUND : pref */
ls_pcie_atu_outbound_set(pcie, idx++,
PCIE_ATU_TYPE_MEM,
pref->phys_start + offset,
pref->bus_start,
pref->size);
- ls_pcie_dump_atu(pcie);
-}
-/* Return 0 if the address is valid, -errno if not valid */ -static int ls_pcie_addr_valid(struct ls_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) && (!ls_pcie_link_up(pcie)))
return -EINVAL;
- if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0))
return -EINVAL;
- return 0;
-}
-int ls_pcie_conf_address(struct udevice *bus, pci_dev_t bdf,
uint offset, void **paddress)
-{
- struct ls_pcie *pcie = dev_get_priv(bus);
- u32 busdev;
- if (ls_pcie_addr_valid(pcie, bdf))
return -EINVAL;
- if (PCI_BUS(bdf) == bus->seq) {
*paddress = pcie->dbi + offset;
return 0;
- }
- busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - bus->seq) |
PCIE_ATU_DEV(PCI_DEV(bdf)) |
PCIE_ATU_FUNC(PCI_FUNC(bdf));
- if (PCI_BUS(bdf) == bus->seq + 1) {
ls_pcie_cfg0_set_busdev(pcie, busdev);
*paddress = pcie->cfg0 + offset;
- } else {
ls_pcie_cfg1_set_busdev(pcie, busdev);
*paddress = pcie->cfg1 + offset;
- }
- return 0;
-}
-static int ls_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
-{
- return pci_generic_mmap_read_config(bus, ls_pcie_conf_address,
bdf, offset, valuep, size);
-}
-static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
-{
- return pci_generic_mmap_write_config(bus, ls_pcie_conf_address,
bdf, offset, value, size);
-}
-/* Clear multi-function bit */ -static void ls_pcie_clear_multifunction(struct ls_pcie *pcie) -{
- writeb(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE);
-}
-/* Fix class value */ -static void ls_pcie_fix_class(struct ls_pcie *pcie) -{
- writew(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE);
-}
-/* Drop MSG TLP except for Vendor MSG */ -static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) -{
- u32 val;
- val = dbi_readl(pcie, PCIE_STRFMR1);
- val &= 0xDFFFFFFF;
- dbi_writel(pcie, val, PCIE_STRFMR1);
-}
-/* Disable all bars in RC mode */ -static void ls_pcie_disable_bars(struct ls_pcie *pcie) -{
- dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_0);
- dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_1);
- dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1);
-}
-static void ls_pcie_setup_ctrl(struct ls_pcie *pcie) -{
- ls_pcie_setup_atu(pcie);
- dbi_writel(pcie, 1, PCIE_DBI_RO_WR_EN);
- ls_pcie_fix_class(pcie);
- ls_pcie_clear_multifunction(pcie);
- ls_pcie_drop_msg_tlp(pcie);
- dbi_writel(pcie, 0, PCIE_DBI_RO_WR_EN);
- ls_pcie_disable_bars(pcie);
- pcie->stream_id_cur = 0;
-}
-static void ls_pcie_ep_setup_atu(struct ls_pcie *pcie) -{
- u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE;
- /* ATU 0 : INBOUND : map BAR0 */
- ls_pcie_atu_inbound_set(pcie, 0, 0, phys);
- /* ATU 1 : INBOUND : map BAR1 */
- phys += PCIE_BAR1_SIZE;
- ls_pcie_atu_inbound_set(pcie, 1, 1, phys);
- /* ATU 2 : INBOUND : map BAR2 */
- phys += PCIE_BAR2_SIZE;
- ls_pcie_atu_inbound_set(pcie, 2, 2, phys);
- /* ATU 3 : INBOUND : map BAR4 */
- phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE;
- ls_pcie_atu_inbound_set(pcie, 3, 4, phys);
- /* ATU 0 : OUTBOUND : map MEM */
- ls_pcie_atu_outbound_set(pcie, 0,
PCIE_ATU_TYPE_MEM,
pcie->cfg_res.start,
0,
CONFIG_SYS_PCI_MEMORY_SIZE);
-}
-/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ -static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) -{
- /* The least inbound window is 4KiB */
- if (size < 4 * 1024)
return;
- switch (bar) {
- case 0:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_0);
break;
- case 1:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_1);
break;
- case 2:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_2);
writel(0, bar_base + PCI_BASE_ADDRESS_3);
break;
- case 4:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_4);
writel(0, bar_base + PCI_BASE_ADDRESS_5);
break;
- default:
break;
- }
-}
-static void ls_pcie_ep_setup_bars(void *bar_base) -{
- /* BAR0 - 32bit - 4K configuration */
- ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE);
- /* BAR1 - 32bit - 8K MSIX*/
- ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE);
- /* BAR2 - 64bit - 4K MEM desciptor */
- ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE);
- /* BAR4 - 64bit - 1M MEM*/
- ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE);
-}
-static void ls_pcie_ep_enable_cfg(struct ls_pcie *pcie) -{
- u32 config;
- config = ctrl_readl(pcie, PCIE_PF_CONFIG);
- config |= PCIE_CONFIG_READY;
- ctrl_writel(pcie, config, PCIE_PF_CONFIG);
-}
-static void ls_pcie_setup_ep(struct ls_pcie *pcie) -{
- u32 sriov;
- sriov = readl(pcie->dbi + PCIE_SRIOV);
- if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) {
int pf, vf;
for (pf = 0; pf < PCIE_PF_NUM; pf++) {
for (vf = 0; vf <= PCIE_VF_NUM; vf++) {
ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf),
PCIE_PF_VF_CTRL);
ls_pcie_ep_setup_bars(pcie->dbi);
ls_pcie_ep_setup_atu(pcie);
}
}
/* Disable CFG2 */
ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL);
- } else {
ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE);
ls_pcie_ep_setup_atu(pcie);
- }
- ls_pcie_ep_enable_cfg(pcie);
-}
-static int ls_pcie_probe(struct udevice *dev) -{
- struct ls_pcie *pcie = dev_get_priv(dev);
- const void *fdt = gd->fdt_blob;
- int node = dev_of_offset(dev);
- u16 link_sta;
- uint svr;
- int ret;
- fdt_size_t cfg_size;
- pcie->bus = dev;
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"dbi", &pcie->dbi_res);
- if (ret) {
printf("ls-pcie: resource \"dbi\" not found\n");
return ret;
- }
- pcie->idx = (pcie->dbi_res.start - PCIE_SYS_BASE_ADDR) /
PCIE_CCSR_SIZE;
- list_add(&pcie->list, &ls_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->dbi = map_physmem(pcie->dbi_res.start,
fdt_resource_size(&pcie->dbi_res),
MAP_NOCACHE);
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"lut", &pcie->lut_res);
- if (!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",
"ctrl", &pcie->ctrl_res);
- if (!ret)
pcie->ctrl = map_physmem(pcie->ctrl_res.start,
fdt_resource_size(&pcie->ctrl_res),
MAP_NOCACHE);
- if (!pcie->ctrl)
pcie->ctrl = pcie->lut;
- if (!pcie->ctrl) {
printf("%s: NOT find CTRL\n", dev->name);
return -1;
- }
- 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;
- }
- /*
* Fix the pcie memory map address and PF control registers address
* for LS2088A series SoCs
*/
- svr = get_svr();
- svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
- if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
svr == SVR_LS2048A || svr == SVR_LS2044A ||
svr == SVR_LS2081A || svr == SVR_LS2041A) {
cfg_size = fdt_resource_size(&pcie->cfg_res);
pcie->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
pcie->cfg_res.end = pcie->cfg_res.start + cfg_size;
pcie->ctrl = pcie->lut + 0x40000;
- }
- pcie->cfg0 = map_physmem(pcie->cfg_res.start,
fdt_resource_size(&pcie->cfg_res),
MAP_NOCACHE);
- pcie->cfg1 = pcie->cfg0 + fdt_resource_size(&pcie->cfg_res) / 2;
- pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian");
- debug("%s dbi:%lx lut:%lx ctrl:0x%lx cfg0:0x%lx, big-endian:%d\n",
dev->name, (unsigned long)pcie->dbi, (unsigned long)pcie->lut,
(unsigned long)pcie->ctrl, (unsigned long)pcie->cfg0,
pcie->big_endian);
- pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f;
- if (pcie->mode == PCI_HEADER_TYPE_NORMAL) {
printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint");
ls_pcie_setup_ep(pcie);
- } else {
printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex");
ls_pcie_setup_ctrl(pcie);
- }
- if (!ls_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_sta = readw(pcie->dbi + PCIE_LINK_STA);
- printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4,
link_sta & PCIE_LINK_SPEED_MASK);
- return 0;
-}
-static const struct dm_pci_ops ls_pcie_ops = {
- .read_config = ls_pcie_read_config,
- .write_config = ls_pcie_write_config,
-};
-static const struct udevice_id ls_pcie_ids[] = {
- { .compatible = "fsl,ls-pcie" },
- { }
-};
-U_BOOT_DRIVER(pci_layerscape) = {
- .name = "pci_layerscape",
- .id = UCLASS_PCI,
- .of_match = ls_pcie_ids,
- .ops = &ls_pcie_ops,
- .probe = ls_pcie_probe,
- .priv_auto_alloc_size = sizeof(struct ls_pcie),
-}; diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 95454bc..217dcda 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /*
- Copyright 2017-2019 NXP
*/
- Copyright 2017-2020 NXP
- Copyright 2014-2015 Freescale Semiconductor, Inc.
- Layerscape PCIe driver
@@ -60,7 +60,8 @@ /* DBI registers */ #define PCIE_SRIOV 0x178 #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ -#define PCIE_DBI_RO_WR_EN 0x8bc +#define PCIE_DBI_RO_WR_EN BIT(0) +#define PCIE_MISC_CONTROL_1_OFF 0x8BC
#define PCIE_LINK_CAP 0x7c #define PCIE_LINK_SPEED_MASK 0xf @@ -82,7 +83,7 @@ PCIE_LCTRL0_CFG2_ENABLE)
#define PCIE_NO_SRIOV_BAR_BASE 0x1000
+#define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */ #define PCIE_PF_NUM 2 #define PCIE_VF_NUM 64
@@ -129,25 +130,52 @@ #define LS1021_LTSSM_STATE_SHIFT 20
struct ls_pcie {
- void __iomem *dbi;
- void __iomem *lut;
- void __iomem *ctrl; int idx;
- bool big_endian;
- int mode;
+};
+struct ls_pcie_rc {
- struct ls_pcie *pcie; struct list_head list; struct udevice *bus; struct fdt_resource dbi_res; struct fdt_resource lut_res; struct fdt_resource ctrl_res; struct fdt_resource cfg_res;
- void __iomem *dbi;
- void __iomem *lut;
- void __iomem *ctrl; void __iomem *cfg0; void __iomem *cfg1;
- bool big_endian; bool enabled; int next_lut_index; int stream_id_cur;
- int mode;
+};
+struct ls_pcie_ep {
- struct fdt_resource addr_res;
- struct ls_pcie *pcie;
- struct udevice *bus;
- void __iomem *addr;
- u32 num_ib_wins;
- u32 num_ob_wins;
- u8 max_functions;
};
extern struct list_head ls_pcie_list;
+unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset); void +dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int +offset); unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int +offset); void ctrl_writel(struct ls_pcie *pcie, unsigned int value, +unsigned int offset); void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
u64 phys, u64 bus_addr, pci_size_t size); void
+ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, int type,
int bar, u64 phys);
+void ls_pcie_dump_atu(struct ls_pcie *pcie); int ls_pcie_link_up(struct +ls_pcie *pcie); void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); void +ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie);
#endif /* _PCIE_LAYERSCAPE_H_ */ diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c new file mode 100644 index 0000000..8d0c99a --- /dev/null +++ b/drivers/pci/pcie_layerscape_ep.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright 2020 NXP
- Layerscape PCIe EP driver
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <pci_ep.h> +#include <asm/io.h> +#include <linux/sizes.h> +#include <linux/log2.h> +#include "pcie_layerscape.h"
+DECLARE_GLOBAL_DATA_PTR;
+static void ls_pcie_ep_enable_cfg(struct ls_pcie_ep *pcie_ep) {
- struct ls_pcie *pcie = pcie_ep->pcie;
- u32 config;
- config = ctrl_readl(pcie, PCIE_PF_CONFIG);
- config |= PCIE_CONFIG_READY;
- ctrl_writel(pcie, config, PCIE_PF_CONFIG); }
+static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar +*ep_bar) {
- struct ls_pcie_ep *pcie_ep = dev_get_priv(dev);
- struct ls_pcie *pcie = pcie_ep->pcie;
- dma_addr_t bar_phys = ep_bar->phys_addr;
- enum pci_barno bar = ep_bar->barno;
- u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
- int flags = ep_bar->flags;
- int type, idx;
- u64 size;
- idx = bar;
- /* BAR size is 2^(aperture + 11) */
- size = max_t(size_t, ep_bar->size, FSL_PCIE_EP_MIN_APERTURE);
- if (!(flags & PCI_BASE_ADDRESS_SPACE))
type = PCIE_ATU_TYPE_MEM;
- else
type = PCIE_ATU_TYPE_IO;
- ls_pcie_atu_inbound_set(pcie, idx, bar, bar_phys, type);
- dbi_writel(pcie, lower_32_bits(size - 1), reg +
PCIE_NO_SRIOV_BAR_BASE);
- dbi_writel(pcie, flags, reg);
- if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
dbi_writel(pcie, upper_32_bits(size - 1),
reg + 4 + PCIE_NO_SRIOV_BAR_BASE);
dbi_writel(pcie, 0, reg + 4);
- }
- return 0;
+}
+static struct pci_ep_ops ls_pcie_ep_ops = {
- .set_bar = ls_ep_set_bar,
+};
+static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep) {
- struct ls_pcie *pcie = pcie_ep->pcie;
- u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE;
- /* ATU 0 : INBOUND : map BAR0 */
- ls_pcie_atu_inbound_set(pcie, 0, PCIE_ATU_TYPE_MEM, 0, phys);
- /* ATU 1 : INBOUND : map BAR1 */
- phys += PCIE_BAR1_SIZE;
- ls_pcie_atu_inbound_set(pcie, 1, PCIE_ATU_TYPE_MEM, 1, phys);
- /* ATU 2 : INBOUND : map BAR2 */
- phys += PCIE_BAR2_SIZE;
- ls_pcie_atu_inbound_set(pcie, 2, PCIE_ATU_TYPE_MEM, 2, phys);
- /* ATU 3 : INBOUND : map BAR4 */
- phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE;
- ls_pcie_atu_inbound_set(pcie, 3, PCIE_ATU_TYPE_MEM, 4, phys);
- /* ATU 0 : OUTBOUND : map MEM */
- ls_pcie_atu_outbound_set(pcie, 0,
PCIE_ATU_TYPE_MEM,
pcie_ep->addr_res.start,
0,
CONFIG_SYS_PCI_MEMORY_SIZE);
+}
+/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ static void +ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) {
- /* The least inbound window is 4KiB */
- if (size < 4 * 1024)
return;
- switch (bar) {
- case 0:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_0);
break;
- case 1:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_1);
break;
- case 2:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_2);
writel(0, bar_base + PCI_BASE_ADDRESS_3);
break;
- case 4:
writel(size - 1, bar_base + PCI_BASE_ADDRESS_4);
writel(0, bar_base + PCI_BASE_ADDRESS_5);
break;
- default:
break;
- }
+}
+static void ls_pcie_ep_setup_bars(void *bar_base) {
- /* BAR0 - 32bit - 4K configuration */
- ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE);
- /* BAR1 - 32bit - 8K MSIX */
- ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE);
- /* BAR2 - 64bit - 4K MEM descriptor */
- ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE);
- /* BAR4 - 64bit - 1M MEM */
- ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); }
+static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) {
- u32 sriov;
- struct ls_pcie *pcie = pcie_ep->pcie;
- sriov = readl(pcie->dbi + PCIE_SRIOV);
- if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) {
int pf, vf;
for (pf = 0; pf < PCIE_PF_NUM; pf++) {
for (vf = 0; vf <= PCIE_VF_NUM; vf++) {
ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf),
PCIE_PF_VF_CTRL);
ls_pcie_ep_setup_bars(pcie->dbi);
ls_pcie_ep_setup_atu(pcie_ep);
}
}
/* Disable CFG2 */
ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL);
- } else {
ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE);
ls_pcie_ep_setup_atu(pcie_ep);
- }
- ls_pcie_ep_enable_cfg(pcie_ep);
+}
+static int ls_pcie_ep_probe(struct udevice *dev) {
- struct ls_pcie_ep *pcie_ep = dev_get_priv(dev);
- struct ls_pcie *pcie;
- u16 link_sta;
- int ret;
- pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL);
- if (!pcie)
return -ENOMEM;
- pcie_ep->pcie = pcie;
- pcie->dbi = (void __iomem *)devfdt_get_addr_index(dev, 0);
- if (!pcie->dbi)
return -ENOMEM;
- pcie->ctrl = (void __iomem *)devfdt_get_addr_index(dev, 1);
- if (!pcie->ctrl)
return -ENOMEM;
- ret = fdt_get_named_resource(gd->fdt_blob, dev_of_offset(dev),
"reg", "reg-names",
"addr_space", &pcie_ep->addr_res);
- if (ret) {
printf("%s: resource \"addr_space\" not found\n", dev->name);
return ret;
- }
- pcie->idx = ((unsigned long)pcie->dbi - PCIE_SYS_BASE_ADDR) /
PCIE_CCSR_SIZE;
- pcie->big_endian = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
"big-endian");
- pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f;
- if (pcie->mode != PCI_HEADER_TYPE_NORMAL)
return 0;
- pcie_ep->max_functions = fdtdec_get_int(gd->fdt_blob,
dev_of_offset(dev),
"max-functions", 1);
- pcie_ep->num_ib_wins = fdtdec_get_int(gd->fdt_blob,
dev_of_offset(dev),
"num-ib-windows", 8);
- pcie_ep->num_ob_wins = fdtdec_get_int(gd->fdt_blob,
dev_of_offset(dev),
"num-ob-windows", 8);
- printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint");
- ls_pcie_setup_ep(pcie_ep);
- if (!ls_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_sta = readw(pcie->dbi + PCIE_LINK_STA);
- printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4,
link_sta & PCIE_LINK_SPEED_MASK);
- return 0;
+}
+static int ls_pcie_ep_remove(struct udevice *dev) {
- return 0;
+}
+const struct udevice_id ls_pcie_ep_ids[] = {
- { .compatible = "fsl,ls-pcie-ep" },
- { }
+};
+U_BOOT_DRIVER(pci_layerscape_ep) = {
- .name = "pci_layerscape_ep",
- .id = UCLASS_PCI_EP,
- .of_match = ls_pcie_ep_ids,
- .ops = &ls_pcie_ep_ops,
- .probe = ls_pcie_ep_probe,
- .remove = ls_pcie_ep_remove,
- .priv_auto_alloc_size = sizeof(struct ls_pcie_ep), };
diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c index ec6acbb..a981f8c 100644 --- a/drivers/pci/pcie_layerscape_fixup.c +++ b/drivers/pci/pcie_layerscape_fixup.c @@ -23,17 +23,19 @@ /*
- Return next available LUT index.
*/ -static int ls_pcie_next_lut_index(struct ls_pcie *pcie) +static int ls_pcie_next_lut_index(struct ls_pcie_rc *pcie_rc) {
- if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT)
return pcie->next_lut_index++;
- if (pcie_rc->next_lut_index < PCIE_LUT_ENTRY_COUNT)
else return -ENOSPC; /* LUT is full */return pcie_rc->next_lut_index++;
}
-static void lut_writel(struct ls_pcie *pcie, unsigned int value, +static void lut_writel(struct ls_pcie_rc *pcie_rc, unsigned int value, unsigned int offset) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- if (pcie->big_endian) out_be32(pcie->lut + offset, value); else
@@ -43,12 +45,12 @@ static void lut_writel(struct ls_pcie *pcie, unsigned int value, /*
- Program a single LUT entry
*/ -static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid,
u32 streamid)
+static void ls_pcie_lut_set_mapping(struct ls_pcie_rc *pcie_rc, 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));
- lut_writel(pcie_rc, devid << 16, PCIE_LUT_UDR(index));
- lut_writel(pcie_rc, streamid | PCIE_LUT_ENABLE,
PCIE_LUT_LDR(index)); }
/* @@ -59,7 +61,8 @@ static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid,
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_ls(void *blob, struct ls_pcie *pcie, +static void fdt_pcie_set_msi_map_entry_ls(void *blob,
struct ls_pcie_rc *pcie_rc, u32 devid, u32 streamid)
{ u32 *prop; @@ -67,10 +70,11 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, int nodeoffset; uint svr; char *compat = NULL;
struct ls_pcie *pcie = pcie_rc->pcie;
/* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
pcie->dbi_res.start);
if (nodeoffset < 0) {pcie_rc->dbi_res.start);
#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -82,7 +86,7 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, compat = CONFIG_FSL_PCIE_COMPAT; if (compat) nodeoffset = fdt_node_offset_by_compat_reg(blob,
compat, pcie->dbi_res.start);
compat, pcie_rc->dbi_res.start);
#endif if (nodeoffset < 0) return; @@ -112,7 +116,8 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie,
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_ls(void *blob, struct ls_pcie *pcie, +static void fdt_pcie_set_iommu_map_entry_ls(void *blob,
struct ls_pcie_rc *pcie_rc, u32 devid, u32 streamid)
{ u32 *prop; @@ -121,10 +126,11 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, int lenp; uint svr; char *compat = NULL;
struct ls_pcie *pcie = pcie_rc->pcie;
/* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
pcie->dbi_res.start);
if (nodeoffset < 0) {pcie_rc->dbi_res.start);
#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -137,7 +143,7 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie,
if (compat) nodeoffset = fdt_node_offset_by_compat_reg(blob,
compat, pcie->dbi_res.start);
compat, pcie_rc->dbi_res.start);
#endif if (nodeoffset < 0) return; @@ -168,7 +174,7 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, static void fdt_fixup_pcie_ls(void *blob) { struct udevice *dev, *bus;
- struct ls_pcie *pcie;
- struct ls_pcie_rc *pcie_rc; int streamid; int index; pci_dev_t bdf;
@@ -179,17 +185,18 @@ static void fdt_fixup_pcie_ls(void *blob) pci_find_next_device(&dev)) { for (bus = dev; device_is_on_pci_bus(bus);) bus = bus->parent;
pcie = dev_get_priv(bus);
pcie_rc = dev_get_priv(bus);
streamid = pcie_next_streamid(pcie->stream_id_cur, pcie->idx);
streamid = pcie_next_streamid(pcie_rc->stream_id_cur,
if (streamid < 0) { debug("ERROR: no stream ids free\n"); continue; } else {pcie_rc->pcie->idx);
pcie->stream_id_cur++;
}pcie_rc->stream_id_cur++;
index = ls_pcie_next_lut_index(pcie);
if (index < 0) { debug("ERROR: no LUT indexes free\n"); continue;index = ls_pcie_next_lut_index(pcie_rc);
@@ -198,27 +205,28 @@ static void fdt_fixup_pcie_ls(void *blob) /* 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_lut_set_mapping(pcie, index, bdf >> 8,
/* update msi-map in device tree */ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8, streamid);
fdt_pcie_set_msi_map_entry_ls(blob, pcie, bdf >> 8,
/* update iommu-map in device tree */fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid);
fdt_pcie_set_iommu_map_entry_ls(blob, pcie, bdf >> 8,
} pcie_board_fix_fdt(blob);fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid);
} #endif
-static void ft_pcie_rc_fix(void *blob, struct ls_pcie *pcie) +static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc) { int off; uint svr; char *compat = NULL;
struct ls_pcie *pcie = pcie_rc->pcie;
off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie",
pcie->dbi_res.start);
if (off < 0) {pcie_rc->dbi_res.start);
#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -230,46 +238,47 @@ static void ft_pcie_rc_fix(void *blob, struct ls_pcie *pcie) compat = CONFIG_FSL_PCIE_COMPAT; if (compat) off = fdt_node_offset_by_compat_reg(blob,
compat, pcie->dbi_res.start);
compat, pcie_rc->dbi_res.start);
#endif if (off < 0) return; }
- if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)
- if (pcie_rc->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_ep_fix(void *blob, struct ls_pcie *pcie) +static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc) { int off;
struct ls_pcie *pcie = pcie_rc->pcie;
off = fdt_node_offset_by_compat_reg(blob,
CONFIG_FSL_PCIE_EP_COMPAT,
pcie->dbi_res.start);
if (off < 0) return;pcie_rc->dbi_res.start);
- if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL)
- if (pcie_rc->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_ls_setup(void *blob, struct ls_pcie *pcie) +static void ft_pcie_ls_setup(void *blob, struct ls_pcie_rc *pcie_rc) {
- ft_pcie_ep_fix(blob, pcie);
- ft_pcie_rc_fix(blob, pcie);
- ft_pcie_ep_fix(blob, pcie_rc);
- ft_pcie_rc_fix(blob, pcie_rc);
}
/* Fixup Kernel DT for PCIe */ void ft_pci_setup_ls(void *blob, bd_t *bd) {
- struct ls_pcie *pcie;
- struct ls_pcie_rc *pcie_rc;
- list_for_each_entry(pcie, &ls_pcie_list, list)
ft_pcie_ls_setup(blob, pcie);
- list_for_each_entry(pcie_rc, &ls_pcie_list, list)
ft_pcie_ls_setup(blob, pcie_rc);
#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) fdt_fixup_pcie_ls(blob); diff --git a/drivers/pci/pcie_layerscape_rc.c b/drivers/pci/pcie_layerscape_rc.c new file mode 100644 index 0000000..927722d --- /dev/null +++ b/drivers/pci/pcie_layerscape_rc.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright 2020 NXP
- Layerscape PCIe driver
- */
+#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> +#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
- defined(CONFIG_ARM)
+#include <asm/arch/clock.h> +#endif +#include "pcie_layerscape.h"
+DECLARE_GLOBAL_DATA_PTR;
+static void ls_pcie_cfg0_set_busdev(struct ls_pcie_rc *pcie_rc, u32 +busdev) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND |
PCIE_ATU_REGION_INDEX0,
PCIE_ATU_VIEWPORT);
- dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); }
+static void ls_pcie_cfg1_set_busdev(struct ls_pcie_rc *pcie_rc, u32 +busdev) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND |
PCIE_ATU_REGION_INDEX1,
PCIE_ATU_VIEWPORT);
- dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); }
+static void ls_pcie_setup_atu(struct ls_pcie_rc *pcie_rc) {
- struct pci_region *io, *mem, *pref;
- unsigned long long offset = 0;
- struct ls_pcie *pcie = pcie_rc->pcie;
- int idx = 0;
- uint svr;
- svr = get_svr();
- if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) ==
SVR_LS102XA) {
offset = LS1021_PCIE_SPACE_OFFSET +
LS1021_PCIE_SPACE_SIZE * pcie->idx;
- }
- /* ATU 0 : OUTBOUND : CFG0 */
- ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_CFG0,
pcie_rc->cfg_res.start + offset,
0,
fdt_resource_size(&pcie_rc->cfg_res) / 2);
- /* ATU 1 : OUTBOUND : CFG1 */
- ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_CFG1,
pcie_rc->cfg_res.start + offset +
fdt_resource_size(&pcie_rc->cfg_res) / 2,
0,
fdt_resource_size(&pcie_rc->cfg_res) / 2);
- pci_get_regions(pcie_rc->bus, &io, &mem, &pref);
- idx = PCIE_ATU_REGION_INDEX1 + 1;
- /* Fix the pcie memory map for LS2088A series SoCs */
- svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
- if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
svr == SVR_LS2048A || svr == SVR_LS2044A ||
svr == SVR_LS2081A || svr == SVR_LS2041A) {
if (io)
io->phys_start = (io->phys_start &
(PCIE_PHYS_SIZE - 1)) +
LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
if (mem)
mem->phys_start = (mem->phys_start &
(PCIE_PHYS_SIZE - 1)) +
LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
if (pref)
pref->phys_start = (pref->phys_start &
(PCIE_PHYS_SIZE - 1)) +
LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
- }
- if (io)
/* ATU : OUTBOUND : IO */
ls_pcie_atu_outbound_set(pcie, idx++,
PCIE_ATU_TYPE_IO,
io->phys_start + offset,
io->bus_start,
io->size);
- if (mem)
/* ATU : OUTBOUND : MEM */
ls_pcie_atu_outbound_set(pcie, idx++,
PCIE_ATU_TYPE_MEM,
mem->phys_start + offset,
mem->bus_start,
mem->size);
- if (pref)
/* ATU : OUTBOUND : pref */
ls_pcie_atu_outbound_set(pcie, idx++,
PCIE_ATU_TYPE_MEM,
pref->phys_start + offset,
pref->bus_start,
pref->size);
- ls_pcie_dump_atu(pcie);
+}
+/* Return 0 if the address is valid, -errno if not valid */ static int +ls_pcie_addr_valid(struct ls_pcie_rc *pcie_rc, pci_dev_t bdf) {
- struct udevice *bus = pcie_rc->bus;
- struct ls_pcie *pcie = pcie_rc->pcie;
- if (pcie->mode == PCI_HEADER_TYPE_NORMAL)
return -ENODEV;
- if (!pcie_rc->enabled)
return -ENXIO;
- if (PCI_BUS(bdf) < bus->seq)
return -EINVAL;
- if ((PCI_BUS(bdf) > bus->seq) && (!ls_pcie_link_up(pcie)))
return -EINVAL;
- if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0))
return -EINVAL;
- return 0;
+}
+int ls_pcie_conf_address(struct udevice *bus, pci_dev_t bdf,
uint offset, void **paddress)
+{
- struct ls_pcie_rc *pcie_rc = dev_get_priv(bus);
- struct ls_pcie *pcie = pcie_rc->pcie;
- u32 busdev;
- if (ls_pcie_addr_valid(pcie_rc, bdf))
return -EINVAL;
- if (PCI_BUS(bdf) == bus->seq) {
*paddress = pcie->dbi + offset;
return 0;
- }
- busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - bus->seq) |
PCIE_ATU_DEV(PCI_DEV(bdf)) |
PCIE_ATU_FUNC(PCI_FUNC(bdf));
- if (PCI_BUS(bdf) == bus->seq + 1) {
ls_pcie_cfg0_set_busdev(pcie_rc, busdev);
*paddress = pcie_rc->cfg0 + offset;
- } else {
ls_pcie_cfg1_set_busdev(pcie_rc, busdev);
*paddress = pcie_rc->cfg1 + offset;
- }
- return 0;
+}
+static int ls_pcie_read_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
+{
- return pci_generic_mmap_read_config(bus, ls_pcie_conf_address,
bdf, offset, valuep, size);
+}
+static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
+{
- return pci_generic_mmap_write_config(bus, ls_pcie_conf_address,
bdf, offset, value, size);
+}
+/* Clear multi-function bit */ +static void ls_pcie_clear_multifunction(struct ls_pcie_rc *pcie_rc) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- writeb(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE); }
+/* Fix class value */ +static void ls_pcie_fix_class(struct ls_pcie_rc *pcie_rc) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- writew(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE); }
+/* Drop MSG TLP except for Vendor MSG */ static void +ls_pcie_drop_msg_tlp(struct ls_pcie_rc *pcie_rc) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- u32 val;
- val = dbi_readl(pcie, PCIE_STRFMR1);
- val &= 0xDFFFFFFF;
- dbi_writel(pcie, val, PCIE_STRFMR1);
+}
+/* Disable all bars in RC mode */ +static void ls_pcie_disable_bars(struct ls_pcie_rc *pcie_rc) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_0);
- dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_1);
- dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1); }
+static void ls_pcie_setup_ctrl(struct ls_pcie_rc *pcie_rc) {
- struct ls_pcie *pcie = pcie_rc->pcie;
- ls_pcie_setup_atu(pcie_rc);
- ls_pcie_dbi_ro_wr_en(pcie);
- ls_pcie_fix_class(pcie_rc);
- ls_pcie_clear_multifunction(pcie_rc);
- ls_pcie_drop_msg_tlp(pcie_rc);
- ls_pcie_dbi_ro_wr_dis(pcie);
- ls_pcie_disable_bars(pcie_rc);
- pcie_rc->stream_id_cur = 0;
+}
+static int ls_pcie_probe(struct udevice *dev) {
- struct ls_pcie_rc *pcie_rc = dev_get_priv(dev);
- const void *fdt = gd->fdt_blob;
- int node = dev_of_offset(dev);
- struct ls_pcie *pcie;
- u16 link_sta;
- uint svr;
- int ret;
- fdt_size_t cfg_size;
- pcie_rc->bus = dev;
- pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL);
- if (!pcie)
return -ENOMEM;
- pcie_rc->pcie = pcie;
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"dbi", &pcie_rc->dbi_res);
- if (ret) {
printf("ls-pcie: resource \"dbi\" not found\n");
return ret;
- }
- pcie->idx = (pcie_rc->dbi_res.start - PCIE_SYS_BASE_ADDR) /
PCIE_CCSR_SIZE;
- list_add(&pcie_rc->list, &ls_pcie_list);
- pcie_rc->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx));
- if (!pcie_rc->enabled) {
printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
return 0;
- }
- pcie->dbi = map_physmem(pcie_rc->dbi_res.start,
fdt_resource_size(&pcie_rc->dbi_res),
MAP_NOCACHE);
- pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f;
- if (pcie->mode == PCI_HEADER_TYPE_NORMAL)
return 0;
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"lut", &pcie_rc->lut_res);
- if (!ret)
pcie->lut = map_physmem(pcie_rc->lut_res.start,
fdt_resource_size(&pcie_rc->lut_res),
MAP_NOCACHE);
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"ctrl", &pcie_rc->ctrl_res);
- if (!ret)
pcie->ctrl = map_physmem(pcie_rc->ctrl_res.start,
fdt_resource_size(&pcie_rc->ctrl_res),
MAP_NOCACHE);
- if (!pcie->ctrl)
pcie->ctrl = pcie->lut;
- if (!pcie->ctrl) {
printf("%s: NOT find CTRL\n", dev->name);
return -1;
- }
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"config", &pcie_rc->cfg_res);
- if (ret) {
printf("%s: resource \"config\" not found\n", dev->name);
return ret;
- }
- /*
* Fix the pcie memory map address and PF control registers address
* for LS2088A series SoCs
*/
- svr = get_svr();
- svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
- if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
svr == SVR_LS2048A || svr == SVR_LS2044A ||
svr == SVR_LS2081A || svr == SVR_LS2041A) {
cfg_size = fdt_resource_size(&pcie_rc->cfg_res);
pcie_rc->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR +
LS2088A_PCIE_PHYS_SIZE * pcie->idx;
pcie_rc->cfg_res.end = pcie_rc->cfg_res.start + cfg_size;
pcie->ctrl = pcie->lut + 0x40000;
- }
- pcie_rc->cfg0 = map_physmem(pcie_rc->cfg_res.start,
fdt_resource_size(&pcie_rc->cfg_res),
MAP_NOCACHE);
- pcie_rc->cfg1 = pcie_rc->cfg0 +
fdt_resource_size(&pcie_rc->cfg_res) / 2;
- pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian");
- debug("%s dbi:%lx lut:%lx ctrl:0x%lx cfg0:0x%lx, big-endian:%d\n",
dev->name, (unsigned long)pcie->dbi, (unsigned long)pcie->lut,
(unsigned long)pcie->ctrl, (unsigned long)pcie_rc->cfg0,
pcie->big_endian);
- printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex");
- ls_pcie_setup_ctrl(pcie_rc);
- if (!ls_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_sta = readw(pcie->dbi + PCIE_LINK_STA);
- printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4,
link_sta & PCIE_LINK_SPEED_MASK);
- return 0;
+}
+static const struct dm_pci_ops ls_pcie_ops = {
- .read_config = ls_pcie_read_config,
- .write_config = ls_pcie_write_config,
+};
+static const struct udevice_id ls_pcie_ids[] = {
- { .compatible = "fsl,ls-pcie" },
- { }
+};
+U_BOOT_DRIVER(pci_layerscape) = {
- .name = "pci_layerscape",
- .id = UCLASS_PCI,
- .of_match = ls_pcie_ids,
- .ops = &ls_pcie_ops,
- .probe = ls_pcie_probe,
- .priv_auto_alloc_size = sizeof(struct ls_pcie_rc), };
-- 2.9.5
Reviewed-by: Hou Zhiqiang Zhiqiang.Hou@nxp.com
participants (3)
-
Priyanka Jain (OSS)
-
Xiaowei Bao
-
Z.q. Hou