xref: /optee_os/core/drivers/atmel_rstc.c (revision 5aa44b2b9b8be5ad8bab1fb0b446fe1115bead2b)
11dc7d0e9SClément Léger // SPDX-License-Identifier: BSD-2-Clause
21dc7d0e9SClément Léger /*
31dc7d0e9SClément Léger  * Copyright (c) 2021, Microchip
41dc7d0e9SClément Léger  */
51dc7d0e9SClément Léger 
61dc7d0e9SClément Léger #include <drivers/atmel_rstc.h>
79e86f0a2STony Han #include <drivers/rstctrl.h>
81dc7d0e9SClément Léger #include <io.h>
91dc7d0e9SClément Léger #include <kernel/dt.h>
109e3c57c8SEtienne Carriere #include <kernel/dt_driver.h>
11*5aa44b2bSTony Han #include <malloc.h>
12c2c7da1dSClément Léger #include <matrix.h>
136370f75dSTony Han #include <platform_config.h>
14*5aa44b2bSTony Han #include <stdbool.h>
159e86f0a2STony Han #include <sys/queue.h>
161dc7d0e9SClément Léger #include <tee_api_defines.h>
171dc7d0e9SClément Léger #include <tee_api_types.h>
181dc7d0e9SClément Léger #include <types_ext.h>
191dc7d0e9SClément Léger 
201dc7d0e9SClément Léger #define AT91_RSTC_CR		0x0
211dc7d0e9SClément Léger #define AT91_RSTC_CR_KEY	SHIFT_U32(0xA5, 24)
221dc7d0e9SClément Léger #define AT91_RSTC_CR_PROCRST	BIT32(0)
231dc7d0e9SClément Léger #define AT91_RSTC_CR_PERRST	BIT32(2)
241dc7d0e9SClément Léger 
25d557d174STony Han #define AT91_RSTC_GRSTR		0xE4
26d557d174STony Han #define AT91_RSTC_GRSTR_USB(x)	SHIFT_U32(1, 4 + (x))
27d557d174STony Han 
281dc7d0e9SClément Léger static vaddr_t rstc_base;
291dc7d0e9SClément Léger 
30*5aa44b2bSTony Han struct sam_reset_data {
31*5aa44b2bSTony Han 	bool rstc_always_secure;
32*5aa44b2bSTony Han 	const struct rstctrl_ops *ops;
33*5aa44b2bSTony Han };
34*5aa44b2bSTony Han 
359e86f0a2STony Han struct sam_rstline {
369e86f0a2STony Han 	unsigned int reset_id;
379e86f0a2STony Han 	struct rstctrl rstctrl;
389e86f0a2STony Han 	SLIST_ENTRY(sam_rstline) link;
399e86f0a2STony Han };
409e86f0a2STony Han 
41*5aa44b2bSTony Han static SLIST_HEAD(, sam_rstline) sam_rst_list =
42*5aa44b2bSTony Han 	SLIST_HEAD_INITIALIZER(sam_rst_list);
43*5aa44b2bSTony Han 
449e86f0a2STony Han static struct sam_rstline *to_sam_rstline(struct rstctrl *ptr)
459e86f0a2STony Han {
469e86f0a2STony Han 	assert(ptr);
479e86f0a2STony Han 
489e86f0a2STony Han 	return container_of(ptr, struct sam_rstline, rstctrl);
499e86f0a2STony Han }
509e86f0a2STony Han 
51*5aa44b2bSTony Han static struct sam_rstline *find_rstline(unsigned int reset_id)
52*5aa44b2bSTony Han {
53*5aa44b2bSTony Han 	struct sam_rstline *sam_rstline = NULL;
54*5aa44b2bSTony Han 
55*5aa44b2bSTony Han 	SLIST_FOREACH(sam_rstline, &sam_rst_list, link)
56*5aa44b2bSTony Han 		if (sam_rstline->reset_id == reset_id)
57*5aa44b2bSTony Han 			break;
58*5aa44b2bSTony Han 
59*5aa44b2bSTony Han 	return sam_rstline;
60*5aa44b2bSTony Han }
61*5aa44b2bSTony Han 
62*5aa44b2bSTony Han static struct
63*5aa44b2bSTony Han sam_rstline *find_or_allocate_rstline(unsigned int reset_id,
64*5aa44b2bSTony Han 				      const struct sam_reset_data *pdata)
65*5aa44b2bSTony Han {
66*5aa44b2bSTony Han 	struct sam_rstline *sam_rstline = find_rstline(reset_id);
67*5aa44b2bSTony Han 
68*5aa44b2bSTony Han 	if (sam_rstline)
69*5aa44b2bSTony Han 		return sam_rstline;
70*5aa44b2bSTony Han 
71*5aa44b2bSTony Han 	sam_rstline = calloc(1, sizeof(*sam_rstline));
72*5aa44b2bSTony Han 	if (sam_rstline) {
73*5aa44b2bSTony Han 		sam_rstline->reset_id = reset_id;
74*5aa44b2bSTony Han 		sam_rstline->rstctrl.ops = pdata->ops;
75*5aa44b2bSTony Han 
76*5aa44b2bSTony Han 		SLIST_INSERT_HEAD(&sam_rst_list, sam_rstline, link);
77*5aa44b2bSTony Han 	}
78*5aa44b2bSTony Han 
79*5aa44b2bSTony Han 	return sam_rstline;
80*5aa44b2bSTony Han }
81*5aa44b2bSTony Han 
829e86f0a2STony Han static TEE_Result reset_assert(struct rstctrl *rstctrl,
839e86f0a2STony Han 			       unsigned int to_us __unused)
849e86f0a2STony Han {
859e86f0a2STony Han 	unsigned int id = to_sam_rstline(rstctrl)->reset_id;
869e86f0a2STony Han 
879e86f0a2STony Han 	io_setbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
889e86f0a2STony Han 	dsb();
899e86f0a2STony Han 
909e86f0a2STony Han 	return TEE_SUCCESS;
919e86f0a2STony Han }
929e86f0a2STony Han 
939e86f0a2STony Han static TEE_Result reset_deassert(struct rstctrl *rstctrl,
949e86f0a2STony Han 				 unsigned int to_us __unused)
959e86f0a2STony Han {
969e86f0a2STony Han 	unsigned int id = to_sam_rstline(rstctrl)->reset_id;
979e86f0a2STony Han 
989e86f0a2STony Han 	io_clrbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
999e86f0a2STony Han 	dsb();
1009e86f0a2STony Han 
1019e86f0a2STony Han 	return TEE_SUCCESS;
1029e86f0a2STony Han }
1039e86f0a2STony Han 
1049e86f0a2STony Han static const struct rstctrl_ops sama7_rstc_ops = {
1059e86f0a2STony Han 	.assert_level = reset_assert,
1069e86f0a2STony Han 	.deassert_level = reset_deassert,
1079e86f0a2STony Han };
1089e86f0a2STony Han DECLARE_KEEP_PAGER(sama7_rstc_ops);
1099e86f0a2STony Han 
110*5aa44b2bSTony Han static const struct sam_reset_data sama7_reset_data = {
111*5aa44b2bSTony Han 	.rstc_always_secure = true,
112*5aa44b2bSTony Han 	.ops = &sama7_rstc_ops
113*5aa44b2bSTony Han };
114*5aa44b2bSTony Han DECLARE_KEEP_PAGER(sama7_reset_data);
115*5aa44b2bSTony Han 
116*5aa44b2bSTony Han struct rstctrl *sam_get_rstctrl(unsigned int reset_id)
117*5aa44b2bSTony Han {
118*5aa44b2bSTony Han 	struct sam_rstline *rstline = NULL;
119*5aa44b2bSTony Han 
120*5aa44b2bSTony Han 	rstline = find_or_allocate_rstline(reset_id, &sama7_reset_data);
121*5aa44b2bSTony Han 	assert(rstline);
122*5aa44b2bSTony Han 
123*5aa44b2bSTony Han 	return &rstline->rstctrl;
124*5aa44b2bSTony Han }
125*5aa44b2bSTony Han 
1261dc7d0e9SClément Léger bool atmel_rstc_available(void)
1271dc7d0e9SClément Léger {
1281dc7d0e9SClément Léger 	return rstc_base != 0;
1291dc7d0e9SClément Léger }
1301dc7d0e9SClément Léger 
1311dc7d0e9SClément Léger void __noreturn atmel_rstc_reset(void)
1321dc7d0e9SClément Léger {
1331dc7d0e9SClément Léger 	uint32_t val = AT91_RSTC_CR_KEY | AT91_RSTC_CR_PROCRST |
1341dc7d0e9SClément Léger 		       AT91_RSTC_CR_PERRST;
1351dc7d0e9SClément Léger 
1361dc7d0e9SClément Léger 	io_write32(rstc_base + AT91_RSTC_CR, val);
1371dc7d0e9SClément Léger 
1381dc7d0e9SClément Léger 	/*
1391dc7d0e9SClément Léger 	 * After the previous write, the CPU will reset so we will never hit
1401dc7d0e9SClément Léger 	 * this loop.
1411dc7d0e9SClément Léger 	 */
1421dc7d0e9SClément Léger 	while (true)
1431dc7d0e9SClément Léger 		;
1441dc7d0e9SClément Léger }
1451dc7d0e9SClément Léger 
146d557d174STony Han void sam_rstc_usb_por(unsigned char id, bool enable)
147d557d174STony Han {
148d557d174STony Han 	if (!atmel_rstc_available())
149d557d174STony Han 		panic();
150d557d174STony Han 
151d557d174STony Han 	if (enable)
152d557d174STony Han 		io_setbits32(rstc_base + AT91_RSTC_GRSTR,
153d557d174STony Han 			     AT91_RSTC_GRSTR_USB(id));
154d557d174STony Han 	else
155d557d174STony Han 		io_clrbits32(rstc_base + AT91_RSTC_GRSTR,
156d557d174STony Han 			     AT91_RSTC_GRSTR_USB(id));
157d557d174STony Han }
158d557d174STony Han 
159379dc2aeSTony Han /* Non-null reference for compat data */
160379dc2aeSTony Han static const uint8_t rstc_always_secure;
161379dc2aeSTony Han 
1621dc7d0e9SClément Léger static TEE_Result atmel_rstc_probe(const void *fdt, int node,
163379dc2aeSTony Han 				   const void *compat_data)
1641dc7d0e9SClément Léger 
1651dc7d0e9SClément Léger {
1661dc7d0e9SClément Léger 	size_t size = 0;
1671dc7d0e9SClément Léger 
168f354a5d8SGatien Chevallier 	if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
169c2c7da1dSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
170c2c7da1dSClément Léger 
171379dc2aeSTony Han 	if (compat_data != &rstc_always_secure)
172c2c7da1dSClément Léger 		matrix_configure_periph_secure(AT91C_ID_SYS);
173c2c7da1dSClément Léger 
174a5d5bbc8SVesa Jääskeläinen 	if (dt_map_dev(fdt, node, &rstc_base, &size, DT_MAP_AUTO) < 0)
1751dc7d0e9SClément Léger 		return TEE_ERROR_GENERIC;
1761dc7d0e9SClément Léger 
1771dc7d0e9SClément Léger 	return TEE_SUCCESS;
1781dc7d0e9SClément Léger }
1791dc7d0e9SClément Léger 
1801dc7d0e9SClément Léger static const struct dt_device_match atmel_rstc_match_table[] = {
1811dc7d0e9SClément Léger 	{ .compatible = "atmel,sama5d3-rstc" },
182379dc2aeSTony Han 	{
183379dc2aeSTony Han 		.compatible = "microchip,sama7g5-rstc",
184379dc2aeSTony Han 		.compat_data = &rstc_always_secure,
185379dc2aeSTony Han 	},
1861dc7d0e9SClément Léger 	{ }
1871dc7d0e9SClément Léger };
1881dc7d0e9SClément Léger 
18961bdedeaSJerome Forissier DEFINE_DT_DRIVER(atmel_rstc_dt_driver) = {
1901dc7d0e9SClément Léger 	.name = "atmel_rstc",
1911dc7d0e9SClément Léger 	.type = DT_DRIVER_NOTYPE,
1921dc7d0e9SClément Léger 	.match_table = atmel_rstc_match_table,
1931dc7d0e9SClément Léger 	.probe = atmel_rstc_probe,
1941dc7d0e9SClément Léger };
195