armv8/ls1043a: fixup GIC offset for ls1043a rev1
authorWenbin Song <wenbin.song@nxp.com>
Tue, 17 Jan 2017 10:31:15 +0000 (18:31 +0800)
committerYork Sun <york.sun@nxp.com>
Wed, 18 Jan 2017 17:29:21 +0000 (09:29 -0800)
The LS1043A rev1.1 silicon supports two types of GIC offset: 4K
alignment and 64K alignment. The bit SCFG_GIC400_ALIGN[GIC_ADDR_BIT]
is used to choose which offset will be used.

The LS1043A rev1.0 silicon only supports the CIG offset with 4K
alignment.

If GIC_ADDR_BIT bit is set, 4K alignment is used, or else 64K alignment
is used. 64K alignment is the default setting.

Overriding the weak smp_kick_all_cpus, the new impletment is able to
detect GIC offset.

The default GIC offset in kernel device tree is using 4K alignment, it
need to be fixed if 64K alignment is detected.

Signed-off-by: Wenbin Song <wenbin.song@nxp.com>
Signed-off-by: Mingkai Hu <mingkai.hu@nxp.com>
Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Reviewed-by: York Sun <york.sun@nxp.com>
arch/arm/cpu/armv8/fsl-layerscape/Kconfig
arch/arm/cpu/armv8/fsl-layerscape/fdt.c
arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
arch/arm/include/asm/arch-fsl-layerscape/config.h
arch/arm/include/asm/arch-fsl-layerscape/immap_lsch2.h
arch/arm/include/asm/arch-fsl-layerscape/soc.h

index 79e2dd66b05949a99d7eb01d255fd8b52ff7d48b..dce1689e0058bb7fb857ffeaa70b03660ef19501 100644 (file)
@@ -90,6 +90,11 @@ config FSL_PCIE_COMPAT
          This compatible is used to find pci controller node in Kernel DT
          to complete fixup.
 
+config HAS_FEATURE_GIC64K_ALIGN
+       bool
+       default y if ARCH_LS1043A
+
+
 menu "Layerscape PPA"
 config FSL_LS_PPA
        bool "FSL Layerscape PPA firmware support"
index c10ccf9063a6cae4977fe5da7fbacf1f152f54c3..f289172c6c508c742f8ddb37fd174de36aae322b 100644 (file)
@@ -133,6 +133,67 @@ void fsl_fdt_disable_usb(void *blob)
        }
 }
 
+#ifdef CONFIG_HAS_FEATURE_GIC64K_ALIGN
+static void fdt_fixup_gic(void *blob)
+{
+       int offset, err;
+       u64 reg[8];
+       struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+       unsigned int val;
+       struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
+       int align_64k = 0;
+
+       val = gur_in32(&gur->svr);
+
+       if (SVR_SOC_VER(val) != SVR_LS1043A) {
+               align_64k = 1;
+       } else if (SVR_REV(val) != REV1_0) {
+               val = scfg_in32(&scfg->gic_align) & (0x01 << GIC_ADDR_BIT);
+               if (!val)
+                       align_64k = 1;
+       }
+
+       offset = fdt_subnode_offset(blob, 0, "interrupt-controller@1400000");
+       if (offset < 0) {
+               printf("WARNING: fdt_subnode_offset can't find node %s: %s\n",
+                      "interrupt-controller@1400000", fdt_strerror(offset));
+               return;
+       }
+
+       /* Fixup gic node align with 64K */
+       if (align_64k) {
+               reg[0] = cpu_to_fdt64(GICD_BASE_64K);
+               reg[1] = cpu_to_fdt64(GICD_SIZE_64K);
+               reg[2] = cpu_to_fdt64(GICC_BASE_64K);
+               reg[3] = cpu_to_fdt64(GICC_SIZE_64K);
+               reg[4] = cpu_to_fdt64(GICH_BASE_64K);
+               reg[5] = cpu_to_fdt64(GICH_SIZE_64K);
+               reg[6] = cpu_to_fdt64(GICV_BASE_64K);
+               reg[7] = cpu_to_fdt64(GICV_SIZE_64K);
+       } else {
+       /* Fixup gic node align with default */
+               reg[0] = cpu_to_fdt64(GICD_BASE);
+               reg[1] = cpu_to_fdt64(GICD_SIZE);
+               reg[2] = cpu_to_fdt64(GICC_BASE);
+               reg[3] = cpu_to_fdt64(GICC_SIZE);
+               reg[4] = cpu_to_fdt64(GICH_BASE);
+               reg[5] = cpu_to_fdt64(GICH_SIZE);
+               reg[6] = cpu_to_fdt64(GICV_BASE);
+               reg[7] = cpu_to_fdt64(GICV_SIZE);
+       }
+
+       err = fdt_setprop(blob, offset, "reg", reg, sizeof(reg));
+       if (err < 0) {
+               printf("WARNING: fdt_setprop can't set %s from node %s: %s\n",
+                      "reg", "interrupt-controller@1400000",
+                      fdt_strerror(err));
+               return;
+       }
+
+       return;
+}
+#endif
+
 void ft_cpu_setup(void *blob, bd_t *bd)
 {
 #ifdef CONFIG_FSL_LSCH2
@@ -177,4 +238,7 @@ void ft_cpu_setup(void *blob, bd_t *bd)
 #endif
        fsl_fdt_disable_usb(blob);
 
+#ifdef CONFIG_HAS_FEATURE_GIC64K_ALIGN
+       fdt_fixup_gic(blob);
+#endif
 }
index 04a2598006510b37463a89f09f4ea39ea7ef1b54..62efa9097e5a29650473ec71e5b47fd5b46b5b28 100644 (file)
 #include <linux/linkage.h>
 #include <asm/gic.h>
 #include <asm/macro.h>
+#include <asm/arch-fsl-layerscape/soc.h>
 #ifdef CONFIG_MP
 #include <asm/arch/mp.h>
 #endif
 #ifdef CONFIG_FSL_LSCH3
 #include <asm/arch-fsl-layerscape/immap_lsch3.h>
-#include <asm/arch-fsl-layerscape/soc.h>
 #endif
 #include <asm/u-boot.h>
 
+/* Get GIC offset
+* For LS1043a rev1.0, GIC base address align with 4k.
+* For LS1043a rev1.1, if DCFG_GIC400_ALIGN[GIC_ADDR_BIT]
+* is set, GIC base address align with 4K, or else align
+* with 64k.
+* output:
+*      x0: the base address of GICD
+*      x1: the base address of GICC
+*/
+ENTRY(get_gic_offset)
+       ldr     x0, =GICD_BASE
+#ifdef CONFIG_GICV2
+       ldr     x1, =GICC_BASE
+#endif
+#ifdef CONFIG_HAS_FEATURE_GIC64K_ALIGN
+       ldr     x2, =DCFG_CCSR_SVR
+       ldr     w2, [x2]
+       rev     w2, w2
+       mov     w3, w2
+       ands    w3, w3, #SVR_WO_E << 8
+       mov     w4, #SVR_LS1043A << 8
+       cmp     w3, w4
+       b.ne    1f
+       ands    w2, w2, #0xff
+       cmp     w2, #REV1_0
+       b.eq    1f
+       ldr     x2, =SCFG_GIC400_ALIGN
+       ldr     w2, [x2]
+       rev     w2, w2
+       tbnz    w2, #GIC_ADDR_BIT, 1f
+       ldr     x0, =GICD_BASE_64K
+#ifdef CONFIG_GICV2
+       ldr     x1, =GICC_BASE_64K
+#endif
+1:
+#endif
+       ret
+ENDPROC(get_gic_offset)
+
+ENTRY(smp_kick_all_cpus)
+       /* Kick secondary cpus up by SGI 0 interrupt */
+#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
+       mov     x29, lr                 /* Save LR */
+       bl      get_gic_offset
+       bl      gic_kick_secondary_cpus
+       mov     lr, x29                 /* Restore LR */
+#endif
+       ret
+ENDPROC(smp_kick_all_cpus)
+
+
 ENTRY(lowlevel_init)
        mov     x29, lr                 /* Save LR */
 
@@ -130,15 +181,14 @@ ENTRY(lowlevel_init)
        /* Initialize GIC Secure Bank Status */
 #if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
        branch_if_slave x0, 1f
-       ldr     x0, =GICD_BASE
+       bl      get_gic_offset
        bl      gic_init_secure
 1:
 #ifdef CONFIG_GICV3
        ldr     x0, =GICR_BASE
        bl      gic_init_secure_percpu
 #elif defined(CONFIG_GICV2)
-       ldr     x0, =GICD_BASE
-       ldr     x1, =GICC_BASE
+       bl      get_gic_offset
        bl      gic_init_secure_percpu
 #endif
 #endif
@@ -413,7 +463,8 @@ ENTRY(secondary_boot_func)
 #if defined(CONFIG_GICV3)
        gic_wait_for_interrupt_m x0
 #elif defined(CONFIG_GICV2)
-        ldr     x0, =GICC_BASE
+       bl      get_gic_offset
+       mov     x0, x1
         gic_wait_for_interrupt_m x0, w1
 #endif
 
index 045825eb979d14849101e42d3e25f951ec041c01..8c426af47e78b906ca9e578f36954f9c81b9c957 100644 (file)
 /* Generic Interrupt Controller Definitions */
 #define GICD_BASE              0x01401000
 #define GICC_BASE              0x01402000
+#define GICH_BASE              0x01404000
+#define GICV_BASE              0x01406000
+#define GICD_SIZE              0x1000
+#define GICC_SIZE              0x2000
+#define GICH_SIZE              0x2000
+#define GICV_SIZE              0x2000
+#ifdef CONFIG_HAS_FEATURE_GIC64K_ALIGN
+#define GICD_BASE_64K          0x01410000
+#define GICC_BASE_64K          0x01420000
+#define GICH_BASE_64K          0x01440000
+#define GICV_BASE_64K          0x01460000
+#define GICD_SIZE_64K          0x10000
+#define GICC_SIZE_64K          0x20000
+#define GICH_SIZE_64K          0x20000
+#define GICV_SIZE_64K          0x20000
+#endif
+
+#define DCFG_CCSR_SVR          0x1ee00a4
+#define REV1_0                 0x10
+#define REV1_1                 0x11
+#define GIC_ADDR_BIT           31
+#define SCFG_GIC400_ALIGN      0x1570188
 
 #define CONFIG_SYS_FSL_MAX_NUM_OF_SEC          1
 
index 6ace3daf01cd95459c60d8aa37f4120bdfb0184d..8ad199f60a1d1d67e68aef8ae160cc4989dcb3ed 100644 (file)
@@ -361,7 +361,8 @@ struct ccsr_scfg {
        u32 qspi_cfg;
        u8 res_160[0x180-0x160];
        u32 dmamcr;
-       u8 res_184[0x18c-0x184];
+       u8 res_184[0x188-0x184];
+       u32 gic_align;
        u32 debug_icid;
        u8 res_190[0x1a4-0x190];
        u32 snpcnfgcr;
index 9bafa6ddfdc450d15c38f699466d3762843fbe51..426fe8ef86b178e321c1d625213780f70e6e78c4 100644 (file)
@@ -59,6 +59,7 @@ struct cpu_type {
 
 #define SVR_MAJ(svr)           (((svr) >> 4) & 0xf)
 #define SVR_MIN(svr)           (((svr) >> 0) & 0xf)
+#define SVR_REV(svr)           (((svr) >> 0) & 0xff)
 #define SVR_SOC_VER(svr)       (((svr) >> 8) & SVR_WO_E)
 #define IS_E_PROCESSOR(svr)    (!((svr >> 8) & 0x1))
 #define IS_SVR_REV(svr, maj, min) \