From 0cfb0b5ca768b2516a5aa7b0f88be0daeea31692 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= <megi@xff.cz>
Date: Sat, 2 Nov 2019 15:14:10 +0100
Subject: firmware: scpi: Add support for sending a SCPI_CMD_SET_SYS_PWR_STATE
 msg

This is NOT the right message to signal SCP we want to suspend the
system, but we use it anyway, because we simply want to do a fixed
function suspend sequence, instead of more complicated and granular
cluster/cpu/system power management.

Normally we'd signal system suspend by sending a CSS power state
message. I guess that can be done later, if wanted.

For now, Linux will kill all secondary CPU cores via MCPM, and SCP
will kill the last CPU, and suspend the system.

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 drivers/firmware/arm_scpi.c   | 10 ++++++++++
 include/linux/scpi_protocol.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 87c323de17b9..0967c9212653 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -187,6 +187,7 @@ enum scpi_drv_cmds {
 	CMD_SENSOR_VALUE,
 	CMD_SET_DEVICE_PWR_STATE,
 	CMD_GET_DEVICE_PWR_STATE,
+	CMD_SET_SYS_PWR_STATE,
 	CMD_MAX_COUNT,
 };
 
@@ -203,6 +204,7 @@ static int scpi_std_commands[CMD_MAX_COUNT] = {
 	SCPI_CMD_SENSOR_VALUE,
 	SCPI_CMD_SET_DEVICE_PWR_STATE,
 	SCPI_CMD_GET_DEVICE_PWR_STATE,
+	SCPI_CMD_SET_SYS_PWR_STATE,
 };
 
 static int scpi_legacy_commands[CMD_MAX_COUNT] = {
@@ -218,6 +220,7 @@ static int scpi_legacy_commands[CMD_MAX_COUNT] = {
 	LEGACY_SCPI_CMD_SENSOR_VALUE,
 	-1, /* SET_DEVICE_PWR_STATE */
 	-1, /* GET_DEVICE_PWR_STATE */
+	LEGACY_SCPI_CMD_SYS_PWR_STATE,
 };
 
 struct scpi_xfer {
@@ -785,6 +788,12 @@ static int scpi_device_set_power_state(u16 dev_id, u8 pstate)
 				 sizeof(dev_set), &stat, sizeof(stat));
 }
 
+static int scpi_sys_set_power_state(u8 pstate)
+{
+	return scpi_send_message(CMD_SET_SYS_PWR_STATE, &pstate,
+				 sizeof(pstate), NULL, 0);
+}
+
 static struct scpi_ops scpi_ops = {
 	.get_version = scpi_get_version,
 	.clk_get_range = scpi_clk_get_range,
@@ -801,6 +810,7 @@ static struct scpi_ops scpi_ops = {
 	.sensor_get_value = scpi_sensor_get_value,
 	.device_get_power_state = scpi_device_get_power_state,
 	.device_set_power_state = scpi_device_set_power_state,
+	.sys_set_power_state = scpi_sys_set_power_state,
 };
 
 struct scpi_ops *get_scpi_ops(void)
diff --git a/include/linux/scpi_protocol.h b/include/linux/scpi_protocol.h
index d2176a56828a..6169348c3b72 100644
--- a/include/linux/scpi_protocol.h
+++ b/include/linux/scpi_protocol.h
@@ -76,6 +76,7 @@ struct scpi_ops {
 	int (*sensor_get_value)(u16, u64 *);
 	int (*device_get_power_state)(u16);
 	int (*device_set_power_state)(u16, u8);
+	int (*sys_set_power_state)(u8);
 };
 
 #if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL)
-- 
2.35.3

