xref: /optee_os/core/drivers/atmel_rstc.c (revision 5aa44b2b9b8be5ad8bab1fb0b446fe1115bead2b)
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 
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 
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
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 
82 static TEE_Result reset_assert(struct rstctrl *rstctrl,
83 			       unsigned int to_us __unused)
84 {
85 	unsigned int id = to_sam_rstline(rstctrl)->reset_id;
86 
87 	io_setbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
88 	dsb();
89 
90 	return TEE_SUCCESS;
91 }
92 
93 static TEE_Result reset_deassert(struct rstctrl *rstctrl,
94 				 unsigned int to_us __unused)
95 {
96 	unsigned int id = to_sam_rstline(rstctrl)->reset_id;
97 
98 	io_clrbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
99 	dsb();
100 
101 	return TEE_SUCCESS;
102 }
103 
104 static const struct rstctrl_ops sama7_rstc_ops = {
105 	.assert_level = reset_assert,
106 	.deassert_level = reset_deassert,
107 };
108 DECLARE_KEEP_PAGER(sama7_rstc_ops);
109 
110 static const struct sam_reset_data sama7_reset_data = {
111 	.rstc_always_secure = true,
112 	.ops = &sama7_rstc_ops
113 };
114 DECLARE_KEEP_PAGER(sama7_reset_data);
115 
116 struct rstctrl *sam_get_rstctrl(unsigned int reset_id)
117 {
118 	struct sam_rstline *rstline = NULL;
119 
120 	rstline = find_or_allocate_rstline(reset_id, &sama7_reset_data);
121 	assert(rstline);
122 
123 	return &rstline->rstctrl;
124 }
125 
126 bool atmel_rstc_available(void)
127 {
128 	return rstc_base != 0;
129 }
130 
131 void __noreturn atmel_rstc_reset(void)
132 {
133 	uint32_t val = AT91_RSTC_CR_KEY | AT91_RSTC_CR_PROCRST |
134 		       AT91_RSTC_CR_PERRST;
135 
136 	io_write32(rstc_base + AT91_RSTC_CR, val);
137 
138 	/*
139 	 * After the previous write, the CPU will reset so we will never hit
140 	 * this loop.
141 	 */
142 	while (true)
143 		;
144 }
145 
146 void sam_rstc_usb_por(unsigned char id, bool enable)
147 {
148 	if (!atmel_rstc_available())
149 		panic();
150 
151 	if (enable)
152 		io_setbits32(rstc_base + AT91_RSTC_GRSTR,
153 			     AT91_RSTC_GRSTR_USB(id));
154 	else
155 		io_clrbits32(rstc_base + AT91_RSTC_GRSTR,
156 			     AT91_RSTC_GRSTR_USB(id));
157 }
158 
159 /* Non-null reference for compat data */
160 static const uint8_t rstc_always_secure;
161 
162 static TEE_Result atmel_rstc_probe(const void *fdt, int node,
163 				   const void *compat_data)
164 
165 {
166 	size_t size = 0;
167 
168 	if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
169 		return TEE_ERROR_BAD_PARAMETERS;
170 
171 	if (compat_data != &rstc_always_secure)
172 		matrix_configure_periph_secure(AT91C_ID_SYS);
173 
174 	if (dt_map_dev(fdt, node, &rstc_base, &size, DT_MAP_AUTO) < 0)
175 		return TEE_ERROR_GENERIC;
176 
177 	return TEE_SUCCESS;
178 }
179 
180 static const struct dt_device_match atmel_rstc_match_table[] = {
181 	{ .compatible = "atmel,sama5d3-rstc" },
182 	{
183 		.compatible = "microchip,sama7g5-rstc",
184 		.compat_data = &rstc_always_secure,
185 	},
186 	{ }
187 };
188 
189 DEFINE_DT_DRIVER(atmel_rstc_dt_driver) = {
190 	.name = "atmel_rstc",
191 	.type = DT_DRIVER_NOTYPE,
192 	.match_table = atmel_rstc_match_table,
193 	.probe = atmel_rstc_probe,
194 };
195