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