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