diff mbox series

[U-Boot] ls1028a: Configure stream IDs for integrated PCI and fix up Linux DT

Message ID 20191127135749.21338-1-alexandru.marginean@nxp.com
State Superseded
Delegated to: Priyanka Jain
Headers show
Series [U-Boot] ls1028a: Configure stream IDs for integrated PCI and fix up Linux DT | expand

Commit Message

Alexandru Marginean Nov. 27, 2019, 1:57 p.m. UTC
Hardware comes out of reset with implicit values, but these are outside
the accepted range for Layerscape gen 3 chassis spec used on LS1028A.
Allocate different IDs and fix up Linux DT to use them.

Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
---
 arch/arm/cpu/armv8/fsl-layerscape/fdt.c       |   9 ++
 .../asm/arch-fsl-layerscape/stream_id_lsch3.h |   8 ++
 board/freescale/ls1028a/ls1028a.c             | 106 ++++++++++++++++++
 3 files changed, 123 insertions(+)

Comments

Bin Meng Nov. 27, 2019, 2:07 p.m. UTC | #1
On Wed, Nov 27, 2019 at 9:58 PM Alex Marginean
<alexandru.marginean@nxp.com> wrote:
>
> Hardware comes out of reset with implicit values, but these are outside
> the accepted range for Layerscape gen 3 chassis spec used on LS1028A.
> Allocate different IDs and fix up Linux DT to use them.
>
> Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
> ---
>  arch/arm/cpu/armv8/fsl-layerscape/fdt.c       |   9 ++
>  .../asm/arch-fsl-layerscape/stream_id_lsch3.h |   8 ++
>  board/freescale/ls1028a/ls1028a.c             | 106 ++++++++++++++++++
>  3 files changed, 123 insertions(+)
>

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Michael Walle Nov. 27, 2019, 2:33 p.m. UTC | #2
Hi Alex,

Am 2019-11-27 14:57, schrieb Alex Marginean:
> Hardware comes out of reset with implicit values, but these are outside
> the accepted range for Layerscape gen 3 chassis spec used on LS1028A.
> Allocate different IDs and fix up Linux DT to use them.
> 
> Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
> ---
>  arch/arm/cpu/armv8/fsl-layerscape/fdt.c       |   9 ++
>  .../asm/arch-fsl-layerscape/stream_id_lsch3.h |   8 ++
>  board/freescale/ls1028a/ls1028a.c             | 106 ++++++++++++++++++

Doh :( is there no other place where to put this fixup? That would mean 
I
have to replicate this code for our custom board and so does every board
which uses the LS1028A. Shouldn't this be in the SoC LS1028A 
architecture
specific code?

>  3 files changed, 123 insertions(+)
> 
> diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
> b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
> index e993209593..1e7e46e88a 100644
> --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
> +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
> @@ -421,6 +421,12 @@ static void fdt_disable_multimedia(void *blob,
> unsigned int svr)
>  }
>  #endif
> 
> +#ifdef CONFIG_PCIE_ECAM_GENERIC
> +__weak void fdt_fixup_ecam(void *blob)
> +{
> +}
> +#endif
> +
>  void ft_cpu_setup(void *blob, bd_t *bd)
>  {
>  	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
> @@ -485,4 +491,7 @@ void ft_cpu_setup(void *blob, bd_t *bd)
>  #ifdef CONFIG_ARCH_LS1028A
>  	fdt_disable_multimedia(blob, svr);
>  #endif
> +#ifdef CONFIG_PCIE_ECAM_GENERIC
> +	fdt_fixup_ecam(blob);
> +#endif
>  }
> diff --git
> a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
> b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
> index 94ea99a349..01d362d183 100644
> --- a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
> +++ b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
> @@ -42,6 +42,10 @@
>   *     -the MC is responsible for allocating and setting up 'isolation 
> context
>   *      IDs (ICIDs) based on the allocated stream IDs for all DPAA2 
> devices.
>   *
> + *  - ECAM (integrated PCI)
> + *     - U-Boot applies the value here to HW and does DT fix-up for 
> both
> + *       'iommu-map' and 'msi-map'
> + *

mhh this is not entirely true, because it is the board code which does 
the fixup,
which may lead to some confusion.

>   * On Chasis-3 SoCs stream IDs are programmed in AMQ registers 
> (32-bits) for
>   * each of the different bus masters.  The relationship between
>   * the AMQ registers and stream IDs is defined in the table below:
> @@ -98,6 +102,10 @@
>  #define FSL_DPAA2_STREAM_ID_START	23
>  #define FSL_DPAA2_STREAM_ID_END		63
> 
> +/* PCI IEPs, this overlaps DPAA2 but these two are exclusive at least
> for now */
> +#define FSL_ECAM_STREAM_ID_START	32
> +#define FSL_ECAM_STREAM_ID_END		63
> +
>  #define FSL_SEC_STREAM_ID		64
>  #define FSL_SEC_JR1_STREAM_ID		65
>  #define FSL_SEC_JR2_STREAM_ID		66
> diff --git a/board/freescale/ls1028a/ls1028a.c
> b/board/freescale/ls1028a/ls1028a.c
> index a9606b8865..1f5dc0d0b2 100644
> --- a/board/freescale/ls1028a/ls1028a.c
> +++ b/board/freescale/ls1028a/ls1028a.c
> @@ -28,6 +28,52 @@
> 
>  DECLARE_GLOBAL_DATA_PTR;
> 
> +#ifdef CONFIG_PCIE_ECAM_GENERIC
> +
> +#define ECAM_IERB_BASE		0x1f0800000ULL
> +#define ECAM_IERB_OFFSET_NA	-1
> +#define ECAM_IERB_FUNC_CNT	ARRAY_SIZE(ierb_offset)
> +/* cache related transaction attributes for PCIe functions */
> +#define ECAM_IERB_MSICAR		(ECAM_IERB_BASE + 0xa400)
> +#define ECAM_IERB_MSICAR_VALUE		0x30
> +
> +/* offset of IERB config register per PCI function */
> +static int ierb_offset[] = {
> +	0x0800,
> +	0x1800,
> +	0x2800,
> +	0x3800,
> +	0x4800,
> +	0x5800,
> +	0x6800,
> +	ECAM_IERB_OFFSET_NA,
> +	0x0804,
> +	0x0808,
> +	0x1804,
> +	0x1808,
> +};
> +
> +/*
> + * Use a custom function for LS1028A, for now this is the only SoC 
> with IERB
> + * and we're currently considering reorganizing IERB for future SoCs.
> + */
> +static void set_ecam_icids(void)
> +{
> +	int i;
> +
> +	out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE);
> +
> +	for (i = 0; i < ECAM_IERB_FUNC_CNT; i++) {
> +		if (ierb_offset[i] == ECAM_IERB_OFFSET_NA)
> +			continue;
> +
> +		out_le32(ECAM_IERB_BASE + ierb_offset[i],
> +			 FSL_ECAM_STREAM_ID_START + i);
> +	}
> +}
> +
> +#endif /* CONFIG_PCIE_ECAM_GENERIC */
> +
>  int config_board_mux(void)
>  {
>  #if defined(CONFIG_TARGET_LS1028AQDS) && defined(CONFIG_FSL_QIXIS)
> @@ -88,6 +134,16 @@ int board_init(void)
>  #endif
> 
>  #endif
> +
> +	/*
> +	 * ICIDs for other hardware blocks are set really early on, before 
> MMU
> +	 * is set up.  For integrated PCI we need access to IERB which is not
> +	 * part of CCSR, so we have to wait for MMU mappings to be applied
> +	 */
> +#ifdef CONFIG_PCIE_ECAM_GENERIC
> +	set_ecam_icids();
> +#endif
> +
>  	return 0;
>  }
> 
> @@ -244,3 +300,53 @@ int checkboard(void)
>  	return 0;
>  }
>  #endif
> +
> +#ifdef CONFIG_PCIE_ECAM_GENERIC
> +
> +static int fdt_setprop_inplace_idx_u32(void *fdt, int nodeoffset,
> +				       const char *name, uint32_t idx, u32 val)
> +{
> +	val = cpu_to_be32(val);
> +	return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
> +						   strlen(name),
> +						   idx * sizeof(val), &val,
> +						   sizeof(val));
> +}
> +
> +static int fdt_getprop_len(void *fdt, int nodeoffset, const char 
> *name)
> +{
> +	int len;
> +
> +	if (fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), &len))
> +		return len;
> +
> +	return 0;
> +}
> +
> +void fdt_fixup_ecam(void *blob)
> +{
> +	int off;
> +
> +	off = fdt_node_offset_by_compatible(blob, 0, 
> "pci-host-ecam-generic");
> +	if (off < 0) {
> +		debug("ECAM node not found\n");
> +		return;
> +	}
> +
> +	if (fdt_getprop_len(blob, off, "msi-map") != 16 ||
> +	    fdt_getprop_len(blob, off, "iommu-map") != 16) {
> +		log_err("invalid msi/iommu-map propertly size in ECAM node\n");
> +		return;
> +	}
> +
> +	fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 2,
> +				    FSL_ECAM_STREAM_ID_START);
> +	fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 3,
> +				    ECAM_IERB_FUNC_CNT);
> +
> +	fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 2,
> +				    FSL_ECAM_STREAM_ID_START);
> +	fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 3,
> +				    ECAM_IERB_FUNC_CNT);
> +}
> +#endif /* CONFIG_PCIE_ECAM_GENERIC */

-michael
Alexandru Marginean Nov. 27, 2019, 2:47 p.m. UTC | #3
Hi Michael,

On 11/27/2019 3:33 PM, Michael Walle wrote:
> Hi Alex,
> 
> Am 2019-11-27 14:57, schrieb Alex Marginean:
>> Hardware comes out of reset with implicit values, but these are outside
>> the accepted range for Layerscape gen 3 chassis spec used on LS1028A.
>> Allocate different IDs and fix up Linux DT to use them.
>>
>> Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
>> ---
>>  arch/arm/cpu/armv8/fsl-layerscape/fdt.c       |   9 ++
>>  .../asm/arch-fsl-layerscape/stream_id_lsch3.h |   8 ++
>>  board/freescale/ls1028a/ls1028a.c             | 106 ++++++++++++++++++
> 
> Doh :( is there no other place where to put this fixup? That would mean I
> have to replicate this code for our custom board and so does every board
> which uses the LS1028A. Shouldn't this be in the SoC LS1028A architecture
> specific code?

Yeah, you're right about that.
It should probably go into armv8/fsl-layerscape/icid.c or somewhere 
around there.
I'll send a v2.

Thanks!
Alex

> 
>>  3 files changed, 123 insertions(+)
>>
>> diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
>> b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
>> index e993209593..1e7e46e88a 100644
>> --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
>> +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
>> @@ -421,6 +421,12 @@ static void fdt_disable_multimedia(void *blob,
>> unsigned int svr)
>>  }
>>  #endif
>>
>> +#ifdef CONFIG_PCIE_ECAM_GENERIC
>> +__weak void fdt_fixup_ecam(void *blob)
>> +{
>> +}
>> +#endif
>> +
>>  void ft_cpu_setup(void *blob, bd_t *bd)
>>  {
>>      struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
>> @@ -485,4 +491,7 @@ void ft_cpu_setup(void *blob, bd_t *bd)
>>  #ifdef CONFIG_ARCH_LS1028A
>>      fdt_disable_multimedia(blob, svr);
>>  #endif
>> +#ifdef CONFIG_PCIE_ECAM_GENERIC
>> +    fdt_fixup_ecam(blob);
>> +#endif
>>  }
>> diff --git
>> a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
>> b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
>> index 94ea99a349..01d362d183 100644
>> --- a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
>> +++ b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
>> @@ -42,6 +42,10 @@
>>   *     -the MC is responsible for allocating and setting up 
>> 'isolation context
>>   *      IDs (ICIDs) based on the allocated stream IDs for all DPAA2 
>> devices.
>>   *
>> + *  - ECAM (integrated PCI)
>> + *     - U-Boot applies the value here to HW and does DT fix-up for both
>> + *       'iommu-map' and 'msi-map'
>> + *
> 
> mhh this is not entirely true, because it is the board code which
> does the fixup, which may lead to some confusion. >
>>   * On Chasis-3 SoCs stream IDs are programmed in AMQ registers 
>> (32-bits) for
>>   * each of the different bus masters.  The relationship between
>>   * the AMQ registers and stream IDs is defined in the table below:
>> @@ -98,6 +102,10 @@
>>  #define FSL_DPAA2_STREAM_ID_START    23
>>  #define FSL_DPAA2_STREAM_ID_END        63
>>
>> +/* PCI IEPs, this overlaps DPAA2 but these two are exclusive at least
>> for now */
>> +#define FSL_ECAM_STREAM_ID_START    32
>> +#define FSL_ECAM_STREAM_ID_END        63
>> +
>>  #define FSL_SEC_STREAM_ID        64
>>  #define FSL_SEC_JR1_STREAM_ID        65
>>  #define FSL_SEC_JR2_STREAM_ID        66
>> diff --git a/board/freescale/ls1028a/ls1028a.c
>> b/board/freescale/ls1028a/ls1028a.c
>> index a9606b8865..1f5dc0d0b2 100644
>> --- a/board/freescale/ls1028a/ls1028a.c
>> +++ b/board/freescale/ls1028a/ls1028a.c
>> @@ -28,6 +28,52 @@
>>
>>  DECLARE_GLOBAL_DATA_PTR;
>>
>> +#ifdef CONFIG_PCIE_ECAM_GENERIC
>> +
>> +#define ECAM_IERB_BASE        0x1f0800000ULL
>> +#define ECAM_IERB_OFFSET_NA    -1
>> +#define ECAM_IERB_FUNC_CNT    ARRAY_SIZE(ierb_offset)
>> +/* cache related transaction attributes for PCIe functions */
>> +#define ECAM_IERB_MSICAR        (ECAM_IERB_BASE + 0xa400)
>> +#define ECAM_IERB_MSICAR_VALUE        0x30
>> +
>> +/* offset of IERB config register per PCI function */
>> +static int ierb_offset[] = {
>> +    0x0800,
>> +    0x1800,
>> +    0x2800,
>> +    0x3800,
>> +    0x4800,
>> +    0x5800,
>> +    0x6800,
>> +    ECAM_IERB_OFFSET_NA,
>> +    0x0804,
>> +    0x0808,
>> +    0x1804,
>> +    0x1808,
>> +};
>> +
>> +/*
>> + * Use a custom function for LS1028A, for now this is the only SoC 
>> with IERB
>> + * and we're currently considering reorganizing IERB for future SoCs.
>> + */
>> +static void set_ecam_icids(void)
>> +{
>> +    int i;
>> +
>> +    out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE);
>> +
>> +    for (i = 0; i < ECAM_IERB_FUNC_CNT; i++) {
>> +        if (ierb_offset[i] == ECAM_IERB_OFFSET_NA)
>> +            continue;
>> +
>> +        out_le32(ECAM_IERB_BASE + ierb_offset[i],
>> +             FSL_ECAM_STREAM_ID_START + i);
>> +    }
>> +}
>> +
>> +#endif /* CONFIG_PCIE_ECAM_GENERIC */
>> +
>>  int config_board_mux(void)
>>  {
>>  #if defined(CONFIG_TARGET_LS1028AQDS) && defined(CONFIG_FSL_QIXIS)
>> @@ -88,6 +134,16 @@ int board_init(void)
>>  #endif
>>
>>  #endif
>> +
>> +    /*
>> +     * ICIDs for other hardware blocks are set really early on, 
>> before MMU
>> +     * is set up.  For integrated PCI we need access to IERB which is 
>> not
>> +     * part of CCSR, so we have to wait for MMU mappings to be applied
>> +     */
>> +#ifdef CONFIG_PCIE_ECAM_GENERIC
>> +    set_ecam_icids();
>> +#endif
>> +
>>      return 0;
>>  }
>>
>> @@ -244,3 +300,53 @@ int checkboard(void)
>>      return 0;
>>  }
>>  #endif
>> +
>> +#ifdef CONFIG_PCIE_ECAM_GENERIC
>> +
>> +static int fdt_setprop_inplace_idx_u32(void *fdt, int nodeoffset,
>> +                       const char *name, uint32_t idx, u32 val)
>> +{
>> +    val = cpu_to_be32(val);
>> +    return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
>> +                           strlen(name),
>> +                           idx * sizeof(val), &val,
>> +                           sizeof(val));
>> +}
>> +
>> +static int fdt_getprop_len(void *fdt, int nodeoffset, const char *name)
>> +{
>> +    int len;
>> +
>> +    if (fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), &len))
>> +        return len;
>> +
>> +    return 0;
>> +}
>> +
>> +void fdt_fixup_ecam(void *blob)
>> +{
>> +    int off;
>> +
>> +    off = fdt_node_offset_by_compatible(blob, 0, 
>> "pci-host-ecam-generic");
>> +    if (off < 0) {
>> +        debug("ECAM node not found\n");
>> +        return;
>> +    }
>> +
>> +    if (fdt_getprop_len(blob, off, "msi-map") != 16 ||
>> +        fdt_getprop_len(blob, off, "iommu-map") != 16) {
>> +        log_err("invalid msi/iommu-map propertly size in ECAM node\n");
>> +        return;
>> +    }
>> +
>> +    fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 2,
>> +                    FSL_ECAM_STREAM_ID_START);
>> +    fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 3,
>> +                    ECAM_IERB_FUNC_CNT);
>> +
>> +    fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 2,
>> +                    FSL_ECAM_STREAM_ID_START);
>> +    fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 3,
>> +                    ECAM_IERB_FUNC_CNT);
>> +}
>> +#endif /* CONFIG_PCIE_ECAM_GENERIC */
> 
> -michael
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> https://lists.denx.de/listinfo/u-boot
diff mbox series

Patch

diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
index e993209593..1e7e46e88a 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
@@ -421,6 +421,12 @@  static void fdt_disable_multimedia(void *blob, unsigned int svr)
 }
 #endif
 
+#ifdef CONFIG_PCIE_ECAM_GENERIC
+__weak void fdt_fixup_ecam(void *blob)
+{
+}
+#endif
+
 void ft_cpu_setup(void *blob, bd_t *bd)
 {
 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
@@ -485,4 +491,7 @@  void ft_cpu_setup(void *blob, bd_t *bd)
 #ifdef CONFIG_ARCH_LS1028A
 	fdt_disable_multimedia(blob, svr);
 #endif
+#ifdef CONFIG_PCIE_ECAM_GENERIC
+	fdt_fixup_ecam(blob);
+#endif
 }
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
index 94ea99a349..01d362d183 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
@@ -42,6 +42,10 @@ 
  *     -the MC is responsible for allocating and setting up 'isolation context
  *      IDs (ICIDs) based on the allocated stream IDs for all DPAA2 devices.
  *
+ *  - ECAM (integrated PCI)
+ *     - U-Boot applies the value here to HW and does DT fix-up for both
+ *       'iommu-map' and 'msi-map'
+ *
  * On Chasis-3 SoCs stream IDs are programmed in AMQ registers (32-bits) for
  * each of the different bus masters.  The relationship between
  * the AMQ registers and stream IDs is defined in the table below:
@@ -98,6 +102,10 @@ 
 #define FSL_DPAA2_STREAM_ID_START	23
 #define FSL_DPAA2_STREAM_ID_END		63
 
+/* PCI IEPs, this overlaps DPAA2 but these two are exclusive at least for now */
+#define FSL_ECAM_STREAM_ID_START	32
+#define FSL_ECAM_STREAM_ID_END		63
+
 #define FSL_SEC_STREAM_ID		64
 #define FSL_SEC_JR1_STREAM_ID		65
 #define FSL_SEC_JR2_STREAM_ID		66
diff --git a/board/freescale/ls1028a/ls1028a.c b/board/freescale/ls1028a/ls1028a.c
index a9606b8865..1f5dc0d0b2 100644
--- a/board/freescale/ls1028a/ls1028a.c
+++ b/board/freescale/ls1028a/ls1028a.c
@@ -28,6 +28,52 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifdef CONFIG_PCIE_ECAM_GENERIC
+
+#define ECAM_IERB_BASE		0x1f0800000ULL
+#define ECAM_IERB_OFFSET_NA	-1
+#define ECAM_IERB_FUNC_CNT	ARRAY_SIZE(ierb_offset)
+/* cache related transaction attributes for PCIe functions */
+#define ECAM_IERB_MSICAR		(ECAM_IERB_BASE + 0xa400)
+#define ECAM_IERB_MSICAR_VALUE		0x30
+
+/* offset of IERB config register per PCI function */
+static int ierb_offset[] = {
+	0x0800,
+	0x1800,
+	0x2800,
+	0x3800,
+	0x4800,
+	0x5800,
+	0x6800,
+	ECAM_IERB_OFFSET_NA,
+	0x0804,
+	0x0808,
+	0x1804,
+	0x1808,
+};
+
+/*
+ * Use a custom function for LS1028A, for now this is the only SoC with IERB
+ * and we're currently considering reorganizing IERB for future SoCs.
+ */
+static void set_ecam_icids(void)
+{
+	int i;
+
+	out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE);
+
+	for (i = 0; i < ECAM_IERB_FUNC_CNT; i++) {
+		if (ierb_offset[i] == ECAM_IERB_OFFSET_NA)
+			continue;
+
+		out_le32(ECAM_IERB_BASE + ierb_offset[i],
+			 FSL_ECAM_STREAM_ID_START + i);
+	}
+}
+
+#endif /* CONFIG_PCIE_ECAM_GENERIC */
+
 int config_board_mux(void)
 {
 #if defined(CONFIG_TARGET_LS1028AQDS) && defined(CONFIG_FSL_QIXIS)
@@ -88,6 +134,16 @@  int board_init(void)
 #endif
 
 #endif
+
+	/*
+	 * ICIDs for other hardware blocks are set really early on, before MMU
+	 * is set up.  For integrated PCI we need access to IERB which is not
+	 * part of CCSR, so we have to wait for MMU mappings to be applied
+	 */
+#ifdef CONFIG_PCIE_ECAM_GENERIC
+	set_ecam_icids();
+#endif
+
 	return 0;
 }
 
@@ -244,3 +300,53 @@  int checkboard(void)
 	return 0;
 }
 #endif
+
+#ifdef CONFIG_PCIE_ECAM_GENERIC
+
+static int fdt_setprop_inplace_idx_u32(void *fdt, int nodeoffset,
+				       const char *name, uint32_t idx, u32 val)
+{
+	val = cpu_to_be32(val);
+	return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
+						   strlen(name),
+						   idx * sizeof(val), &val,
+						   sizeof(val));
+}
+
+static int fdt_getprop_len(void *fdt, int nodeoffset, const char *name)
+{
+	int len;
+
+	if (fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), &len))
+		return len;
+
+	return 0;
+}
+
+void fdt_fixup_ecam(void *blob)
+{
+	int off;
+
+	off = fdt_node_offset_by_compatible(blob, 0, "pci-host-ecam-generic");
+	if (off < 0) {
+		debug("ECAM node not found\n");
+		return;
+	}
+
+	if (fdt_getprop_len(blob, off, "msi-map") != 16 ||
+	    fdt_getprop_len(blob, off, "iommu-map") != 16) {
+		log_err("invalid msi/iommu-map propertly size in ECAM node\n");
+		return;
+	}
+
+	fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 2,
+				    FSL_ECAM_STREAM_ID_START);
+	fdt_setprop_inplace_idx_u32(blob, off, "msi-map", 3,
+				    ECAM_IERB_FUNC_CNT);
+
+	fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 2,
+				    FSL_ECAM_STREAM_ID_START);
+	fdt_setprop_inplace_idx_u32(blob, off, "iommu-map", 3,
+				    ECAM_IERB_FUNC_CNT);
+}
+#endif /* CONFIG_PCIE_ECAM_GENERIC */