1 /*
2  * Copyright (c) 2024, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "interrupts_bl2.h"
9 
10 #include "device_definition.h"
11 #include "host_system.h"
12 #include "mhu_v3_x.h"
13 #include "tfm_hal_device_header.h"
14 
15 #include <stdint.h>
16 
17 /* Enum for id of each doorbell channel of the scp to rse MHU */
18 enum mhu_scp_rse_doorbell_channel {
19     MHU_SCP_RSE_RESERVED_CHANNEL_ID = 0,
20     MHU_SCP_RSE_SYSTOP_ON_CHANNEL_ID = 1,
21     MHU_SCP_RSE_CHANNEL_COUNT,
22 };
23 
24 #define MHU_SCP_SYSTOP_FLAG 0x1
25 
mhu_scp_rse_systop_on_doorbell_handler(uint32_t value)26 static int mhu_scp_rse_systop_on_doorbell_handler(uint32_t value)
27 {
28     /* Only flag 0 is used to indicate SYSTOP ON */
29     if ((value & MHU_SCP_SYSTOP_FLAG) != MHU_SCP_SYSTOP_FLAG) {
30         return 1;
31     }
32 
33     host_system_scp_signal_ap_ready();
34 
35     return 0;
36 }
37 
38 /* Function prototype to use for mhu channel vector pointers */
39 typedef int (*mhu_vector_t) (uint32_t);
40 
41 /* Array of function pointers to call if a message is received on a channel */
42 static mhu_vector_t mhu_scp_rse_doorbell_vector[MHU_SCP_RSE_CHANNEL_COUNT] = {
43     [MHU_SCP_RSE_SYSTOP_ON_CHANNEL_ID] = mhu_scp_rse_systop_on_doorbell_handler,
44 };
45 
46 /* Function to handle the SCP to RSE MHUv3 combined MBX interrupt */
CMU_MHU4_Receiver_Handler(void)47 void CMU_MHU4_Receiver_Handler(void)
48 {
49     uint32_t ch, value, mask = 0;
50     enum mhu_v3_x_error_t status;
51 
52     for (ch = 0; ch < MHU_SCP_RSE_CHANNEL_COUNT; ch++) {
53         /* Read the doorbell channel value */
54         status = mhu_v3_x_doorbell_read(&MHU_V3_SCP_TO_RSE_DEV, ch, &value);
55         if (status != MHU_V_3_X_ERR_NONE) {
56             break;
57         }
58 
59         /* If this channel has a message (non zero value) */
60         if (value != 0) {
61 
62             /* If no handler for channel then enter error state. */
63             if (mhu_scp_rse_doorbell_vector[ch] == NULL) {
64                 while (1);
65             }
66             /* Call the vector function for this channel */
67             status = mhu_scp_rse_doorbell_vector[ch](value);
68             if (status != 0){
69                 while (1);
70             }
71 
72             /* Update mask value to clear the doorbell */
73             mask = value;
74             break;
75         }
76     }
77 
78     /* Clear the pending interrupt */
79     mhu_v3_x_doorbell_clear(&MHU_V3_SCP_TO_RSE_DEV, ch, mask);
80 }
81 
interrupts_bl2_init(void)82 int32_t interrupts_bl2_init(void) {
83     /* Register interrupt handler for SCP to RSE MHUv3 */
84     NVIC_SetVector(CMU_MHU4_Receiver_IRQn, CMU_MHU4_Receiver_Handler);
85     if (NVIC_GetVector(CMU_MHU4_Receiver_IRQn) != CMU_MHU4_Receiver_Handler) {
86         return 1;
87     }
88     return 0;
89 }
90