Juno: Implement PSCI SYSTEM_OFF and SYSTEM_RESET APIs

This patch adds the Juno platform specific handlers for PSCI
SYSTEM_OFF and SYSTEM_RESET operations.

Change-Id: Ie389adead533ec2314af44d721b4d0f306147c7d
diff --git a/plat/juno/plat_pm.c b/plat/juno/plat_pm.c
index 27a1227..74ce89f 100644
--- a/plat/juno/plat_pm.c
+++ b/plat/juno/plat_pm.c
@@ -30,6 +30,7 @@
 
 #include <assert.h>
 #include <arch_helpers.h>
+#include <debug.h>
 #include <cci400.h>
 #include <errno.h>
 #include <platform.h>
@@ -239,6 +240,41 @@
 }
 
 /*******************************************************************************
+ * Juno handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 juno_system_off(void)
+{
+	uint32_t response;
+
+	/* Send the power down request to the SCP */
+	response = scpi_sys_power_state(scpi_system_shutdown);
+
+	if (response != SCP_OK) {
+		ERROR("Juno System Off: SCP error %u.\n", response);
+		panic();
+	}
+	wfi();
+	ERROR("Juno System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 juno_system_reset(void)
+{
+	uint32_t response;
+
+	/* Send the system reset request to the SCP */
+	response = scpi_sys_power_state(scpi_system_reboot);
+
+	if (response != SCP_OK) {
+		ERROR("Juno System Reset: SCP error %u.\n", response);
+		panic();
+	}
+	wfi();
+	ERROR("Juno System Reset: operation not handled.\n");
+	panic();
+}
+
+/*******************************************************************************
  * Export the platform handlers to enable psci to invoke them
  ******************************************************************************/
 static const plat_pm_ops_t juno_ops = {
@@ -246,7 +282,9 @@
 	.affinst_on_finish	= juno_affinst_on_finish,
 	.affinst_off		= juno_affinst_off,
 	.affinst_suspend	= juno_affinst_suspend,
-	.affinst_suspend_finish	= juno_affinst_suspend_finish
+	.affinst_suspend_finish	= juno_affinst_suspend_finish,
+	.system_off		= juno_system_off,
+	.system_reset		= juno_system_reset
 };
 
 /*******************************************************************************
diff --git a/plat/juno/scpi.c b/plat/juno/scpi.c
index c1677aa..950c00b 100644
--- a/plat/juno/scpi.c
+++ b/plat/juno/scpi.c
@@ -124,3 +124,17 @@
 	state |= css_state << 16;
 	scpi_secure_send32(SCPI_CMD_SET_CSS_POWER_STATE, state);
 }
+
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
+{
+	uint32_t *response;
+	size_t size;
+	uint8_t state = system_state & 0xff;
+
+	/* Send the command */
+	*(__typeof__(state) *)scpi_secure_message_start() = state;
+	scpi_secure_message_send(SCPI_CMD_SYS_POWER_STATE, sizeof(state));
+	scpi_secure_message_receive((void *)&response, &size);
+	scpi_secure_message_end();
+	return *response;
+}
diff --git a/plat/juno/scpi.h b/plat/juno/scpi.h
index 1112980..8a5ef65 100644
--- a/plat/juno/scpi.h
+++ b/plat/juno/scpi.h
@@ -59,6 +59,7 @@
 typedef enum {
 	SCPI_CMD_SCP_READY = 0x01,
 	SCPI_CMD_SET_CSS_POWER_STATE = 0x04,
+	SCPI_CMD_SYS_POWER_STATE = 0x08
 } scpi_command_t;
 
 typedef enum {
@@ -67,8 +68,15 @@
 	scpi_power_off = 3,
 } scpi_power_state_t;
 
+typedef enum {
+	scpi_system_shutdown = 0,
+	scpi_system_reboot = 1,
+	scpi_system_reset = 2
+} scpi_system_state_t;
+
 extern int scpi_wait_ready(void);
 extern void scpi_set_css_power_state(unsigned mpidr, scpi_power_state_t cpu_state,
 		scpi_power_state_t cluster_state, scpi_power_state_t css_state);
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state);
 
 #endif	/* __SCPI_H__ */