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