| /* |
| * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. |
| * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include <arch.h> |
| #include <asm_macros.S> |
| #include <common/bl_common.h> |
| #include <common/runtime_svc.h> |
| #include <cortex_a57.h> |
| #include <platform_def.h> |
| |
| #include "rcar_def.h" |
| |
| .globl plat_get_my_entrypoint |
| .extern plat_set_my_stack |
| .globl platform_mem_init |
| |
| .globl plat_crash_console_init |
| .globl plat_crash_console_putc |
| .globl plat_crash_console_flush |
| .globl plat_invalidate_icache |
| .globl plat_report_exception |
| .globl plat_secondary_reset |
| .globl plat_reset_handler |
| .globl plat_my_core_pos |
| .extern rcar_log_init |
| |
| .extern console_rcar_init |
| .extern console_rcar_putc |
| .extern console_rcar_flush |
| |
| #if IMAGE_BL2 |
| #define INT_ID_MASK (0x3ff) |
| .extern bl2_interrupt_error_type |
| .extern bl2_interrupt_error_id |
| .globl bl2_enter_bl31 |
| .extern gicv2_acknowledge_interrupt |
| .extern rcar_swdt_exec |
| #endif |
| |
| /* ----------------------------------------------------- |
| * void platform_get_core_pos (mpidr) |
| * ----------------------------------------------------- |
| */ |
| func platform_get_core_pos |
| and x1, x0, #MPIDR_CPU_MASK |
| and x0, x0, #MPIDR_CLUSTER_MASK |
| add x0, x1, x0, LSR #6 |
| ret |
| endfunc platform_get_core_pos |
| |
| /* ----------------------------------------------------- |
| * void platform_my_core_pos |
| * ----------------------------------------------------- |
| */ |
| func plat_my_core_pos |
| mrs x0, mpidr_el1 |
| b platform_get_core_pos |
| endfunc plat_my_core_pos |
| |
| /* ----------------------------------------------------- |
| * void platform_get_my_entrypoint (unsigned int mpid); |
| * |
| * Main job of this routine is to distinguish between |
| * a cold and warm boot. |
| * On a cold boot the secondaries first wait for the |
| * platform to be initialized after which they are |
| * hotplugged in. The primary proceeds to perform the |
| * platform initialization. |
| * On a warm boot, each cpu jumps to the address in its |
| * mailbox. |
| * |
| * TODO: Not a good idea to save lr in a temp reg |
| * ----------------------------------------------------- |
| */ |
| func plat_get_my_entrypoint |
| mrs x0, mpidr_el1 |
| mov x9, x30 /* lr */ |
| |
| #if defined(IMAGE_BL2) |
| /* always cold boot on bl2 */ |
| mov x0, #0 |
| ret x9 |
| #else |
| ldr x1, =BOOT_KIND_BASE |
| ldr x21, [x1] |
| |
| /* Check the reset info */ |
| and x1, x21, #0x000c |
| cmp x1, #0x0008 |
| beq el3_panic |
| cmp x1, #0x000c |
| beq el3_panic |
| |
| /* Check the boot kind */ |
| and x1, x21, #0x0003 |
| cmp x1, #0x0002 |
| beq el3_panic |
| cmp x1, #0x0003 |
| beq el3_panic |
| |
| /* warm boot or cold boot */ |
| and x1, x21, #1 |
| cmp x1, #0 |
| bne warm_reset |
| |
| /* Cold boot */ |
| mov x0, #0 |
| b exit |
| |
| warm_reset: |
| /* -------------------------------------------------------------------- |
| * A per-cpu mailbox is maintained in the trusted SDRAM. Its flushed out |
| * of the caches after every update using normal memory so its safe to |
| * read it here with SO attributes |
| * --------------------------------------------------------------------- |
| */ |
| ldr x10, =MBOX_BASE |
| bl platform_get_core_pos |
| lsl x0, x0, #CACHE_WRITEBACK_SHIFT |
| ldr x0, [x10, x0] |
| cbz x0, _panic |
| exit: |
| ret x9 |
| _panic: |
| b do_panic |
| #endif |
| |
| endfunc plat_get_my_entrypoint |
| |
| /* --------------------------------------------- |
| * plat_secondary_reset |
| * |
| * --------------------------------------------- |
| */ |
| func plat_secondary_reset |
| mrs x0, sctlr_el3 |
| bic x0, x0, #SCTLR_EE_BIT |
| msr sctlr_el3, x0 |
| isb |
| |
| mrs x0, cptr_el3 |
| bic w0, w0, #TCPAC_BIT |
| bic w0, w0, #TTA_BIT |
| bic w0, w0, #TFP_BIT |
| msr cptr_el3, x0 |
| |
| mov_imm x0, PARAMS_BASE |
| mov_imm x2, BL31_BASE |
| ldr x3, =BOOT_KIND_BASE |
| mov x1, #0x1 |
| str x1, [x3] |
| br x2 /* jump to BL31 */ |
| nop |
| nop |
| nop |
| endfunc plat_secondary_reset |
| |
| /* --------------------------------------------- |
| * plat_enter_bl31 |
| * |
| * --------------------------------------------- |
| */ |
| func bl2_enter_bl31 |
| mov x20, x0 |
| /* |
| * MMU needs to be disabled because both BL2 and BL31 execute |
| * in EL3, and therefore share the same address space. |
| * BL31 will initialize the address space according to its |
| * own requirement. |
| */ |
| #if RCAR_BL2_DCACHE == 1 |
| /* Disable mmu and data cache */ |
| bl disable_mmu_el3 |
| /* Data cache clean and invalidate */ |
| mov x0, #DCCISW |
| bl dcsw_op_all |
| /* TLB invalidate all, EL3 */ |
| tlbi alle3 |
| #endif /* RCAR_BL2_DCACHE == 1 */ |
| bl disable_mmu_icache_el3 |
| /* Invalidate instruction cache */ |
| ic iallu |
| dsb sy |
| isb |
| ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] |
| msr elr_el3, x0 |
| msr spsr_el3, x1 |
| exception_return |
| endfunc bl2_enter_bl31 |
| |
| /* ----------------------------------------------------- |
| * void platform_mem_init (void); |
| * |
| * Zero out the mailbox registers in the shared memory |
| * and set the rcar_boot_kind_flag. |
| * The mmu is turned off right now and only the primary can |
| * ever execute this code. Secondaries will read the |
| * mailboxes using SO accesses. |
| * ----------------------------------------------------- |
| */ |
| func platform_mem_init |
| #if !IMAGE_BL2 |
| ldr x0, =MBOX_BASE |
| mov w1, #PLATFORM_CORE_COUNT |
| loop: |
| str xzr, [x0], #CACHE_WRITEBACK_GRANULE |
| subs w1, w1, #1 |
| b.gt loop |
| #endif |
| ret |
| endfunc platform_mem_init |
| |
| /* --------------------------------------------- |
| * void plat_report_exception(unsigned int type) |
| * Function to report an unhandled exception |
| * with platform-specific means. |
| * --------------------------------------------- |
| */ |
| func plat_report_exception |
| /* Switch to SP_EL0 */ |
| msr spsel, #0 |
| #if IMAGE_BL2 |
| mov w1, #FIQ_SP_EL0 |
| cmp w0, w1 |
| beq rep_exec_fiq_elx |
| b rep_exec_panic_type |
| rep_exec_fiq_elx: |
| bl gicv2_acknowledge_interrupt |
| mov x2, #INT_ID_MASK |
| and x0, x0, x2 |
| mov x1, #ARM_IRQ_SEC_WDT |
| cmp x0, x1 |
| bne rep_exec_panic_id |
| mrs x0, ELR_EL3 |
| b rcar_swdt_exec |
| rep_exec_panic_type: |
| /* x0 is interrupt TYPE */ |
| b bl2_interrupt_error_type |
| rep_exec_panic_id: |
| /* x0 is interrupt ID */ |
| b bl2_interrupt_error_id |
| rep_exec_end: |
| #endif |
| ret |
| endfunc plat_report_exception |
| |
| /* --------------------------------------------- |
| * int plat_crash_console_init(void) |
| * Function to initialize log area |
| * --------------------------------------------- |
| */ |
| func plat_crash_console_init |
| #if IMAGE_BL2 |
| mov x0, #0 |
| #else |
| mov x1, sp |
| mov_imm x2, RCAR_CRASH_STACK |
| mov sp, x2 |
| str x1, [sp, #-16]! |
| str x30, [sp, #-16]! |
| bl console_rcar_init |
| ldr x30, [sp], #16 |
| ldr x1, [sp], #16 |
| mov sp, x1 |
| #endif |
| ret |
| endfunc plat_crash_console_init |
| |
| /* --------------------------------------------- |
| * int plat_crash_console_putc(int c) |
| * Function to store a character to log area |
| * --------------------------------------------- |
| */ |
| func plat_crash_console_putc |
| mov x1, sp |
| mov_imm x2, RCAR_CRASH_STACK |
| mov sp, x2 |
| str x1, [sp, #-16]! |
| str x30, [sp, #-16]! |
| str x3, [sp, #-16]! |
| str x4, [sp, #-16]! |
| str x5, [sp, #-16]! |
| bl console_rcar_putc |
| ldr x5, [sp], #16 |
| ldr x4, [sp], #16 |
| ldr x3, [sp], #16 |
| ldr x30, [sp], #16 |
| ldr x1, [sp], #16 |
| mov sp, x1 |
| ret |
| endfunc plat_crash_console_putc |
| |
| /* --------------------------------------------- |
| * void plat_crash_console_flush() |
| * --------------------------------------------- |
| */ |
| func plat_crash_console_flush |
| b console_rcar_flush |
| endfunc plat_crash_console_flush |
| |
| /* -------------------------------------------------------------------- |
| * void plat_reset_handler(void); |
| * |
| * Before adding code in this function, refer to the guidelines in |
| * docs/firmware-design.md to determine whether the code should reside |
| * within the FIRST_RESET_HANDLER_CALL block or not. |
| * |
| * For R-Car H3: |
| * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 |
| * - Set the L2 Data setup latency to 1 (i.e. 1 cycles) for Cortex-A57 |
| * - Set the L2 Data RAM latency to 3 (i.e. 4 cycles) for Cortex-A57 |
| * For R-Car M3/M3N: |
| * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 |
| * - Set the L2 Data setup latency to 0 (i.e. 0 cycles) for Cortex-A57 |
| * - Set the L2 Data RAM latency to 3 (i.e. 4 cycles) for Cortex-A57 |
| * |
| * -------------------------------------------------------------------- |
| */ |
| func plat_reset_handler |
| /* |
| * On R-Car H3 : x2 := 0 |
| * On R-Car M3/M3N: x2 := 1 |
| */ |
| /* read PRR */ |
| ldr x0, =0xFFF00044 |
| ldr w0, [x0] |
| ubfx w0, w0, 8, 8 |
| /* H3? */ |
| cmp w0, #0x4F |
| b.eq RCARH3 |
| /* set R-Car M3/M3N */ |
| mov x2, #1 |
| b CHK_A5x |
| RCARH3: |
| /* set R-Car H3 */ |
| mov x2, #0 |
| /* -------------------------------------------------------------------- |
| * Determine whether this code is executed on a Cortex-A53 or on a |
| * Cortex-A57 core. |
| * -------------------------------------------------------------------- |
| */ |
| CHK_A5x: |
| mrs x0, midr_el1 |
| ubfx x1, x0, MIDR_PN_SHIFT, #12 |
| cmp w1, #((CORTEX_A57_MIDR >> MIDR_PN_SHIFT) & MIDR_PN_MASK) |
| b.eq A57 |
| ret |
| A57: |
| /* Get data from CORTEX_A57_L2CTLR_EL1 */ |
| mrs x0, CORTEX_A57_L2CTLR_EL1 |
| /* |
| * On R-Car H3/M3/M3N |
| * |
| * L2 Tag RAM latency is bit8-6 of CORTEX_A57_L2CTLR_EL1 |
| * L2 Data RAM setup is bit5 of CORTEX_A57_L2CTLR_EL1 |
| * L2 Data RAM latency is bit2-0 of CORTEX_A57_L2CTLR_EL1 |
| */ |
| /* clear bit of L2 RAM */ |
| /* ~(0x1e7) -> x1 */ |
| mov x1, #0x1e7 |
| neg x1, x1 |
| /* clear bit of L2 RAM -> x0 */ |
| and x0, x0, x1 |
| /* L2 Tag RAM latency (3 cycles) */ |
| orr x0, x0, #0x2 << 6 |
| /* If M3/M3N then L2 RAM setup is 0 */ |
| cbnz x2, M3_L2 |
| /* L2 Data RAM setup (1 cycle) */ |
| orr x0, x0, #0x1 << 5 |
| M3_L2: |
| /* L2 Data RAM latency (4 cycles) */ |
| orr x0, x0, #0x3 |
| /* Store data to L2CTLR_EL1 */ |
| msr CORTEX_A57_L2CTLR_EL1, x0 |
| apply_l2_ram_latencies: |
| ret |
| endfunc plat_reset_handler |
| |
| /* --------------------------------------------- |
| * void plat_invalidate_icache(void) |
| * Instruction Cache Invalidate All to PoU |
| * --------------------------------------------- |
| */ |
| func plat_invalidate_icache |
| ic iallu |
| |
| ret |
| endfunc plat_invalidate_icache |