1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     Reset domain HAL
9  */
10 
11 #include <fwk_mm.h>
12 #include <fwk_module.h>
13 #include <fwk_module_idx.h>
14 #include <fwk_notification.h>
15 #include <mod_reset_domain.h>
16 
17 /*
18  * Module and devices contexts for Reset Domain
19  */
20 
21 /* Device context */
22 struct rd_dev_ctx {
23     const struct mod_reset_domain_dev_config *config;
24     struct mod_reset_domain_drv_api *driver_api;
25 };
26 
27 /* Module context */
28 struct mod_rd_ctx {
29     const struct mod_reset_domain_config *config;
30     struct rd_dev_ctx *dev_ctx_table;
31     unsigned int dev_count;
32 };
33 
34 /*
35  * Internal variables
36  */
37 static struct mod_rd_ctx module_reset_ctx;
38 
39 /*
40  * API functions
41  */
set_reset_state(fwk_id_t reset_dev_id,enum mod_reset_domain_mode mode,uint32_t reset_state,uintptr_t cookie)42 static int set_reset_state(fwk_id_t reset_dev_id,
43                            enum mod_reset_domain_mode mode,
44                            uint32_t reset_state,
45                            uintptr_t cookie)
46 {
47     struct rd_dev_ctx *reset_ctx;
48     unsigned int reset_domain_idx = fwk_id_get_element_idx(reset_dev_id);
49 
50     reset_ctx = &module_reset_ctx.dev_ctx_table[reset_domain_idx];
51 
52     return reset_ctx->driver_api->set_reset_state(reset_ctx->config->driver_id,
53                                                   mode, reset_state, cookie);
54 }
55 
56 /* HAL API */
57 static const struct mod_reset_domain_api reset_api = {
58     .set_reset_state = set_reset_state,
59 };
60 
61 #ifdef BUILD_HAS_NOTIFICATION
reset_issued_notify(fwk_id_t dev_id,uint32_t reset_state,uintptr_t cookie)62 static int reset_issued_notify(fwk_id_t dev_id,
63                                uint32_t reset_state,
64                                uintptr_t cookie)
65 {
66     int domain_id = -1;
67     unsigned int i;
68     struct rd_dev_ctx *reset_ctx;
69     unsigned int notification_count;
70     struct fwk_event notification_event = {
71         .id = module_reset_ctx.config->notification_id,
72         .source_id = fwk_module_id_reset_domain,
73     };
74 
75     struct mod_reset_domain_notification_event_params* params =
76         (struct mod_reset_domain_notification_event_params*)
77         notification_event.params;
78 
79     /* Loop through device context table to get the associated domain_id */
80     for (i = 0; i < module_reset_ctx.dev_count; i++) {
81         reset_ctx = &module_reset_ctx.dev_ctx_table[i];
82         if (fwk_id_is_equal(reset_ctx->config->driver_id, dev_id)) {
83             domain_id = (int)i;
84             break;
85         }
86     }
87 
88     if (domain_id < 0)
89         return FWK_E_PARAM;
90 
91     params->domain_id = (uint32_t)domain_id;
92     params->reset_state = reset_state;
93     params->cookie = cookie;
94 
95     return fwk_notification_notify(&notification_event, &notification_count);
96 }
97 #endif /* BUILD_HAS_NOTIFICATION */
98 
rd_process_event(const struct fwk_event * event,struct fwk_event * resp)99 static int rd_process_event(
100     const struct fwk_event *event,
101     struct fwk_event *resp)
102 {
103 #ifdef BUILD_HAS_NOTIFICATION
104     struct mod_reset_domain_autoreset_event_params* params =
105         (struct mod_reset_domain_autoreset_event_params*)event->params;
106 #endif
107 
108     if (!fwk_id_is_equal(mod_reset_domain_autoreset_event_id,
109                          event->id))
110         return FWK_E_SUPPORT;
111 
112 #ifdef BUILD_HAS_NOTIFICATION
113     return reset_issued_notify(params->dev_id,
114                                params->reset_state, params->cookie);
115 #else
116     return FWK_SUCCESS;
117 #endif
118 }
119 
120 /*
121  * Framework handlers
122  */
rd_init(fwk_id_t module_id,unsigned int dev_count,const void * data)123 static int rd_init(fwk_id_t module_id,
124                    unsigned int dev_count,
125                    const void *data)
126 {
127     module_reset_ctx.config = (struct mod_reset_domain_config *)data;
128     module_reset_ctx.dev_ctx_table = fwk_mm_calloc(dev_count,
129                                              sizeof(struct rd_dev_ctx));
130     module_reset_ctx.dev_count = dev_count;
131 
132     return FWK_SUCCESS;
133 }
134 
rd_element_init(fwk_id_t element_id,unsigned int sub_dev_count,const void * data)135 static int rd_element_init(fwk_id_t element_id,
136                            unsigned int sub_dev_count,
137                            const void *data)
138 {
139     struct rd_dev_ctx *reset_ctx = NULL;
140 
141     reset_ctx = &module_reset_ctx.dev_ctx_table[
142         fwk_id_get_element_idx(element_id)];
143 
144     reset_ctx->config = (const struct mod_reset_domain_dev_config *)data;
145 
146     return FWK_SUCCESS;
147 }
148 
rd_bind(fwk_id_t id,unsigned int round)149 static int rd_bind(fwk_id_t id, unsigned int round)
150 {
151     struct rd_dev_ctx *reset_ctx = NULL;
152 
153     /* Nothing to do during subsequent round of calls */
154     if (round != 0)
155         return FWK_SUCCESS;
156 
157     if (!fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT))
158         return FWK_SUCCESS;
159 
160     reset_ctx = module_reset_ctx.dev_ctx_table + fwk_id_get_element_idx(id);
161 
162     return fwk_module_bind(reset_ctx->config->driver_id,
163                            reset_ctx->config->driver_api_id,
164                            &reset_ctx->driver_api);
165 }
166 
rd_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)167 static int rd_process_bind_request(fwk_id_t source_id,
168                                    fwk_id_t target_id,
169                                    fwk_id_t api_id,
170                                    const void **api)
171 {
172     enum mod_reset_domain_api_type api_id_type =
173         (enum mod_reset_domain_api_type)fwk_id_get_api_idx(api_id);
174 
175     switch (api_id_type) {
176     case MOD_RESET_DOMAIN_API_TYPE_HAL:
177         *api = &reset_api;
178         break;
179 
180     default:
181         return FWK_E_ACCESS;
182     }
183 
184     return FWK_SUCCESS;
185 }
186 
187 const struct fwk_module module_reset_domain = {
188     .type = FWK_MODULE_TYPE_HAL,
189     .api_count = (unsigned int)MOD_RESET_DOMAIN_API_COUNT,
190 #ifdef BUILD_HAS_NOTIFICATION
191     .notification_count = (unsigned int)MOD_RESET_DOMAIN_NOTIFICATION_IDX_COUNT,
192 #endif
193     .event_count = (unsigned int)MOD_RESET_DOMAIN_EVENT_IDX_COUNT,
194     .init = rd_init,
195     .element_init = rd_element_init,
196     .bind = rd_bind,
197     .process_bind_request = rd_process_bind_request,
198     .process_event = rd_process_event,
199 };
200