diff options
Diffstat (limited to 'arch/arm/cpu/armv7/sunxi')
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/board.c | 18 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/cpu_info.c | 11 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/psci_sun6i.S | 280 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/psci_sun7i.S (renamed from arch/arm/cpu/armv7/sunxi/psci.S) | 14 |
5 files changed, 310 insertions, 19 deletions
diff --git a/arch/arm/cpu/armv7/sunxi/Makefile b/arch/arm/cpu/armv7/sunxi/Makefile index 6a0299f..76c7e55 100644 --- a/arch/arm/cpu/armv7/sunxi/Makefile +++ b/arch/arm/cpu/armv7/sunxi/Makefile @@ -13,7 +13,9 @@ obj-y += clock.o obj-y += cpu_info.o obj-y += dram_helpers.o obj-y += pinmux.o +ifndef CONFIG_MACH_SUN9I obj-y += usb_phy.o +endif obj-$(CONFIG_MACH_SUN6I) += prcm.o obj-$(CONFIG_MACH_SUN8I) += prcm.o obj-$(CONFIG_MACH_SUN9I) += prcm.o @@ -33,7 +35,9 @@ obj-$(CONFIG_AXP221_POWER) += pmic_bus.o ifndef CONFIG_SPL_BUILD ifdef CONFIG_ARMV7_PSCI -obj-y += psci.o +obj-$(CONFIG_MACH_SUN6I) += psci_sun6i.o +obj-$(CONFIG_MACH_SUN7I) += psci_sun7i.o +obj-$(CONFIG_MACH_SUN8I) += psci_sun6i.o endif endif diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index e6730c0..a82c8b9 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -64,6 +64,10 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPH(20), SUN6I_GPH_UART0); sunxi_gpio_set_cfgpin(SUNXI_GPH(21), SUN6I_GPH_UART0); sunxi_gpio_set_pull(SUNXI_GPH(21), SUNXI_GPIO_PULL_UP); +#elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN9I) + sunxi_gpio_set_cfgpin(SUNXI_GPH(12), SUN9I_GPH_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPH(13), SUN9I_GPH_UART0); + sunxi_gpio_set_pull(SUNXI_GPH(13), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN5I) sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG_UART1); sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG_UART1); @@ -115,17 +119,19 @@ void s_init(void) #ifdef CONFIG_SPL_BUILD /* The sunxi internal brom will try to loader external bootloader * from mmc0, nand flash, mmc2. - * Unfortunately we can't check how SPL was loaded so assume - * it's always the first SD/MMC controller + * + * Unfortunately we can't check how SPL was loaded so assume it's + * always the first SD/MMC controller, unless it was explicitly + * stated that SPL is on nand flash. */ u32 spl_boot_device(void) { -#ifdef CONFIG_SPL_FEL +#if defined(CONFIG_SPL_NAND_SUPPORT) /* - * This is the legacy compile time configuration for a special FEL - * enabled build. It has many restrictions and can only boot over USB. + * This is compile time configuration informing SPL, that it + * was loaded from nand flash. */ - return BOOT_DEVICE_BOARD; + return BOOT_DEVICE_NAND; #else /* * When booting from the SD card, the "eGON.BT0" signature is expected diff --git a/arch/arm/cpu/armv7/sunxi/cpu_info.c b/arch/arm/cpu/armv7/sunxi/cpu_info.c index 30ec4ac..a276fad 100644 --- a/arch/arm/cpu/armv7/sunxi/cpu_info.c +++ b/arch/arm/cpu/armv7/sunxi/cpu_info.c @@ -11,6 +11,7 @@ #include <asm/arch/cpu.h> #include <asm/arch/clock.h> #include <axp221.h> +#include <errno.h> #ifdef CONFIG_MACH_SUN6I int sunxi_get_ss_bonding_id(void) @@ -68,6 +69,8 @@ int print_cpuinfo(void) puts("CPU: Allwinner A23 (SUN8I)\n"); #elif defined CONFIG_MACH_SUN8I_A33 puts("CPU: Allwinner A33 (SUN8I)\n"); +#elif defined CONFIG_MACH_SUN9I + puts("CPU: Allwinner A80 (SUN9I)\n"); #else #warning Please update cpu_info.c with correct CPU information puts("CPU: SUNXI Family\n"); @@ -78,18 +81,16 @@ int print_cpuinfo(void) int sunxi_get_sid(unsigned int *sid) { -#if defined CONFIG_MACH_SUN6I || defined CONFIG_MACH_SUN8I_A23 #ifdef CONFIG_AXP221_POWER return axp221_get_sid(sid); -#else - return -ENODEV; -#endif -#else +#elif defined SUNXI_SID_BASE int i; for (i = 0; i< 4; i++) sid[i] = readl(SUNXI_SID_BASE + 4 * i); return 0; +#else + return -ENODEV; #endif } diff --git a/arch/arm/cpu/armv7/sunxi/psci_sun6i.S b/arch/arm/cpu/armv7/sunxi/psci_sun6i.S new file mode 100644 index 0000000..d4cb51e --- /dev/null +++ b/arch/arm/cpu/armv7/sunxi/psci_sun6i.S @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2015 - Chen-Yu Tsai + * Author: Chen-Yu Tsai <wens@csie.org> + * + * Based on psci_sun7i.S by Marc Zyngier <marc.zyngier@arm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <asm/gic.h> +#include <asm/macro.h> +#include <asm/psci.h> +#include <asm/arch/cpu.h> + +/* + * Memory layout: + * + * SECURE_RAM to text_end : + * ._secure_text section + * text_end to ALIGN_PAGE(text_end): + * nothing + * ALIGN_PAGE(text_end) to ALIGN_PAGE(text_end) + 0x1000) + * 1kB of stack per CPU (4 CPUs max). + */ + + .pushsection ._secure.text, "ax" + + .arch_extension sec + +#define ONE_MS (CONFIG_TIMER_CLK_FREQ / 1000) +#define TEN_MS (10 * ONE_MS) +#define GICD_BASE 0x1c81000 +#define GICC_BASE 0x1c82000 + +.macro timer_wait reg, ticks + @ Program CNTP_TVAL + movw \reg, #(\ticks & 0xffff) + movt \reg, #(\ticks >> 16) + mcr p15, 0, \reg, c14, c2, 0 + isb + @ Enable physical timer, mask interrupt + mov \reg, #3 + mcr p15, 0, \reg, c14, c2, 1 + @ Poll physical timer until ISTATUS is on +1: isb + mrc p15, 0, \reg, c14, c2, 1 + ands \reg, \reg, #4 + bne 1b + @ Disable timer + mov \reg, #0 + mcr p15, 0, \reg, c14, c2, 1 + isb +.endm + +.globl psci_fiq_enter +psci_fiq_enter: + push {r0-r12} + + @ Switch to secure + mrc p15, 0, r7, c1, c1, 0 + bic r8, r7, #1 + mcr p15, 0, r8, c1, c1, 0 + isb + + @ Validate reason based on IAR and acknowledge + movw r8, #(GICC_BASE & 0xffff) + movt r8, #(GICC_BASE >> 16) + ldr r9, [r8, #GICC_IAR] + movw r10, #0x3ff + movt r10, #0 + cmp r9, r10 @ skip spurious interrupt 1023 + beq out + movw r10, #0x3fe @ ...and 1022 + cmp r9, r10 + beq out + str r9, [r8, #GICC_EOIR] @ acknowledge the interrupt + dsb + + @ Compute CPU number + lsr r9, r9, #10 + and r9, r9, #0xf + + movw r8, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r8, #(SUN6I_CPUCFG_BASE >> 16) + + @ Wait for the core to enter WFI + lsl r11, r9, #6 @ x64 + add r11, r11, r8 + +1: ldr r10, [r11, #0x48] + tst r10, #(1 << 2) + bne 2f + timer_wait r10, ONE_MS + b 1b + + @ Reset CPU +2: mov r10, #0 + str r10, [r11, #0x40] + + @ Lock CPU + mov r10, #1 + lsl r11, r10, r9 @ r11 is now CPU mask + ldr r10, [r8, #0x1e4] + bic r10, r10, r11 + str r10, [r8, #0x1e4] + + movw r8, #(SUNXI_PRCM_BASE & 0xffff) + movt r8, #(SUNXI_PRCM_BASE >> 16) + + @ Set power gating + ldr r10, [r8, #0x100] + orr r10, r10, r11 + str r10, [r8, #0x100] + timer_wait r10, ONE_MS + +#ifdef CONFIG_MACH_SUN6I + @ Activate power clamp + lsl r12, r9, #2 @ x4 + add r12, r12, r8 + mov r10, #0xff + str r10, [r12, #0x140] +#endif + + movw r8, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r8, #(SUN6I_CPUCFG_BASE >> 16) + + @ Unlock CPU + ldr r10, [r8, #0x1e4] + orr r10, r10, r11 + str r10, [r8, #0x1e4] + + @ Restore security level +out: mcr p15, 0, r7, c1, c1, 0 + + pop {r0-r12} + subs pc, lr, #4 + + @ r1 = target CPU + @ r2 = target PC +.globl psci_cpu_on +psci_cpu_on: + push {lr} + + mov r0, r1 + bl psci_get_cpu_stack_top @ get stack top of target CPU + str r2, [r0] @ store target PC at stack top + dsb + + movw r0, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r0, #(SUN6I_CPUCFG_BASE >> 16) + + @ CPU mask + and r1, r1, #3 @ only care about first cluster + mov r4, #1 + lsl r4, r4, r1 + + ldr r6, =psci_cpu_entry + str r6, [r0, #0x1a4] @ PRIVATE_REG (boot vector) + + @ Assert reset on target CPU + mov r6, #0 + lsl r5, r1, #6 @ 64 bytes per CPU + add r5, r5, #0x40 @ Offset from base + add r5, r5, r0 @ CPU control block + str r6, [r5] @ Reset CPU + + @ l1 invalidate + ldr r6, [r0, #0x184] @ CPUCFG_GEN_CTRL_REG + bic r6, r6, r4 + str r6, [r0, #0x184] + + @ Lock CPU (Disable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG + bic r6, r6, r4 + str r6, [r0, #0x1e4] + + movw r0, #(SUNXI_PRCM_BASE & 0xffff) + movt r0, #(SUNXI_PRCM_BASE >> 16) + +#ifdef CONFIG_MACH_SUN6I + @ Release power clamp + lsl r5, r1, #2 @ 1 register per CPU + add r5, r5, r0 @ PRCM + movw r6, #0x1ff + movt r6, #0 +1: lsrs r6, r6, #1 + str r6, [r5, #0x140] @ CPUx_PWR_CLAMP + bne 1b +#endif + + timer_wait r6, TEN_MS + + @ Clear power gating + ldr r6, [r0, #0x100] @ CPU_PWROFF_GATING + bic r6, r6, r4 + str r6, [r0, #0x100] + + @ re-calculate CPU control register address + movw r0, #(SUN6I_CPUCFG_BASE & 0xffff) + movt r0, #(SUN6I_CPUCFG_BASE >> 16) + + @ Deassert reset on target CPU + mov r6, #3 + lsl r5, r1, #6 @ 64 bytes per CPU + add r5, r5, #0x40 @ Offset from base + add r5, r5, r0 @ CPU control block + str r6, [r5] + + @ Unlock CPU (Enable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG + orr r6, r6, r4 + str r6, [r0, #0x1e4] + + mov r0, #ARM_PSCI_RET_SUCCESS @ Return PSCI_RET_SUCCESS + pop {pc} + +.globl psci_cpu_off +psci_cpu_off: + bl psci_cpu_off_common + + @ Ask CPU0 to pull the rug... + movw r0, #(GICD_BASE & 0xffff) + movt r0, #(GICD_BASE >> 16) + movw r1, #15 @ SGI15 + movt r1, #1 @ Target is CPU0 + str r1, [r0, #GICD_SGIR] + dsb + +1: wfi + b 1b + +.globl psci_arch_init +psci_arch_init: + mov r6, lr + + movw r4, #(GICD_BASE & 0xffff) + movt r4, #(GICD_BASE >> 16) + + ldr r5, [r4, #GICD_IGROUPRn] + bic r5, r5, #(1 << 15) @ SGI15 as Group-0 + str r5, [r4, #GICD_IGROUPRn] + + mov r5, #0 @ Set SGI15 priority to 0 + strb r5, [r4, #(GICD_IPRIORITYRn + 15)] + + add r4, r4, #0x1000 @ GICC address + + mov r5, #0xff + str r5, [r4, #GICC_PMR] @ Be cool with non-secure + + ldr r5, [r4, #GICC_CTLR] + orr r5, r5, #(1 << 3) @ Switch FIQEn on + str r5, [r4, #GICC_CTLR] + + mrc p15, 0, r5, c1, c1, 0 @ Read SCR + orr r5, r5, #4 @ Enable FIQ in monitor mode + bic r5, r5, #1 @ Secure mode + mcr p15, 0, r5, c1, c1, 0 @ Write SCR + isb + + bl psci_get_cpu_id @ CPU ID => r0 + bl psci_get_cpu_stack_top @ stack top => r0 + mov sp, r0 + + bx r6 + + .globl psci_text_end +psci_text_end: + .popsection diff --git a/arch/arm/cpu/armv7/sunxi/psci.S b/arch/arm/cpu/armv7/sunxi/psci_sun7i.S index 7ec0500..bbfeec8 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.S +++ b/arch/arm/cpu/armv7/sunxi/psci_sun7i.S @@ -165,12 +165,12 @@ psci_cpu_on: str r6, [r5] @ Reset CPU @ l1 invalidate - ldr r6, [r0, #0x184] + ldr r6, [r0, #0x184] @ CPUCFG_GEN_CTRL_REG bic r6, r6, r4 str r6, [r0, #0x184] - @ Lock CPU - ldr r6, [r0, #0x1e4] + @ Lock CPU (Disable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG bic r6, r6, r4 str r6, [r0, #0x1e4] @@ -178,13 +178,13 @@ psci_cpu_on: movw r6, #0x1ff movt r6, #0 1: lsrs r6, r6, #1 - str r6, [r0, #0x1b0] + str r6, [r0, #0x1b0] @ CPU1_PWR_CLAMP bne 1b timer_wait r1, TEN_MS @ Clear power gating - ldr r6, [r0, #0x1b4] + ldr r6, [r0, #0x1b4] @ CPU1_PWROFF_REG bic r6, r6, #1 str r6, [r0, #0x1b4] @@ -192,8 +192,8 @@ psci_cpu_on: mov r6, #3 str r6, [r5] - @ Unlock CPU - ldr r6, [r0, #0x1e4] + @ Unlock CPU (Enable external debug access) + ldr r6, [r0, #0x1e4] @ CPUCFG_DBG_CTL1_REG orr r6, r6, r4 str r6, [r0, #0x1e4] |