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
caam_pwr_add_backup(vaddr_t baseaddr,const struct reglist * regs,size_t nbentries)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 */
do_save_regs(void)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 */
do_restore_regs(void)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 */
pm_enter(uint32_t pm_hint)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 */
pm_resume(uint32_t pm_hint)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
pm_enter_resume(enum pm_op op,uint32_t pm_hint,const struct pm_callback_handle * pm_handle __unused)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
caam_pwr_init(void)173 void caam_pwr_init(void)
174 {
175 register_pm_driver_cb(pm_enter_resume, NULL, "caam_pwr");
176 }
177