1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * Message Handling Unit 3 (MHU3) Device Driver.
9 */
10
11 #include <internal/mhu3.h>
12
13 #include <mod_mhu3.h>
14 #include <mod_transport.h>
15
16 #include <fwk_id.h>
17 #include <fwk_interrupt.h>
18 #include <fwk_log.h>
19 #include <fwk_mm.h>
20 #include <fwk_module.h>
21 #include <fwk_module_idx.h>
22 #include <fwk_status.h>
23
24 #include <stddef.h>
25 #include <stdint.h>
26
27 /*
28 * Maximum number doorbell channels.
29 *
30 * MHUv3 architecture supports up to 128 channels but
31 * only few channels are expected to be configured on
32 * a typical platform for communication between
33 * SCP <---> MCP
34 * SCP <---> RSS
35 * SCP <---> AP
36 * SCP <---> LCPn
37 */
38 #define MHU_DOORBELL_CHANNEL_COUNT_MAX 6
39
40 /* MHU channel context */
41 struct mhu3_channel_ctx {
42 /* ID of the transport channel the MHUv3 channel is bound to */
43 fwk_id_t transport_id;
44 /* Indicates whether the transport channel is bound to the MHUv3 channel */
45 bool transport_id_bound;
46 /* Transport API */
47 const struct mod_transport_driver_input_api *transport_api;
48 /*! Fast Channel Callback Parameter */
49 uintptr_t callback_param;
50 /*! Fast Channel Callback on isr */
51 void (*callback)(uintptr_t param);
52 };
53
54 /* MHU device context */
55 struct mhu3_device_ctx {
56 /* Pointer to the device configuration */
57 const struct mod_mhu3_device_config *config;
58 /* Table of channel contexts */
59 struct mhu3_channel_ctx *channel_ctx_table;
60 /* Number of channels (represented by sub-elements) */
61 unsigned int channels_count;
62 };
63
64 /* MHU context */
65 struct mod_mhu3_ctx {
66 /* Table of device contexts */
67 struct mhu3_device_ctx *device_ctx_table;
68 /* Number of devices in the device context table */
69 unsigned int device_count;
70 };
71
72 static struct mod_mhu3_ctx mhu3_ctx;
73
mhu3_isr(void)74 static void mhu3_isr(void)
75 {
76 int status;
77 unsigned int interrupt;
78 unsigned int device_idx;
79 struct mhu3_device_ctx *device_ctx;
80 struct mod_mhu3_channel_config *channel;
81 struct mhu3_channel_ctx *channel_ctx;
82 struct mhu3_mbx_reg *mbx_reg;
83 struct mhu3_mbx_mdbcw_reg *mdbcw_reg;
84 unsigned int pending = 0U;
85
86 status = fwk_interrupt_get_current(&interrupt);
87 if (status != FWK_SUCCESS) {
88 return;
89 }
90
91 for (device_idx = 0U; device_idx < mhu3_ctx.device_count; device_idx++) {
92 device_ctx = &mhu3_ctx.device_ctx_table[device_idx];
93 if (device_ctx->config->irq == interrupt) {
94 break;
95 }
96 }
97
98 if (device_idx >= mhu3_ctx.device_count) {
99 return;
100 }
101 mbx_reg = (struct mhu3_mbx_reg *)device_ctx->config->in;
102 /*
103 * In case we need to use it for doorbell. This way we don't have to assign
104 * it every time we have a doorbell channel inside the loop
105 */
106 mdbcw_reg = (struct mhu3_mbx_mdbcw_reg
107 *)((uint8_t *)mbx_reg + MHU3_MBX_MDBCW_PAGE_OFFSET);
108
109 while (pending < device_ctx->channels_count) {
110 channel = &(device_ctx->config->channels[pending]);
111 channel_ctx = &(device_ctx->channel_ctx_table[pending]);
112 switch (channel->type) {
113 case MOD_MHU3_CHANNEL_TYPE_DBCH:
114 /*
115 * This implementation will not work if configured hardware(MHU3)
116 * requires to support more than 32 doorbell channels.
117 *
118 * Status of the interrupts of doorbell channel
119 * is read using MBX_DBCH_INT_ST<n> register where
120 * n = 0..3, that is, each 32 bits of MBX_DBCH_INT_ST<n> will
121 * indicate status of each corresponding doorbell channel
122 * 0b1 indicates interrupt pending.
123 *
124 * NOTE: We only check MBX_DBCH_INT_ST[0] because
125 * although MHUv3 supports upto 128 channels, it is not
126 * expected hardware to be configured more than 32 channels.
127 */
128 if (((1u << channel->dbch.mbx_channel) &
129 mbx_reg->MBX_DBCH_INT_ST[0]) != 0u) {
130 /*
131 * Clear Doorbell flag, we should clear only the flag(bit) which
132 * is set. However, we are using only one flag(bit) of
133 * corresponding doorbell channel for communication.
134 */
135 mdbcw_reg[channel->dbch.mbx_channel].MDBCW_CLR |=
136 (1UL << channel->dbch.mbx_flag_pos);
137 if (channel_ctx->transport_id_bound) {
138 channel_ctx->transport_api->signal_message(
139 channel_ctx->transport_id);
140 }
141 }
142 break;
143
144 case MOD_MHU3_CHANNEL_TYPE_FCH:
145 if (((mbx_reg->MBX_FCH_GRP_INT_ST[channel->fch.grp_num] >>
146 channel->fch.idx) &
147 1u) != 0u) {
148 channel_ctx = &(device_ctx->channel_ctx_table[pending]);
149 /*
150 * We only check for whether the callback is NULL as the
151 * register callback function checks for both callback and
152 * callback_param before registering so that we can save a few
153 * cycles here.
154 */
155 if (channel_ctx->callback != NULL) {
156 channel_ctx->callback(channel_ctx->callback_param);
157 }
158 }
159 break;
160
161 default:
162 break;
163 }
164 pending++;
165 }
166 }
167
mhu3_raise_interrupt(fwk_id_t ch_id)168 static int mhu3_raise_interrupt(fwk_id_t ch_id)
169 {
170 int status;
171 struct mhu3_device_ctx *device_ctx;
172 unsigned int ch_idx;
173 struct mhu3_pbx_reg *pbx_reg;
174 struct mhu3_pbx_pdbcw_reg *pdbcw_reg;
175 struct mod_mhu3_channel_config *channel;
176 struct mod_mhu3_dbch_config *dbch_channel;
177
178 device_ctx = &mhu3_ctx.device_ctx_table[fwk_id_get_element_idx(ch_id)];
179 ch_idx = fwk_id_get_sub_element_idx(ch_id);
180 pbx_reg = (struct mhu3_pbx_reg *)device_ctx->config->out;
181 channel = &(device_ctx->config->channels[ch_idx]);
182
183 switch (channel->type) {
184 case MOD_MHU3_CHANNEL_TYPE_DBCH:
185 pdbcw_reg = (struct mhu3_pbx_pdbcw_reg
186 *)((uint8_t *)pbx_reg + MHU3_PBX_PDBCW_PAGE_OFFSET);
187 dbch_channel = &(channel->dbch);
188 /*
189 * We can use up to 32 flags(bits) per channels for 32 events, however
190 * we are using only 1 flag(bit) per channel
191 */
192 if ((pdbcw_reg[dbch_channel->pbx_channel].PDBCW_ST &
193 0x1u << dbch_channel->pbx_flag_pos) == 0u) {
194 pdbcw_reg[dbch_channel->pbx_channel].PDBCW_SET |= 0x1u
195 << dbch_channel->pbx_flag_pos;
196 status = FWK_SUCCESS;
197 } else {
198 status = FWK_E_STATE;
199 }
200 break;
201
202 default:
203 status = FWK_E_PARAM;
204 break;
205 }
206
207 return status;
208 }
209
210 #ifdef BUILD_HAS_FAST_CHANNELS
211
mhu3_get_fch(fwk_id_t fch_id,struct fast_channel_addr * fch)212 static int mhu3_get_fch(fwk_id_t fch_id, struct fast_channel_addr *fch)
213 {
214 int status = FWK_E_PARAM;
215 unsigned int ch_idx, fch_offset;
216 struct mhu3_device_ctx *device_ctx;
217 struct mhu3_pbx_reg *pbx_reg, *pbx_reg_target;
218 struct mhu3_mbx_reg *mbx_reg, *mbx_reg_target;
219 uintptr_t fcw_regs, fcw_regs_target;
220 struct mod_mhu3_channel_config *channel;
221 struct mod_mhu3_fc_config *fch_channel;
222 uint32_t fch_cfg0;
223
224 if (!fwk_module_is_valid_sub_element_id(fch_id) || (fch == NULL)) {
225 return status;
226 }
227
228 device_ctx = &mhu3_ctx.device_ctx_table[fwk_id_get_element_idx(fch_id)];
229 ch_idx = fwk_id_get_sub_element_idx(fch_id);
230 pbx_reg = (struct mhu3_pbx_reg *)device_ctx->config->out;
231 mbx_reg = (struct mhu3_mbx_reg *)device_ctx->config->in;
232
233 pbx_reg_target = (struct mhu3_pbx_reg *)device_ctx->config->out_target;
234 mbx_reg_target = (struct mhu3_mbx_reg *)device_ctx->config->in_target;
235
236 channel = &(device_ctx->config->channels[ch_idx]);
237
238 switch (channel->type) {
239 case MOD_MHU3_CHANNEL_TYPE_FCH:
240 fch_channel = &(channel->fch);
241 if (fch_channel->direction == MOD_MHU3_FCH_DIR_OUT) {
242 fcw_regs = (uintptr_t)pbx_reg + MHU3_PBX_PFCW_PAGE_OFFSET;
243 fcw_regs_target =
244 (uintptr_t)mbx_reg_target + MHU3_MBX_MDFCW_PAGE_OFFSET;
245 fch_cfg0 = pbx_reg->PBX_FCH_CFG0;
246
247 status = FWK_SUCCESS;
248 } else if (fch_channel->direction == MOD_MHU3_FCH_DIR_IN) {
249 fcw_regs = (uintptr_t)mbx_reg + MHU3_MBX_MDFCW_PAGE_OFFSET;
250 fcw_regs_target =
251 (uintptr_t)pbx_reg_target + MHU3_PBX_PFCW_PAGE_OFFSET;
252 fch_cfg0 = mbx_reg->MBX_FCH_CFG0;
253
254 status = FWK_SUCCESS;
255 }
256
257 if (status == FWK_SUCCESS) {
258 fch_offset = fch_channel->idx +
259 fch_channel->grp_num *
260 MHU3_MASKED_RECOVER(
261 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCH_PER_GRP_MASK,
262 MHU3_FCH_CFG0_NUM_FCH_PER_GRP_BITSTART,
263 MHU3_FCH_CFG0_NUM_FCH_PER_GRP_LEN);
264 fch->length = (MHU3_MASKED_RECOVER(
265 fch_cfg0 & MHU3_FCH_CFG0_FCH_WS_MASK,
266 MHU3_FCH_CFG0_FCH_WS_BITSTART,
267 MHU3_FCH_CFG0_FCH_WS_LEN) == FCH_WS_32BIT) ?
268 sizeof(uint32_t) :
269 sizeof(uint64_t);
270 fch_offset *= fch->length;
271 fch->local_view_address = fcw_regs + fch_offset;
272 fch->target_view_address = fcw_regs_target + fch_offset;
273 }
274
275 break;
276
277 default:
278 break;
279 }
280
281 return status;
282 }
283
mhu3_fch_register_callback(fwk_id_t fch_id,uintptr_t param,void (* fch_callback)(uintptr_t param))284 static int mhu3_fch_register_callback(
285 fwk_id_t fch_id,
286 uintptr_t param,
287 void (*fch_callback)(uintptr_t param))
288 {
289 struct mhu3_device_ctx *device_ctx;
290 unsigned int ch_idx;
291 struct mhu3_channel_ctx *channel_ctx;
292
293 if ((fch_callback == NULL) || ((void *)param == NULL)) {
294 return FWK_E_PARAM;
295 }
296
297 if (!fwk_module_is_valid_sub_element_id(fch_id)) {
298 return FWK_E_PARAM;
299 }
300
301 device_ctx = &mhu3_ctx.device_ctx_table[fwk_id_get_element_idx(fch_id)];
302 ch_idx = fwk_id_get_sub_element_idx(fch_id);
303 channel_ctx = &(device_ctx->channel_ctx_table[ch_idx]);
304 channel_ctx->callback = fch_callback;
305 channel_ctx->callback_param = param;
306
307 return FWK_SUCCESS;
308 }
309
310 #endif
311
312 static struct mod_transport_driver_api mhu3_mod_transport_driver_api = {
313 .trigger_event = mhu3_raise_interrupt,
314 #ifdef BUILD_HAS_FAST_CHANNELS
315 .get_fch = mhu3_get_fch,
316 .fch_register_callback = mhu3_fch_register_callback,
317 #endif
318 };
319
320 /*
321 * Framework handlers
322 */
323
mhu3_init(fwk_id_t module_id,unsigned int device_count,const void * unused)324 static int mhu3_init(
325 fwk_id_t module_id,
326 unsigned int device_count,
327 const void *unused)
328 {
329 if (device_count == 0U) {
330 return FWK_E_PARAM;
331 }
332
333 mhu3_ctx.device_ctx_table =
334 fwk_mm_calloc(device_count, sizeof(mhu3_ctx.device_ctx_table[0]));
335
336 mhu3_ctx.device_count = device_count;
337
338 return FWK_SUCCESS;
339 }
340
mhu3_device_init(fwk_id_t device_id,unsigned int sub_element_count,const void * data)341 static int mhu3_device_init(
342 fwk_id_t device_id,
343 unsigned int sub_element_count,
344 const void *data)
345 {
346 int status = FWK_SUCCESS;
347 struct mod_mhu3_device_config *config =
348 (struct mod_mhu3_device_config *)data;
349 struct mhu3_device_ctx *device_ctx;
350 struct mhu3_mbx_reg *mbx_reg;
351 struct mhu3_pbx_reg *pbx_reg;
352 uint32_t fch_cfg0, ext_suprt;
353 struct mod_mhu3_channel_config *channel;
354 unsigned int channel_num;
355
356 if ((config->in == 0u) || (config->out == 0u)) {
357 return FWK_E_PARAM;
358 }
359
360 device_ctx = &mhu3_ctx.device_ctx_table[fwk_id_get_element_idx(device_id)];
361
362 device_ctx->config = config;
363 device_ctx->channels_count = sub_element_count;
364 device_ctx->channel_ctx_table = fwk_mm_calloc(
365 sub_element_count, sizeof(device_ctx->channel_ctx_table[0]));
366
367 mbx_reg = (struct mhu3_mbx_reg *)device_ctx->config->in;
368 pbx_reg = (struct mhu3_pbx_reg *)device_ctx->config->out;
369
370 /*
371 * Loop to verify that the desired Fast Channel Number and Group
372 * are correct according to Hardware
373 */
374 for (channel_num = 0u; channel_num < sub_element_count; channel_num++) {
375 channel = &(device_ctx->config->channels[channel_num]);
376 if (channel->type == MOD_MHU3_CHANNEL_TYPE_FCH) {
377 if (channel->fch.direction == MOD_MHU3_FCH_DIR_IN) {
378 fch_cfg0 = mbx_reg->MBX_FCH_CFG0;
379 ext_suprt = mbx_reg->MBX_FEAT_SPT0;
380 } else {
381 fch_cfg0 = pbx_reg->PBX_FCH_CFG0;
382 ext_suprt = pbx_reg->PBX_FEAT_SPT0;
383 }
384 if (((ext_suprt & MHU3_FEAT_SPT0_FCE_SPT_MASK) == 0u) ||
385 (channel->fch.grp_num >
386 MHU3_MASKED_RECOVER(
387 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCG_MASK,
388 MHU3_FCH_CFG0_NUM_FCG_BITSTART,
389 MHU3_FCH_CFG0_NUM_FCG_LEN))) {
390 status = FWK_E_PARAM;
391 break;
392 }
393 if ((fch_cfg0 & MHU3_FCH_CFG0_NUM_FCH_PER_GRP_MASK) == 0u) {
394 if (channel->fch.idx >
395 MHU3_MASKED_RECOVER(
396 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCH_MASK,
397 MHU3_FCH_CFG0_NUM_FCH_BITSTART,
398 MHU3_FCH_CFG0_NUM_FCH_LEN)) {
399 status = FWK_E_PARAM;
400 break;
401 }
402 } else {
403 if (channel->fch.idx >
404 MHU3_MASKED_RECOVER(
405 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCH_PER_GRP_MASK,
406 MHU3_FCH_CFG0_NUM_FCH_PER_GRP_BITSTART,
407 MHU3_FCH_CFG0_NUM_FCH_PER_GRP_LEN)) {
408 status = FWK_E_PARAM;
409 break;
410 }
411 if ((channel->fch.grp_num ==
412 MHU3_MASKED_RECOVER(
413 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCG_MASK,
414 MHU3_FCH_CFG0_NUM_FCG_BITSTART,
415 MHU3_FCH_CFG0_NUM_FCG_LEN)) &&
416 ((fch_cfg0 & MHU3_FCH_CFG0_NUM_FCG_MASK) != 0u)) {
417 /*
418 * Verify that the last Group contains an appropiate amounts
419 * of Channels.
420 */
421 if (channel->fch.idx >=
422 (MHU3_MASKED_RECOVER(
423 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCH_MASK,
424 MHU3_FCH_CFG0_NUM_FCH_BITSTART,
425 MHU3_FCH_CFG0_NUM_FCH_LEN) -
426 (MHU3_MASKED_RECOVER(
427 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCG_MASK,
428 MHU3_FCH_CFG0_NUM_FCG_BITSTART,
429 MHU3_FCH_CFG0_NUM_FCG_LEN) -
430 1u) *
431 MHU3_MASKED_RECOVER(
432 fch_cfg0 & MHU3_FCH_CFG0_NUM_FCH_PER_GRP_MASK,
433 MHU3_FCH_CFG0_NUM_FCH_PER_GRP_BITSTART,
434 MHU3_FCH_CFG0_NUM_FCH_PER_GRP_LEN))) {
435 status = FWK_E_PARAM;
436 break;
437 }
438 }
439 }
440 }
441 }
442
443 return status;
444 }
445
mhu3_bind(fwk_id_t id,unsigned int round)446 static int mhu3_bind(fwk_id_t id, unsigned int round)
447 {
448 int status;
449 struct mhu3_device_ctx *device_ctx;
450 struct mhu3_channel_ctx *channel_ctx;
451 unsigned int channel_idx;
452
453 if ((round == 1) && fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) {
454 device_ctx = &mhu3_ctx.device_ctx_table[fwk_id_get_element_idx(id)];
455
456 for (channel_idx = 0; channel_idx < device_ctx->channels_count;
457 channel_idx++) {
458 channel_ctx = &device_ctx->channel_ctx_table[channel_idx];
459 if (channel_ctx->transport_id_bound) {
460 status = fwk_module_bind(
461 channel_ctx->transport_id,
462 FWK_ID_API(
463 FWK_MODULE_IDX_TRANSPORT,
464 MOD_TRANSPORT_API_IDX_DRIVER_INPUT),
465 channel_ctx->transport_api);
466
467 if (status != FWK_SUCCESS) {
468 /* Unable to bind back to TRANSPORT channel */
469 fwk_unexpected();
470 return status;
471 }
472 }
473 }
474 }
475
476 return FWK_SUCCESS;
477 }
478
mhu3_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)479 static int mhu3_process_bind_request(
480 fwk_id_t source_id,
481 fwk_id_t target_id,
482 fwk_id_t api_id,
483 const void **api)
484 {
485 enum mod_mhu3_api_idx api_id_type;
486 struct mhu3_device_ctx *device_ctx;
487 struct mhu3_channel_ctx *channel_ctx;
488 unsigned int ch_idx;
489
490 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_SUB_ELEMENT)) {
491 /*
492 * Something tried to bind to the module or an element. Only binding to
493 * a slot (sub-element) is allowed.
494 */
495 fwk_unexpected();
496 return FWK_E_ACCESS;
497 }
498
499 device_ctx = &mhu3_ctx.device_ctx_table[fwk_id_get_element_idx(target_id)];
500 ch_idx = fwk_id_get_sub_element_idx(target_id);
501
502 channel_ctx = &(device_ctx->channel_ctx_table[ch_idx]);
503 api_id_type = (enum mod_mhu3_api_idx)fwk_id_get_api_idx(api_id);
504
505 switch (api_id_type) {
506 case MOD_MHU3_API_IDX_TRANSPORT_DRIVER:
507 channel_ctx->transport_id = source_id;
508 channel_ctx->transport_id_bound = true;
509 *api = &mhu3_mod_transport_driver_api;
510 break;
511
512 default:
513 /* Invalid config */
514 fwk_unexpected();
515 return FWK_E_PARAM;
516 }
517
518 return FWK_SUCCESS;
519 }
520
mhu3_start(fwk_id_t id)521 static int mhu3_start(fwk_id_t id)
522 {
523 int status;
524 unsigned int i;
525 struct mhu3_device_ctx *device_ctx;
526 struct mhu3_pbx_reg *pbx;
527 struct mhu3_mbx_reg *mbx;
528
529 if (fwk_id_get_type(id) == FWK_ID_TYPE_MODULE) {
530 return FWK_SUCCESS;
531 }
532
533 device_ctx = &mhu3_ctx.device_ctx_table[fwk_id_get_element_idx(id)];
534
535 pbx = (struct mhu3_pbx_reg *)device_ctx->config->out;
536 mbx = (struct mhu3_mbx_reg *)device_ctx->config->in;
537 if (pbx != NULL) {
538 pbx->PBX_CTRL |= MHU3_OP_REQ;
539 }
540 if (mbx != NULL) {
541 mbx->MBX_CTRL |= MHU3_OP_REQ;
542 }
543
544 status = fwk_interrupt_set_isr(device_ctx->config->irq, &mhu3_isr);
545 if (status != FWK_SUCCESS) {
546 return status;
547 }
548
549 status = fwk_interrupt_enable(device_ctx->config->irq);
550 if (status != FWK_SUCCESS) {
551 return status;
552 }
553
554 for (i = 0u; i < device_ctx->channels_count; i++) {
555 if (device_ctx->config->channels[i].type == MOD_MHU3_CHANNEL_TYPE_FCH) {
556 mbx->MBX_FCH_CTRL |= SCP_MHU3_MBX_INT_EN;
557 mbx->MBX_FCG_INT_EN |= 1u
558 << device_ctx->config->channels[i].fch.grp_num;
559 }
560 }
561
562 return FWK_SUCCESS;
563 }
564
565 /* MHU module definition */
566 const struct fwk_module module_mhu3 = {
567 .type = FWK_MODULE_TYPE_DRIVER,
568 .api_count = (unsigned int)MOD_MHU3_API_IDX_COUNT,
569 .init = mhu3_init,
570 .element_init = mhu3_device_init,
571 .bind = mhu3_bind,
572 .start = mhu3_start,
573 .process_bind_request = mhu3_process_bind_request,
574 };
575