diff --git a/arch/arm/cpu/armv8/fsl-lsch3/fdt.c b/arch/arm/cpu/armv8/fsl-lsch3/fdt.c index b9fd559..567c419 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/fdt.c +++ b/arch/arm/cpu/armv8/fsl-lsch3/fdt.c @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef CONFIG_FSL_ESDHC #include #endif @@ -58,6 +59,113 @@ void ft_fixup_cpu(void *blob) } #endif +/* + * the burden is on the the caller to not request a count + * exceeding the bounds of the stream_ids[] array + */ +void alloc_stream_ids(int start_id, int count, u32 *stream_ids, int max_cnt) +{ + int i; + + if (count > max_cnt) { + printf("\n%s: ERROR: max per-device stream ID count exceed\n", + __func__); + return; + } + + for (i = 0; i < count; i++) + stream_ids[i] = start_id++; +} + +/* + * This function updates the mmu-masters property on the SMMU + * node as per the SMMU binding-- phandle and list of stream IDs + * for each MMU master. + */ +void append_mmu_masters(void *blob, const char *smmu_path, + const char *master_name, u32 *stream_ids, int count) +{ + u32 phandle; + int smmu_nodeoffset; + int master_nodeoffset; + int i; + + /* get phandle of mmu master device */ + master_nodeoffset = fdt_path_offset(blob, master_name); + if (master_nodeoffset < 0) { + printf("\n%s: ERROR: master not found\n", __func__); + return; + } + phandle = fdt_get_phandle(blob, master_nodeoffset); + if (!phandle) { /* if master has no phandle, create one */ + phandle = fdt_create_phandle(blob, master_nodeoffset); + if (!phandle) { + printf("\n%s: ERROR: unable to create phandle\n", + __func__); + return; + } + } + + /* append it to mmu-masters */ + smmu_nodeoffset = fdt_path_offset(blob, smmu_path); + if (fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", + phandle) < 0) { + printf("\n%s: ERROR: unable to update SMMU node\n", __func__); + return; + } + + /* for each stream ID, append to mmu-masters */ + for (i = 0; i < count; i++) { + fdt_appendprop_u32(blob, smmu_nodeoffset, "mmu-masters", + stream_ids[i]); + } + + /* fix up #stream-id-cells with stream ID count */ + if (fdt_setprop_u32(blob, master_nodeoffset, "#stream-id-cells", + count) < 0) + printf("\n%s: ERROR: unable to update #stream-id-cells\n", + __func__); +} + + +/* + * The info below summarizes how streamID partitioning works + * for ls2085a and how it is conveyed to the OS via the device tree. + * + * -non-PCI legacy, platform devices (USB, SD/MMC, SATA, DMA) + * -all legacy devices get a unique ICID assigned and programmed in + * their AMQR registers by u-boot + * -u-boot updates the hardware device tree with streamID properties + * for each platform/legacy device (smmu-masters property) + * + * -PCIe + * -for each PCI controller that is active (as per RCW settings), + * u-boot will allocate a range of ICID and convey that to Linux via + * the device tree (smmu-masters property) + * + * -DPAA2 + * -u-boot will allocate a range of ICIDs to be used by the Management + * Complex for containers and will set these values in the MC DPC image. + * -the MC is responsible for allocating and setting up ICIDs + * for all DPAA2 devices. + * + */ +static void fdt_fixup_smmu(void *blob) +{ + int nodeoffset; + + nodeoffset = fdt_path_offset(blob, "/iommu@5000000"); + if (nodeoffset < 0) { + printf("\n%s: WARNING: no SMMU node found\n", __func__); + return; + } + + /* fixup for all PCI controllers */ +#ifdef CONFIG_PCI + fdt_fixup_smmu_pcie(blob); +#endif +} + void ft_cpu_setup(void *blob, bd_t *bd) { #ifdef CONFIG_MP @@ -76,4 +184,6 @@ void ft_cpu_setup(void *blob, bd_t *bd) #if defined(CONFIG_FSL_ESDHC) fdt_fixup_esdhc(blob, bd); #endif + + fdt_fixup_smmu(blob); } diff --git a/arch/arm/include/asm/arch-fsl-lsch3/fdt.h b/arch/arm/include/asm/arch-fsl-lsch3/fdt.h new file mode 100644 index 0000000..21d20fb --- /dev/null +++ b/arch/arm/include/asm/arch-fsl-lsch3/fdt.h @@ -0,0 +1,10 @@ +/* + * Copyright 2015 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +void alloc_stream_ids(int start_id, int count, u32 *stream_ids, int max_cnt); +void append_mmu_masters(void *blob, const char *smmu_path, + const char *master_name, u32 *stream_ids, int count); +void fdt_fixup_smmu_pcie(void *blob); diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 402c519..3ef4975 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifndef CONFIG_SYS_PCI_MEMORY_BUS #define CONFIG_SYS_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE @@ -528,3 +529,64 @@ void ft_pci_setup(void *blob, bd_t *bd) { } #endif + +#ifdef CONFIG_LS2085A + +void pcie_set_available_streamids(void *blob, const char *pcie_path, + u32 *stream_ids, int count) +{ + int nodeoffset; + int i; + + nodeoffset = fdt_path_offset(blob, pcie_path); + if (nodeoffset < 0) { + printf("\n%s: ERROR: unable to update PCIe node\n", __func__); + return; + } + + /* for each stream ID, append to mmu-masters */ + for (i = 0; i < count; i++) { + fdt_appendprop_u32(blob, nodeoffset, "available-stream-ids", + stream_ids[i]); + } +} + +#define MAX_STREAM_IDS 4 +void fdt_fixup_smmu_pcie(void *blob) +{ + int count; + u32 stream_ids[MAX_STREAM_IDS]; + + #ifdef CONFIG_PCIE1 + /* PEX1 stream ID fixup */ + count = FSL_PEX1_STREAM_ID_END - FSL_PEX1_STREAM_ID_START + 1; + alloc_stream_ids(FSL_PEX1_STREAM_ID_START, count, stream_ids, + MAX_STREAM_IDS); + pcie_set_available_streamids(blob, "/pcie@3400000", stream_ids, count); + #endif + + #ifdef CONFIG_PCIE2 + /* PEX2 stream ID fixup */ + count = FSL_PEX2_STREAM_ID_END - FSL_PEX2_STREAM_ID_START + 1; + alloc_stream_ids(FSL_PEX2_STREAM_ID_START, count, stream_ids, + MAX_STREAM_IDS); + pcie_set_available_streamids(blob, "/pcie@3500000", stream_ids, count); + #endif + + #ifdef CONFIG_PCIE3 + /* PEX3 stream ID fixup */ + count = FSL_PEX3_STREAM_ID_END - FSL_PEX3_STREAM_ID_START + 1; + alloc_stream_ids(FSL_PEX3_STREAM_ID_START, count, stream_ids, + MAX_STREAM_IDS); + pcie_set_available_streamids(blob, "/pcie@3600000", stream_ids, count); + #endif + + #ifdef CONFIG_PCIE4 + /* PEX4 stream ID fixup */ + count = FSL_PEX4_STREAM_ID_END - FSL_PEX4_STREAM_ID_START + 1; + alloc_stream_ids(FSL_PEX4_STREAM_ID_START, count, stream_ids, + MAX_STREAM_IDS); + pcie_set_available_streamids(blob, "/pcie@3700000", stream_ids, count); + #endif +} +#endif