xref: /optee_os/core/drivers/atmel_rstc.c (revision 2befa23ddbb1b29e69eecac3ae71104c132d3d35)
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>
115aa44b2bSTony Han #include <malloc.h>
12c2c7da1dSClément Léger #include <matrix.h>
136370f75dSTony Han #include <platform_config.h>
145aa44b2bSTony 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 
305aa44b2bSTony Han struct sam_reset_data {
315aa44b2bSTony Han 	bool rstc_always_secure;
325aa44b2bSTony Han 	const struct rstctrl_ops *ops;
335aa44b2bSTony Han };
345aa44b2bSTony 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 
415aa44b2bSTony Han static SLIST_HEAD(, sam_rstline) sam_rst_list =
425aa44b2bSTony Han 	SLIST_HEAD_INITIALIZER(sam_rst_list);
435aa44b2bSTony Han 
to_sam_rstline(struct rstctrl * ptr)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 
find_rstline(unsigned int reset_id)515aa44b2bSTony Han static struct sam_rstline *find_rstline(unsigned int reset_id)
525aa44b2bSTony Han {
535aa44b2bSTony Han 	struct sam_rstline *sam_rstline = NULL;
545aa44b2bSTony Han 
555aa44b2bSTony Han 	SLIST_FOREACH(sam_rstline, &sam_rst_list, link)
565aa44b2bSTony Han 		if (sam_rstline->reset_id == reset_id)
575aa44b2bSTony Han 			break;
585aa44b2bSTony Han 
595aa44b2bSTony Han 	return sam_rstline;
605aa44b2bSTony Han }
615aa44b2bSTony Han 
625aa44b2bSTony Han static struct
find_or_allocate_rstline(unsigned int reset_id,const struct sam_reset_data * pdata)635aa44b2bSTony Han sam_rstline *find_or_allocate_rstline(unsigned int reset_id,
645aa44b2bSTony Han 				      const struct sam_reset_data *pdata)
655aa44b2bSTony Han {
665aa44b2bSTony Han 	struct sam_rstline *sam_rstline = find_rstline(reset_id);
675aa44b2bSTony Han 
685aa44b2bSTony Han 	if (sam_rstline)
695aa44b2bSTony Han 		return sam_rstline;
705aa44b2bSTony Han 
715aa44b2bSTony Han 	sam_rstline = calloc(1, sizeof(*sam_rstline));
725aa44b2bSTony Han 	if (sam_rstline) {
735aa44b2bSTony Han 		sam_rstline->reset_id = reset_id;
745aa44b2bSTony Han 		sam_rstline->rstctrl.ops = pdata->ops;
755aa44b2bSTony Han 
765aa44b2bSTony Han 		SLIST_INSERT_HEAD(&sam_rst_list, sam_rstline, link);
775aa44b2bSTony Han 	}
785aa44b2bSTony Han 
795aa44b2bSTony Han 	return sam_rstline;
805aa44b2bSTony Han }
815aa44b2bSTony Han 
sam_rstctrl_dt_get(struct dt_pargs * args,void * data,struct rstctrl ** out_rstctrl)82*2befa23dSTony Han static TEE_Result sam_rstctrl_dt_get(struct dt_pargs *args, void *data,
83*2befa23dSTony Han 				     struct rstctrl **out_rstctrl)
84*2befa23dSTony Han {
85*2befa23dSTony Han 	struct sam_rstline *sam_rstline = NULL;
86*2befa23dSTony Han 
87*2befa23dSTony Han 	if (args->args_count != 1)
88*2befa23dSTony Han 		return TEE_ERROR_BAD_PARAMETERS;
89*2befa23dSTony Han 
90*2befa23dSTony Han 	sam_rstline = find_or_allocate_rstline(args->args[0], data);
91*2befa23dSTony Han 	if (!sam_rstline)
92*2befa23dSTony Han 		return TEE_ERROR_OUT_OF_MEMORY;
93*2befa23dSTony Han 
94*2befa23dSTony Han 	*out_rstctrl = &sam_rstline->rstctrl;
95*2befa23dSTony Han 
96*2befa23dSTony Han 	return TEE_SUCCESS;
97*2befa23dSTony Han }
98*2befa23dSTony Han 
reset_assert(struct rstctrl * rstctrl,unsigned int to_us __unused)999e86f0a2STony Han static TEE_Result reset_assert(struct rstctrl *rstctrl,
1009e86f0a2STony Han 			       unsigned int to_us __unused)
1019e86f0a2STony Han {
1029e86f0a2STony Han 	unsigned int id = to_sam_rstline(rstctrl)->reset_id;
1039e86f0a2STony Han 
1049e86f0a2STony Han 	io_setbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
1059e86f0a2STony Han 	dsb();
1069e86f0a2STony Han 
1079e86f0a2STony Han 	return TEE_SUCCESS;
1089e86f0a2STony Han }
1099e86f0a2STony Han 
reset_deassert(struct rstctrl * rstctrl,unsigned int to_us __unused)1109e86f0a2STony Han static TEE_Result reset_deassert(struct rstctrl *rstctrl,
1119e86f0a2STony Han 				 unsigned int to_us __unused)
1129e86f0a2STony Han {
1139e86f0a2STony Han 	unsigned int id = to_sam_rstline(rstctrl)->reset_id;
1149e86f0a2STony Han 
1159e86f0a2STony Han 	io_clrbits32(rstc_base + RESET_OFFSET(id), BIT(RESET_BIT_POS(id)));
1169e86f0a2STony Han 	dsb();
1179e86f0a2STony Han 
1189e86f0a2STony Han 	return TEE_SUCCESS;
1199e86f0a2STony Han }
1209e86f0a2STony Han 
1219e86f0a2STony Han static const struct rstctrl_ops sama7_rstc_ops = {
1229e86f0a2STony Han 	.assert_level = reset_assert,
1239e86f0a2STony Han 	.deassert_level = reset_deassert,
1249e86f0a2STony Han };
1259e86f0a2STony Han DECLARE_KEEP_PAGER(sama7_rstc_ops);
1269e86f0a2STony Han 
1275aa44b2bSTony Han static const struct sam_reset_data sama7_reset_data = {
1285aa44b2bSTony Han 	.rstc_always_secure = true,
1295aa44b2bSTony Han 	.ops = &sama7_rstc_ops
1305aa44b2bSTony Han };
1315aa44b2bSTony Han DECLARE_KEEP_PAGER(sama7_reset_data);
1325aa44b2bSTony Han 
sam_get_rstctrl(unsigned int reset_id)1335aa44b2bSTony Han struct rstctrl *sam_get_rstctrl(unsigned int reset_id)
1345aa44b2bSTony Han {
1355aa44b2bSTony Han 	struct sam_rstline *rstline = NULL;
1365aa44b2bSTony Han 
1375aa44b2bSTony Han 	rstline = find_or_allocate_rstline(reset_id, &sama7_reset_data);
1385aa44b2bSTony Han 	assert(rstline);
1395aa44b2bSTony Han 
1405aa44b2bSTony Han 	return &rstline->rstctrl;
1415aa44b2bSTony Han }
1425aa44b2bSTony Han 
atmel_rstc_available(void)1431dc7d0e9SClément Léger bool atmel_rstc_available(void)
1441dc7d0e9SClément Léger {
1451dc7d0e9SClément Léger 	return rstc_base != 0;
1461dc7d0e9SClément Léger }
1471dc7d0e9SClément Léger 
atmel_rstc_reset(void)1481dc7d0e9SClément Léger void __noreturn atmel_rstc_reset(void)
1491dc7d0e9SClément Léger {
1501dc7d0e9SClément Léger 	uint32_t val = AT91_RSTC_CR_KEY | AT91_RSTC_CR_PROCRST |
1511dc7d0e9SClément Léger 		       AT91_RSTC_CR_PERRST;
1521dc7d0e9SClément Léger 
1531dc7d0e9SClément Léger 	io_write32(rstc_base + AT91_RSTC_CR, val);
1541dc7d0e9SClément Léger 
1551dc7d0e9SClément Léger 	/*
1561dc7d0e9SClément Léger 	 * After the previous write, the CPU will reset so we will never hit
1571dc7d0e9SClément Léger 	 * this loop.
1581dc7d0e9SClément Léger 	 */
1591dc7d0e9SClément Léger 	while (true)
1601dc7d0e9SClément Léger 		;
1611dc7d0e9SClément Léger }
1621dc7d0e9SClément Léger 
sam_rstc_usb_por(unsigned char id,bool enable)163d557d174STony Han void sam_rstc_usb_por(unsigned char id, bool enable)
164d557d174STony Han {
165d557d174STony Han 	if (!atmel_rstc_available())
166d557d174STony Han 		panic();
167d557d174STony Han 
168d557d174STony Han 	if (enable)
169d557d174STony Han 		io_setbits32(rstc_base + AT91_RSTC_GRSTR,
170d557d174STony Han 			     AT91_RSTC_GRSTR_USB(id));
171d557d174STony Han 	else
172d557d174STony Han 		io_clrbits32(rstc_base + AT91_RSTC_GRSTR,
173d557d174STony Han 			     AT91_RSTC_GRSTR_USB(id));
174d557d174STony Han }
175d557d174STony Han 
atmel_rstc_probe(const void * fdt,int node,const void * compat_data)1761dc7d0e9SClément Léger static TEE_Result atmel_rstc_probe(const void *fdt, int node,
177379dc2aeSTony Han 				   const void *compat_data)
1781dc7d0e9SClément Léger 
1791dc7d0e9SClément Léger {
180*2befa23dSTony Han 	struct sam_reset_data *pdata = (struct sam_reset_data *)compat_data;
1811dc7d0e9SClément Léger 	size_t size = 0;
1821dc7d0e9SClément Léger 
183f354a5d8SGatien Chevallier 	if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
184c2c7da1dSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
185c2c7da1dSClément Léger 
186*2befa23dSTony Han 	if (pdata && pdata->rstc_always_secure)
187c2c7da1dSClément Léger 		matrix_configure_periph_secure(AT91C_ID_SYS);
188c2c7da1dSClément Léger 
189a5d5bbc8SVesa Jääskeläinen 	if (dt_map_dev(fdt, node, &rstc_base, &size, DT_MAP_AUTO) < 0)
1901dc7d0e9SClément Léger 		return TEE_ERROR_GENERIC;
1911dc7d0e9SClément Léger 
192*2befa23dSTony Han 	if (pdata)
193*2befa23dSTony Han 		return rstctrl_register_provider(fdt, node, sam_rstctrl_dt_get,
194*2befa23dSTony Han 						 pdata);
195*2befa23dSTony Han 
1961dc7d0e9SClément Léger 	return TEE_SUCCESS;
1971dc7d0e9SClément Léger }
1981dc7d0e9SClément Léger 
1991dc7d0e9SClément Léger static const struct dt_device_match atmel_rstc_match_table[] = {
2001dc7d0e9SClément Léger 	{ .compatible = "atmel,sama5d3-rstc" },
201379dc2aeSTony Han 	{
202379dc2aeSTony Han 		.compatible = "microchip,sama7g5-rstc",
203*2befa23dSTony Han 		.compat_data = &sama7_reset_data,
204379dc2aeSTony Han 	},
2051dc7d0e9SClément Léger 	{ }
2061dc7d0e9SClément Léger };
2071dc7d0e9SClément Léger 
20861bdedeaSJerome Forissier DEFINE_DT_DRIVER(atmel_rstc_dt_driver) = {
2091dc7d0e9SClément Léger 	.name = "atmel_rstc",
210*2befa23dSTony Han 	.type = DT_DRIVER_RSTCTRL,
2111dc7d0e9SClément Léger 	.match_table = atmel_rstc_match_table,
2121dc7d0e9SClément Léger 	.probe = atmel_rstc_probe,
2131dc7d0e9SClément Léger };
214