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