/*
 * Secure entry function for CPU Core #1
 *
 * (C) Copyright 2016
 * Texas Instruments, <www.ti.com>
 *
 * Author :
 *	Harinarayan Bhatta <harinarayan@ti.com>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <config.h>
#include <asm/arch/omap.h>
#include <asm/omap_common.h>
#include <linux/linkage.h>

.arch_extension sec

#if !defined(CONFIG_SYS_DCACHE_OFF)
.global flush_dcache_range
#endif

#define AUX_CORE_BOOT_0		0x48281800
#define AUX_CORE_BOOT_1		0x48281804

#ifdef CONFIG_DRA7XX
/* DRA7xx ROM code function "startup_BootSlave". This function is where CPU1
 * waits on WFE, polling on AUX_CORE_BOOT_x registers.
 * This address is same for J6 and J6 Eco.
 */
#define ROM_FXN_STARTUP_BOOTSLAVE     0x00038a64
#endif

/* Assembly core where CPU1 is woken up into
 * No need to save-restore registers, does not use stack.
 */
LENTRY(cpu1_entry)
	ldr	r4, =omap_smc_sec_cpu1_args
	ldm	r4, {r0,r1,r2,r3}	@ Retrieve args

	mov	r6, #0xFF	@ Indicate new Task call
	mov	r12, #0x00	@ Secure Service ID in R12

	dsb
	dmb
	smc	0		@ SMC #0 to enter monitor mode

	b	.Lend		@ exit at end of the service execution
	nop

	@ In case of IRQ happening in Secure, then ARM will branch here.
	@ At that moment, IRQ will be pending and ARM will jump to Non Secure
	@ IRQ handler
	mov	r12, #0xFE

	dsb
	dmb
	smc	0		@ SMC #0 to enter monitor mode

.Lend:
	ldr	r4, =omap_smc_sec_cpu1_args
	str	r0, [r4, #0x10]		@ save return value
	ldr	r4, =AUX_CORE_BOOT_0
	mov	r5, #0x0
	str	r5, [r4]
	ldr	r4, =ROM_FXN_STARTUP_BOOTSLAVE
	sev				@ Tell CPU0 we are done
	bx	r4			@ Jump back to ROM
END(cpu1_entry)

/*
 * u32 omap_smc_sec_cpu1(u32 service, u32 proc_id, u32 flag, u32 *params);
 *
 * Makes a secure ROM/PPA call on CPU Core #1 on supported platforms.
 * Assumes that CPU #1 is waiting in ROM code and not yet woken up or used by
 * u-boot.
 */
ENTRY(omap_smc_sec_cpu1)
	push	{r4, r5, lr}
	ldr	r4, =omap_smc_sec_cpu1_args
	stm	r4, {r0,r1,r2,r3}	@ Save args to memory
#if !defined(CONFIG_SYS_DCACHE_OFF)
	mov	r0, r4
	mov	r1, #CONFIG_SYS_CACHELINE_SIZE
	add	r1, r0, r1		@ dcache is not enabled on CPU1, so
	blx	flush_dcache_range	@ flush the cache on args buffer
#endif
	ldr	r4, =AUX_CORE_BOOT_1
	ldr	r5, =cpu1_entry
	str	r5, [r4]		@ Setup CPU1 entry function
	ldr	r4, =AUX_CORE_BOOT_0
	mov	r5, #0x10
	str	r5, [r4]		@ Tell ROM to exit while loop
	sev				@ Wake up CPU1
.Lwait:
	wfe				@ Wait for CPU1 to finish
	nop
	ldr	r5, [r4]		@ Check if CPU1 is done
	cmp	r5, #0
	bne	.Lwait

	ldr	r4, =omap_smc_sec_cpu1_args
	ldr	r0, [r4, #0x10]         @ Retrieve return value
	pop	{r4, r5, pc}
ENDPROC(omap_smc_sec_cpu1)

/*
 * Buffer to save function arguments and return value for omap_smc_sec_cpu1
 */
.section .data
omap_smc_sec_cpu1_args:
#if !defined(CONFIG_SYS_DCACHE_OFF)
	.balign CONFIG_SYS_CACHELINE_SIZE
	.rept  CONFIG_SYS_CACHELINE_SIZE/4
	.word 0
	.endr
#else
	.rept 5
	.word 0
	.endr
#endif
END(omap_smc_sec_cpu1_args)
