// SPDX-License-Identifier: GPL-2.0-only
/*
* System Control and Power Interface (SCPI) Message Protocol driver
*
* SCPI Message Protocol is used between the System Control Processor(SCP)
* and the Application Processors(AP). The Message Handling Unit(MHU)
* provides a mechanism for inter-processor communication between SCP's
* Cortex M3 and AP.
*
* SCP offers control and management of the core/cluster power states,
* various power domain DVFS including the core/cluster, certain system
* clocks configuration, thermal sensors and many others.
*
* Copyright (C) 2015 ARM Ltd.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitmap.h>
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/property.h>
#include <linux/pm_opp.h>
#include <linux/scpi_protocol.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/spinlock.h>
#define CMD_ID_MASK GENMASK(6, 0)
#define CMD_TOKEN_ID_MASK GENMASK(15, 8)
#define CMD_DATA_SIZE_MASK GENMASK(24, 16)
#define CMD_LEGACY_DATA_SIZE_MASK GENMASK(28, 20)
#define PACK_SCPI_CMD(cmd_id, tx_sz) \
(FIELD_PREP(CMD_ID_MASK, cmd_id) | \
FIELD_PREP(CMD_DATA_SIZE_MASK, tx_sz))
#define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \
(FIELD_PREP(CMD_ID_MASK, cmd_id) | \
FIELD_PREP(CMD_LEGACY_DATA_SIZE_MASK, tx_sz))
#define CMD_SIZE(cmd) FIELD_GET(CMD_DATA_SIZE_MASK, cmd)
#define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK | CMD_ID_MASK)
#define CMD_XTRACT_UNIQ(cmd) ((cmd) & CMD_UNIQ_MASK)
#define SCPI_SLOT 0
#define MAX_DVFS_DOMAINS 8
#define MAX_DVFS_OPPS 16
#define PROTO_REV_MAJOR_MASK GENMASK(31, 16)
#define PROTO_REV_MINOR_MASK GENMASK(15, 0)
#define FW_REV_MAJOR_MASK GENMASK(31, 24)
#define FW_REV_MINOR_MASK GENMASK(23, 16)
#define FW_REV_PATCH_MASK GENMASK(15, 0)
#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
enum scpi_error_codes {
SCPI_SUCCESS = 0, /* Success */
SCPI_ERR_PARAM = 1, /* Invalid parameter(s) */
SCPI_ERR_ALIGN = 2, /* Invalid alignment */
SCPI_ERR_SIZE = 3, /* Invalid size */
SCPI_ERR_HANDLER = 4, /* Invalid handler/callback */
SCPI_ERR_ACCESS = 5, /* Invalid access/permission denied */
SCPI_ERR_RANGE = 6, /* Value out of range */
SCPI_ERR_TIMEOUT = 7, /* Timeout has occurred */
SCPI_ERR_NOMEM = 8, /* Invalid memory area or pointer */
SCPI_ERR_PWRSTATE = 9, /* Invalid power state */
SCPI_ERR_SUPPORT = 10, /* Not supported or disabled */
SCPI_ERR_DEVICE = 11, /* Device error */
SCPI_ERR_BUSY = 12, /* Device busy */
SCPI_ERR_MAX
};
/* SCPI Standard commands */
enum scpi_std_cmd {
SCPI_CMD_INVALID = 0x00,
SCPI_CMD_SCPI_READY = 0x01,
SCPI_CMD_SCPI_CAPABILITIES = 0x02,
SCPI_CMD_SET_CSS_PWR_STATE = 0x03,
SCPI_CMD_GET_CSS_PWR_STATE = 0x04,
SCPI_CMD_SET_SYS_PWR_STATE = 0x05,
SCPI_CMD_SET_CPU_TIMER = 0x06,
SCPI_CMD_CANCEL_CPU_TIMER = 0x07,
SCPI_CMD_DVFS_CAPABILITIES = 0x08,
SCPI_CMD_GET_DVFS_INFO = 0x09,
SCPI_CMD_SET_DVFS = 0x0a,
SCPI_CMD_GET_DVFS = 0x0b,
SCPI_CMD_GET_DVFS_STAT = 0x0c,
SCPI_CMD_CLOCK_CAPABILITIES = 0x0d,
SCPI_CMD_GET_CLOCK_INFO = 0x0e,
SCPI_CMD_SET_CLOCK_VALUE = 0x0f,
SCPI_CMD_GET_CLOCK_VALUE = 0x10,
SCPI_CMD_PSU_CAPABILITIES = 0x11,
SCPI_CMD_GET_PSU_INFO = 0x12,
SCPI_CMD_SET_PSU = 0x13,
SCPI_CMD_GET_PSU = 0x14,
SCPI_CMD_SENSOR_CAPABILITIES = 0x15,
SCPI_CMD_SENSOR_INFO = 0x16,
SCPI_CMD_SENSOR_VALUE = 0x17,
SCPI_CMD_SENSOR_CFG_PERIODIC = 0x18,
SCPI_CMD_SENSOR_CFG_BOUNDS = 0x19,
SCPI_CMD_SENSOR_ASYNC_VALUE = 0x1a,
SCPI_CMD_SET_DEVICE_PWR_STATE = 0x1b,
SCPI_CMD_GET_DEVICE_PWR_STATE = 0x1c,
SCPI_CMD_COUNT
};
/* SCPI Legacy Commands */
enum legacy_scpi_std_cmd {
LEGACY_SCPI_CMD_INVALID = 0x00,
LEGACY_SCPI_CMD_SCPI_READY = 0x01,
LEGACY_SCPI_CMD_SCPI_CAPABILITIES = 0x02,
LEGACY_SCPI_CMD_EVENT = 0x03,
LEGACY_SCPI_CMD_SET_CSS_PWR_STATE = 0x04,
LEGACY_SCPI_CMD_GET_CSS_PWR_STATE = 0x05,
LEGACY_SCPI_CMD_CFG_PWR_STATE_STAT = 0x06,
LEGACY_SCPI_CMD_GET_PWR_STATE_STAT = 0x07,
LEGACY_SCPI_CMD_SYS_PWR_STATE = 0x08,
LEGACY_SCPI_CMD_L2_READY = 0x09,
LEGACY_SCPI_CMD_SET_AP_TIMER = 0x0a,
LEGACY_SCPI_CMD_CANCEL_AP_TIME = 0x0b,
LEGACY_SCPI_CMD_DVFS_CAPABILITIES = 0x0c,
LEGACY_SCPI_CMD_GET_DVFS_INFO = 0x0d,
LEGACY_SCPI_CMD_SET_DVFS = 0x0e,
LEGACY_SCPI_CMD_GET_DVFS = 0x0f,
LEGACY_SCPI_CMD_GET_DVFS_STAT = 0x10,
LEGACY_SCPI_CMD_SET_RTC = 0x11,
LEGACY_SCPI_CMD_GET_RTC = 0x12,
LEGACY_SCPI_CMD_CLOCK_CAPABILITIES = 0x13,
LEGACY_SCPI_CMD_SET_CLOCK_INDEX = 0x14,
LEGACY_SCPI_CMD_SET_CLOCK_VALUE = 0x15,
LEGACY_SCPI_CMD_GET_CLOCK_VALUE = 0x16,
LEGACY_SCPI_CMD_PSU_CAPABILITIES = 0x17,
LEGACY_SCPI_CMD_SET_PSU = 0x18,
LEGACY_SCPI_CMD_GET_PSU = 0x19,
LEGACY_SCPI_CMD_SENSOR_CAPABILITIES = 0x1a,
LEGACY_SCPI_CMD_SENSOR_INFO = 0x1b,
LEGACY_SCPI_CMD_SENSOR_VALUE = 0x1c,