[PATCH 1/9] pci: layerscape: Split the EP and RC driver
Z.q. Hou
zhiqiang.hou at nxp.com
Tue Apr 28 14:23:23 CEST 2020
> -----Original Message-----
> From: Xiaowei Bao <xiaowei.bao at nxp.com>
> Sent: 2020年3月22日 19:13
> To: M.h. Lian <minghuan.lian at nxp.com>; Z.q. Hou
> <zhiqiang.hou at nxp.com>; Mingkai Hu <mingkai.hu at nxp.com>;
> bmeng.cn at gmail.com; yamada.masahiro at socionext.com;
> u-boot at lists.denx.de
> Cc: Xiaowei Bao <xiaowei.bao at 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 at 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.Hou at nxp.com>
More information about the U-Boot
mailing list