diff options
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 5 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/fdt.c | 64 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S | 61 |
3 files changed, 125 insertions, 5 deletions
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig index 79e2dd6..dce1689 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig +++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig @@ -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" diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c index c10ccf9..f289172 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c @@ -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 } diff --git a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S index 04a2598..62efa90 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S +++ b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S @@ -10,15 +10,66 @@ #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 |