1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2021, Microchip 4 */ 5 6 #include <assert.h> 7 #include <drivers/atmel_saic.h> 8 #include <dt-bindings/interrupt-controller/irq.h> 9 #include <io.h> 10 #include <kernel/boot.h> 11 #include <kernel/dt.h> 12 #include <kernel/interrupt.h> 13 #include <kernel/pm.h> 14 #include <libfdt.h> 15 #include <sam_sfr.h> 16 #include <tee_api_types.h> 17 #include <trace.h> 18 19 #define AT91_AIC_MAX_PRIO 8 20 21 #define SAMA5D2_AIC_MAX_IRQS 77 22 23 #define SAMA5D2_AIC_MAX_IRQS32 ((SAMA5D2_AIC_MAX_IRQS + 31) / 32) 24 25 struct saic_data { 26 struct itr_chip chip; 27 vaddr_t base; 28 size_t nr_irqs; 29 uint32_t external[SAMA5D2_AIC_MAX_IRQS32]; 30 }; 31 32 static struct saic_data saic; 33 34 static void saic_register_pm(void); 35 36 static void saic_write_reg(uint32_t reg, uint32_t val) 37 { 38 io_write32(saic.base + reg, val); 39 } 40 41 static uint32_t saic_read_reg(uint32_t reg) 42 { 43 return io_read32(saic.base + reg); 44 } 45 46 void interrupt_main_handler(void) 47 { 48 uint32_t irqnr = saic_read_reg(AT91_AIC_IVR); 49 50 interrupt_call_handlers(&saic.chip, irqnr); 51 saic_write_reg(AT91_AIC_EOICR, 0); 52 } 53 54 static void saic_select_it(size_t it) 55 { 56 assert(!(it & ~AT91_AIC_SSR_ITSEL_MASK)); 57 58 saic_write_reg(AT91_AIC_SSR, it); 59 } 60 61 static void saic_configure_it(size_t it, uint32_t src_type, uint32_t priority) 62 { 63 saic_select_it(it); 64 saic_write_reg(AT91_AIC_SMR, src_type | priority); 65 } 66 67 static bool is_external_it(size_t it) 68 { 69 uint32_t it_grp = it / 32; 70 uint32_t it_off = it % 32; 71 72 if (it >= saic.nr_irqs) 73 panic(); 74 75 return saic.external[it_grp] & BIT32(it_off); 76 } 77 78 static TEE_Result saic_get_src_type(uint32_t dt_level, size_t it, 79 uint32_t *src_type) 80 { 81 switch (dt_level) { 82 case IRQ_TYPE_EDGE_RISING: 83 *src_type = AT91_AIC_SMR_POS_EDGE; 84 break; 85 case IRQ_TYPE_EDGE_FALLING: 86 if (!is_external_it(it)) 87 return TEE_ERROR_BAD_PARAMETERS; 88 89 *src_type = AT91_AIC_SMR_NEG_EDGE; 90 break; 91 case IRQ_TYPE_LEVEL_HIGH: 92 *src_type = AT91_AIC_SMR_HIGH_LEVEL; 93 break; 94 case IRQ_TYPE_LEVEL_LOW: 95 if (!is_external_it(it)) 96 return TEE_ERROR_BAD_PARAMETERS; 97 98 *src_type = AT91_AIC_SMR_LEVEL; 99 break; 100 default: 101 return TEE_ERROR_BAD_PARAMETERS; 102 } 103 104 return TEE_SUCCESS; 105 } 106 107 static void saic_add(struct itr_chip *chip __unused, size_t it, 108 uint32_t type, uint32_t prio) 109 { 110 uint32_t src_type = AT91_AIC_SMR_HIGH_LEVEL; 111 112 if (it >= saic.nr_irqs) 113 panic(); 114 115 if (saic_get_src_type(type, it, &src_type)) 116 panic("Invalid interrupt specifier"); 117 118 saic_configure_it(it, src_type, prio); 119 } 120 121 static void saic_enable(struct itr_chip *chip __unused, size_t it) 122 { 123 saic_select_it(it); 124 saic_write_reg(AT91_AIC_IECR, 1); 125 } 126 127 static void saic_disable(struct itr_chip *chip __unused, size_t it) 128 { 129 saic_select_it(it); 130 saic_write_reg(AT91_AIC_IDCR, 1); 131 } 132 133 static const struct itr_ops saic_ops = { 134 .add = saic_add, 135 .mask = saic_disable, 136 .unmask = saic_enable, 137 .enable = saic_enable, 138 .disable = saic_disable, 139 }; 140 141 static int saic_dt_get_irq(const uint32_t *properties, int len, 142 uint32_t *type, uint32_t *prio) 143 { 144 int it = DT_INFO_INVALID_INTERRUPT; 145 uint32_t src_type = 0; 146 uint32_t priority = 0; 147 uint32_t irq_type = 0; 148 149 len /= sizeof(uint32_t); 150 151 if (len != 3) 152 return DT_INFO_INVALID_INTERRUPT; 153 154 it = fdt32_to_cpu(properties[0]); 155 if (it >= (int)saic.nr_irqs) 156 return DT_INFO_INVALID_INTERRUPT; 157 158 irq_type = fdt32_to_cpu(properties[1]); 159 if (saic_get_src_type(irq_type, it, &src_type)) 160 return DT_INFO_INVALID_INTERRUPT; 161 162 priority = fdt32_to_cpu(properties[2]); 163 if (priority >= AT91_AIC_MAX_PRIO) 164 return DT_INFO_INVALID_INTERRUPT; 165 166 if (type) 167 *type = irq_type; 168 169 if (prio) 170 *prio = priority; 171 172 return it; 173 } 174 175 static struct saic_data saic = { 176 .chip = { 177 .ops = &saic_ops, 178 .dt_get_irq = &saic_dt_get_irq, 179 }, 180 }; 181 182 static void saic_clear_aicredir(void) 183 { 184 vaddr_t sfr_base = sam_sfr_base(); 185 uint32_t aicredir_val = 0; 186 187 aicredir_val = io_read32(sfr_base + AT91_SFR_SN1); 188 aicredir_val ^= AT91_SFR_AICREDIR_XOR_KEY; 189 aicredir_val &= AT91_SFR_AICREDIR_KEY_MASK; 190 191 /* 192 * We explicitly don't want to redirect secure interrupts to non secure 193 * AIC. By default, AT91Bootstrap does so on some platforms. 194 */ 195 io_write32(sfr_base + AT91_SFR_AICREDIR, aicredir_val); 196 } 197 198 static void saic_init_external(const void *fdt, int node) 199 { 200 int i = 0; 201 int len = 0; 202 int it_grp = 0; 203 int it_off = 0; 204 size_t it = 0; 205 const uint32_t *external = NULL; 206 207 external = fdt_getprop(fdt, node, "atmel,external-irqs", &len); 208 if (!external) 209 return; 210 211 len /= sizeof(uint32_t); 212 for (i = 0; i < len; i++) { 213 it = fdt32_to_cpu(external[i]); 214 215 DMSG("IRQ %zu is external", it); 216 217 if (it >= saic.nr_irqs) 218 panic(); 219 220 it_grp = it / 32; 221 it_off = it % 32; 222 223 saic.external[it_grp] |= BIT32(it_off); 224 } 225 } 226 227 static void saic_init_hw(void) 228 { 229 unsigned int i = 0; 230 231 saic_clear_aicredir(); 232 233 /* Disable write protect if any */ 234 saic_write_reg(AT91_AIC_WPMR, AT91_AIC_WPKEY); 235 236 /* Pop the (potential) interrupt stack (8 priority) */ 237 for (i = 0; i < 8; i++) 238 saic_write_reg(AT91_AIC_EOICR, 0); 239 240 /* Disable and clear all interrupts initially */ 241 for (i = 0; i < saic.nr_irqs; i++) { 242 saic_write_reg(AT91_AIC_IDCR, 1); 243 saic_write_reg(AT91_AIC_ICCR, 1); 244 /* Set interrupt vector to hold interrupt number */ 245 saic_select_it(i); 246 saic_write_reg(AT91_AIC_SVR, i); 247 } 248 249 saic_write_reg(AT91_AIC_SPU, 0xffffffff); 250 251 /* Disable AIC debugging */ 252 saic_write_reg(AT91_AIC_DCR, 0); 253 } 254 255 TEE_Result atmel_saic_setup(void) 256 { 257 int node = -1; 258 int ret = 0; 259 size_t size = 0; 260 const void *fdt = get_embedded_dt(); 261 262 /* There is only 1 SAIC controller */ 263 if (saic.base) 264 return TEE_ERROR_GENERIC; 265 266 node = fdt_node_offset_by_compatible(fdt, -1, "atmel,sama5d2-saic"); 267 if (node < 0) 268 return TEE_ERROR_GENERIC; 269 270 ret = dt_map_dev(fdt, node, &saic.base, &size, DT_MAP_AUTO); 271 if (ret) { 272 EMSG("Failed to map SAIC"); 273 return TEE_ERROR_GENERIC; 274 } 275 276 saic.chip.ops = &saic_ops; 277 saic.nr_irqs = SAMA5D2_AIC_MAX_IRQS; 278 279 saic_init_external(fdt, node); 280 saic_init_hw(); 281 282 interrupt_main_init(&saic.chip); 283 saic_register_pm(); 284 285 return TEE_SUCCESS; 286 } 287 288 #ifdef CFG_PM_ARM32 289 290 static struct { 291 uint8_t smr[SAMA5D2_AIC_MAX_IRQS]; 292 } saic_state; 293 294 static void saic_resume(void) 295 { 296 uint8_t it = 0; 297 298 saic_init_hw(); 299 300 for (it = 0; it < SAMA5D2_AIC_MAX_IRQS; it++) { 301 saic_select_it(it); 302 saic_write_reg(AT91_AIC_SMR, saic_state.smr[it]); 303 } 304 } 305 306 static void saic_suspend(void) 307 { 308 uint8_t it = 0; 309 310 for (it = 0; it < SAMA5D2_AIC_MAX_IRQS; it++) { 311 saic_select_it(it); 312 saic_state.smr[it] = saic_read_reg(AT91_AIC_SMR); 313 } 314 } 315 316 static TEE_Result saic_pm(enum pm_op op, uint32_t pm_hint __unused, 317 const struct pm_callback_handle *hdl __unused) 318 { 319 switch (op) { 320 case PM_OP_RESUME: 321 saic_resume(); 322 break; 323 case PM_OP_SUSPEND: 324 saic_suspend(); 325 break; 326 default: 327 panic("Invalid PM operation"); 328 } 329 330 return TEE_SUCCESS; 331 } 332 333 static void saic_register_pm(void) 334 { 335 register_pm_core_service_cb(saic_pm, NULL, "saic"); 336 } 337 #else 338 static void saic_register_pm(void) 339 { 340 } 341 #endif 342