Commit e7541f90 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'scpi-updates-4.10' of...

Merge tag 'scpi-updates-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/drivers

Pull "SCPI updates for v4.10" from Sudeep Holla:

1. Adds support for pre-v1.0 SCPI protocol versions

2. Adds support for SCPI used on Amlogic GXBB SoC platforms using the
   newly added pre-v1.0 SCPI protocol

3. Decouples some platform specific details from generic SCPI binding

* tag 'scpi-updates-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scpi: add support for pre-v1.0 SCPI compatible
  Documentation: bindings: Add support for Amlogic GXBB SCPI protocol
  Documentation: bindings: add compatible specific to pre v1.0 SCPI protocols
  Documentation: bindings: decouple juno specific details from generic binding
  firmware: arm_scpi: allow firmware with get_capabilities not implemented
  firmware: arm_scpi: add alternative legacy structures, functions and macros
  firmware: arm_scpi: increase MAX_DVFS_OPPS to 16 entries
  firmware: arm_scpi: add command indirection to support legacy commands
parents bc28ba81 8358c6b5
System Control and Power Interface (SCPI) Message Protocol
(in addition to the standard binding in [0])
----------------------------------------------------------
Required properties
- compatible : should be "amlogic,meson-gxbb-scpi"
AMLOGIC SRAM and Shared Memory for SCPI
------------------------------------
Required properties:
- compatible : should be "amlogic,meson-gxbb-sram"
Each sub-node represents the reserved area for SCPI.
Required sub-node properties:
- compatible : should be "amlogic,meson-gxbb-scp-shmem" for SRAM based shared
memory on Amlogic GXBB SoC.
[0] Documentation/devicetree/bindings/arm/arm,scpi.txt
......@@ -7,7 +7,10 @@ by Linux to initiate various system control and power operations.
Required properties:
- compatible : should be "arm,scpi"
- compatible : should be
* "arm,scpi" : For implementations complying to SCPI v1.0 or above
* "arm,scpi-pre-1.0" : For implementations complying to all
unversioned releases prior to SCPI v1.0
- mboxes: List of phandle and mailbox channel specifiers
All the channels reserved by remote SCP firmware for use by
SCPI message protocol should be specified in any order
......@@ -59,18 +62,14 @@ SRAM and Shared Memory for SCPI
A small area of SRAM is reserved for SCPI communication between application
processors and SCP.
Required properties:
- compatible : should be "arm,juno-sram-ns" for Non-secure SRAM on Juno
The rest of the properties should follow the generic mmio-sram description
found in ../../sram/sram.txt
The properties should follow the generic mmio-sram description found in [3]
Each sub-node represents the reserved area for SCPI.
Required sub-node properties:
- reg : The base offset and size of the reserved area with the SRAM
- compatible : should be "arm,juno-scp-shmem" for Non-secure SRAM based
shared memory on Juno platforms
- compatible : should be "arm,scp-shmem" for Non-secure SRAM based
shared memory
Sensor bindings for the sensors based on SCPI Message Protocol
--------------------------------------------------------------
......@@ -81,11 +80,9 @@ Required properties:
- #thermal-sensor-cells: should be set to 1. This property follows the
thermal device tree bindings[2].
Valid cell values are raw identifiers (Sensor
ID) as used by the firmware. Refer to
platform documentation for your
implementation for the IDs to use. For Juno
R0 and Juno R1 refer to [3].
Valid cell values are raw identifiers (Sensor ID)
as used by the firmware. Refer to platform details
for your implementation for the IDs to use.
Power domain bindings for the power domains based on SCPI Message Protocol
------------------------------------------------------------
......@@ -112,7 +109,7 @@ Required properties:
[0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/thermal/thermal.txt
[3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html
[3] Documentation/devicetree/bindings/sram/sram.txt
[4] Documentation/devicetree/bindings/power/power_domain.txt
Example:
......
System Control and Power Interface (SCPI) Message Protocol
(in addition to the standard binding in [0])
Juno SRAM and Shared Memory for SCPI
------------------------------------
Required properties:
- compatible : should be "arm,juno-sram-ns" for Non-secure SRAM
Each sub-node represents the reserved area for SCPI.
Required sub-node properties:
- reg : The base offset and size of the reserved area with the SRAM
- compatible : should be "arm,juno-scp-shmem" for Non-secure SRAM based
shared memory on Juno platforms
Sensor bindings for the sensors based on SCPI Message Protocol
--------------------------------------------------------------
Required properties:
- compatible : should be "arm,scpi-sensors".
- #thermal-sensor-cells: should be set to 1.
For Juno R0 and Juno R1 refer to [1] for the
sensor identifiers
[0] Documentation/devicetree/bindings/arm/arm,scpi.txt
[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html
......@@ -50,20 +50,27 @@
#define CMD_TOKEN_ID_MASK 0xff
#define CMD_DATA_SIZE_SHIFT 16
#define CMD_DATA_SIZE_MASK 0x1ff
#define CMD_LEGACY_DATA_SIZE_SHIFT 20
#define CMD_LEGACY_DATA_SIZE_MASK 0x1ff
#define PACK_SCPI_CMD(cmd_id, tx_sz) \
((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
(((tx_sz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT))
#define ADD_SCPI_TOKEN(cmd, token) \
((cmd) |= (((token) & CMD_TOKEN_ID_MASK) << CMD_TOKEN_ID_SHIFT))
#define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \
((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
(((tx_sz) & CMD_LEGACY_DATA_SIZE_MASK) << CMD_LEGACY_DATA_SIZE_SHIFT))
#define CMD_SIZE(cmd) (((cmd) >> CMD_DATA_SIZE_SHIFT) & CMD_DATA_SIZE_MASK)
#define CMD_LEGACY_SIZE(cmd) (((cmd) >> CMD_LEGACY_DATA_SIZE_SHIFT) & \
CMD_LEGACY_DATA_SIZE_MASK)
#define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK << CMD_TOKEN_ID_SHIFT | 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 8
#define MAX_DVFS_OPPS 16
#define DVFS_LATENCY(hdr) (le32_to_cpu(hdr) >> 16)
#define DVFS_OPP_COUNT(hdr) ((le32_to_cpu(hdr) >> 8) & 0xff)
......@@ -99,6 +106,7 @@ enum scpi_error_codes {
SCPI_ERR_MAX
};
/* SCPI Standard commands */
enum scpi_std_cmd {
SCPI_CMD_INVALID = 0x00,
SCPI_CMD_SCPI_READY = 0x01,
......@@ -132,6 +140,108 @@ enum scpi_std_cmd {
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,
LEGACY_SCPI_CMD_SENSOR_CFG_PERIODIC = 0x1d,
LEGACY_SCPI_CMD_SENSOR_CFG_BOUNDS = 0x1e,
LEGACY_SCPI_CMD_SENSOR_ASYNC_VALUE = 0x1f,
LEGACY_SCPI_CMD_COUNT
};
/* List all commands that are required to go through the high priority link */
static int legacy_hpriority_cmds[] = {
LEGACY_SCPI_CMD_GET_CSS_PWR_STATE,
LEGACY_SCPI_CMD_CFG_PWR_STATE_STAT,
LEGACY_SCPI_CMD_GET_PWR_STATE_STAT,
LEGACY_SCPI_CMD_SET_DVFS,
LEGACY_SCPI_CMD_GET_DVFS,
LEGACY_SCPI_CMD_SET_RTC,
LEGACY_SCPI_CMD_GET_RTC,
LEGACY_SCPI_CMD_SET_CLOCK_INDEX,
LEGACY_SCPI_CMD_SET_CLOCK_VALUE,
LEGACY_SCPI_CMD_GET_CLOCK_VALUE,
LEGACY_SCPI_CMD_SET_PSU,
LEGACY_SCPI_CMD_GET_PSU,
LEGACY_SCPI_CMD_SENSOR_CFG_PERIODIC,
LEGACY_SCPI_CMD_SENSOR_CFG_BOUNDS,
};
/* List all commands used by this driver, used as indexes */
enum scpi_drv_cmds {
CMD_SCPI_CAPABILITIES = 0,
CMD_GET_CLOCK_INFO,
CMD_GET_CLOCK_VALUE,
CMD_SET_CLOCK_VALUE,
CMD_GET_DVFS,
CMD_SET_DVFS,
CMD_GET_DVFS_INFO,
CMD_SENSOR_CAPABILITIES,
CMD_SENSOR_INFO,
CMD_SENSOR_VALUE,
CMD_SET_DEVICE_PWR_STATE,
CMD_GET_DEVICE_PWR_STATE,
CMD_MAX_COUNT,
};
static int scpi_std_commands[CMD_MAX_COUNT] = {
SCPI_CMD_SCPI_CAPABILITIES,
SCPI_CMD_GET_CLOCK_INFO,
SCPI_CMD_GET_CLOCK_VALUE,
SCPI_CMD_SET_CLOCK_VALUE,
SCPI_CMD_GET_DVFS,
SCPI_CMD_SET_DVFS,
SCPI_CMD_GET_DVFS_INFO,
SCPI_CMD_SENSOR_CAPABILITIES,
SCPI_CMD_SENSOR_INFO,
SCPI_CMD_SENSOR_VALUE,
SCPI_CMD_SET_DEVICE_PWR_STATE,
SCPI_CMD_GET_DEVICE_PWR_STATE,
};
static int scpi_legacy_commands[CMD_MAX_COUNT] = {
LEGACY_SCPI_CMD_SCPI_CAPABILITIES,
-1, /* GET_CLOCK_INFO */
LEGACY_SCPI_CMD_GET_CLOCK_VALUE,
LEGACY_SCPI_CMD_SET_CLOCK_VALUE,
LEGACY_SCPI_CMD_GET_DVFS,
LEGACY_SCPI_CMD_SET_DVFS,
LEGACY_SCPI_CMD_GET_DVFS_INFO,
LEGACY_SCPI_CMD_SENSOR_CAPABILITIES,
LEGACY_SCPI_CMD_SENSOR_INFO,
LEGACY_SCPI_CMD_SENSOR_VALUE,
-1, /* SET_DEVICE_PWR_STATE */
-1, /* GET_DEVICE_PWR_STATE */
};
struct scpi_xfer {
u32 slot; /* has to be first element */
u32 cmd;
......@@ -160,7 +270,10 @@ struct scpi_chan {
struct scpi_drvinfo {
u32 protocol_version;
u32 firmware_version;
bool is_legacy;
int num_chans;
int *commands;
DECLARE_BITMAP(cmd_priority, LEGACY_SCPI_CMD_COUNT);
atomic_t next_chan;
struct scpi_ops *scpi_ops;
struct scpi_chan *channels;
......@@ -177,6 +290,11 @@ struct scpi_shared_mem {
u8 payload[0];
} __packed;
struct legacy_scpi_shared_mem {
__le32 status;
u8 payload[0];
} __packed;
struct scp_capabilities {
__le32 protocol_version;
__le32 event_version;
......@@ -202,6 +320,12 @@ struct clk_set_value {
__le32 rate;
} __packed;
struct legacy_clk_set_value {
__le32 rate;
__le16 id;
__le16 reserved;
} __packed;
struct dvfs_info {
__le32 header;
struct {
......@@ -273,19 +397,43 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
return;
}
/* Command type is not replied by the SCP Firmware in legacy Mode
* We should consider that command is the head of pending RX commands
* if the list is not empty. In TX only mode, the list would be empty.
*/
if (scpi_info->is_legacy) {
match = list_first_entry(&ch->rx_pending, struct scpi_xfer,
node);
list_del(&match->node);
} else {
list_for_each_entry(t, &ch->rx_pending, node)
if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) {
list_del(&t->node);
match = t;
break;
}
}
/* check if wait_for_completion is in progress or timed-out */
if (match && !completion_done(&match->done)) {
unsigned int len;
if (scpi_info->is_legacy) {
struct legacy_scpi_shared_mem *mem = ch->rx_payload;
/* RX Length is not replied by the legacy Firmware */
len = match->rx_len;
match->status = le32_to_cpu(mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
} else {
struct scpi_shared_mem *mem = ch->rx_payload;
unsigned int len = min(match->rx_len, CMD_SIZE(cmd));
len = min(match->rx_len, CMD_SIZE(cmd));
match->status = le32_to_cpu(mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
}
if (match->rx_len > len)
memset(match->rx_buf + len, 0, match->rx_len - len);
complete(&match->done);
......@@ -297,7 +445,10 @@ static void scpi_handle_remote_msg(struct mbox_client *c, void *msg)
{
struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
struct scpi_shared_mem *mem = ch->rx_payload;
u32 cmd = le32_to_cpu(mem->command);
u32 cmd = 0;
if (!scpi_info->is_legacy)
cmd = le32_to_cpu(mem->command);
scpi_process_cmd(ch, cmd);
}
......@@ -309,8 +460,13 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload;
if (t->tx_buf)
if (t->tx_buf) {
if (scpi_info->is_legacy)
memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len);
else
memcpy_toio(mem->payload, t->tx_buf, t->tx_len);
}
if (t->rx_buf) {
if (!(++ch->token))
++ch->token;
......@@ -319,6 +475,8 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
list_add_tail(&t->node, &ch->rx_pending);
spin_unlock_irqrestore(&ch->rx_lock, flags);
}
if (!scpi_info->is_legacy)
mem->command = cpu_to_le32(t->cmd);
}
......@@ -344,23 +502,38 @@ static void put_scpi_xfer(struct scpi_xfer *t, struct scpi_chan *ch)
mutex_unlock(&ch->xfers_lock);
}
static int scpi_send_message(u8 cmd, void *tx_buf, unsigned int tx_len,
static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len,
void *rx_buf, unsigned int rx_len)
{
int ret;
u8 chan;
u8 cmd;
struct scpi_xfer *msg;
struct scpi_chan *scpi_chan;
chan = atomic_inc_return(&scpi_info->next_chan) % scpi_info->num_chans;
if (scpi_info->commands[idx] < 0)
return -EOPNOTSUPP;
cmd = scpi_info->commands[idx];
if (scpi_info->is_legacy)
chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0;
else
chan = atomic_inc_return(&scpi_info->next_chan) %
scpi_info->num_chans;
scpi_chan = scpi_info->channels + chan;
msg = get_scpi_xfer(scpi_chan);
if (!msg)
return -ENOMEM;
if (scpi_info->is_legacy) {
msg->cmd = PACK_LEGACY_SCPI_CMD(cmd, tx_len);
msg->slot = msg->cmd;
} else {
msg->slot = BIT(SCPI_SLOT);
msg->cmd = PACK_SCPI_CMD(cmd, tx_len);
}
msg->tx_buf = tx_buf;
msg->tx_len = tx_len;
msg->rx_buf = rx_buf;
......@@ -397,7 +570,7 @@ scpi_clk_get_range(u16 clk_id, unsigned long *min, unsigned long *max)
struct clk_get_info clk;
__le16 le_clk_id = cpu_to_le16(clk_id);
ret = scpi_send_message(SCPI_CMD_GET_CLOCK_INFO, &le_clk_id,
ret = scpi_send_message(CMD_GET_CLOCK_INFO, &le_clk_id,
sizeof(le_clk_id), &clk, sizeof(clk));
if (!ret) {
*min = le32_to_cpu(clk.min_rate);
......@@ -412,8 +585,9 @@ static unsigned long scpi_clk_get_val(u16 clk_id)
struct clk_get_value clk;
__le16 le_clk_id = cpu_to_le16(clk_id);
ret = scpi_send_message(SCPI_CMD_GET_CLOCK_VALUE, &le_clk_id,
ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id,
sizeof(le_clk_id), &clk, sizeof(clk));
return ret ? ret : le32_to_cpu(clk.rate);
}
......@@ -425,7 +599,19 @@ static int scpi_clk_set_val(u16 clk_id, unsigned long rate)
.rate = cpu_to_le32(rate)
};
return scpi_send_message(SCPI_CMD_SET_CLOCK_VALUE, &clk, sizeof(clk),
return scpi_send_message(CMD_SET_CLOCK_VALUE, &clk, sizeof(clk),
&stat, sizeof(stat));
}
static int legacy_scpi_clk_set_val(u16 clk_id, unsigned long rate)
{
int stat;
struct legacy_clk_set_value clk = {
.id = cpu_to_le16(clk_id),
.rate = cpu_to_le32(rate)
};
return scpi_send_message(CMD_SET_CLOCK_VALUE, &clk, sizeof(clk),
&stat, sizeof(stat));
}
......@@ -434,8 +620,9 @@ static int scpi_dvfs_get_idx(u8 domain)
int ret;
u8 dvfs_idx;
ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain),
ret = scpi_send_message(CMD_GET_DVFS, &domain, sizeof(domain),
&dvfs_idx, sizeof(dvfs_idx));
return ret ? ret : dvfs_idx;
}
......@@ -444,7 +631,7 @@ static int scpi_dvfs_set_idx(u8 domain, u8 index)
int stat;
struct dvfs_set dvfs = {domain, index};
return scpi_send_message(SCPI_CMD_SET_DVFS, &dvfs, sizeof(dvfs),
return scpi_send_message(CMD_SET_DVFS, &dvfs, sizeof(dvfs),
&stat, sizeof(stat));
}
......@@ -468,9 +655,8 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
if (scpi_info->dvfs[domain]) /* data already populated */
return scpi_info->dvfs[domain];
ret = scpi_send_message(SCPI_CMD_GET_DVFS_INFO, &domain, sizeof(domain),
ret = scpi_send_message(CMD_GET_DVFS_INFO, &domain, sizeof(domain),
&buf, sizeof(buf));
if (ret)
return ERR_PTR(ret);
......@@ -503,7 +689,7 @@ static int scpi_sensor_get_capability(u16 *sensors)
struct sensor_capabilities cap_buf;
int ret;
ret = scpi_send_message(SCPI_CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf,
ret = scpi_send_message(CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf,
sizeof(cap_buf));
if (!ret)
*sensors = le16_to_cpu(cap_buf.sensors);
......@@ -517,7 +703,7 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info)
struct _scpi_sensor_info _info;
int ret;
ret = scpi_send_message(SCPI_CMD_SENSOR_INFO, &id, sizeof(id),
ret = scpi_send_message(CMD_SENSOR_INFO, &id, sizeof(id),
&_info, sizeof(_info));
if (!ret) {
memcpy(info, &_info, sizeof(*info));
......@@ -533,7 +719,7 @@ static int scpi_sensor_get_value(u16 sensor, u64 *val)
struct sensor_value buf;
int ret;
ret = scpi_send_message(SCPI_CMD_SENSOR_VALUE, &id, sizeof(id),
ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id),
&buf, sizeof(buf));
if (!ret)
*val = (u64)le32_to_cpu(buf.hi_val) << 32 |
......@@ -548,7 +734,7 @@ static int scpi_device_get_power_state(u16 dev_id)
u8 pstate;
__le16 id = cpu_to_le16(dev_id);
ret = scpi_send_message(SCPI_CMD_GET_DEVICE_PWR_STATE, &id,
ret = scpi_send_message(CMD_GET_DEVICE_PWR_STATE, &id,
sizeof(id), &pstate, sizeof(pstate));
return ret ? ret : pstate;
}
......@@ -561,7 +747,7 @@ static int scpi_device_set_power_state(u16 dev_id, u8 pstate)
.pstate = pstate,
};
return scpi_send_message(SCPI_CMD_SET_DEVICE_PWR_STATE, &dev_set,
return scpi_send_message(CMD_SET_DEVICE_PWR_STATE, &dev_set,
sizeof(dev_set), &stat, sizeof(stat));
}
......@@ -591,12 +777,16 @@ static int scpi_init_versions(struct scpi_drvinfo *info)
int ret;
struct scp_capabilities caps;
ret = scpi_send_message(SCPI_CMD_SCPI_CAPABILITIES, NULL, 0,
ret = scpi_send_message(CMD_SCPI_CAPABILITIES, NULL, 0,
&caps, sizeof(caps));
if (!ret) {
info->protocol_version = le32_to_cpu(caps.protocol_version);
info->firmware_version = le32_to_cpu(caps.platform_version);
}
/* Ignore error if not implemented */
if (scpi_info->is_legacy && ret == -EOPNOTSUPP)
return 0;
return ret;
}
......@@ -681,6 +871,11 @@ static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch)
return 0;
}
static const struct of_device_id legacy_scpi_of_match[] = {
{.compatible = "arm,scpi-pre-1.0"},
{},
};
static int scpi_probe(struct platform_device *pdev)
{
int count, idx, ret;
......@@ -693,6 +888,9 @@ static int scpi_probe(struct platform_device *pdev)
if (!scpi_info)
return -ENOMEM;
if (of_match_device(legacy_scpi_of_match, &pdev->dev))
scpi_info->is_legacy = true;
count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
if (count < 0) {
dev_err(dev, "no mboxes property in '%s'\n", np->full_name);
......@@ -755,8 +953,21 @@ static int scpi_probe(struct platform_device *pdev)
scpi_info->channels = scpi_chan;
scpi_info->num_chans = count;
scpi_info->commands = scpi_std_commands;
platform_set_drvdata(pdev, scpi_info);
if (scpi_info->is_legacy) {
/* Replace with legacy variants */
scpi_ops.clk_set_val = legacy_scpi_clk_set_val;
scpi_info->commands = scpi_legacy_commands;
/* Fill priority bitmap */
for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++)
set_bit(legacy_hpriority_cmds[idx],
scpi_info->cmd_priority);
}
ret = scpi_init_versions(scpi_info);
if (ret) {
dev_err(dev, "incorrect or no SCP firmware found\n");
......@@ -781,6 +992,7 @@ static int scpi_probe(struct platform_device *pdev)
static const struct of_device_id scpi_of_match[] = {
{.compatible = "arm,scpi"},
{.compatible = "arm,scpi-pre-1.0"},
{},
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment