1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2021, Microchip 4 */ 5 6 #include <assert.h> 7 #include <at91_clk.h> 8 #include <drivers/atmel_shdwc.h> 9 #include <drivers/pm/sam/atmel_pm.h> 10 #include <drivers/sam/at91_ddr.h> 11 #include <io.h> 12 #include <kernel/boot.h> 13 #include <kernel/dt.h> 14 #include <kernel/pm.h> 15 #include <kernel/tlb_helpers.h> 16 #include <libfdt.h> 17 #include <matrix.h> 18 #include <mm/core_memprot.h> 19 #include <smc_ids.h> 20 #include <sm/pm.h> 21 #include <stdbool.h> 22 #include <tee_api_types.h> 23 24 #include "at91_pm.h" 25 26 #if CFG_ATMEL_PM_SUSPEND_MODE < AT91_PM_STANDBY || \ 27 CFG_ATMEL_PM_SUSPEND_MODE > AT91_PM_BACKUP 28 #error Invalid suspend mode, please check CFG_ATMEL_PM_SUSPEND_MODE 29 #endif 30 31 #define AT91_SECUMOD_SYSR 0x04 32 #define AT91_SECUMOD_RAMRDY 0x14 33 #define AT91_SECUMOD_RAMRDY_READY BIT(0) 34 35 static struct at91_pm_data soc_pm; 36 37 /* Backup canary */ 38 static uint32_t canary = 0xA5A5A5A5; 39 40 /* Backup mode information used by at91bootstrap */ 41 static struct at91bootstrap_bu { 42 uint32_t suspended; 43 uint32_t reserved; 44 uint32_t *canary; 45 uint32_t resume; 46 } *at91bootstrap_bu; 47 48 static vaddr_t at91_suspend_sram_base; 49 static void (*at91_suspend_sram_fn)(struct at91_pm_data *); 50 51 enum sm_handler_ret at91_pm_set_suspend_mode(struct thread_smc_args *args) 52 { 53 unsigned int mode = args->a1; 54 55 /* 56 * We don't expect this function to be called simultaneously while we 57 * are entering suspend/resume function. On sama5d2, this is not a 58 * problem since this SoC is a single core one but in order to prevent 59 * any other SoC support to be added without handling this concurrency, 60 * check that we are compiled for a single core. 61 */ 62 COMPILE_TIME_ASSERT(CFG_TEE_CORE_NB_CORE == 1); 63 64 if (mode > AT91_PM_BACKUP) { 65 args->a0 = SAMA5_SMC_SIP_RETURN_EINVAL; 66 return SM_HANDLER_SMC_HANDLED; 67 } 68 DMSG("Setting suspend mode to %u", mode); 69 70 args->a0 = SAMA5_SMC_SIP_RETURN_SUCCESS; 71 soc_pm.mode = mode; 72 73 return SM_HANDLER_SMC_HANDLED; 74 } 75 76 enum sm_handler_ret at91_pm_get_suspend_mode(struct thread_smc_args *args) 77 { 78 args->a1 = soc_pm.mode; 79 args->a0 = SAMA5_SMC_SIP_RETURN_SUCCESS; 80 81 return SM_HANDLER_SMC_HANDLED; 82 } 83 84 static void at91_pm_copy_suspend_to_sram(void) 85 { 86 memcpy((void *)at91_suspend_sram_base, &at91_pm_suspend_in_sram, 87 at91_pm_suspend_in_sram_sz); 88 89 cache_op_inner(DCACHE_AREA_CLEAN, (void *)at91_suspend_sram_base, 90 at91_pm_suspend_in_sram_sz); 91 cache_op_inner(ICACHE_AREA_INVALIDATE, at91_suspend_sram_fn, 92 at91_pm_suspend_in_sram_sz); 93 } 94 95 void atmel_pm_cpu_idle(void) 96 { 97 uint32_t lpr0 = 0; 98 uint32_t saved_lpr0 = 0; 99 100 saved_lpr0 = io_read32(soc_pm.ramc + AT91_DDRSDRC_LPR); 101 lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB; 102 lpr0 |= AT91_DDRSDRC_LPCB_POWER_DOWN; 103 104 io_write32(soc_pm.ramc + AT91_DDRSDRC_LPR, lpr0); 105 106 cpu_idle(); 107 108 io_write32(soc_pm.ramc + AT91_DDRSDRC_LPR, saved_lpr0); 109 } 110 111 static void at91_sama5d2_config_shdwc_ws(vaddr_t shdwc, uint32_t *mode, 112 uint32_t *polarity) 113 { 114 uint32_t val = 0; 115 116 /* SHDWC.WUIR */ 117 val = io_read32(shdwc + AT91_SHDW_WUIR); 118 *mode |= val & AT91_SHDW_WKUPEN_MASK; 119 *polarity |= (val >> AT91_SHDW_WKUPT_SHIFT) & AT91_SHDW_WKUPT_MASK; 120 } 121 122 static int at91_sama5d2_config_pmc_ws(vaddr_t pmc, uint32_t mode, 123 uint32_t polarity) 124 { 125 io_write32(pmc + AT91_PMC_FSMR, mode); 126 io_write32(pmc + AT91_PMC_FSPR, polarity); 127 128 return 0; 129 } 130 131 struct wakeup_source_info { 132 unsigned int pmc_fsmr_bit; 133 unsigned int shdwc_mr_bit; 134 bool set_polarity; 135 }; 136 137 static const struct wakeup_source_info ws_info[] = { 138 { .pmc_fsmr_bit = AT91_PMC_FSTT(10), .set_polarity = true }, 139 { .pmc_fsmr_bit = AT91_PMC_RTCAL, .shdwc_mr_bit = BIT(17) }, 140 { .pmc_fsmr_bit = AT91_PMC_USBAL }, 141 { .pmc_fsmr_bit = AT91_PMC_SDMMC_CD }, 142 }; 143 144 struct wakeup_src { 145 const char *compatible; 146 const struct wakeup_source_info *info; 147 }; 148 149 static const struct wakeup_src sama5d2_ws_ids[] = { 150 { .compatible = "atmel,sama5d2-gem", .info = &ws_info[0] }, 151 { .compatible = "atmel,at91rm9200-rtc", .info = &ws_info[1] }, 152 { .compatible = "atmel,sama5d3-udc", .info = &ws_info[2] }, 153 { .compatible = "atmel,at91rm9200-ohci", .info = &ws_info[2] }, 154 { .compatible = "usb-ohci", .info = &ws_info[2] }, 155 { .compatible = "atmel,at91sam9g45-ehci", .info = &ws_info[2] }, 156 { .compatible = "usb-ehci", .info = &ws_info[2] }, 157 { .compatible = "atmel,sama5d2-sdhci", .info = &ws_info[3] } 158 }; 159 160 static bool dev_is_wakeup_source(const void *fdt, int node) 161 { 162 return fdt_get_property(fdt, node, "wakeup-source", NULL); 163 } 164 165 static int at91_pm_config_ws_ulp1(bool set) 166 { 167 const struct wakeup_source_info *wsi = NULL; 168 const struct wakeup_src *wsrc = NULL; 169 unsigned int polarity = 0; 170 unsigned int mode = 0; 171 unsigned int val = 0; 172 unsigned int src = 0; 173 int node = 0; 174 175 if (!set) { 176 io_write32(soc_pm.pmc + AT91_PMC_FSMR, mode); 177 return TEE_SUCCESS; 178 } 179 180 at91_sama5d2_config_shdwc_ws(soc_pm.shdwc, &mode, &polarity); 181 182 val = io_read32(soc_pm.shdwc + AT91_SHDW_MR); 183 184 /* Loop through defined wakeup sources. */ 185 for (src = 0; src < ARRAY_SIZE(sama5d2_ws_ids); src++) { 186 wsrc = &sama5d2_ws_ids[src]; 187 wsi = wsrc->info; 188 189 node = fdt_node_offset_by_compatible(soc_pm.fdt, -1, 190 wsrc->compatible); 191 while (node >= 0) { 192 if (dev_is_wakeup_source(soc_pm.fdt, node)) { 193 /* Check if enabled on SHDWC. */ 194 if (wsi->shdwc_mr_bit && 195 !(val & wsi->shdwc_mr_bit)) 196 goto next_node; 197 198 mode |= wsi->pmc_fsmr_bit; 199 if (wsi->set_polarity) 200 polarity |= wsi->pmc_fsmr_bit; 201 } 202 next_node: 203 node = fdt_node_offset_by_compatible(soc_pm.fdt, node, 204 wsrc->compatible); 205 } 206 } 207 208 if (!mode) { 209 EMSG("AT91: PM: no ULP1 wakeup sources found!"); 210 return TEE_ERROR_BAD_STATE; 211 } 212 213 at91_sama5d2_config_pmc_ws(soc_pm.pmc, mode, polarity); 214 215 return TEE_SUCCESS; 216 } 217 218 /* 219 * Verify that all the clocks are correct before entering 220 * slow-clock mode. 221 */ 222 static bool at91_pm_verify_clocks(void) 223 { 224 int i = 0; 225 uint32_t scsr = 0; 226 227 scsr = io_read32(soc_pm.pmc + AT91_PMC_SCSR); 228 229 /* USB must not be using PLLB */ 230 if ((scsr & (AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP)) != 0) { 231 EMSG("AT91: PM - Suspend-to-RAM with USB still active"); 232 return false; 233 } 234 235 /* PCK0..PCK3 must be disabled, or configured to use clk32k */ 236 for (i = 0; i < 4; i++) { 237 uint32_t css = 0; 238 239 if ((scsr & (AT91_PMC_PCK0 << i)) == 0) 240 continue; 241 css = io_read32(soc_pm.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; 242 if (css != AT91_PMC_CSS_SLOW) { 243 EMSG("AT91: PM - Suspend-to-RAM with PCK%d src %"PRId32, 244 i, css); 245 return false; 246 } 247 } 248 249 return true; 250 } 251 252 static TEE_Result at91_write_backup_data(void) 253 { 254 uint32_t val = 0; 255 256 while (true) { 257 val = io_read32(soc_pm.secumod + AT91_SECUMOD_RAMRDY); 258 if (val & AT91_SECUMOD_RAMRDY_READY) 259 break; 260 } 261 262 io_write32((vaddr_t)&at91bootstrap_bu->suspended, 1); 263 io_write32((vaddr_t)&at91bootstrap_bu->canary, virt_to_phys(&canary)); 264 io_write32((vaddr_t)&at91bootstrap_bu->resume, 265 virt_to_phys((void *)(vaddr_t)at91_pm_cpu_resume)); 266 267 return TEE_SUCCESS; 268 } 269 270 static TEE_Result at91_enter_backup(void) 271 { 272 int ret = -1; 273 TEE_Result res = TEE_ERROR_GENERIC; 274 275 res = at91_write_backup_data(); 276 if (res) 277 return res; 278 279 pm_change_state(PM_OP_SUSPEND, 0); 280 ret = sm_pm_cpu_suspend((uint32_t)&soc_pm, 281 (void *)at91_suspend_sram_fn); 282 if (ret < 0) { 283 DMSG("Suspend failed"); 284 res = TEE_ERROR_BAD_STATE; 285 } else { 286 res = TEE_SUCCESS; 287 } 288 289 pm_change_state(PM_OP_RESUME, 0); 290 if (res) 291 return res; 292 293 /* SRAM content is lost after resume */ 294 at91_pm_copy_suspend_to_sram(); 295 296 return TEE_SUCCESS; 297 } 298 299 TEE_Result atmel_pm_suspend(uintptr_t entry, struct sm_nsec_ctx *nsec) 300 { 301 TEE_Result res = TEE_ERROR_GENERIC; 302 uint32_t sctlr = 0; 303 304 DMSG("Entering suspend mode %d", soc_pm.mode); 305 306 if (soc_pm.mode >= AT91_PM_ULP0) { 307 if (!at91_pm_verify_clocks()) 308 return TEE_ERROR_BAD_STATE; 309 } 310 311 if (soc_pm.mode == AT91_PM_ULP1) 312 at91_pm_config_ws_ulp1(true); 313 314 sm_save_unbanked_regs(&nsec->ub_regs); 315 316 /* 317 * In order to run code for low-power out of SRAM without abort, 318 * configure regions with write permission with not forced to 319 * XN (Execute-never) attribute. 320 */ 321 if (IS_ENABLED(CFG_HWSUPP_MEM_PERM_WXN)) { 322 sctlr = read_sctlr(); 323 if (sctlr & SCTLR_WXN) { 324 write_sctlr(sctlr & ~SCTLR_WXN); 325 tlbi_all(); 326 } 327 } 328 329 if (soc_pm.mode == AT91_PM_BACKUP) { 330 res = at91_enter_backup(); 331 } else { 332 at91_suspend_sram_fn(&soc_pm); 333 res = TEE_SUCCESS; 334 } 335 336 /* Restore the XN attribute */ 337 if (IS_ENABLED(CFG_HWSUPP_MEM_PERM_WXN)) { 338 if (sctlr & SCTLR_WXN) { 339 write_sctlr(sctlr); 340 tlbi_all(); 341 } 342 } 343 344 if (soc_pm.mode == AT91_PM_ULP1) 345 at91_pm_config_ws_ulp1(false); 346 347 sm_restore_unbanked_regs(&nsec->ub_regs); 348 349 /* 350 * If the system went to backup mode, register state was lost and must 351 * be restored by jumping to the user provided entry point 352 */ 353 if (res == TEE_SUCCESS && soc_pm.mode == AT91_PM_BACKUP) 354 nsec->mon_lr = entry; 355 356 DMSG("Exiting suspend mode %d, res %"PRIx32, soc_pm.mode, res); 357 358 return res; 359 } 360 361 static TEE_Result at91_pm_dt_dram_init(const void *fdt) 362 { 363 int node = -1; 364 size_t size = 0; 365 366 node = fdt_node_offset_by_compatible(fdt, -1, "atmel,sama5d3-ddramc"); 367 if (node < 0) 368 return TEE_ERROR_ITEM_NOT_FOUND; 369 370 if (dt_map_dev(fdt, node, &soc_pm.ramc, &size, DT_MAP_AUTO) < 0) 371 return TEE_ERROR_GENERIC; 372 373 return TEE_SUCCESS; 374 } 375 376 static TEE_Result at91_pm_backup_init(const void *fdt) 377 { 378 enum dt_map_dev_directive mapping = DT_MAP_AUTO; 379 int node = -1; 380 size_t size = 0; 381 382 node = fdt_node_offset_by_compatible(fdt, -1, "atmel,sama5d2-sfrbu"); 383 if (node < 0) 384 return TEE_ERROR_ITEM_NOT_FOUND; 385 386 if (IS_ENABLED(CFG_SAMA7G5)) 387 mapping = DT_MAP_SECURE; 388 389 if (dt_map_dev(fdt, node, &soc_pm.sfrbu, &size, mapping) < 0) 390 return TEE_ERROR_GENERIC; 391 392 if (fdt_get_status(fdt, node) == DT_STATUS_OK_SEC) 393 /* for SAMA7G5 SFRBU is always secured, no need to configre */ 394 if (!IS_ENABLED(CFG_SAMA7G5)) 395 matrix_configure_periph_secure(AT91C_ID_SFRBU); 396 397 return TEE_SUCCESS; 398 } 399 400 static TEE_Result at91_pm_sram_init(const void *fdt) 401 { 402 int node = -1; 403 size_t size = 0; 404 paddr_t at91_suspend_sram_pbase; 405 size_t suspend_sz = at91_pm_suspend_in_sram_sz; 406 407 node = fdt_node_offset_by_compatible(fdt, -1, "atmel,sama5d2-sram"); 408 if (node < 0) 409 return TEE_ERROR_ITEM_NOT_FOUND; 410 411 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 412 return TEE_ERROR_GENERIC; 413 414 if (dt_map_dev(fdt, node, &at91_suspend_sram_base, &size, 415 DT_MAP_AUTO) < 0) 416 return TEE_ERROR_GENERIC; 417 418 at91_suspend_sram_pbase = virt_to_phys((void *)at91_suspend_sram_base); 419 420 /* 421 * Map the secure ram suspend code with the memory area type 422 * "MEM_AREA_TEE_COHERENT" to make it non-cacheable. 423 * Mapping with memory area type "MEM_AREA_TEE_RAM" would enable 424 * cacheable attribute and might cause abort in some cases. 425 */ 426 at91_suspend_sram_fn = core_mmu_add_mapping(MEM_AREA_TEE_COHERENT, 427 at91_suspend_sram_pbase, 428 suspend_sz); 429 if (!at91_suspend_sram_fn) { 430 EMSG("Failed to remap sram as executable"); 431 return TEE_ERROR_GENERIC; 432 } 433 434 at91_pm_copy_suspend_to_sram(); 435 436 return TEE_SUCCESS; 437 } 438 439 static TEE_Result at91_securam_init(const void *fdt) 440 { 441 int node = -1; 442 size_t size = 0; 443 struct clk *clk = NULL; 444 TEE_Result res = TEE_ERROR_GENERIC; 445 446 node = fdt_node_offset_by_compatible(fdt, -1, "atmel,sama5d2-securam"); 447 if (node < 0) 448 return TEE_ERROR_ITEM_NOT_FOUND; 449 450 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 451 return TEE_ERROR_GENERIC; 452 453 if (dt_map_dev(fdt, node, &soc_pm.securam, &size, DT_MAP_AUTO) < 0) 454 return TEE_ERROR_GENERIC; 455 456 res = clk_dt_get_by_index(fdt, node, 0, &clk); 457 if (res) 458 return res; 459 460 if (clk_enable(clk)) 461 return TEE_ERROR_GENERIC; 462 463 if (size < sizeof(struct at91bootstrap_bu)) 464 return TEE_ERROR_SHORT_BUFFER; 465 466 at91bootstrap_bu = (void *)soc_pm.securam; 467 468 node = fdt_node_offset_by_compatible(fdt, -1, "atmel,sama5d2-secumod"); 469 if (node < 0) 470 return TEE_ERROR_ITEM_NOT_FOUND; 471 472 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC) 473 return TEE_ERROR_GENERIC; 474 475 if (dt_map_dev(fdt, node, &soc_pm.secumod, &size, DT_MAP_AUTO) < 0) 476 return TEE_ERROR_GENERIC; 477 478 return TEE_SUCCESS; 479 } 480 481 static TEE_Result sam_pm_init_all(const void *fdt, vaddr_t shdwc) 482 { 483 TEE_Result res = TEE_ERROR_GENERIC; 484 485 soc_pm.fdt = fdt; 486 soc_pm.shdwc = shdwc; 487 soc_pm.pmc = at91_pmc_get_base(); 488 if (!soc_pm.pmc) 489 return TEE_ERROR_GENERIC; 490 491 soc_pm.mode = CFG_ATMEL_PM_SUSPEND_MODE; 492 493 res = at91_securam_init(fdt); 494 if (res) 495 return res; 496 497 res = at91_pm_dt_dram_init(fdt); 498 if (res) 499 return res; 500 501 res = at91_pm_backup_init(fdt); 502 if (res) 503 return res; 504 505 res = at91_pm_sram_init(fdt); 506 if (res) 507 return res; 508 509 return TEE_SUCCESS; 510 } 511 512 TEE_Result sam_pm_init(const void *fdt, vaddr_t shdwc) 513 { 514 if (sam_pm_init_all(fdt, shdwc)) 515 panic("Failed to setup PM for this MPU"); 516 517 return TEE_SUCCESS; 518 } 519