aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/firmware/arm_scmi/common.h84
-rw-r--r--drivers/firmware/arm_scmi/driver.c44
-rw-r--r--drivers/firmware/arm_scmi/msg.c5
-rw-r--r--drivers/firmware/arm_scmi/shmem.c5
4 files changed, 136 insertions, 2 deletions
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index d5b78681b292..90404ac0629f 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -373,6 +373,8 @@ struct scmi_shared_mem_operations {
bool tx, struct resource *res);
};
+const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void);
+
/* declarations for message passing transports */
struct scmi_msg_payld;
@@ -400,6 +402,88 @@ struct scmi_message_operations {
size_t max_len, struct scmi_xfer *xfer);
};
+const struct scmi_message_operations *scmi_message_operations_get(void);
+
+/**
+ * struct scmi_transport_core_operations - Transpoert core operations
+ *
+ * @bad_message_trace: An helper to report a malformed/unexpected message
+ * @rx_callback: Callback to report received messages
+ * @shmem: Datagram operations for shared memory based transports
+ * @msg: Datagram operations for message based transports
+ */
+struct scmi_transport_core_operations {
+ void (*bad_message_trace)(struct scmi_chan_info *cinfo,
+ u32 msg_hdr, enum scmi_bad_msg err);
+ void (*rx_callback)(struct scmi_chan_info *cinfo, u32 msg_hdr,
+ void *priv);
+ const struct scmi_shared_mem_operations *shmem;
+ const struct scmi_message_operations *msg;
+};
+
+/**
+ * struct scmi_transport - A structure representing a configured transport
+ *
+ * @supplier: Device representing the transport and acting as a supplier for
+ * the core SCMI stack
+ * @desc: Transport descriptor
+ * @core_ops: A pointer to a pointer used by the core SCMI stack to make the
+ * core transport operations accessible to the transports.
+ */
+struct scmi_transport {
+ struct device *supplier;
+ const struct scmi_desc *desc;
+ struct scmi_transport_core_operations **core_ops;
+};
+
+#define DEFINE_SCMI_TRANSPORT_DRIVER(__tag, __drv, __desc, __match, __core_ops)\
+static void __tag##_dev_free(void *data) \
+{ \
+ struct platform_device *spdev = data; \
+ \
+ platform_device_unregister(spdev); \
+} \
+ \
+static int __tag##_probe(struct platform_device *pdev) \
+{ \
+ struct device *dev = &pdev->dev; \
+ struct platform_device *spdev; \
+ struct scmi_transport strans; \
+ int ret; \
+ \
+ spdev = platform_device_alloc("arm-scmi", PLATFORM_DEVID_AUTO); \
+ if (!spdev) \
+ return -ENOMEM; \
+ \
+ device_set_of_node_from_dev(&spdev->dev, dev); \
+ \
+ strans.supplier = dev; \
+ strans.desc = &(__desc); \
+ strans.core_ops = &(__core_ops); \
+ \
+ ret = platform_device_add_data(spdev, &strans, sizeof(strans)); \
+ if (ret) \
+ goto err; \
+ \
+ ret = platform_device_add(spdev); \
+ if (ret) \
+ goto err; \
+ \
+ return devm_add_action_or_reset(dev, __tag##_dev_free, spdev); \
+ \
+err: \
+ platform_device_put(spdev); \
+ return ret; \
+} \
+ \
+static struct platform_driver __drv = { \
+ .driver = { \
+ .name = #__tag "_transport", \
+ .of_match_table = __match, \
+ }, \
+ .probe = __tag##_probe, \
+}
+
extern const struct scmi_shared_mem_operations scmi_shmem_ops;
extern const struct scmi_message_operations scmi_msg_ops;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index ca910079d718..708efe6f9be6 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -196,6 +196,11 @@ struct scmi_info {
#define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb)
#define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb)
+static struct scmi_transport_core_operations scmi_trans_core_ops = {
+ .bad_message_trace = scmi_bad_message_trace,
+ .rx_callback = scmi_rx_callback,
+};
+
static unsigned long
scmi_vendor_protocol_signature(unsigned int protocol_id, char *vendor_id,
char *sub_vendor_id, u32 impl_ver)
@@ -3017,6 +3022,28 @@ static int scmi_debugfs_raw_mode_setup(struct scmi_info *info)
return ret;
}
+static const struct scmi_desc *scmi_transport_setup(struct device *dev)
+{
+ struct scmi_transport *trans;
+
+ trans = dev_get_platdata(dev);
+ if (!trans || !trans->desc || !trans->supplier || !trans->core_ops)
+ return NULL;
+
+ if (!device_link_add(dev, trans->supplier, DL_FLAG_AUTOREMOVE_CONSUMER)) {
+ dev_err(dev,
+ "Adding link to supplier transport device failed\n");
+ return NULL;
+ }
+
+ /* Provide core transport ops */
+ *trans->core_ops = &scmi_trans_core_ops;
+
+ dev_info(dev, "Using %s\n", dev_driver_string(trans->supplier));
+
+ return trans->desc;
+}
+
static int scmi_probe(struct platform_device *pdev)
{
int ret;
@@ -3029,8 +3056,14 @@ static int scmi_probe(struct platform_device *pdev)
struct device_node *child, *np = dev->of_node;
desc = of_device_get_match_data(dev);
- if (!desc)
- return -EINVAL;
+ if (!desc) {
+ desc = scmi_transport_setup(dev);
+ if (!desc) {
+ err_str = "transport invalid\n";
+ ret = -EINVAL;
+ goto out_err;
+ }
+ }
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -3197,6 +3230,7 @@ clear_txrx_setup:
clear_ida:
ida_free(&scmi_id, info->id);
+out_err:
return dev_err_probe(dev, ret, "%s", err_str);
}
@@ -3388,6 +3422,12 @@ static int __init scmi_driver_init(void)
if (ret)
return ret;
+ if (IS_ENABLED(CONFIG_ARM_SCMI_HAVE_SHMEM))
+ scmi_trans_core_ops.shmem = scmi_shared_mem_operations_get();
+
+ if (IS_ENABLED(CONFIG_ARM_SCMI_HAVE_MSG))
+ scmi_trans_core_ops.msg = scmi_message_operations_get();
+
if (IS_ENABLED(CONFIG_ARM_SCMI_NEED_DEBUGFS))
scmi_top_dentry = scmi_debugfs_init();
diff --git a/drivers/firmware/arm_scmi/msg.c b/drivers/firmware/arm_scmi/msg.c
index f5f6c2c55577..18337f9191d0 100644
--- a/drivers/firmware/arm_scmi/msg.c
+++ b/drivers/firmware/arm_scmi/msg.c
@@ -118,3 +118,8 @@ const struct scmi_message_operations scmi_msg_ops = {
.fetch_response = msg_fetch_response,
.fetch_notification = msg_fetch_notification,
};
+
+const struct scmi_message_operations *scmi_message_operations_get(void)
+{
+ return &scmi_msg_ops;
+}
diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c
index 477d391968c6..3fba05e1560c 100644
--- a/drivers/firmware/arm_scmi/shmem.c
+++ b/drivers/firmware/arm_scmi/shmem.c
@@ -187,3 +187,8 @@ const struct scmi_shared_mem_operations scmi_shmem_ops = {
.channel_intr_enabled = shmem_channel_intr_enabled,
.setup_iomap = shmem_setup_iomap,
};
+
+const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void)
+{
+ return &scmi_shmem_ops;
+}