1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     JUNO Reset Domain Driver
9  *     Arm platforms don't have proper reset domains. However for completeness,
10  *     this driver demonstrates reset functionality using Juno UART as an
11  *     example reset domain peripheral. Only auto reset functionality is
12  *     implemented as explicit assert/de-assert complicates functionality of
13  *     UART peripheral.
14  */
15 
16 #include <juno_scc.h>
17 #include <system_mmap.h>
18 
19 #include <mod_juno_reset_domain.h>
20 #include <mod_reset_domain.h>
21 
22 #include <fwk_assert.h>
23 #include <fwk_core.h>
24 #include <fwk_macros.h>
25 #include <fwk_mm.h>
26 #include <fwk_module.h>
27 #include <fwk_module_idx.h>
28 #include <fwk_status.h>
29 
30 enum dev_state {
31     DEVICE_STATE_NORMAL = 0,
32     DEVICE_STATE_RESET = 1
33 };
34 
35 struct juno_reset_dev_ctx {
36     void *config;
37     bool reset_state;
38 };
39 
40 struct juno_reset_domain_module_ctx {
41     const struct mod_reset_domain_drv_input_api *drv_input_api;
42     fwk_id_t reset_domain_hal_id;
43     struct juno_reset_dev_ctx *dev_ctx_table;
44     uint32_t cookie;
45 };
46 
47 static struct juno_reset_domain_module_ctx module_juno_reset_ctx;
48 
49 /* Helper functions */
handle_uart_reset_set_state(struct juno_reset_dev_ctx * dev_ctx)50 static int handle_uart_reset_set_state(struct juno_reset_dev_ctx *dev_ctx)
51 {
52     int retry = 5;
53     int status = FWK_E_DEVICE;
54 
55     struct mod_juno_reset_uart_config* uart_config =
56         (struct mod_juno_reset_uart_config*)dev_ctx->config;
57 
58     if (dev_ctx->reset_state == DEVICE_STATE_RESET) {
59         return FWK_E_STATE;
60     }
61 
62     /* Reset UART device */
63     dev_ctx->reset_state = DEVICE_STATE_RESET;
64     *uart_config->reset_reg |= uart_config->reset_mask;
65 
66     /* Check if reset of the device has been taken place
67      * On juno board unlikely we will see mutliple retries.
68      */
69     while (retry--) {
70         if (*uart_config->reset_reg & uart_config->reset_mask) {
71             /* We are only supporting auto reset and architecture reset
72              * so clear juno UART reset.
73              */
74             *uart_config->reset_reg &= ~uart_config->reset_mask;
75             status = FWK_SUCCESS;
76             dev_ctx->reset_state = DEVICE_STATE_NORMAL;
77             break;
78         }
79     }
80 
81     return status;
82 }
83 
84 /*
85  * Module APIs
86  */
juno_set_reset_state(fwk_id_t dev_id,enum mod_reset_domain_mode mode,uint32_t reset_state,uintptr_t cookie)87 static int juno_set_reset_state(fwk_id_t dev_id,
88                                 enum mod_reset_domain_mode mode,
89                                 uint32_t reset_state,
90                                 uintptr_t cookie)
91 {
92     int status;
93     struct juno_reset_dev_ctx *dev_ctx;
94     struct mod_reset_domain_autoreset_event_params *params;
95     struct fwk_event autoreset_event = {
96         .id = mod_reset_domain_autoreset_event_id,
97         .target_id = fwk_module_id_reset_domain,
98     };
99     unsigned int domain_idx = fwk_id_get_element_idx(dev_id);
100 
101     if (domain_idx >= JUNO_RESET_DOMAIN_IDX_COUNT) {
102         return FWK_E_PARAM;
103     }
104 
105     dev_ctx = &module_juno_reset_ctx.dev_ctx_table[domain_idx];
106 
107     if (domain_idx == JUNO_RESET_DOMAIN_IDX_UART) {
108         status = handle_uart_reset_set_state(dev_ctx);
109         if (status != FWK_SUCCESS) {
110             return status;
111         }
112 
113         params = (struct mod_reset_domain_autoreset_event_params *)
114                      autoreset_event.params;
115         params->dev_id = dev_id;
116         params->reset_state = reset_state;
117         params->cookie = cookie;
118         fwk_put_event(&autoreset_event);
119     }
120 
121     return FWK_SUCCESS;
122 }
123 
124 static struct mod_reset_domain_drv_api juno_reset_domain_drv_api = {
125     .set_reset_state = juno_set_reset_state,
126 };
127 
128 /*
129  * Framework handlers
130  */
juno_reset_domain_init(fwk_id_t module_id,unsigned int element_count,const void * data)131 static int juno_reset_domain_init(fwk_id_t module_id,
132                                   unsigned int element_count,
133                                   const void *data)
134 {
135     /* This module supports only one reset device
136      */
137     fwk_assert(element_count == 1);
138     module_juno_reset_ctx.dev_ctx_table = fwk_mm_calloc(element_count,
139                                              sizeof(struct juno_reset_dev_ctx));
140 
141     return FWK_SUCCESS;
142 }
143 
juno_reset_domain_element_init(fwk_id_t element_id,unsigned int sub_element_count,const void * data)144 static int juno_reset_domain_element_init(fwk_id_t element_id,
145                                           unsigned int sub_element_count,
146                                           const void *data)
147 {
148     struct juno_reset_dev_ctx* dev_ctx = NULL;
149 
150     dev_ctx = &module_juno_reset_ctx.dev_ctx_table[
151         fwk_id_get_element_idx(element_id)];
152     dev_ctx->config = (void*)data;
153 
154     return FWK_SUCCESS;
155 }
156 
juno_reset_domain_bind(fwk_id_t id,unsigned int round)157 static int juno_reset_domain_bind(fwk_id_t id, unsigned int round)
158 {
159    return FWK_SUCCESS;
160 }
161 
juno_reset_domain_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)162 static int juno_reset_domain_process_bind_request(fwk_id_t source_id,
163                                                   fwk_id_t target_id,
164                                                   fwk_id_t api_id,
165                                                   const void **api)
166 {
167     fwk_id_t mod_juno_reset_domain_api_id_driver =
168         FWK_ID_API_INIT(FWK_MODULE_IDX_JUNO_RESET_DOMAIN,
169                         MOD_JUNO_RESET_DOMAIN_API_IDX_DRIVER);
170 
171     if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT) ||
172         !fwk_id_is_equal(api_id, mod_juno_reset_domain_api_id_driver) ||
173         api == NULL) {
174         return FWK_E_PARAM;
175     }
176 
177     *api = &juno_reset_domain_drv_api;
178 
179     module_juno_reset_ctx.reset_domain_hal_id = source_id;
180 
181     return FWK_SUCCESS;
182 }
183 
juno_reset_domain_start(fwk_id_t id)184 static int juno_reset_domain_start(fwk_id_t id)
185 {
186     return FWK_SUCCESS;
187 }
188 
189 struct fwk_module module_juno_reset_domain = {
190     .type = FWK_MODULE_TYPE_DRIVER,
191     .api_count = MOD_JUNO_RESET_DOMAIN_API_IDX_COUNT,
192     .init = juno_reset_domain_init,
193     .element_init = juno_reset_domain_element_init,
194     .bind = juno_reset_domain_bind,
195     .process_bind_request = juno_reset_domain_process_bind_request,
196     .start = juno_reset_domain_start,
197 };
198