1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2021, Linaro Limited
4 */
5
6 #ifndef __DRIVERS_RSTCTRL_H
7 #define __DRIVERS_RSTCTRL_H
8
9 #include <kernel/dt.h>
10 #include <kernel/dt_driver.h>
11 #include <stdint.h>
12 #include <tee_api_types.h>
13
14 struct rstctrl;
15
16 struct rstctrl_ops {
17 /*
18 * Operators on reset control(s) exposed by a reset controller
19 *
20 * @assert_level: Assert reset level on control with a timeout hint
21 * @deassert_level: Deassert reset level on control with a timeout hint
22 * @get_name: Get a string name for the controller, or NULL is none
23 *
24 * Operator functions @assert_level and @deassert_level use arguments:
25 * @rstctrl: Reset controller
26 * @id: Identifier for the reset level control in the reset controller
27 * @to_ms: Timeout in microseconds or RSTCTRL_NO_TIMEOUT, may be ignored
28 * by reset controller.
29 * Return a TEE_Result compliant code.
30 */
31 TEE_Result (*assert_level)(struct rstctrl *rstctrl, unsigned int to_us);
32 TEE_Result (*deassert_level)(struct rstctrl *rstctrl,
33 unsigned int to_us);
34 const char *(*get_name)(struct rstctrl *rstctrl);
35 };
36
37 /*
38 * struct rstctrl - Instance of a control exposed by a reset controller
39 * @ops: Operators of the reset controller
40 * @exclusive: Set when a consumer has exclusive control on the reset level
41 */
42 struct rstctrl {
43 const struct rstctrl_ops *ops;
44 bool exclusive;
45 };
46
47 /**
48 * RSTCTRL_DECLARE - Declare a reset controller driver with a single
49 * device tree compatible string.
50 *
51 * @__name: Reset controller driver name
52 * @__compat: Compatible string
53 * @__probe: Reset controller probe function
54 */
55 #define RSTCTRL_DT_DECLARE(__name, __compat, __probe) \
56 static const struct dt_device_match __name ## _match_table[] = { \
57 { .compatible = __compat }, \
58 { } \
59 }; \
60 DEFINE_DT_DRIVER(__name ## _dt_driver) = { \
61 .name = # __name, \
62 .type = DT_DRIVER_RSTCTRL, \
63 .match_table = __name ## _match_table, \
64 .probe = __probe, \
65 }
66
67 /*
68 * Platform driver may ignore the timeout hint according to their
69 * capabilities. RSTCTRL_NO_TIMEOUT specifies no timeout hint.
70 */
71 #define RSTCTRL_NO_TIMEOUT 0
72
73 /*
74 * rstctrl_assert_to - Assert reset control possibly with timeout
75 * rstctrl_assert - Assert reset control
76 * rstctrl_deassert_to - Deassert reset control possibly with timeout
77 * rstctrl_deassert - Deassert reset control
78 *
79 * @rstctrl: Reset controller
80 * @to_us: Timeout in microseconds
81 * Return a TEE_Result compliant code
82 */
rstctrl_assert_to(struct rstctrl * rstctrl,unsigned int to_us)83 static inline TEE_Result rstctrl_assert_to(struct rstctrl *rstctrl,
84 unsigned int to_us)
85 {
86 return rstctrl->ops->assert_level(rstctrl, to_us);
87 }
88
rstctrl_assert(struct rstctrl * rstctrl)89 static inline TEE_Result rstctrl_assert(struct rstctrl *rstctrl)
90 {
91 return rstctrl_assert_to(rstctrl, RSTCTRL_NO_TIMEOUT);
92 }
93
rstctrl_deassert_to(struct rstctrl * rstctrl,unsigned int to_us)94 static inline TEE_Result rstctrl_deassert_to(struct rstctrl *rstctrl,
95 unsigned int to_us)
96 {
97 return rstctrl->ops->deassert_level(rstctrl, to_us);
98 }
99
rstctrl_deassert(struct rstctrl * rstctrl)100 static inline TEE_Result rstctrl_deassert(struct rstctrl *rstctrl)
101 {
102 return rstctrl_deassert_to(rstctrl, RSTCTRL_NO_TIMEOUT);
103 }
104
105 /*
106 * rstctrl_name - Get a name for the reset level control or NULL
107 *
108 * @rstctrl: Reset controller
109 * Return a pointer to controller name or NULL
110 */
rstctrl_name(struct rstctrl * rstctrl)111 static inline const char *rstctrl_name(struct rstctrl *rstctrl)
112 {
113 if (rstctrl->ops->get_name)
114 return rstctrl->ops->get_name(rstctrl);
115
116 return NULL;
117 }
118
119 /**
120 * rstctrl_dt_get_exclusive - Get exclusive access to reset controller
121 *
122 * @rstctrl: Reset controller
123 * Return a TEE_Result compliant value
124 */
125 TEE_Result rstctrl_get_exclusive(struct rstctrl *rstctrl);
126
127 /**
128 * rstctrl_put_exclusive - Release exclusive access to target
129 *
130 * @rstctrl: Reset controller
131 */
132 void rstctrl_put_exclusive(struct rstctrl *rstctrl);
133
134 /**
135 * rstctrl_ops_is_valid - Check reset controller ops is valid
136 *
137 * @ops: Reference to reset controller operator instance
138 */
rstctrl_ops_is_valid(const struct rstctrl_ops * ops)139 static inline bool rstctrl_ops_is_valid(const struct rstctrl_ops *ops)
140 {
141 return ops && ops->assert_level && ops->deassert_level;
142 }
143
144 #ifdef CFG_DT
145 /**
146 * rstctrl_dt_get_by_index - Get a reset controller at a specific index in
147 * 'resets' property
148 *
149 * @fdt: Device tree to work on
150 * @nodeoffset: Node offset of the subnode containing a 'resets' property
151 * @index: Reset controller index in 'resets' property
152 * @rstctrl: Output reset controller reference upon success
153 *
154 * Return TEE_SUCCESS in case of success
155 * Return TEE_ERROR_DEFER_DRIVER_INIT if reset controller is not initialized
156 * Return TEE_ERROR_ITEM_NOT_FOUND if the resets property does not exist
157 * Return a TEE_Result compliant code in case of error
158 */
rstctrl_dt_get_by_index(const void * fdt,int nodeoffset,unsigned int index,struct rstctrl ** rstctrl)159 static inline TEE_Result rstctrl_dt_get_by_index(const void *fdt,
160 int nodeoffset,
161 unsigned int index,
162 struct rstctrl **rstctrl)
163 {
164 TEE_Result res = TEE_ERROR_GENERIC;
165
166 *rstctrl = dt_driver_device_from_node_idx_prop("resets", fdt,
167 nodeoffset, index,
168 DT_DRIVER_RSTCTRL, &res);
169 return res;
170 }
171 #else
rstctrl_dt_get_by_index(const void * fdt __unused,int nodeoffset __unused,unsigned int index __unused,struct rstctrl ** rstctrl)172 static inline TEE_Result rstctrl_dt_get_by_index(const void *fdt __unused,
173 int nodeoffset __unused,
174 unsigned int index __unused,
175 struct rstctrl **rstctrl)
176 {
177 *rstctrl = NULL;
178 return TEE_ERROR_NOT_SUPPORTED;
179 }
180 #endif /*CFG_DT*/
181
182 /**
183 * rstctrl_dt_get_by_name - Get a reset controller matching a name in the
184 * 'reset-names' property
185 *
186 * @fdt: Device tree to work on
187 * @nodeoffset: Node offset of the subnode containing a 'resets' property
188 * @name: Reset controller name to get
189 * @rstctrl: Output reset controller reference upon success
190 *
191 * Return TEE_SUCCESS in case of success
192 * Return TEE_ERROR_DEFER_DRIVER_INIT if reset controller is not initialized
193 * Return TEE_ERROR_ITEM_NOT_FOUND if the reset-names property does not exist
194 * Return a TEE_Result compliant code in case of error
195 */
196 TEE_Result rstctrl_dt_get_by_name(const void *fdt, int nodeoffset,
197 const char *name, struct rstctrl **rstctrl);
198
199 /**
200 * rstctrl_dt_get_func - Typedef of function to get reset controller from
201 * devicetree properties
202 *
203 * @a: Pointer to devicetree description of the reset controller to parse
204 * @data: Pointer to data given at rstctrl_dt_register_provider() call
205 * @res: Output result code of the operation:
206 * TEE_SUCCESS in case of success
207 * TEE_ERROR_DEFER_DRIVER_INIT if reset controller is not initialized
208 * Any TEE_Result compliant code in case of error.
209 *
210 * Returns a struct rstctrl pointer pointing to a reset controller matching
211 * the devicetree description or NULL if invalid description in which case
212 * @res provides the error code.
213 */
214 typedef struct rstctrl *(*rstctrl_dt_get_func)(struct dt_driver_phandle_args *a,
215 void *data, TEE_Result *res);
216
217 /**
218 * rstctrl_dt_register_provider - Register a reset controller provider
219 *
220 * @fdt: Device tree to work on
221 * @nodeoffset: Node offset of the reset controller
222 * @get_dt_rstctrl: Callback to match the reset controller with a struct rstctrl
223 * @data: Data which will be passed to the get_dt_rstctrl callback
224 * Returns TEE_Result value
225 */
226 static inline
227 TEE_Result rstctrl_register_provider(const void *fdt, int nodeoffset,
228 rstctrl_dt_get_func get_dt_rstctrl,
229 void *data)
230 {
231 return dt_driver_register_provider(fdt, nodeoffset,
232 (get_of_device_func)get_dt_rstctrl,
233 data, DT_DRIVER_RSTCTRL);
234 }
235 #endif /* __DRIVERS_RSTCTRL_H */
236
237