> -----Original Message----- > From: Xiaowei Bao <xiaowei....@nxp.com> > Sent: 2020年3月22日 19:13 > To: M.h. Lian <minghuan.l...@nxp.com>; Z.q. Hou > <zhiqiang....@nxp.com>; Mingkai Hu <mingkai...@nxp.com>; > bmeng...@gmail.com; yamada.masah...@socionext.com; > u-boot@lists.denx.de > Cc: Xiaowei Bao <xiaowei....@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....@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), }; > -- > 2.9.5
Reviewed-by: Hou Zhiqiang <zhiqiang....@nxp.com>