/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
* Copyright 2018-2023 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/



/*******************************************************************************
 * DESCRIPTION   : Image load function
 ******************************************************************************/
/******************************************************************************
 * @file          loader_s4.S
 * - Version      : 0.06
 * @brief         
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 02.02.2022 0.01     First Release
 *         : 27.06.2022 0.02     Remove unused definitions
 *         : 02.08.2022 0.03     Support WDT
 *         : 31.10.2022 0.04     License notation change.
 *         : 14.12.2022 0.05     Support MMU
 *         : 17.02.2023 0.06     Modified instruction and General purpose
 *                               register to lower case.
 *****************************************************************************/

#include "asm_macros.S"

/* SCTLR definitions */ 
#define SCTLR_M_BIT        (1 << 0)
#define SCTLR_A_BIT        (1 << 1)
#define SCTLR_SA_BIT       (1 << 3)
#define SCTLR_I_BIT        (1 << 12)
#define SCTLR_WXN_BIT      (1 << 19)
#define SCTLR_EE_BIT       (1 << 25)
#define SCTLR_RESET_VAL    (SCTLR_SA_BIT)
#define SCTLR_MMU_ON       (SCTLR_M_BIT)
#define SCTLR_OFF          ~(SCTLR_M_BIT | SCTLR_I_BIT | SCTLR_A_BIT)

/* SCR definitions */
#define SCR_RES1_BITS		((1 << 4) | (1 << 5))
#define SCR_TWEDEL_SHIFT	(30)
#define SCR_TWEDEL_MASK		(0xf)
#define SCR_AMVOFFEN_BIT	(1 << 35)
#define SCR_TWEDEn_BIT		(1 << 29)
#define SCR_ECVEN_BIT		(1 << 28)
#define SCR_FGTEN_BIT		(1 << 27)
#define SCR_ATA_BIT		(1 << 26)
#define SCR_FIEN_BIT		(1 << 21)
#define SCR_EEL2_BIT		(1 << 18)
#define SCR_API_BIT		(1 << 17)
#define SCR_APK_BIT		(1 << 16)
#define SCR_TERR_BIT		(1 << 15)
#define SCR_TWE_BIT		(1 << 13)
#define SCR_TWI_BIT		(1 << 12)
#define SCR_ST_BIT		(1 << 11)
#define SCR_RW_BIT		(1 << 10)
#define SCR_SIF_BIT		(1 << 9)
#define SCR_HCE_BIT		(1 << 8)
#define SCR_SMD_BIT		(1 << 7)
#define SCR_EA_BIT		(1 << 3)
#define SCR_FIQ_BIT		(1 << 2)
#define SCR_IRQ_BIT		(1 << 1)
#define SCR_NS_BIT		(1 << 0)
#define SCR_VALID_BIT_MASK	(0x2f8f)
#define SCR_RESET_VAL		SCR_RES1_BITS

/* CPSR/SPSR definitions */
#define DAIF_FIQ_BIT		(1 << 0)
#define DAIF_IRQ_BIT		(1 << 1)
#define DAIF_ABT_BIT		(1 << 2)
#define DAIF_DBG_BIT		(1 << 3)
#define SPSR_DAIF_SHIFT		(6)
#define SPSR_DAIF_MASK		(0xf)

#define SPSR_AIF_SHIFT		(6)
#define SPSR_AIF_MASK		(0x7)

#define SPSR_E_SHIFT		(9)
#define SPSR_E_MASK		(0x1)
#define SPSR_E_LITTLE		(0x0)
#define SPSR_E_BIG		(0x1)

#define SPSR_T_SHIFT		(5)
#define SPSR_T_MASK		(0x1)
#define SPSR_T_ARM		(0x0)
#define SPSR_T_THUMB		(0x1)

#define SPSR_M_SHIFT		(4)
#define SPSR_M_MASK		(0x1)
#define SPSR_M_AARCH64		(0x0)
#define SPSR_M_AARCH32		(0x1)

#define SPSR_EL_SHIFT		(2)
#define SPSR_EL_WIDTH		(2)

/* TCR definitions */
#define TCR_BIT31_RES1      (1 << 31)
#define TCR_BIT23_RES1      (1 << 23)
#define TCR_PS              (0 << 16)
#define TCR_TG0             (0 << 14)
#define TCR_SH0             (3 << 12)
#define TCR_ORGN0           (3 << 10)
#define TCR_IRGN0           (3 << 8)
#define TCR_T0SZ            (32 << 0)

#define TCR_VAL             \
        (TCR_BIT31_RES1 | TCR_BIT23_RES1 | TCR_PS | TCR_TG0 | TCR_SH0 | TCR_ORGN0 | TCR_IRGN0 | TCR_T0SZ)

/* MAIR definitions */
#define MAIR_ATTR0          (0x00 <<  0)   /* Device-nGnRnE memory */
#define MAIR_ATTR1          (0x4A <<  8)   /* Normal memory, Outer Non-cacheable, Inner Write-Through Non-transient */
#define MAIR_ATTR2          (0x44 << 16)   /* Normal memory, Outer Non-cacheable, Inner Non-cacheable */
#define MAIR_ATTR3          (0x00 << 24)
#define MAIR_ATTR4          (0x00 << 32)
#define MAIR_ATTR5          (0x00 << 40)
#define MAIR_ATTR6          (0x00 << 48)
#define MAIR_ATTR7          (0x00 << 56)

#define MAIR_VAL             \
        (MAIR_ATTR7 | MAIR_ATTR6 | MAIR_ATTR5 | MAIR_ATTR4 | MAIR_ATTR3 | MAIR_ATTR2 | MAIR_ATTR1 | MAIR_ATTR0)
#define MAIR_INIT_VAL       (0x44E048E000098AA4)

#define BIT_64Cx(nr)		(1 << (nr))
#define SPSR_SSBS_BIT_AARCH64	BIT_64Cx(12)
#define SPSR_SSBS_BIT_AARCH32	BIT_64Cx(23)

#define DISABLE_ALL_EXCEPTIONS \
		(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)

#define DISABLE_INTERRUPTS	(DAIF_FIQ_BIT | DAIF_IRQ_BIT)
#define MODE_RW_SHIFT		(0x4)
#define MODE_SP_MASK		(0x1)
#define MODE_SP_SHIFT		(0x0)
#define MODE_EL_MASK		(0x3)
#define MODE_EL_SHIFT		(0x2)
#define MODE_EL3		(0x3)

#define MODE_RW_64		(0x0)
#define MODE_SP_ELX		(0x1)

#define SPSR_64 (((MODE_RW_64 << MODE_RW_SHIFT) | \
((MODE_EL3 & MODE_EL_MASK) << MODE_EL_SHIFT) | \
((MODE_SP_ELX & MODE_SP_MASK) << MODE_SP_SHIFT) |             \
((DISABLE_ALL_EXCEPTIONS & SPSR_DAIF_MASK) << SPSR_DAIF_SHIFT)) &      \
(~(SPSR_SSBS_BIT_AARCH64)))


	.global	Startup

/*****************************************************************************
 *	Reset Hander
 *****************************************************************************/
Startup:
	/* initialize registers*/
	ldr		x0, =0
	ldr		x1, =0
	ldr		x2, =0
	ldr		x3, =0
	ldr		x4, =0
	ldr		x5, =0
	ldr		x6, =0
	ldr		x7, =0
	ldr		x8, =0
	ldr		x9, =0
	ldr		x10, =0
	ldr		x11, =0
	ldr		x12, =0
	ldr		x13, =0
	ldr		x14, =0
	ldr		x15, =0
	ldr		x16, =0
	ldr		x17, =0
	ldr		x18, =0
	ldr		x19, =0
	ldr		x20, =0
	ldr		x21, =0
	ldr		x22, =0
	ldr		x23, =0
	ldr		x24, =0
	ldr		x25, =0
	ldr		x26, =0
	ldr		x27, =0
	ldr		x28, =0
	ldr		x29, =0
	ldr		x30, =0

	ldr x0, =__STACKS_END__

    mrs x1, sctlr_el3
	mov_imm	x0, (SCTLR_RESET_VAL & ~(SCTLR_EE_BIT | SCTLR_WXN_BIT \
            | SCTLR_SA_BIT | SCTLR_A_BIT))
    orr x0, x0, x1
	msr	sctlr_el3, x0
	isb

	mov	x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
	mrs	x0, sctlr_el3
	orr	x0, x0, x1
	msr	sctlr_el3, x0
	isb

    mrs x1, scr_el3
	mov_imm	x0, ((SCR_RESET_VAL | SCR_EA_BIT | SCR_SIF_BIT | SCR_FIQ_BIT ) \
			& ~(SCR_TWE_BIT | SCR_TWI_BIT | SCR_SMD_BIT))
    orr x0, x0, x1
	msr	scr_el3, x0

	/* ---------------------------------------------------------------------
	 * Set the exception vectors.
	 * ---------------------------------------------------------------------
	 */
	adr	x0, loader_exceptions
	msr	vbar_el3, x0
	isb

    msr	daifclr, #(DAIF_ABT_BIT | DAIF_FIQ_BIT)

	/* ---------------------------------------------------------------------
	 * Set the MMU table.
	 * ---------------------------------------------------------------------
	 */
    ldr x0 ,=TCR_VAL
    msr tcr_el3, x0

    ldr x0, =MAIR_VAL
    msr mair_el3, x0

    ldr x0, =g_loader_level1_table
    msr ttbr0_el3, x0

    /* ---------------------------------------------------------------------
     * Enable MMU.
     * ---------------------------------------------------------------------
     */

    isb
    tlbi alle3
    isb

    mrs x0, sctlr_el3
    ldr x1 ,=SCTLR_MMU_ON
    orr x0, x0, x1
    msr sctlr_el3, x0

    dsb sy
    isb
    tlbi alle3
    isb

	/* clear bss section */
	mov	x0, #0x0
	ldr	x1, =__BSS_START__
	ldr	x2, =__BSS_SIZE__
bss_loop:
	subs	x2, x2, #4
	bcc	bss_end
	str	w0, [x1, x2]
	b	bss_loop
bss_end:

	/* copy data section */
	ldr	x0, =__DATA_COPY_START__
	ldr	x1, =__DATA_START__
	ldr	x2, =__DATA_SIZE__
data_loop:
	subs	x2, x2, #4
	bcc	data_end
	ldr	w3, [x0, x2]
	str	w3, [x1, x2]
	b	data_loop
data_end:

	msr	spsel, #0

	ldr x0, =__STACKS_END__
	mov	sp, x0

	bl loader_main

	msr	elr_el3, x0

	mov     x0, #SPSR_64
	msr	spsr_el3, x0

    /* ---------------------------------------------------------------------
     * Disable MMU.
     * ---------------------------------------------------------------------
     */
    mrs x0, sctlr_el3
    ldr x1 ,=SCTLR_OFF
    and x0, x0, x1
    msr sctlr_el3, x0

    dsb sy
    isb
    tlbi alle3
    ic iallu

    /* ---------------------------------------------------------------------
     * Set initial value.
     * ---------------------------------------------------------------------
     */
    msr ttbr0_el3, xzr

    ldr x0, =MAIR_INIT_VAL
    msr mair_el3, x0

    msr tcr_el3, xzr

	msr	vbar_el3, xzr
    isb

	eret


	.end