1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2022-2023, Linaro Limited and Contributors. All rights
4  * reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Description:
9  *     Interface SCP-firmware reset module with OP-TEE reset resources.
10  */
11 
12 #include <fwk_macros.h>
13 #include <fwk_mm.h>
14 #include <fwk_module.h>
15 #include <fwk_log.h>
16 
17 #include <mod_optee_reset.h>
18 #include <mod_reset_domain.h>
19 
20 #include <compiler.h>
21 #include <drivers/rstctrl.h>
22 #include <tee_api_types.h>
23 
24 #include <stdbool.h>
25 
26 #define MOD_NAME "[SCMI RESET] "
27 
28 #define TIMEOUT_US_1MS 1000
29 
30 /* Device context */
31 struct optee_reset_dev_ctx {
32     struct rstctrl *rstctrl;
33 };
34 
35 /* Module context */
36 struct optee_reset_ctx {
37     struct optee_reset_dev_ctx *dev_ctx_table;
38     unsigned int dev_count;
39 };
40 
41 static struct optee_reset_ctx module_ctx;
42 
is_exposed(struct optee_reset_dev_ctx * ctx)43 static bool is_exposed(struct optee_reset_dev_ctx *ctx)
44 {
45     return ctx->rstctrl != NULL;
46 }
47 
48 /*
49  * Driver API functions
50  */
reset_set_state(fwk_id_t dev_id,enum mod_reset_domain_mode mode,uint32_t reset_state,uintptr_t cookie)51 static int reset_set_state(fwk_id_t dev_id, enum mod_reset_domain_mode mode,
52                            uint32_t reset_state, uintptr_t cookie)
53 {
54     struct optee_reset_dev_ctx *ctx = NULL;
55     int status = FWK_SUCCESS;
56 
57     if (!fwk_module_is_valid_element_id(dev_id)) {
58         return FWK_E_PARAM;
59     }
60 
61     ctx = &module_ctx.dev_ctx_table[fwk_id_get_element_idx(dev_id)];
62 
63     if (!is_exposed(ctx)) {
64         return FWK_E_ACCESS;
65     }
66 
67     /* Whatever the reset_state set, we consider a unique context loss mode */
68     if (reset_state) {
69         FWK_LOG_INFO(MOD_NAME "Override requested SCMI reset state %#"PRIx32,
70             reset_state);
71     }
72 
73     switch (mode) {
74     case MOD_RESET_DOMAIN_MODE_EXPLICIT_ASSERT:
75         FWK_LOG_DEBUG(
76             MOD_NAME "SCMI reset %u: assert(%s)",
77             fwk_id_get_element_idx(dev_id),
78             rstctrl_name(ctx->rstctrl));
79 
80         if (rstctrl_assert(ctx->rstctrl)) {
81             status = FWK_E_DEVICE;
82         }
83         break;
84     case MOD_RESET_DOMAIN_MODE_EXPLICIT_DEASSERT:
85         FWK_LOG_DEBUG(
86             MOD_NAME "SCMI reset %u: deassert(%s)",
87             fwk_id_get_element_idx(dev_id),
88             rstctrl_name(ctx->rstctrl));
89 
90         if (rstctrl_deassert(ctx->rstctrl)) {
91             status = FWK_E_DEVICE;
92         }
93         break;
94     case MOD_RESET_DOMAIN_AUTO_RESET:
95         FWK_LOG_DEBUG(
96             MOD_NAME "SCMI reset %u: cycle(%s)",
97             fwk_id_get_element_idx(dev_id),
98             rstctrl_name(ctx->rstctrl));
99 
100         if (rstctrl_assert_to(ctx->rstctrl, TIMEOUT_US_1MS)) {
101             status = FWK_E_TIMEOUT;
102         }
103         if (rstctrl_deassert_to(ctx->rstctrl, TIMEOUT_US_1MS)) {
104             status = FWK_E_TIMEOUT;
105         }
106         break;
107     default:
108         return FWK_E_PARAM;
109     }
110 
111     return status;
112 }
113 
114 static const struct mod_reset_domain_drv_api api_optee_reset = {
115     .set_reset_state = reset_set_state,
116 };
117 
118 /*
119  * Framework handler functions
120  */
121 
optee_reset_init(fwk_id_t module_id,unsigned int element_count,const void * data)122 static int optee_reset_init(fwk_id_t module_id, unsigned int element_count,
123                             const void *data)
124 {
125     module_ctx.dev_count = element_count;
126 
127     if (element_count == 0) {
128         return FWK_SUCCESS;
129     }
130 
131     module_ctx.dev_ctx_table = fwk_mm_calloc(element_count,
132                                              sizeof(struct optee_reset_dev_ctx));
133 
134     return FWK_SUCCESS;
135 }
136 
optee_reset_element_init(fwk_id_t element_id,unsigned int unused __unused,const void * data)137 static int optee_reset_element_init(fwk_id_t element_id,
138                                     unsigned int unused __unused,
139                                     const void *data)
140 {
141     struct optee_reset_dev_ctx *ctx = NULL;
142     const struct mod_optee_reset_dev_config *config = NULL;
143 
144     if (!fwk_module_is_valid_element_id(element_id)) {
145         return FWK_E_PARAM;
146     }
147 
148     ctx = &module_ctx.dev_ctx_table[fwk_id_get_element_idx(element_id)];
149     config = (const struct mod_optee_reset_dev_config *)data;
150 
151     ctx->rstctrl = config->rstctrl;
152 
153     return FWK_SUCCESS;
154 }
155 
optee_reset_process_bind_request(fwk_id_t requester_id,fwk_id_t id,fwk_id_t api_type,const void ** api)156 static int optee_reset_process_bind_request(fwk_id_t requester_id, fwk_id_t id,
157                                             fwk_id_t api_type, const void **api)
158 {
159     *api = &api_optee_reset;
160 
161     return FWK_SUCCESS;
162 }
163 
164 const struct fwk_module module_optee_reset = {
165     .type = FWK_MODULE_TYPE_DRIVER,
166     .api_count = 1,
167     .init = optee_reset_init,
168     .element_init = optee_reset_element_init,
169     .process_bind_request = optee_reset_process_bind_request,
170 };
171