/* * 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 #include #include #include #include #include #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