xref: /rk3399_ARM-atf/drivers/arm/mhu/mhu_wrapper_v2_x.c (revision af26d7d6f01068809f17cc2d49a9b3d573c640a9)
1*af26d7d6STamas Ban /*
2*af26d7d6STamas Ban  * Copyright (c) 2022, Arm Limited. All rights reserved.
3*af26d7d6STamas Ban  *
4*af26d7d6STamas Ban  * SPDX-License-Identifier: BSD-3-Clause
5*af26d7d6STamas Ban  */
6*af26d7d6STamas Ban 
7*af26d7d6STamas Ban #include <assert.h>
8*af26d7d6STamas Ban #include <stddef.h>
9*af26d7d6STamas Ban #include <stdint.h>
10*af26d7d6STamas Ban #include <string.h>
11*af26d7d6STamas Ban 
12*af26d7d6STamas Ban #include <drivers/arm/mhu.h>
13*af26d7d6STamas Ban 
14*af26d7d6STamas Ban #include "mhu_v2_x.h"
15*af26d7d6STamas Ban 
16*af26d7d6STamas Ban #define MHU_NOTIFY_VALUE	(1234u)
17*af26d7d6STamas Ban 
18*af26d7d6STamas Ban /*
19*af26d7d6STamas Ban  * MHU devices for host:
20*af26d7d6STamas Ban  * HSE: Host to Secure Enclave (sender device)
21*af26d7d6STamas Ban  * SEH: Secure Enclave to Host (receiver device)
22*af26d7d6STamas Ban  */
23*af26d7d6STamas Ban struct mhu_v2_x_dev_t MHU1_HSE_DEV = {0, MHU_V2_X_SENDER_FRAME};
24*af26d7d6STamas Ban struct mhu_v2_x_dev_t MHU1_SEH_DEV = {0, MHU_V2_X_RECEIVER_FRAME};
25*af26d7d6STamas Ban 
26*af26d7d6STamas Ban static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v2_x_error_t err)
27*af26d7d6STamas Ban {
28*af26d7d6STamas Ban 	switch (err) {
29*af26d7d6STamas Ban 	case MHU_V_2_X_ERR_NONE:
30*af26d7d6STamas Ban 		return MHU_ERR_NONE;
31*af26d7d6STamas Ban 	case MHU_V_2_X_ERR_NOT_INIT:
32*af26d7d6STamas Ban 		return MHU_ERR_NOT_INIT;
33*af26d7d6STamas Ban 	case MHU_V_2_X_ERR_ALREADY_INIT:
34*af26d7d6STamas Ban 		return MHU_ERR_ALREADY_INIT;
35*af26d7d6STamas Ban 	case MHU_V_2_X_ERR_UNSUPPORTED_VERSION:
36*af26d7d6STamas Ban 		return MHU_ERR_UNSUPPORTED_VERSION;
37*af26d7d6STamas Ban 	case MHU_V_2_X_ERR_INVALID_ARG:
38*af26d7d6STamas Ban 		return MHU_ERR_INVALID_ARG;
39*af26d7d6STamas Ban 	case MHU_V_2_X_ERR_GENERAL:
40*af26d7d6STamas Ban 		return MHU_ERR_GENERAL;
41*af26d7d6STamas Ban 	default:
42*af26d7d6STamas Ban 		return MHU_ERR_GENERAL;
43*af26d7d6STamas Ban 	}
44*af26d7d6STamas Ban }
45*af26d7d6STamas Ban 
46*af26d7d6STamas Ban static enum mhu_v2_x_error_t signal_and_wait_for_clear(void)
47*af26d7d6STamas Ban {
48*af26d7d6STamas Ban 	enum mhu_v2_x_error_t err;
49*af26d7d6STamas Ban 	struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV;
50*af26d7d6STamas Ban 	uint32_t val = MHU_NOTIFY_VALUE;
51*af26d7d6STamas Ban 	/* Using the last channel for notifications */
52*af26d7d6STamas Ban 	uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
53*af26d7d6STamas Ban 
54*af26d7d6STamas Ban 	err = mhu_v2_x_channel_send(dev, channel_notify, val);
55*af26d7d6STamas Ban 	if (err != MHU_V_2_X_ERR_NONE) {
56*af26d7d6STamas Ban 		return err;
57*af26d7d6STamas Ban 	}
58*af26d7d6STamas Ban 
59*af26d7d6STamas Ban 	do {
60*af26d7d6STamas Ban 		err = mhu_v2_x_channel_poll(dev, channel_notify, &val);
61*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
62*af26d7d6STamas Ban 			break;
63*af26d7d6STamas Ban 		}
64*af26d7d6STamas Ban 	} while (val != 0);
65*af26d7d6STamas Ban 
66*af26d7d6STamas Ban 	return err;
67*af26d7d6STamas Ban }
68*af26d7d6STamas Ban 
69*af26d7d6STamas Ban static enum mhu_v2_x_error_t wait_for_signal(void)
70*af26d7d6STamas Ban {
71*af26d7d6STamas Ban 	enum mhu_v2_x_error_t err;
72*af26d7d6STamas Ban 	struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
73*af26d7d6STamas Ban 	uint32_t val = 0;
74*af26d7d6STamas Ban 	/* Using the last channel for notifications */
75*af26d7d6STamas Ban 	uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
76*af26d7d6STamas Ban 
77*af26d7d6STamas Ban 	do {
78*af26d7d6STamas Ban 		err = mhu_v2_x_channel_receive(dev, channel_notify, &val);
79*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
80*af26d7d6STamas Ban 			break;
81*af26d7d6STamas Ban 		}
82*af26d7d6STamas Ban 	} while (val != MHU_NOTIFY_VALUE);
83*af26d7d6STamas Ban 
84*af26d7d6STamas Ban 	return err;
85*af26d7d6STamas Ban }
86*af26d7d6STamas Ban 
87*af26d7d6STamas Ban static enum mhu_v2_x_error_t clear_and_wait_for_next_signal(void)
88*af26d7d6STamas Ban {
89*af26d7d6STamas Ban 	enum mhu_v2_x_error_t err;
90*af26d7d6STamas Ban 	struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
91*af26d7d6STamas Ban 	uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
92*af26d7d6STamas Ban 	uint32_t i;
93*af26d7d6STamas Ban 
94*af26d7d6STamas Ban 	/* Clear all channels */
95*af26d7d6STamas Ban 	for (i = 0; i < num_channels; ++i) {
96*af26d7d6STamas Ban 		err = mhu_v2_x_channel_clear(dev, i);
97*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
98*af26d7d6STamas Ban 			return err;
99*af26d7d6STamas Ban 		}
100*af26d7d6STamas Ban 	}
101*af26d7d6STamas Ban 
102*af26d7d6STamas Ban 	return wait_for_signal();
103*af26d7d6STamas Ban }
104*af26d7d6STamas Ban 
105*af26d7d6STamas Ban enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base)
106*af26d7d6STamas Ban {
107*af26d7d6STamas Ban 	enum mhu_v2_x_error_t err;
108*af26d7d6STamas Ban 
109*af26d7d6STamas Ban 	assert(mhu_sender_base != (uintptr_t)NULL);
110*af26d7d6STamas Ban 
111*af26d7d6STamas Ban 	MHU1_HSE_DEV.base = mhu_sender_base;
112*af26d7d6STamas Ban 
113*af26d7d6STamas Ban 	err = mhu_v2_x_driver_init(&MHU1_HSE_DEV, MHU_REV_READ_FROM_HW);
114*af26d7d6STamas Ban 	return error_mapping_to_mhu_error_t(err);
115*af26d7d6STamas Ban }
116*af26d7d6STamas Ban 
117*af26d7d6STamas Ban enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base)
118*af26d7d6STamas Ban {
119*af26d7d6STamas Ban 	enum mhu_v2_x_error_t err;
120*af26d7d6STamas Ban 	uint32_t num_channels, i;
121*af26d7d6STamas Ban 
122*af26d7d6STamas Ban 	assert(mhu_receiver_base != (uintptr_t)NULL);
123*af26d7d6STamas Ban 
124*af26d7d6STamas Ban 	MHU1_SEH_DEV.base = mhu_receiver_base;
125*af26d7d6STamas Ban 
126*af26d7d6STamas Ban 	err = mhu_v2_x_driver_init(&MHU1_SEH_DEV, MHU_REV_READ_FROM_HW);
127*af26d7d6STamas Ban 	if (err != MHU_V_2_X_ERR_NONE) {
128*af26d7d6STamas Ban 		return error_mapping_to_mhu_error_t(err);
129*af26d7d6STamas Ban 	}
130*af26d7d6STamas Ban 
131*af26d7d6STamas Ban 	num_channels = mhu_v2_x_get_num_channel_implemented(&MHU1_SEH_DEV);
132*af26d7d6STamas Ban 
133*af26d7d6STamas Ban 	/* Mask all channels except the notifying channel */
134*af26d7d6STamas Ban 	for (i = 0; i < (num_channels - 1); ++i) {
135*af26d7d6STamas Ban 		err = mhu_v2_x_channel_mask_set(&MHU1_SEH_DEV, i, UINT32_MAX);
136*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
137*af26d7d6STamas Ban 			return error_mapping_to_mhu_error_t(err);
138*af26d7d6STamas Ban 		}
139*af26d7d6STamas Ban 	}
140*af26d7d6STamas Ban 
141*af26d7d6STamas Ban 	/* The last channel is used for notifications */
142*af26d7d6STamas Ban 	err = mhu_v2_x_channel_mask_clear(
143*af26d7d6STamas Ban 		&MHU1_SEH_DEV, (num_channels - 1), UINT32_MAX);
144*af26d7d6STamas Ban 	return error_mapping_to_mhu_error_t(err);
145*af26d7d6STamas Ban }
146*af26d7d6STamas Ban 
147*af26d7d6STamas Ban /*
148*af26d7d6STamas Ban  * Public function. See mhu.h
149*af26d7d6STamas Ban  *
150*af26d7d6STamas Ban  * The basic steps of transferring a message:
151*af26d7d6STamas Ban  * 1.	Initiate MHU transfer.
152*af26d7d6STamas Ban  * 2.	Send over the size of the payload on Channel 1. It is the very first
153*af26d7d6STamas Ban  *	4 Bytes of the transfer. Continue with Channel 2.
154*af26d7d6STamas Ban  * 3.	Send over the payload, writing the channels one after the other
155*af26d7d6STamas Ban  *	(4 Bytes each). The last available channel is reserved for controlling
156*af26d7d6STamas Ban  *	the transfer.
157*af26d7d6STamas Ban  *	When the last channel is reached or no more data is left, STOP.
158*af26d7d6STamas Ban  * 4.	Notify the receiver using the last channel and wait for acknowledge.
159*af26d7d6STamas Ban  *	If there is still data to transfer, jump to step 3. Otherwise, proceed.
160*af26d7d6STamas Ban  * 5.	Close MHU transfer.
161*af26d7d6STamas Ban  *
162*af26d7d6STamas Ban  */
163*af26d7d6STamas Ban enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size)
164*af26d7d6STamas Ban {
165*af26d7d6STamas Ban 	enum mhu_v2_x_error_t err;
166*af26d7d6STamas Ban 	struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV;
167*af26d7d6STamas Ban 	uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
168*af26d7d6STamas Ban 	uint32_t chan = 0;
169*af26d7d6STamas Ban 	uint32_t i;
170*af26d7d6STamas Ban 	uint32_t *p;
171*af26d7d6STamas Ban 
172*af26d7d6STamas Ban 	/* For simplicity, require the send_buffer to be 4-byte aligned */
173*af26d7d6STamas Ban 	if ((uintptr_t)send_buffer & 0x3U) {
174*af26d7d6STamas Ban 		return MHU_ERR_INVALID_ARG;
175*af26d7d6STamas Ban 	}
176*af26d7d6STamas Ban 
177*af26d7d6STamas Ban 	err = mhu_v2_x_initiate_transfer(dev);
178*af26d7d6STamas Ban 	if (err != MHU_V_2_X_ERR_NONE) {
179*af26d7d6STamas Ban 		return error_mapping_to_mhu_error_t(err);
180*af26d7d6STamas Ban 	}
181*af26d7d6STamas Ban 
182*af26d7d6STamas Ban 	/* First send over the size of the actual message */
183*af26d7d6STamas Ban 	err = mhu_v2_x_channel_send(dev, chan, (uint32_t)size);
184*af26d7d6STamas Ban 	if (err != MHU_V_2_X_ERR_NONE) {
185*af26d7d6STamas Ban 		return error_mapping_to_mhu_error_t(err);
186*af26d7d6STamas Ban 	}
187*af26d7d6STamas Ban 	chan++;
188*af26d7d6STamas Ban 
189*af26d7d6STamas Ban 	p = (uint32_t *)send_buffer;
190*af26d7d6STamas Ban 	for (i = 0; i < size; i += 4) {
191*af26d7d6STamas Ban 		err = mhu_v2_x_channel_send(dev, chan, *p++);
192*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
193*af26d7d6STamas Ban 			return error_mapping_to_mhu_error_t(err);
194*af26d7d6STamas Ban 		}
195*af26d7d6STamas Ban 		if (++chan == (num_channels - 1)) {
196*af26d7d6STamas Ban 			err = signal_and_wait_for_clear();
197*af26d7d6STamas Ban 			if (err != MHU_V_2_X_ERR_NONE) {
198*af26d7d6STamas Ban 				return error_mapping_to_mhu_error_t(err);
199*af26d7d6STamas Ban 			}
200*af26d7d6STamas Ban 			chan = 0;
201*af26d7d6STamas Ban 		}
202*af26d7d6STamas Ban 	}
203*af26d7d6STamas Ban 
204*af26d7d6STamas Ban 	/* Signal the end of transfer.
205*af26d7d6STamas Ban 	 *   It's not required to send a signal when the message was
206*af26d7d6STamas Ban 	 *   perfectly-aligned (num_channels - 1 channels were used in the last
207*af26d7d6STamas Ban 	 *   round) preventing it from signaling twice at the end of transfer.
208*af26d7d6STamas Ban 	 */
209*af26d7d6STamas Ban 	if (chan != 0) {
210*af26d7d6STamas Ban 		err = signal_and_wait_for_clear();
211*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
212*af26d7d6STamas Ban 			return error_mapping_to_mhu_error_t(err);
213*af26d7d6STamas Ban 		}
214*af26d7d6STamas Ban 	}
215*af26d7d6STamas Ban 
216*af26d7d6STamas Ban 	err = mhu_v2_x_close_transfer(dev);
217*af26d7d6STamas Ban 	return error_mapping_to_mhu_error_t(err);
218*af26d7d6STamas Ban }
219*af26d7d6STamas Ban 
220*af26d7d6STamas Ban /*
221*af26d7d6STamas Ban  * Public function. See mhu.h
222*af26d7d6STamas Ban  *
223*af26d7d6STamas Ban  * The basic steps of receiving a message:
224*af26d7d6STamas Ban  * 1.	Read the size of the payload from Channel 1. It is the very first
225*af26d7d6STamas Ban  *	4 Bytes of the transfer. Continue with Channel 2.
226*af26d7d6STamas Ban  * 2.	Receive the payload, read the channels one after the other
227*af26d7d6STamas Ban  *	(4 Bytes each). The last available channel is reserved for controlling
228*af26d7d6STamas Ban  *	the transfer.
229*af26d7d6STamas Ban  *	When the last channel is reached clear all the channels
230*af26d7d6STamas Ban  *	(also sending an acknowledge on the last channel).
231*af26d7d6STamas Ban  * 3.	If there is still data to receive wait for a notification on the last
232*af26d7d6STamas Ban  *	channel and jump to step 2 as soon as it arrived. Otherwise, proceed.
233*af26d7d6STamas Ban  * 4.	End of transfer.
234*af26d7d6STamas Ban  *
235*af26d7d6STamas Ban  */
236*af26d7d6STamas Ban enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size)
237*af26d7d6STamas Ban {
238*af26d7d6STamas Ban 	enum mhu_v2_x_error_t err;
239*af26d7d6STamas Ban 	struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV;
240*af26d7d6STamas Ban 	uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev);
241*af26d7d6STamas Ban 	uint32_t chan = 0;
242*af26d7d6STamas Ban 	uint32_t message_len;
243*af26d7d6STamas Ban 	uint32_t i;
244*af26d7d6STamas Ban 	uint32_t *p;
245*af26d7d6STamas Ban 
246*af26d7d6STamas Ban 	/* For simplicity, require:
247*af26d7d6STamas Ban 	 * - the receive_buffer to be 4-byte aligned,
248*af26d7d6STamas Ban 	 * - the buffer size to be a multiple of 4.
249*af26d7d6STamas Ban 	 */
250*af26d7d6STamas Ban 	if (((uintptr_t)receive_buffer & 0x3U) || (*size & 0x3U)) {
251*af26d7d6STamas Ban 		return MHU_ERR_INVALID_ARG;
252*af26d7d6STamas Ban 	}
253*af26d7d6STamas Ban 
254*af26d7d6STamas Ban 	/* Busy wait for incoming reply */
255*af26d7d6STamas Ban 	err = wait_for_signal();
256*af26d7d6STamas Ban 	if (err != MHU_V_2_X_ERR_NONE) {
257*af26d7d6STamas Ban 		return error_mapping_to_mhu_error_t(err);
258*af26d7d6STamas Ban 	}
259*af26d7d6STamas Ban 
260*af26d7d6STamas Ban 	/* The first word is the length of the actual message */
261*af26d7d6STamas Ban 	err = mhu_v2_x_channel_receive(dev, chan, &message_len);
262*af26d7d6STamas Ban 	if (err != MHU_V_2_X_ERR_NONE) {
263*af26d7d6STamas Ban 		return error_mapping_to_mhu_error_t(err);
264*af26d7d6STamas Ban 	}
265*af26d7d6STamas Ban 	chan++;
266*af26d7d6STamas Ban 
267*af26d7d6STamas Ban 	if (message_len > *size) {
268*af26d7d6STamas Ban 		/* Message buffer too small */
269*af26d7d6STamas Ban 		*size = message_len;
270*af26d7d6STamas Ban 		return MHU_ERR_BUFFER_TOO_SMALL;
271*af26d7d6STamas Ban 	}
272*af26d7d6STamas Ban 
273*af26d7d6STamas Ban 	p = (uint32_t *)receive_buffer;
274*af26d7d6STamas Ban 	for (i = 0; i < message_len; i += 4) {
275*af26d7d6STamas Ban 		err = mhu_v2_x_channel_receive(dev, chan, p++);
276*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
277*af26d7d6STamas Ban 			return error_mapping_to_mhu_error_t(err);
278*af26d7d6STamas Ban 		}
279*af26d7d6STamas Ban 
280*af26d7d6STamas Ban 		/* Only wait for next transfer if there is still missing data */
281*af26d7d6STamas Ban 		if (++chan == (num_channels - 1) && (message_len - i) > 4) {
282*af26d7d6STamas Ban 			/* Busy wait for next transfer */
283*af26d7d6STamas Ban 			err = clear_and_wait_for_next_signal();
284*af26d7d6STamas Ban 			if (err != MHU_V_2_X_ERR_NONE) {
285*af26d7d6STamas Ban 				return error_mapping_to_mhu_error_t(err);
286*af26d7d6STamas Ban 			}
287*af26d7d6STamas Ban 			chan = 0;
288*af26d7d6STamas Ban 		}
289*af26d7d6STamas Ban 	}
290*af26d7d6STamas Ban 
291*af26d7d6STamas Ban 	/* Clear all channels */
292*af26d7d6STamas Ban 	for (i = 0; i < num_channels; ++i) {
293*af26d7d6STamas Ban 		err = mhu_v2_x_channel_clear(dev, i);
294*af26d7d6STamas Ban 		if (err != MHU_V_2_X_ERR_NONE) {
295*af26d7d6STamas Ban 			return error_mapping_to_mhu_error_t(err);
296*af26d7d6STamas Ban 		}
297*af26d7d6STamas Ban 	}
298*af26d7d6STamas Ban 
299*af26d7d6STamas Ban 	*size = message_len;
300*af26d7d6STamas Ban 
301*af26d7d6STamas Ban 	return MHU_ERR_NONE;
302*af26d7d6STamas Ban }
303