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