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