xref: /rk3399_ARM-atf/drivers/arm/sfcp/sfcp_core/sfcp_link_hal.c (revision 2801427972c4b0d4c0165edb509f21186103f21f)
1 /*
2  * Copyright (c) 2026, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <assert.h>
9 #include <string.h>
10 
11 #if PLAT_MHU_VERSION == 2
12 #include "mhu_v2_x.h"
13 #endif
14 #if PLAT_MHU_VERSION == 3
15 #include "mhu_v3_x.h"
16 #endif
17 #include "sfcp_link_hal.h"
18 #include "sfcp_platform.h"
19 
20 #define MHU_REQUIRED_NUMBER_CHANNELS (4)
21 #define MHU_NOTIFY_VALUE (1234u)
22 
23 #if PLAT_MHU_VERSION == 2
24 #define MHU_V2_ENABLED
25 #elif PLAT_MHU_VERSION == 3
26 #define MHU_V3_ENABLED
27 #endif
28 
get_routing_tables_and_rse_id(const uint8_t ** routing_tables,size_t * routing_tables_size,uint32_t * rse_id)29 static void get_routing_tables_and_rse_id(const uint8_t **routing_tables,
30 					  size_t *routing_tables_size,
31 					  uint32_t *rse_id)
32 {
33 	*rse_id = sfcp_platform_get_my_node_id();
34 
35 	sfcp_platform_get_routing_tables(routing_tables, routing_tables_size);
36 }
37 
sfcp_hal_get_route(sfcp_node_id_t node_id)38 sfcp_link_id_t sfcp_hal_get_route(sfcp_node_id_t node_id)
39 {
40 	uint32_t rse_id;
41 	const uint8_t *routing_tables;
42 	size_t routing_tables_size;
43 
44 	get_routing_tables_and_rse_id(&routing_tables, &routing_tables_size,
45 				      &rse_id);
46 
47 	assert(node_id != rse_id);
48 
49 	if (node_id >= routing_tables_size) {
50 		return 0;
51 	}
52 
53 	return routing_tables[node_id];
54 }
55 
sfcp_hal_get_my_node_id(sfcp_node_id_t * node_id)56 enum sfcp_hal_error_t sfcp_hal_get_my_node_id(sfcp_node_id_t *node_id)
57 {
58 	*node_id = sfcp_platform_get_my_node_id();
59 
60 	return SFCP_HAL_ERROR_SUCCESS;
61 }
62 
mhu_driver_init(void * mhu_device,enum sfcp_platform_device_type_t type)63 static uint32_t mhu_driver_init(void *mhu_device,
64 				enum sfcp_platform_device_type_t type)
65 {
66 	switch (type) {
67 #ifdef MHU_V2_ENABLED
68 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
69 		return mhu_v2_x_driver_init(mhu_device, MHU_REV_READ_FROM_HW);
70 #endif
71 #ifdef MHU_V3_ENABLED
72 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
73 		return mhu_v3_x_driver_init(mhu_device);
74 #endif
75 	default:
76 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
77 	}
78 }
79 
mhu_get_num_mhu_channels(void * mhu_device,enum sfcp_platform_device_type_t type)80 static uint32_t mhu_get_num_mhu_channels(void *mhu_device,
81 					 enum sfcp_platform_device_type_t type)
82 {
83 	switch (type) {
84 #ifdef MHU_V2_ENABLED
85 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
86 		return mhu_v2_x_get_num_channel_implemented(mhu_device);
87 #endif
88 #ifdef MHU_V3_ENABLED
89 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3: {
90 		uint8_t num_ch;
91 		enum mhu_v3_x_error_t mhu_v3_err;
92 
93 		mhu_v3_err = mhu_v3_x_get_num_channel_implemented(
94 			mhu_device, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch);
95 		if (mhu_v3_err != MHU_V_3_X_ERR_NONE) {
96 			assert(false);
97 			return 0;
98 		}
99 
100 		return num_ch;
101 	}
102 #endif
103 	default:
104 		return 0;
105 	}
106 }
107 
mhu_channel_mask_set(void * mhu_device,uint32_t channel,uint32_t mask,enum sfcp_platform_device_type_t type)108 static uint32_t mhu_channel_mask_set(void *mhu_device, uint32_t channel,
109 				     uint32_t mask,
110 				     enum sfcp_platform_device_type_t type)
111 {
112 	switch (type) {
113 #ifdef MHU_V2_ENABLED
114 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
115 		return mhu_v2_x_channel_mask_set(mhu_device, channel, mask);
116 #endif
117 #ifdef MHU_V3_ENABLED
118 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
119 		return mhu_v3_x_doorbell_mask_set(mhu_device, channel, mask);
120 #endif
121 	default:
122 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
123 	}
124 }
125 
mhu_channel_mask_clear(void * mhu_device,uint32_t channel,uint32_t mask,enum sfcp_platform_device_type_t type)126 static uint32_t mhu_channel_mask_clear(void *mhu_device, uint32_t channel,
127 				       uint32_t mask,
128 				       enum sfcp_platform_device_type_t type)
129 {
130 	switch (type) {
131 #ifdef MHU_V2_ENABLED
132 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
133 		return mhu_v2_x_channel_mask_clear(mhu_device, channel, mask);
134 #endif
135 #ifdef MHU_V3_ENABLED
136 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
137 		return mhu_v3_x_doorbell_mask_clear(mhu_device, channel, mask);
138 #endif
139 	default:
140 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
141 	}
142 }
143 
144 static uint32_t
mhu_channel_interrupt_enable(void * mhu_device,uint32_t channel,enum sfcp_platform_device_type_t type)145 mhu_channel_interrupt_enable(void *mhu_device, uint32_t channel,
146 			     enum sfcp_platform_device_type_t type)
147 {
148 	switch (type) {
149 #ifdef MHU_V2_ENABLED
150 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
151 		/* Only enable global interrupt for MHUv2 */
152 		return mhu_v2_x_interrupt_enable(mhu_device,
153 						 MHU_2_1_INTR_CHCOMB_MASK);
154 #endif
155 #ifdef MHU_V3_ENABLED
156 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
157 		return mhu_v3_x_channel_interrupt_enable(
158 			mhu_device, channel, MHU_V3_X_CHANNEL_TYPE_DBCH);
159 #endif
160 	default:
161 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
162 	}
163 }
164 
165 static uint32_t
mhu_channel_interrupt_disable(void * mhu_device,uint32_t channel,enum sfcp_platform_device_type_t type)166 mhu_channel_interrupt_disable(void *mhu_device, uint32_t channel,
167 			      enum sfcp_platform_device_type_t type)
168 {
169 	switch (type) {
170 #ifdef MHU_V2_ENABLED
171 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
172 		/* Only disable global interrupt for MHUv2 */
173 		return mhu_v2_x_interrupt_disable(mhu_device,
174 						  MHU_2_1_INTR_CHCOMB_MASK);
175 #endif
176 #ifdef MHU_V3_ENABLED
177 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
178 		return mhu_v3_x_channel_interrupt_disable(
179 			mhu_device, channel, MHU_V3_X_CHANNEL_TYPE_DBCH);
180 #endif
181 	default:
182 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
183 	}
184 }
185 
mhu_channel_send(void * mhu_device,uint32_t channel,uint32_t value,enum sfcp_platform_device_type_t type)186 static uint32_t mhu_channel_send(void *mhu_device, uint32_t channel,
187 				 uint32_t value,
188 				 enum sfcp_platform_device_type_t type)
189 {
190 	switch (type) {
191 #ifdef MHU_V2_ENABLED
192 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
193 		return mhu_v2_x_channel_send(mhu_device, channel, value);
194 #endif
195 #ifdef MHU_V3_ENABLED
196 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
197 		return mhu_v3_x_doorbell_write(mhu_device, channel, value);
198 #endif
199 	default:
200 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
201 	}
202 }
203 
204 static uint32_t
mhu_channel_send_device_receive(void * mhu_device,uint32_t channel,uint32_t * value,enum sfcp_platform_device_type_t type)205 mhu_channel_send_device_receive(void *mhu_device, uint32_t channel,
206 				uint32_t *value,
207 				enum sfcp_platform_device_type_t type)
208 {
209 	switch (type) {
210 #ifdef MHU_V2_ENABLED
211 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
212 		return mhu_v2_x_channel_poll(mhu_device, channel, value);
213 #endif
214 #ifdef MHU_V3_ENABLED
215 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
216 		return mhu_v3_x_doorbell_read(mhu_device, channel, value);
217 #endif
218 	default:
219 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
220 	}
221 }
222 
223 static uint32_t
mhu_channel_receive_device_receive(void * mhu_device,uint32_t channel,uint32_t * value,enum sfcp_platform_device_type_t type)224 mhu_channel_receive_device_receive(void *mhu_device, uint32_t channel,
225 				   uint32_t *value,
226 				   enum sfcp_platform_device_type_t type)
227 {
228 	switch (type) {
229 #ifdef MHU_V2_ENABLED
230 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
231 		return mhu_v2_x_channel_receive(mhu_device, channel, value);
232 #endif
233 #ifdef MHU_V3_ENABLED
234 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
235 		return mhu_v3_x_doorbell_read(mhu_device, channel, value);
236 #endif
237 	default:
238 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
239 	}
240 }
241 
mhu_channel_clear(void * mhu_device,uint32_t channel,enum sfcp_platform_device_type_t type)242 static uint32_t mhu_channel_clear(void *mhu_device, uint32_t channel,
243 				  enum sfcp_platform_device_type_t type)
244 {
245 	switch (type) {
246 #ifdef MHU_V2_ENABLED
247 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
248 		return mhu_v2_x_channel_clear(mhu_device, channel);
249 #endif
250 #ifdef MHU_V3_ENABLED
251 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
252 		return mhu_v3_x_doorbell_clear(mhu_device, channel, UINT32_MAX);
253 #endif
254 	default:
255 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
256 	}
257 }
258 
mhu_initiate_transfer(void * mhu_device,enum sfcp_platform_device_type_t type)259 static uint32_t mhu_initiate_transfer(void *mhu_device,
260 				      enum sfcp_platform_device_type_t type)
261 {
262 	switch (type) {
263 #ifdef MHU_V2_ENABLED
264 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
265 		return mhu_v2_x_initiate_transfer(mhu_device);
266 #endif
267 #ifdef MHU_V3_ENABLED
268 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
269 		/* Not required in MHUv3 */
270 		return 0;
271 #endif
272 	default:
273 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
274 	}
275 }
276 
mhu_close_transfer(void * mhu_device,enum sfcp_platform_device_type_t type)277 static uint32_t mhu_close_transfer(void *mhu_device,
278 				   enum sfcp_platform_device_type_t type)
279 {
280 	switch (type) {
281 #ifdef MHU_V2_ENABLED
282 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
283 		return mhu_v2_x_close_transfer(mhu_device);
284 #endif
285 #ifdef MHU_V3_ENABLED
286 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
287 		/* Not required in MHUv3 */
288 		return 0;
289 #endif
290 	default:
291 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
292 	}
293 }
294 
295 static enum sfcp_hal_error_t
mhu_send_signal_poll_loop(void * mhu_send_device,void * mhu_recv_device,enum sfcp_platform_device_type_t type)296 mhu_send_signal_poll_loop(void *mhu_send_device, void *mhu_recv_device,
297 			  enum sfcp_platform_device_type_t type)
298 {
299 	const uint32_t send_num_channels =
300 		mhu_get_num_mhu_channels(mhu_send_device, type);
301 	const uint32_t recv_num_channels =
302 		mhu_get_num_mhu_channels(mhu_recv_device, type);
303 	uint32_t mhu_err;
304 	uint32_t send_signal;
305 	uint32_t recv_signal;
306 
307 	/* Signal using the last channel */
308 	mhu_err = mhu_channel_send(mhu_send_device, send_num_channels - 1,
309 				   MHU_NOTIFY_VALUE, type);
310 	if (mhu_err != 0) {
311 		return mhu_err;
312 	}
313 
314 	do {
315 		mhu_err = mhu_channel_send_device_receive(mhu_send_device,
316 							  send_num_channels - 1,
317 							  &send_signal, type);
318 		if (mhu_err != 0) {
319 			return mhu_err;
320 		}
321 
322 		/* Also check the receive device, if we find that a signal is pending
323 		 * for us there, both devices are talking to each other at once. Return
324 		 * an error and let the higher layers decide what to do
325 		 */
326 		mhu_err = mhu_channel_receive_device_receive(
327 			mhu_recv_device, recv_num_channels - 1, &recv_signal,
328 			type);
329 		if (mhu_err != 0) {
330 			return mhu_err;
331 		}
332 
333 		if ((recv_signal & MHU_NOTIFY_VALUE) == MHU_NOTIFY_VALUE) {
334 			return SFCP_HAL_ERROR_SEND_MESSAGE_BUS_BUSY;
335 		}
336 	} while ((send_signal & MHU_NOTIFY_VALUE) == MHU_NOTIFY_VALUE);
337 
338 	return 0;
339 }
340 
mhu_recv_signal_poll_loop(void * mhu_recv_device,enum sfcp_platform_device_type_t type)341 static uint32_t mhu_recv_signal_poll_loop(void *mhu_recv_device,
342 					  enum sfcp_platform_device_type_t type)
343 {
344 	const uint32_t recv_num_channels =
345 		mhu_get_num_mhu_channels(mhu_recv_device, type);
346 	uint32_t mhu_err;
347 	uint32_t recv_signal;
348 
349 	/* ACK current transfer by clearing all channels */
350 	for (uint32_t i = 0; i < recv_num_channels; ++i) {
351 		mhu_err = mhu_channel_clear(mhu_recv_device, i, type);
352 		if (mhu_err != 0) {
353 			return mhu_err;
354 		}
355 	}
356 
357 	/* Wait for next sender transfer */
358 	do {
359 		mhu_err = mhu_channel_receive_device_receive(
360 			mhu_recv_device, recv_num_channels - 1, &recv_signal,
361 			type);
362 		if (mhu_err != 0) {
363 			return mhu_err;
364 		}
365 	} while ((recv_signal & MHU_NOTIFY_VALUE) != MHU_NOTIFY_VALUE);
366 
367 	return 0;
368 }
369 
370 static enum sfcp_hal_error_t
mhu_message_is_available(void * mhu_recv_device,bool * is_available,enum sfcp_platform_device_type_t type)371 mhu_message_is_available(void *mhu_recv_device, bool *is_available,
372 			 enum sfcp_platform_device_type_t type)
373 {
374 	const uint32_t num_channels =
375 		mhu_get_num_mhu_channels(mhu_recv_device, type);
376 	uint32_t mhu_err;
377 	uint32_t value;
378 
379 	mhu_err = mhu_channel_receive_device_receive(
380 		mhu_recv_device, num_channels - 1, &value, type);
381 	if (mhu_err != 0) {
382 		return mhu_err;
383 	}
384 
385 	*is_available = (value == MHU_NOTIFY_VALUE);
386 
387 	return SFCP_HAL_ERROR_SUCCESS;
388 }
389 
mhu_check_message_alignment(const uint8_t * message,size_t message_size)390 static enum sfcp_hal_error_t mhu_check_message_alignment(const uint8_t *message,
391 							 size_t message_size)
392 {
393 	if ((message == NULL) ||
394 	    (((uintptr_t)message % sizeof(uint32_t)) != 0)) {
395 		return SFCP_HAL_ERROR_INVALID_MESSAGE_ARGUMENT;
396 	}
397 
398 	if (message_size == 0) {
399 		return SFCP_HAL_ERROR_INVALID_MESSAGE_SIZE;
400 	}
401 
402 	return 0;
403 }
404 
405 static enum sfcp_hal_error_t
mhu_send_message(void * mhu_send_device,void * mhu_recv_device,const uint8_t * message,size_t message_size,enum sfcp_platform_device_type_t type)406 mhu_send_message(void *mhu_send_device, void *mhu_recv_device,
407 		 const uint8_t *message, size_t message_size,
408 		 enum sfcp_platform_device_type_t type)
409 {
410 	const uint32_t num_channels =
411 		mhu_get_num_mhu_channels(mhu_send_device, type);
412 	uint32_t channel;
413 	uint32_t mhu_err;
414 	bool is_available;
415 	const uint32_t *message_ptr;
416 	uint32_t message_send_buf;
417 	size_t bytes_left;
418 
419 	mhu_err = mhu_check_message_alignment(message, message_size);
420 	if (mhu_err != 0) {
421 		return mhu_err;
422 	}
423 
424 	/* Check for incoming message on receiver device and do not allow sending
425 	 * a message while another is pending
426 	 */
427 	mhu_err =
428 		mhu_message_is_available(mhu_recv_device, &is_available, type);
429 	if (mhu_err != 0) {
430 		return mhu_err;
431 	}
432 
433 	if (is_available) {
434 		return SFCP_HAL_ERROR_SEND_MESSAGE_BUS_BUSY;
435 	}
436 
437 	mhu_err = mhu_initiate_transfer(mhu_send_device, type);
438 	if (mhu_err != 0) {
439 		return mhu_err;
440 	}
441 
442 	/* First send over the size of the actual message */
443 	channel = 0;
444 	mhu_err =
445 		mhu_channel_send(mhu_send_device, channel, message_size, type);
446 	if (mhu_err != 0) {
447 		return mhu_err;
448 	}
449 
450 	channel++;
451 	message_ptr = (const uint32_t *)message;
452 	bytes_left = message_size;
453 	while (bytes_left > 0) {
454 		if (bytes_left >= sizeof(uint32_t)) {
455 			message_send_buf = *message_ptr++;
456 			bytes_left -= sizeof(uint32_t);
457 		} else {
458 			/* A few bytes still to send, pad the remaining bytes */
459 			message_send_buf = 0;
460 			memcpy(&message_send_buf, message_ptr, bytes_left);
461 			bytes_left = 0;
462 		}
463 
464 		mhu_err = mhu_channel_send(mhu_send_device, channel,
465 					   message_send_buf, type);
466 		if (mhu_err != 0) {
467 			return mhu_err;
468 		}
469 
470 		if (++channel == (num_channels - 1)) {
471 			mhu_err = mhu_send_signal_poll_loop(
472 				mhu_send_device, mhu_recv_device, type);
473 			if (mhu_err != 0) {
474 				return mhu_err;
475 			}
476 
477 			channel = 0;
478 		}
479 	}
480 
481 	if (channel != 0) {
482 		mhu_err = mhu_send_signal_poll_loop(mhu_send_device,
483 						    mhu_recv_device, type);
484 		if (mhu_err != 0) {
485 			return mhu_err;
486 		}
487 	}
488 
489 	mhu_err = mhu_close_transfer(mhu_send_device, type);
490 	if (mhu_err != 0) {
491 		return mhu_err;
492 	}
493 
494 	return SFCP_HAL_ERROR_SUCCESS;
495 }
496 
sfcp_hal_send_message(sfcp_link_id_t link_id,const uint8_t * message,size_t message_size)497 enum sfcp_hal_error_t sfcp_hal_send_message(sfcp_link_id_t link_id,
498 					    const uint8_t *message,
499 					    size_t message_size)
500 {
501 	struct sfcp_platform_device_t send_device, recv_device;
502 
503 	send_device = sfcp_platform_get_send_device(link_id);
504 	recv_device = sfcp_platform_get_receive_device(link_id);
505 
506 	switch (send_device.type) {
507 #ifdef MHU_V2_ENABLED
508 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
509 		return mhu_send_message((void *)send_device.device,
510 					(void *)recv_device.device, message,
511 					message_size,
512 					SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
513 #endif
514 #ifdef MHU_V3_ENABLED
515 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
516 		return mhu_send_message((void *)send_device.device,
517 					(void *)recv_device.device, message,
518 					message_size,
519 					SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
520 #endif
521 	default:
522 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
523 	}
524 
525 	return SFCP_HAL_ERROR_SUCCESS;
526 }
527 
sfcp_hal_is_message_available(sfcp_link_id_t link_id,bool * is_available)528 enum sfcp_hal_error_t sfcp_hal_is_message_available(sfcp_link_id_t link_id,
529 						    bool *is_available)
530 {
531 	struct sfcp_platform_device_t device;
532 
533 	device = sfcp_platform_get_receive_device(link_id);
534 
535 	switch (device.type) {
536 #ifdef MHU_V2_ENABLED
537 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
538 		return mhu_message_is_available(
539 			(void *)device.device, is_available,
540 			SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
541 #endif
542 #ifdef MHU_V3_ENABLED
543 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
544 		return mhu_message_is_available(
545 			(void *)device.device, is_available,
546 			SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
547 #endif
548 	default:
549 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
550 	}
551 
552 	return SFCP_HAL_ERROR_SUCCESS;
553 }
554 
555 static enum sfcp_hal_error_t
mhu_get_receive_message_size(void * mhu_recv_device,size_t * message_size,enum sfcp_platform_device_type_t type)556 mhu_get_receive_message_size(void *mhu_recv_device, size_t *message_size,
557 			     enum sfcp_platform_device_type_t type)
558 {
559 	uint32_t mhu_err;
560 	uint32_t read_val;
561 
562 	mhu_err = mhu_channel_receive_device_receive(
563 		mhu_recv_device, 0, &read_val, type);
564 	if (mhu_err != 0) {
565 		return mhu_err;
566 	}
567 
568 	*message_size = read_val;
569 	return SFCP_HAL_ERROR_SUCCESS;
570 }
571 
sfcp_hal_get_receive_message_size(sfcp_link_id_t link_id,size_t * message_size)572 enum sfcp_hal_error_t sfcp_hal_get_receive_message_size(sfcp_link_id_t link_id,
573 							size_t *message_size)
574 {
575 	struct sfcp_platform_device_t device;
576 
577 	device = sfcp_platform_get_receive_device(link_id);
578 
579 	switch (device.type) {
580 #ifdef MHU_V2_ENABLED
581 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
582 		return mhu_get_receive_message_size(
583 			(void *)device.device, message_size,
584 			SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
585 #endif
586 #ifdef MHU_V3_ENABLED
587 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
588 		return mhu_get_receive_message_size(
589 			(void *)device.device, message_size,
590 			SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
591 #endif
592 	default:
593 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
594 	}
595 
596 	return SFCP_HAL_ERROR_SUCCESS;
597 }
598 
599 static enum sfcp_hal_error_t
mhu_receive_message(void * mhu_recv_device,uint8_t * message,size_t total_message_size,size_t already_received,size_t size_to_receive,enum sfcp_platform_device_type_t type)600 mhu_receive_message(void *mhu_recv_device, uint8_t *message,
601 		    size_t total_message_size, size_t already_received,
602 		    size_t size_to_receive,
603 		    enum sfcp_platform_device_type_t type)
604 {
605 	const uint32_t num_channels =
606 		mhu_get_num_mhu_channels(mhu_recv_device, type);
607 	uint32_t mhu_err;
608 	uint32_t channel;
609 	uint32_t *message_ptr;
610 	size_t bytes_left;
611 	size_t already_received_words;
612 	uint32_t message_recv_buf;
613 
614 	mhu_err = mhu_check_message_alignment(message, size_to_receive);
615 	if (mhu_err != 0) {
616 		return mhu_err;
617 	}
618 
619 	/* Must have only already received 4-byte aligned size */
620 	if ((already_received % sizeof(uint32_t)) != 0) {
621 		return SFCP_HAL_ERROR_INVALID_MESSAGE_ARGUMENT;
622 	}
623 
624 	already_received_words = already_received / sizeof(uint32_t);
625 
626 	/* First pass only has num_channels - 2 words as 1 word
627 	 * for message size and other for signalling */
628 	if (already_received_words < (num_channels - 2)) {
629 		channel = 1 + already_received_words;
630 	} else {
631 		channel = (already_received_words - (num_channels - 2)) %
632 			  (num_channels - 1);
633 	}
634 
635 	message_ptr = (uint32_t *)message;
636 	bytes_left = size_to_receive;
637 	while (bytes_left > 0) {
638 		size_t total_received;
639 
640 		mhu_err = mhu_channel_receive_device_receive(
641 			mhu_recv_device, channel, &message_recv_buf, type);
642 		if (mhu_err != 0) {
643 			return mhu_err;
644 		}
645 
646 		if (bytes_left >= sizeof(uint32_t)) {
647 			*message_ptr++ = message_recv_buf;
648 			bytes_left -= sizeof(uint32_t);
649 		} else {
650 			memcpy(message_ptr, &message_recv_buf, bytes_left);
651 			bytes_left = 0;
652 		}
653 
654 		total_received =
655 			(size_to_receive - bytes_left) + already_received;
656 
657 		/* Only wait for next transfer if there is still missing data */
658 		if ((++channel == (num_channels - 1)) &&
659 		    (total_message_size > total_received)) {
660 			/* Busy wait for next transfer */
661 			mhu_err = mhu_recv_signal_poll_loop(mhu_recv_device,
662 							    type);
663 			if (mhu_err != 0) {
664 				return mhu_err;
665 			}
666 
667 			channel = 0;
668 		}
669 	}
670 
671 	/* Only clear channels on exit if we have received the
672 	 * whole message
673 	 */
674 	if (total_message_size == (already_received + size_to_receive)) {
675 		for (uint32_t i = 0; i < num_channels; i++) {
676 			mhu_err = mhu_channel_clear(mhu_recv_device, i, type);
677 			if (mhu_err != 0) {
678 				return mhu_err;
679 			}
680 		}
681 	}
682 
683 	return SFCP_HAL_ERROR_SUCCESS;
684 }
685 
sfcp_hal_receive_message(sfcp_link_id_t link_id,uint8_t * message,size_t total_message_size,size_t already_received,size_t size_to_receive)686 enum sfcp_hal_error_t sfcp_hal_receive_message(sfcp_link_id_t link_id,
687 					       uint8_t *message,
688 					       size_t total_message_size,
689 					       size_t already_received,
690 					       size_t size_to_receive)
691 {
692 	struct sfcp_platform_device_t device;
693 	enum sfcp_hal_error_t hal_error;
694 	bool message_is_available;
695 
696 	device = sfcp_platform_get_receive_device(link_id);
697 
698 	/* Cannot receive more than the total message size */
699 	if ((already_received + size_to_receive) > total_message_size) {
700 		return SFCP_HAL_ERROR_INVALID_RECEIVE_SIZE;
701 	}
702 
703 	hal_error =
704 		sfcp_hal_is_message_available(link_id, &message_is_available);
705 	if (hal_error != SFCP_HAL_ERROR_SUCCESS) {
706 		return hal_error;
707 	}
708 
709 	if (!message_is_available) {
710 		return SFCP_HAL_ERROR_MESSAGE_NOT_AVAILABLE;
711 	}
712 
713 	switch (device.type) {
714 #ifdef MHU_V2_ENABLED
715 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
716 		return mhu_receive_message((void *)device.device, message,
717 					   total_message_size, already_received,
718 					   size_to_receive,
719 					   SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
720 #endif
721 #ifdef MHU_V3_ENABLED
722 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
723 		return mhu_receive_message((void *)device.device, message,
724 					   total_message_size, already_received,
725 					   size_to_receive,
726 					   SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
727 #endif
728 	default:
729 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
730 	}
731 
732 	return SFCP_HAL_ERROR_SUCCESS;
733 }
734 
735 static enum sfcp_hal_error_t
mhu_init_sender(void * mhu_sender_dev,enum sfcp_platform_device_type_t type)736 mhu_init_sender(void *mhu_sender_dev, enum sfcp_platform_device_type_t type)
737 {
738 	uint32_t mhu_err;
739 	uint32_t num_channels;
740 
741 	mhu_err = mhu_driver_init(mhu_sender_dev, type);
742 	if (mhu_err != 0) {
743 		return mhu_err;
744 	}
745 
746 	num_channels = mhu_get_num_mhu_channels(mhu_sender_dev, type);
747 	if (num_channels < MHU_REQUIRED_NUMBER_CHANNELS) {
748 		return SFCP_HAL_ERROR_DEVICE_UNSUPPORTED;
749 	}
750 
751 	/* Sender interrupts are not used */
752 	for (uint32_t channel = 0; channel < num_channels; channel++) {
753 		mhu_err = mhu_channel_interrupt_disable(mhu_sender_dev, channel,
754 							type);
755 		if (mhu_err != 0) {
756 			return mhu_err;
757 		}
758 	}
759 
760 	return SFCP_HAL_ERROR_SUCCESS;
761 }
762 
763 static enum sfcp_hal_error_t
mhu_init_receiver(void * mhu_receiver_dev,enum sfcp_platform_device_type_t type)764 mhu_init_receiver(void *mhu_receiver_dev, enum sfcp_platform_device_type_t type)
765 {
766 	uint32_t mhu_err;
767 	uint32_t num_channels;
768 
769 	/* Initialize MHUv3 */
770 	mhu_err = mhu_driver_init(mhu_receiver_dev, type);
771 	if (mhu_err != 0) {
772 		return mhu_err;
773 	}
774 
775 	num_channels = mhu_get_num_mhu_channels(mhu_receiver_dev, type);
776 	if (num_channels < MHU_REQUIRED_NUMBER_CHANNELS) {
777 		return SFCP_HAL_ERROR_DEVICE_UNSUPPORTED;
778 	}
779 
780 	/* Mask all channels except the notifying channel */
781 	for (uint32_t channel = 0; channel < (num_channels - 1); channel++) {
782 		mhu_err = mhu_channel_mask_set(mhu_receiver_dev, channel,
783 					       UINT32_MAX, type);
784 		if (mhu_err != 0) {
785 			return mhu_err;
786 		}
787 	}
788 
789 	/* Unmask doorbell notification channel interrupt */
790 	mhu_err = mhu_channel_mask_clear(mhu_receiver_dev, num_channels - 1,
791 					 UINT32_MAX, type);
792 	if (mhu_err != 0) {
793 		return mhu_err;
794 	}
795 
796 	/*
797 	 * Enable the doorbell channel's contribution to mailbox combined
798 	 * interrupt.
799 	 */
800 	mhu_err = mhu_channel_interrupt_enable(mhu_receiver_dev,
801 					       num_channels - 1, type);
802 	if (mhu_err != 0) {
803 		return mhu_err;
804 	}
805 
806 	return SFCP_HAL_ERROR_SUCCESS;
807 }
808 
809 static enum sfcp_hal_error_t
init_sender_receiver(struct sfcp_platform_device_t device,bool is_sender)810 init_sender_receiver(struct sfcp_platform_device_t device, bool is_sender)
811 {
812 	switch (device.type) {
813 #ifdef MHU_V2_ENABLED
814 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV2:
815 		if (is_sender) {
816 			return mhu_init_sender((void *)device.device,
817 					       SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
818 		} else {
819 			return mhu_init_receiver(
820 				(void *)device.device,
821 				SFCP_PLATFORM_DEVICE_TYPE_MHUV2);
822 		}
823 #endif
824 #ifdef MHU_V3_ENABLED
825 	case SFCP_PLATFORM_DEVICE_TYPE_MHUV3:
826 		if (is_sender) {
827 			return mhu_init_sender((void *)device.device,
828 					       SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
829 		} else {
830 			return mhu_init_receiver(
831 				(void *)device.device,
832 				SFCP_PLATFORM_DEVICE_TYPE_MHUV3);
833 		}
834 #endif
835 	default:
836 		return SFCP_HAL_ERROR_UNSUPPORTED_DEVICE;
837 	}
838 
839 	return SFCP_HAL_ERROR_SUCCESS;
840 }
841 
sfcp_hal_init(void)842 enum sfcp_hal_error_t sfcp_hal_init(void)
843 {
844 	enum sfcp_hal_error_t hal_err;
845 	uint32_t rse_id;
846 	const uint8_t *routing_tables;
847 	size_t routing_tables_size;
848 	sfcp_link_id_t link_id;
849 
850 	get_routing_tables_and_rse_id(&routing_tables, &routing_tables_size,
851 				      &rse_id);
852 
853 	for (sfcp_node_id_t node = 0; node < routing_tables_size; node++) {
854 		if (node == rse_id) {
855 			continue;
856 		}
857 
858 		link_id = routing_tables[node];
859 		if (link_id == 0) {
860 			/* No route to node */
861 			continue;
862 		}
863 
864 		hal_err = init_sender_receiver(
865 			sfcp_platform_get_send_device(link_id), true);
866 		if (hal_err != SFCP_HAL_ERROR_SUCCESS) {
867 			return hal_err;
868 		}
869 
870 		hal_err = init_sender_receiver(
871 			sfcp_platform_get_receive_device(link_id), false);
872 		if (hal_err != SFCP_HAL_ERROR_SUCCESS) {
873 			return hal_err;
874 		}
875 	}
876 
877 	return SFCP_HAL_ERROR_SUCCESS;
878 }
879