1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2021, Microchip
4 */
5
6 #include <drivers/atmel_rstc.h>
7 #include <drivers/rstctrl.h>
8 #include <io.h>
9 #include <kernel/dt.h>
10 #include <kernel/dt_driver.h>
11 #include <malloc.h>
12 #include <matrix.h>
13 #include <platform_config.h>
14 #include <stdbool.h>
15 #include <sys/queue.h>
16 #include <tee_api_defines.h>
17 #include <tee_api_types.h>
18 #include <types_ext.h>
19
20 #define AT91_RSTC_CR 0x0
21 #define AT91_RSTC_CR_KEY SHIFT_U32(0xA5, 24)
22 #define AT91_RSTC_CR_PROCRST BIT32(0)
23 #define AT91_RSTC_CR_PERRST BIT32(2)
24
25 #define AT91_RSTC_GRSTR 0xE4
26 #define AT91_RSTC_GRSTR_USB(x) SHIFT_U32(1, 4 + (x))
27
28 static vaddr_t rstc_base;
29
30 struct sam_reset_data {
31 bool rstc_always_secure;
32 const struct rstctrl_ops *ops;
33 };
34
35 struct sam_rstline {
36 unsigned int reset_id;
37 struct rstctrl rstctrl;
38 SLIST_ENTRY(sam_rstline) link;
39 };
40
41 static SLIST_HEAD(, sam_rstline) sam_rst_list =
42 SLIST_HEAD_INITIALIZER(sam_rst_list);
43
to_sam_rstline(struct rstctrl * ptr)44 static struct sam_rstline *to_sam_rstline(struct rstctrl *ptr)
45 {
46 assert(ptr);
47
48 return container_of(ptr, struct sam_rstline, rstctrl);
49 }
50
find_rstline(unsigned int reset_id)51 static struct sam_rstline *find_rstline(unsigned int reset_id)
52 {
53 struct sam_rstline *sam_rstline = NULL;
54
55 SLIST_FOREACH(sam_rstline, &sam_rst_list, link)
56 if (sam_rstline->reset_id == reset_id)
57 break;
58
59 return sam_rstline;
60 }
61
62 static struct
find_or_allocate_rstline(unsigned int reset_id,const struct sam_reset_data * pdata)63 sam_rstline *find_or_allocate_rstline(unsigned int reset_id,
64 const struct sam_reset_data *pdata)
65 {
66 struct sam_rstline *sam_rstline = find_rstline(reset_id);
67
68 if (sam_rstline)
69 return sam_rstline;
70
71 sam_rstline = calloc(1, sizeof(*sam_rstline));
72 if (sam_rstline) {
73 sam_rstline->reset_id = reset_id;
74 sam_rstline->rstctrl.ops = pdata->ops;
75
76 SLIST_INSERT_HEAD(&sam_rst_list, sam_rstline, link);
77 }
78
79 return sam_rstline;
80 }
81
sam_rstctrl_dt_get(struct dt_pargs * args,void * data,struct rstctrl ** out_rstctrl)82 static TEE_Result sam_rstctrl_dt_get(struct dt_pargs *args, void *data,
83 struct rstctrl **out_rstctrl)
84 {
85 struct sam_rstline *sam_rstline = NULL;
86
87 if (args->args_count != 1)
88 return TEE_ERROR_BAD_PARAMETERS;
89
90 sam_rstline = find_or_allocate_rstline(args->args[0], data);
91 if (!sam_rstline)
92 return TEE_ERROR_OUT_OF_MEMORY;
93
94 *out_rstctrl = &sam_rstline->rstctrl;
95
96 return TEE_SUCCESS;
97 }
98
reset_assert(struct rstctrl * rstctrl,unsigned int to_us __unused)99 static TEE_Result reset_assert(struct rstctrl *rstctrl,
100 unsigned int to_us __unused)
101 {
102 unsigned int id = to_sam_rstline(rstctrl)->reset_id;
103
104 io_setbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
105 dsb();
106
107 return TEE_SUCCESS;
108 }
109
reset_deassert(struct rstctrl * rstctrl,unsigned int to_us __unused)110 static TEE_Result reset_deassert(struct rstctrl *rstctrl,
111 unsigned int to_us __unused)
112 {
113 unsigned int id = to_sam_rstline(rstctrl)->reset_id;
114
115 io_clrbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
116 dsb();
117
118 return TEE_SUCCESS;
119 }
120
121 static const struct rstctrl_ops sama7_rstc_ops = {
122 .assert_level = reset_assert,
123 .deassert_level = reset_deassert,
124 };
125 DECLARE_KEEP_PAGER(sama7_rstc_ops);
126
127 static const struct sam_reset_data sama7_reset_data = {
128 .rstc_always_secure = true,
129 .ops = &sama7_rstc_ops
130 };
131 DECLARE_KEEP_PAGER(sama7_reset_data);
132
sam_get_rstctrl(unsigned int reset_id)133 struct rstctrl *sam_get_rstctrl(unsigned int reset_id)
134 {
135 struct sam_rstline *rstline = NULL;
136
137 rstline = find_or_allocate_rstline(reset_id, &sama7_reset_data);
138 assert(rstline);
139
140 return &rstline->rstctrl;
141 }
142
atmel_rstc_available(void)143 bool atmel_rstc_available(void)
144 {
145 return rstc_base != 0;
146 }
147
atmel_rstc_reset(void)148 void __noreturn atmel_rstc_reset(void)
149 {
150 uint32_t val = AT91_RSTC_CR_KEY | AT91_RSTC_CR_PROCRST |
151 AT91_RSTC_CR_PERRST;
152
153 io_write32(rstc_base + AT91_RSTC_CR, val);
154
155 /*
156 * After the previous write, the CPU will reset so we will never hit
157 * this loop.
158 */
159 while (true)
160 ;
161 }
162
sam_rstc_usb_por(unsigned char id,bool enable)163 void sam_rstc_usb_por(unsigned char id, bool enable)
164 {
165 if (!atmel_rstc_available())
166 panic();
167
168 if (enable)
169 io_setbits32(rstc_base + AT91_RSTC_GRSTR,
170 AT91_RSTC_GRSTR_USB(id));
171 else
172 io_clrbits32(rstc_base + AT91_RSTC_GRSTR,
173 AT91_RSTC_GRSTR_USB(id));
174 }
175
atmel_rstc_probe(const void * fdt,int node,const void * compat_data)176 static TEE_Result atmel_rstc_probe(const void *fdt, int node,
177 const void *compat_data)
178
179 {
180 struct sam_reset_data *pdata = (struct sam_reset_data *)compat_data;
181 size_t size = 0;
182
183 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
184 return TEE_ERROR_BAD_PARAMETERS;
185
186 if (pdata && pdata->rstc_always_secure)
187 matrix_configure_periph_secure(AT91C_ID_SYS);
188
189 if (dt_map_dev(fdt, node, &rstc_base, &size, DT_MAP_AUTO) < 0)
190 return TEE_ERROR_GENERIC;
191
192 if (pdata)
193 return rstctrl_register_provider(fdt, node, sam_rstctrl_dt_get,
194 pdata);
195
196 return TEE_SUCCESS;
197 }
198
199 static const struct dt_device_match atmel_rstc_match_table[] = {
200 { .compatible = "atmel,sama5d3-rstc" },
201 {
202 .compatible = "microchip,sama7g5-rstc",
203 .compat_data = &sama7_reset_data,
204 },
205 { }
206 };
207
208 DEFINE_DT_DRIVER(atmel_rstc_dt_driver) = {
209 .name = "atmel_rstc",
210 .type = DT_DRIVER_RSTCTRL,
211 .match_table = atmel_rstc_match_table,
212 .probe = atmel_rstc_probe,
213 };
214