1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2018-2019, 2021, 2023 NXP 4 * 5 * Brief CAAM Power state management. 6 */ 7 #include <caam_common.h> 8 #include <caam_hal_clk.h> 9 #include <caam_io.h> 10 #include <caam_jr.h> 11 #include <caam_mp.h> 12 #include <caam_pwr.h> 13 #include <caam_status.h> 14 #include <caam_utils_status.h> 15 #include <kernel/pm.h> 16 #include <kernel/panic.h> 17 #include <malloc.h> 18 19 static SLIST_HEAD(, 20 backup_data) data_list = SLIST_HEAD_INITIALIZER(backup_data); 21 22 void caam_pwr_add_backup(vaddr_t baseaddr, const struct reglist *regs, 23 size_t nbentries) 24 { 25 struct backup_data *newelem = NULL; 26 struct backup_data *elem = NULL; 27 uint32_t idx = 0; 28 uint32_t nbregs = 0; 29 30 newelem = malloc(sizeof(*newelem)); 31 if (!newelem) 32 panic(); 33 34 /* Count the number of registers to save/restore */ 35 for (idx = 0; idx < nbentries; idx++) 36 nbregs += regs[idx].nbregs; 37 38 newelem->baseaddr = baseaddr; 39 newelem->nbentries = nbentries; 40 newelem->regs = regs; 41 newelem->val = malloc(nbregs * sizeof(*newelem->val)); 42 43 if (!newelem->val) 44 panic(); 45 46 /* Add the new backup data element at the end of the list */ 47 elem = SLIST_FIRST(&data_list); 48 if (elem) { 49 while (SLIST_NEXT(elem, next)) 50 elem = SLIST_NEXT(elem, next); 51 52 SLIST_INSERT_AFTER(elem, newelem, next); 53 } else { 54 SLIST_INSERT_HEAD(&data_list, newelem, next); 55 } 56 } 57 58 /* Backup all registers present in the data_list */ 59 static void do_save_regs(void) 60 { 61 struct backup_data *elem = NULL; 62 const struct reglist *reg = NULL; 63 uint32_t idx = 0; 64 uint32_t validx = 0; 65 uint32_t regidx = 0; 66 67 SLIST_FOREACH(elem, &data_list, next) { 68 reg = elem->regs; 69 validx = 0; 70 for (idx = 0; idx < elem->nbentries; idx++, reg++) { 71 for (regidx = 0; regidx < reg->nbregs; 72 regidx++, validx++) { 73 elem->val[validx] = 74 io_caam_read32(elem->baseaddr + 75 reg->offset + 76 (4 * regidx)); 77 elem->val[validx] &= ~reg->mask_clr; 78 79 PWR_TRACE("Save @0x%" PRIxPTR "=0x%" PRIx32, 80 elem->baseaddr + reg->offset + 81 4 * regidx, 82 elem->val[validx]); 83 } 84 } 85 } 86 } 87 88 /* Restore all registers present in the data_list */ 89 static void do_restore_regs(void) 90 { 91 struct backup_data *elem = NULL; 92 const struct reglist *reg = NULL; 93 uint32_t idx = 0; 94 uint32_t validx = 0; 95 uint32_t regidx = 0; 96 97 SLIST_FOREACH(elem, &data_list, next) { 98 reg = elem->regs; 99 validx = 0; 100 for (idx = 0; idx < elem->nbentries; idx++, reg++) { 101 for (regidx = 0; regidx < reg->nbregs; 102 regidx++, validx++) { 103 PWR_TRACE("Restore @0x%" PRIxPTR "=0x%" PRIx32, 104 elem->baseaddr + reg->offset + 105 4 * regidx, 106 elem->val[validx]); 107 io_caam_write32(elem->baseaddr + reg->offset + 108 4 * regidx, 109 elem->val[validx] | 110 reg->mask_set); 111 } 112 } 113 } 114 } 115 116 /* 117 * CAAM Power state preparation/entry 118 * 119 * @pm_hint Power mode type 120 */ 121 static TEE_Result pm_enter(uint32_t pm_hint) 122 { 123 enum caam_status ret = CAAM_BUSY; 124 125 PWR_TRACE("CAAM power mode %" PRIu32 " entry", pm_hint); 126 127 if (pm_hint == PM_HINT_CLOCK_STATE) { 128 ret = caam_jr_halt(); 129 } else if (pm_hint == PM_HINT_CONTEXT_STATE) { 130 do_save_regs(); 131 ret = caam_jr_flush(); 132 } 133 134 if (ret == CAAM_NO_ERROR) 135 return TEE_SUCCESS; 136 else 137 return TEE_ERROR_GENERIC; 138 } 139 140 /* 141 * CAAM Power state resume 142 * 143 * @pm_hint Power mode type 144 */ 145 static TEE_Result pm_resume(uint32_t pm_hint) 146 { 147 enum caam_status ret = CAAM_FAILURE; 148 149 PWR_TRACE("CAAM power mode %" PRIu32 " resume", pm_hint); 150 if (pm_hint == PM_HINT_CONTEXT_STATE) { 151 caam_hal_clk_enable(true); 152 do_restore_regs(); 153 } 154 155 caam_jr_resume(pm_hint); 156 157 ret = caam_mp_resume(pm_hint); 158 159 return caam_status_to_tee_result(ret); 160 } 161 162 /* 163 * Power Management Callback function executed when system enter or resume 164 * from a power mode 165 * 166 * @op Operation mode SUSPEND/RESUME 167 * @pm_hint Power mode type 168 * @pm_handle Driver private handle (not used) 169 */ 170 static TEE_Result 171 pm_enter_resume(enum pm_op op, uint32_t pm_hint, 172 const struct pm_callback_handle *pm_handle __unused) 173 { 174 if (op == PM_OP_SUSPEND) 175 return pm_enter(pm_hint); 176 else 177 return pm_resume(pm_hint); 178 } 179 180 void caam_pwr_init(void) 181 { 182 register_pm_driver_cb(pm_enter_resume, NULL, "caam_pwr"); 183 } 184