diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie_layerscape.c | 42 | ||||
-rw-r--r-- | drivers/pci/pcie_layerscape.h | 10 | ||||
-rw-r--r-- | drivers/pci/pcie_layerscape_fixup.c | 94 |
3 files changed, 133 insertions, 13 deletions
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index b6806cf67b..1c5a33ac28 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -167,6 +167,27 @@ static void ls_pcie_setup_atu(struct ls_pcie *pcie) 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) { + 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++, @@ -409,6 +430,11 @@ static void ls_pcie_ep_setup_bars(void *bar_base) ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); } +static void ls_pcie_ep_enable_cfg(struct ls_pcie *pcie) +{ + ctrl_writel(pcie, PCIE_CONFIG_READY, PCIE_PF_CONFIG); +} + static void ls_pcie_setup_ep(struct ls_pcie *pcie) { u32 sriov; @@ -432,6 +458,8 @@ static void ls_pcie_setup_ep(struct ls_pcie *pcie) 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) @@ -442,6 +470,7 @@ static int ls_pcie_probe(struct udevice *dev) u8 header_type; u16 link_sta; bool ep_mode; + uint svr; int ret; pcie->bus = dev; @@ -495,6 +524,19 @@ static int ls_pcie_probe(struct udevice *dev) 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) { + pcie->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + pcie->ctrl = pcie->lut + 0x40000; + } + pcie->cfg0 = map_physmem(pcie->cfg_res.start, fdt_resource_size(&pcie->cfg_res), MAP_NOCACHE); diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 1e635ef1f2..e3324a5e52 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -26,6 +26,10 @@ #define CONFIG_SYS_PCI_EP_MEMORY_BASE CONFIG_SYS_LOAD_ADDR #endif +#define PCIE_PHYS_SIZE 0x200000000 +#define LS2088A_PCIE_PHYS_SIZE 0x800000000 +#define LS2088A_PCIE1_PHYS_ADDR 0x2000000000 + /* iATU registers */ #define PCIE_ATU_VIEWPORT 0x900 #define PCIE_ATU_REGION_INBOUND (0x1 << 31) @@ -94,8 +98,10 @@ #define PCIE_LUT_ENTRY_COUNT 32 /* PF Controll registers */ +#define PCIE_PF_CONFIG 0x14 #define PCIE_PF_VF_CTRL 0x7F8 #define PCIE_PF_DBG 0x7FC +#define PCIE_CONFIG_READY (1 << 0) #define PCIE_SRDS_PRTCL(idx) (PCIE1 + (idx)) #define PCIE_SYS_BASE_ADDR 0x3400000 @@ -107,6 +113,10 @@ #define SVR_LS102XA 0 #define SVR_VAR_PER_SHIFT 8 #define SVR_LS102XA_MASK 0x700 +#define SVR_LS2088A 0x870900 +#define SVR_LS2084A 0x870910 +#define SVR_LS2048A 0x870920 +#define SVR_LS2044A 0x870930 /* LS1021a PCIE space */ #define LS1021_PCIE_SPACE_OFFSET 0x4000000000ULL diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c index 19ede2f104..d504bbda37 100644 --- a/drivers/pci/pcie_layerscape_fixup.c +++ b/drivers/pci/pcie_layerscape_fixup.c @@ -15,7 +15,7 @@ #include <fdt_support.h> #include "pcie_layerscape.h" -#ifdef CONFIG_FSL_LSCH3 +#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) /* * Return next available LUT index. */ @@ -72,19 +72,26 @@ static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie *pcie, u32 *prop; u32 phandle; int nodeoffset; + uint svr; + char *compat = NULL; /* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", pcie->dbi_res.start); if (nodeoffset < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ - nodeoffset = fdt_node_offset_by_compat_reg(blob, - CONFIG_FSL_PCIE_COMPAT, pcie->dbi_res.start); + svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; + if (svr == SVR_LS2088A || svr == SVR_LS2084A || + svr == SVR_LS2048A || svr == SVR_LS2044A) + compat = "fsl,ls2088a-pcie"; + else + compat = CONFIG_FSL_PCIE_COMPAT; + if (compat) + nodeoffset = fdt_node_offset_by_compat_reg(blob, + compat, pcie->dbi_res.start); +#endif if (nodeoffset < 0) return; -#else - return; -#endif } /* get phandle to MSI controller */ @@ -103,6 +110,58 @@ static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie *pcie, fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1); } +/* + * An iommu-map is a property to be added to the pci controller + * node. It is a table, where each entry consists of 4 fields + * e.g.: + * + * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count] + * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>; + */ +static void fdt_pcie_set_iommu_map_entry(void *blob, struct ls_pcie *pcie, + u32 devid, u32 streamid) +{ + u32 *prop; + u32 iommu_map[4]; + int nodeoffset; + int lenp; + + /* find pci controller node */ + nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", + pcie->dbi_res.start); + if (nodeoffset < 0) { +#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ + nodeoffset = fdt_node_offset_by_compat_reg(blob, + CONFIG_FSL_PCIE_COMPAT, pcie->dbi_res.start); + if (nodeoffset < 0) + return; +#else + return; +#endif + } + + /* get phandle to iommu controller */ + prop = fdt_getprop_w(blob, nodeoffset, "iommu-map", &lenp); + if (prop == NULL) { + debug("\n%s: ERROR: missing iommu-map: PCIe%d\n", + __func__, pcie->idx); + return; + } + + /* set iommu-map row */ + iommu_map[0] = cpu_to_fdt32(devid); + iommu_map[1] = *++prop; + iommu_map[2] = cpu_to_fdt32(streamid); + iommu_map[3] = cpu_to_fdt32(1); + + if (devid == 0) { + fdt_setprop_inplace(blob, nodeoffset, "iommu-map", + iommu_map, 16); + } else { + fdt_appendprop(blob, nodeoffset, "iommu-map", iommu_map, 16); + } +} + static void fdt_fixup_pcie(void *blob) { struct udevice *dev, *bus; @@ -139,6 +198,9 @@ static void fdt_fixup_pcie(void *blob) /* update msi-map in device tree */ fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8, streamid); + /* update iommu-map in device tree */ + fdt_pcie_set_iommu_map_entry(blob, pcie, bdf >> 8, + streamid); } } #endif @@ -146,19 +208,25 @@ static void fdt_fixup_pcie(void *blob) static void ft_pcie_ls_setup(void *blob, struct ls_pcie *pcie) { int off; + uint svr; + char *compat = NULL; off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", pcie->dbi_res.start); if (off < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ - off = fdt_node_offset_by_compat_reg(blob, - CONFIG_FSL_PCIE_COMPAT, - pcie->dbi_res.start); + svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; + if (svr == SVR_LS2088A || svr == SVR_LS2084A || + svr == SVR_LS2048A || svr == SVR_LS2044A) + compat = "fsl,ls2088a-pcie"; + else + compat = CONFIG_FSL_PCIE_COMPAT; + if (compat) + off = fdt_node_offset_by_compat_reg(blob, + compat, pcie->dbi_res.start); +#endif if (off < 0) return; -#else - return; -#endif } if (pcie->enabled) @@ -175,7 +243,7 @@ void ft_pci_setup(void *blob, bd_t *bd) list_for_each_entry(pcie, &ls_pcie_list, list) ft_pcie_ls_setup(blob, pcie); -#ifdef CONFIG_FSL_LSCH3 +#if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) fdt_fixup_pcie(blob); #endif } |