aboutsummaryrefslogtreecommitdiff
path: root/drivers/firmware/arm_scmi/driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/arm_scmi/driver.c')
-rw-r--r--drivers/firmware/arm_scmi/driver.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 0fda87a7ec72..45f31eaf085a 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -108,18 +108,22 @@ struct scmi_desc {
* @dev: Device pointer
* @desc: SoC description for this instance
* @handle: Instance of SCMI handle to send to clients
+ * @version: SCMI revision information containing protocol version,
+ * implementation version and (sub-)vendor identification.
* @cl: Mailbox Client
* @tx_chan: Transmit mailbox channel
* @rx_chan: Receive mailbox channel
* @tx_payload: Transmit mailbox channel payload area
* @rx_payload: Receive mailbox channel payload area
* @minfo: Message info
+ * @protocols_imp: list of protocols implemented
* @node: list head
* @users: Number of users of this instance
*/
struct scmi_info {
struct device *dev;
const struct scmi_desc *desc;
+ struct scmi_revision_info version;
struct scmi_handle handle;
struct mbox_client cl;
struct mbox_chan *tx_chan;
@@ -127,6 +131,7 @@ struct scmi_info {
void __iomem *tx_payload;
void __iomem *rx_payload;
struct scmi_xfers_info minfo;
+ u8 *protocols_imp;
struct list_head node;
int users;
};
@@ -445,6 +450,60 @@ int scmi_one_xfer_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
}
/**
+ * scmi_version_get() - command to get the revision of the SCMI entity
+ *
+ * @handle: Handle to SCMI entity information
+ *
+ * Updates the SCMI information in the internal data structure.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+int scmi_version_get(const struct scmi_handle *handle, u8 protocol,
+ u32 *version)
+{
+ int ret;
+ __le32 *rev_info;
+ struct scmi_xfer *t;
+
+ ret = scmi_one_xfer_init(handle, PROTOCOL_VERSION, protocol, 0,
+ sizeof(*version), &t);
+ if (ret)
+ return ret;
+
+ ret = scmi_do_xfer(handle, t);
+ if (!ret) {
+ rev_info = t->rx.buf;
+ *version = le32_to_cpu(*rev_info);
+ }
+
+ scmi_one_xfer_put(handle, t);
+ return ret;
+}
+
+void scmi_setup_protocol_implemented(const struct scmi_handle *handle,
+ u8 *prot_imp)
+{
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ info->protocols_imp = prot_imp;
+}
+
+static bool
+scmi_is_protocol_implemented(const struct scmi_handle *handle, u8 prot_id)
+{
+ int i;
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ if (!info->protocols_imp)
+ return false;
+
+ for (i = 0; i < MAX_PROTOCOLS_IMP; i++)
+ if (info->protocols_imp[i] == prot_id)
+ return true;
+ return false;
+}
+
+/**
* scmi_handle_get() - Get the SCMI handle for a device
*
* @dev: pointer to device for which we want SCMI handle
@@ -635,6 +694,11 @@ static int scmi_probe(struct platform_device *pdev)
desc = of_match_device(scmi_of_match, dev)->data;
+ if (of_property_match_string(np, "method", "mailbox-doorbell") < 0) {
+ dev_err(dev, "invalid method property in %s\n", np->full_name);
+ return -EINVAL;
+ }
+
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -680,6 +744,12 @@ static int scmi_probe(struct platform_device *pdev)
handle = &info->handle;
handle->dev = info->dev;
+ handle->version = &info->version;
+ ret = scmi_base_protocol_init(handle);
+ if (ret) {
+ dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
+ goto out;
+ }
mutex_lock(&scmi_list_mutex);
list_add_tail(&info->node, &scmi_list);