diff options
Diffstat (limited to 'drivers/firmware/arm_scmi/driver.c')
-rw-r--r-- | drivers/firmware/arm_scmi/driver.c | 70 |
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); |