1 /*
2  * Copyright 2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 #include "mailbox.h"
9 
10 LOG_MODULE_REGISTER(scmi_mbox);
11 
scmi_mbox_cb(const struct device * mbox,mbox_channel_id_t channel_id,void * user_data,struct mbox_msg * data)12 static void scmi_mbox_cb(const struct device *mbox,
13 			 mbox_channel_id_t channel_id,
14 			 void *user_data,
15 			 struct mbox_msg *data)
16 {
17 	struct scmi_channel *scmi_chan = user_data;
18 
19 	if (scmi_chan->cb) {
20 		scmi_chan->cb(scmi_chan);
21 	}
22 }
23 
scmi_mbox_send_message(const struct device * transport,struct scmi_channel * chan,struct scmi_message * msg)24 static int scmi_mbox_send_message(const struct device *transport,
25 				  struct scmi_channel *chan,
26 				  struct scmi_message *msg)
27 {
28 	struct scmi_mbox_channel *mbox_chan;
29 	int ret;
30 
31 	mbox_chan = chan->data;
32 
33 	ret = scmi_shmem_write_message(mbox_chan->shmem, msg);
34 	if (ret < 0) {
35 		LOG_ERR("failed to write message to shmem: %d", ret);
36 		return ret;
37 	}
38 
39 	ret = mbox_send_dt(&mbox_chan->tx, NULL);
40 	if (ret < 0) {
41 		LOG_ERR("failed to ring doorbell: %d", ret);
42 		return ret;
43 	}
44 
45 	return 0;
46 }
47 
scmi_mbox_read_message(const struct device * transport,struct scmi_channel * chan,struct scmi_message * msg)48 static int scmi_mbox_read_message(const struct device *transport,
49 				  struct scmi_channel *chan,
50 				  struct scmi_message *msg)
51 {
52 	struct scmi_mbox_channel *mbox_chan;
53 
54 	mbox_chan = chan->data;
55 
56 	return scmi_shmem_read_message(mbox_chan->shmem, msg);
57 }
58 
scmi_mbox_channel_is_free(const struct device * transport,struct scmi_channel * chan)59 static bool scmi_mbox_channel_is_free(const struct device *transport,
60 				      struct scmi_channel *chan)
61 {
62 	struct scmi_mbox_channel *mbox_chan = chan->data;
63 
64 	return scmi_shmem_channel_status(mbox_chan->shmem) &
65 		SCMI_SHMEM_CHAN_STATUS_BUSY_BIT;
66 }
67 
scmi_mbox_setup_chan(const struct device * transport,struct scmi_channel * chan,bool tx)68 static int scmi_mbox_setup_chan(const struct device *transport,
69 				struct scmi_channel *chan,
70 				bool tx)
71 {
72 	int ret;
73 	struct scmi_mbox_channel *mbox_chan;
74 	struct mbox_dt_spec *tx_reply;
75 
76 	mbox_chan = chan->data;
77 
78 	if (!tx) {
79 		return -ENOTSUP;
80 	}
81 
82 	if (mbox_chan->tx_reply.dev) {
83 		tx_reply = &mbox_chan->tx_reply;
84 	} else {
85 		tx_reply = &mbox_chan->tx;
86 	}
87 
88 	ret = mbox_register_callback_dt(tx_reply, scmi_mbox_cb, chan);
89 	if (ret < 0) {
90 		LOG_ERR("failed to register tx reply cb");
91 		return ret;
92 	}
93 
94 	ret = mbox_set_enabled_dt(tx_reply, true);
95 	if (ret < 0) {
96 		LOG_ERR("failed to enable tx reply dbell");
97 	}
98 
99 	/* enable interrupt-based communication */
100 	scmi_shmem_update_flags(mbox_chan->shmem,
101 				SCMI_SHMEM_CHAN_FLAG_IRQ_BIT,
102 				SCMI_SHMEM_CHAN_FLAG_IRQ_BIT);
103 
104 	return 0;
105 }
106 
107 static struct scmi_transport_api scmi_mbox_api = {
108 	.setup_chan = scmi_mbox_setup_chan,
109 	.send_message = scmi_mbox_send_message,
110 	.read_message = scmi_mbox_read_message,
111 	.channel_is_free = scmi_mbox_channel_is_free,
112 };
113 
114 DT_INST_SCMI_MAILBOX_DEFINE(0, PRE_KERNEL_1,
115 			    CONFIG_ARM_SCMI_TRANSPORT_INIT_PRIORITY,
116 			    &scmi_mbox_api);
117