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_configure(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 .configure = saic_configure, 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 if (len != 3) 150 return DT_INFO_INVALID_INTERRUPT; 151 152 it = fdt32_to_cpu(properties[0]); 153 if (it >= (int)saic.nr_irqs) 154 return DT_INFO_INVALID_INTERRUPT; 155 156 irq_type = fdt32_to_cpu(properties[1]); 157 if (saic_get_src_type(irq_type, it, &src_type)) 158 return DT_INFO_INVALID_INTERRUPT; 159 160 priority = fdt32_to_cpu(properties[2]); 161 if (priority >= AT91_AIC_MAX_PRIO) 162 return DT_INFO_INVALID_INTERRUPT; 163 164 if (type) 165 *type = irq_type; 166 167 if (prio) 168 *prio = priority; 169 170 return it; 171 } 172 173 static struct saic_data saic = { 174 .chip = { 175 .ops = &saic_ops, 176 .dt_get_irq = &saic_dt_get_irq, 177 }, 178 }; 179 180 static void saic_clear_aicredir(void) 181 { 182 vaddr_t sfr_base = sam_sfr_base(); 183 uint32_t aicredir_val = 0; 184 185 aicredir_val = io_read32(sfr_base + AT91_SFR_SN1); 186 aicredir_val ^= AT91_SFR_AICREDIR_XOR_KEY; 187 aicredir_val &= AT91_SFR_AICREDIR_KEY_MASK; 188 189 /* 190 * We explicitly don't want to redirect secure interrupts to non secure 191 * AIC. By default, AT91Bootstrap does so on some platforms. 192 */ 193 io_write32(sfr_base + AT91_SFR_AICREDIR, aicredir_val); 194 } 195 196 static void saic_init_external(const void *fdt, int node) 197 { 198 int i = 0; 199 int len = 0; 200 int it_grp = 0; 201 int it_off = 0; 202 size_t it = 0; 203 const uint32_t *external = NULL; 204 205 external = fdt_getprop(fdt, node, "atmel,external-irqs", &len); 206 if (!external) 207 return; 208 209 len /= sizeof(uint32_t); 210 for (i = 0; i < len; i++) { 211 it = fdt32_to_cpu(external[i]); 212 213 DMSG("IRQ %zu is external", it); 214 215 if (it >= saic.nr_irqs) 216 panic(); 217 218 it_grp = it / 32; 219 it_off = it % 32; 220 221 saic.external[it_grp] |= BIT32(it_off); 222 } 223 } 224 225 static void saic_init_hw(void) 226 { 227 unsigned int i = 0; 228 229 saic_clear_aicredir(); 230 231 /* Disable write protect if any */ 232 saic_write_reg(AT91_AIC_WPMR, AT91_AIC_WPKEY); 233 234 /* Pop the (potential) interrupt stack (8 priority) */ 235 for (i = 0; i < 8; i++) 236 saic_write_reg(AT91_AIC_EOICR, 0); 237 238 /* Disable and clear all interrupts initially */ 239 for (i = 0; i < saic.nr_irqs; i++) { 240 saic_write_reg(AT91_AIC_IDCR, 1); 241 saic_write_reg(AT91_AIC_ICCR, 1); 242 /* Set interrupt vector to hold interrupt number */ 243 saic_select_it(i); 244 saic_write_reg(AT91_AIC_SVR, i); 245 } 246 247 saic_write_reg(AT91_AIC_SPU, 0xffffffff); 248 249 /* Disable AIC debugging */ 250 saic_write_reg(AT91_AIC_DCR, 0); 251 } 252 253 TEE_Result atmel_saic_setup(void) 254 { 255 int node = -1; 256 int ret = 0; 257 size_t size = 0; 258 const void *fdt = get_embedded_dt(); 259 260 /* There is only 1 SAIC controller */ 261 if (saic.base) 262 return TEE_ERROR_GENERIC; 263 264 node = fdt_node_offset_by_compatible(fdt, -1, "atmel,sama5d2-saic"); 265 if (node < 0) 266 return TEE_ERROR_GENERIC; 267 268 ret = dt_map_dev(fdt, node, &saic.base, &size, DT_MAP_AUTO); 269 if (ret) { 270 EMSG("Failed to map SAIC"); 271 return TEE_ERROR_GENERIC; 272 } 273 274 saic.chip.ops = &saic_ops; 275 saic.nr_irqs = SAMA5D2_AIC_MAX_IRQS; 276 277 saic_init_external(fdt, node); 278 saic_init_hw(); 279 280 interrupt_main_init(&saic.chip); 281 saic_register_pm(); 282 283 return TEE_SUCCESS; 284 } 285 286 #ifdef CFG_PM_ARM32 287 288 static struct { 289 uint8_t smr[SAMA5D2_AIC_MAX_IRQS]; 290 } saic_state; 291 292 static void saic_resume(void) 293 { 294 uint8_t it = 0; 295 296 saic_init_hw(); 297 298 for (it = 0; it < SAMA5D2_AIC_MAX_IRQS; it++) { 299 saic_select_it(it); 300 saic_write_reg(AT91_AIC_SMR, saic_state.smr[it]); 301 } 302 } 303 304 static void saic_suspend(void) 305 { 306 uint8_t it = 0; 307 308 for (it = 0; it < SAMA5D2_AIC_MAX_IRQS; it++) { 309 saic_select_it(it); 310 saic_state.smr[it] = saic_read_reg(AT91_AIC_SMR); 311 } 312 } 313 314 static TEE_Result saic_pm(enum pm_op op, uint32_t pm_hint __unused, 315 const struct pm_callback_handle *hdl __unused) 316 { 317 switch (op) { 318 case PM_OP_RESUME: 319 saic_resume(); 320 break; 321 case PM_OP_SUSPEND: 322 saic_suspend(); 323 break; 324 default: 325 panic("Invalid PM operation"); 326 } 327 328 return TEE_SUCCESS; 329 } 330 331 static void saic_register_pm(void) 332 { 333 register_pm_core_service_cb(saic_pm, NULL, "saic"); 334 } 335 #else 336 static void saic_register_pm(void) 337 { 338 } 339 #endif 340