1 /*
2 * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
3 * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <config/interface/config_store.h>
9 #include <config/interface/config_blob.h>
10 #include <platform/interface/device_region.h>
11 #include <platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h>
12 #include <trace.h>
13 #include <errno.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <stddef.h>
17 #include <limits.h>
18
19 #include "openamp_messenger_api.h"
20
21 #define MHU_V_2_NOTIFY_CHANNEL 0
22 #define MHU_V_2_NOTIFY_VALUE 0xff
23
24 struct openamp_mhu {
25 struct device_region rx_region;
26 struct device_region tx_region;
27 struct mhu_v2_x_dev_t rx_dev;
28 struct mhu_v2_x_dev_t tx_dev;
29 };
30
openamp_mhu_device_get(const char * dev,struct device_region * dev_region)31 static int openamp_mhu_device_get(const char *dev,
32 struct device_region *dev_region)
33 {
34 bool found;
35
36 found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
37 dev_region, sizeof(*dev_region));
38 if (!found)
39 return -EINVAL;
40
41 if (!dev_region->base_addr)
42 return -EINVAL;
43
44 IMSG("mhu: device region found: %s addr: 0x%p size: %lu", dev,
45 (void *)dev_region->base_addr, dev_region->io_region_size);
46
47 return 0;
48 }
49
openamp_mhu_receive(struct openamp_messenger * openamp)50 int openamp_mhu_receive(struct openamp_messenger *openamp)
51 {
52 struct mhu_v2_x_dev_t *rx_dev;
53 enum mhu_v2_x_error_t ret;
54 struct openamp_mhu *mhu;
55 uint32_t channel = 0;
56 uint32_t irq_status;
57
58 if (!openamp->transport) {
59 EMSG("openamp: mhu: receive transport not initialized");
60 return -EINVAL;
61 }
62
63 mhu = openamp->transport;
64 rx_dev = &mhu->rx_dev;
65
66 irq_status = 0;
67
68 do {
69 irq_status = mhu_v2_x_get_interrupt_status(rx_dev);
70 } while(!irq_status);
71
72 ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
73 if (ret < 0)
74 return -1;
75
76 ret = mhu_v2_x_channel_clear(rx_dev, channel);
77 if (ret != MHU_V_2_X_ERR_NONE) {
78 EMSG("openamp: mhu: failed to clear channel: %d", channel);
79 return -EPROTO;
80 }
81
82 return 0;
83 }
84
openamp_mhu_notify_peer(struct openamp_messenger * openamp)85 int openamp_mhu_notify_peer(struct openamp_messenger *openamp)
86 {
87 struct mhu_v2_x_dev_t *tx_dev;
88 enum mhu_v2_x_error_t ret;
89 struct openamp_mhu *mhu;
90 uint32_t access_ready;
91
92 if (!openamp->transport) {
93 EMSG("openamp: mhu: notify transport not initialized");
94 return -EINVAL;
95 }
96
97 mhu = openamp->transport;
98 tx_dev = &mhu->tx_dev;
99
100 ret = mhu_v2_x_set_access_request(tx_dev);
101 if (ret != MHU_V_2_X_ERR_NONE) {
102 EMSG("openamp: mhu: set access request failed");
103 return -EPROTO;
104 }
105
106 do {
107 ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
108 if (ret != MHU_V_2_X_ERR_NONE) {
109 EMSG("openamp: mhu: failed to get access_ready");
110 return -EPROTO;
111 }
112 } while (!access_ready);
113
114 ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
115 MHU_V_2_NOTIFY_VALUE);
116 if (ret != MHU_V_2_X_ERR_NONE) {
117 EMSG("openamp: mhu: failed send over channel");
118 return -EPROTO;
119 }
120
121 ret = mhu_v2_x_reset_access_request(tx_dev);
122 if (ret != MHU_V_2_X_ERR_NONE) {
123 EMSG("openamp: mhu: failed reset access request");
124 return -EPROTO;
125 }
126
127 return 0;
128 }
129
openamp_mhu_init(struct openamp_messenger * openamp)130 int openamp_mhu_init(struct openamp_messenger *openamp)
131 {
132 struct mhu_v2_x_dev_t *rx_dev;
133 struct mhu_v2_x_dev_t *tx_dev;
134 struct openamp_mhu *mhu;
135 int ret;
136
137 /* if we already have initialized skip this */
138 if (openamp->transport)
139 return 0;
140
141 mhu = malloc(sizeof(*mhu));
142 if (!mhu)
143 return -1;
144
145 ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
146 if (ret < 0)
147 goto free_mhu;
148
149 ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
150 if (ret < 0)
151 goto free_mhu;
152
153 rx_dev = &mhu->rx_dev;
154 tx_dev = &mhu->tx_dev;
155
156 rx_dev->base = mhu->rx_region.base_addr;
157 rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
158
159 tx_dev->base = mhu->tx_region.base_addr;
160 tx_dev->frame = MHU_V2_X_SENDER_FRAME;
161
162 ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
163 if (ret < 0)
164 goto free_mhu;
165
166 ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
167 if (ret < 0)
168 goto free_mhu;
169
170 openamp->transport = (void *)mhu;
171
172 return 0;
173
174 free_mhu:
175 free(mhu);
176
177 return ret;
178 }
179
openamp_mhu_deinit(struct openamp_messenger * openamp)180 int openamp_mhu_deinit(struct openamp_messenger *openamp)
181 {
182 struct openamp_mhu *mhu;
183
184 if (!openamp->transport)
185 return 0;
186
187 mhu = openamp->transport;
188 free(mhu);
189
190 openamp->transport = NULL;
191
192 return 0;
193 }
194