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