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