.section .text.drivers.psci

// Initializes the PSCI with a fixed method.
//
// ## Arguments
//
// - x0: 0 if the SMC method should be used, 1 if the HVC method should be used.
.global psci.init_with
psci.init_with:
	cmp x0, #2
	b.hs psci.init_with.error
	ldr x1, =psci.init_with.funcs
	ldr x0, [x1, x0, lsl 3]
	ldr x1, =psci.function
	str x0, [x1]
	ret
psci.init_with.error:
	ldr x0, =psci.init_with.error_msg
	mov x1, psci.init_with.error_msg.len
	bl panic

// Performs a call to the hypervisor. This should be used if the PSCI node in
// the devicetree has a method of `hvc`.
psci.function_hvc:
	hvc #0
	ret

// Performs a call to the secure monitor. This should be used if the PSCI node
// in the devicetree has a method of `smc`.
psci.function_smc:
	smc #0
	ret

// Powers off the system.
.global psci.system_off
psci.system_off:
	ldr x15, =psci.function
	ldr x15, [x15]

	mov x0, #0x84000000
	movk x0, #0x8
	br x15

// Resets the system.
.global psci.system_reset
psci.system_reset:
	ldr x15, =psci.function
	ldr x15, [x15]

	mov x0, #0x84000000
	movk x0, #0x9
	br x15

.section .rodata.drivers.psci

psci.init_with.error_msg: .ascii "Invalid value passed to psci.init_with!"
.set psci.init_with.error_msg.len, . - psci.init_with.error_msg

.align 8
psci.init_with.funcs:
	.quad psci.function_smc
	.quad psci.function_hvc

.section .bss.drivers.psci

.align 8
psci.function: .skip 8

// vi: set ft=arm64asm :