xref: /optee_os/core/drivers/crypto/caam/caam_pwr.c (revision d538d2936c2273c669de2892b6b290d9782c1554)
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 
caam_pwr_add_backup(vaddr_t baseaddr,const struct reglist * regs,size_t nbentries)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 */
do_save_regs(void)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 */
do_restore_regs(void)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  */
pm_enter(uint32_t pm_hint)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  */
pm_resume(uint32_t pm_hint)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
pm_enter_resume(enum pm_op op,uint32_t pm_hint,const struct pm_callback_handle * pm_handle __unused)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 
caam_pwr_init(void)180 void caam_pwr_init(void)
181 {
182 	register_pm_driver_cb(pm_enter_resume, NULL, "caam_pwr");
183 }
184