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