1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2021-2023, STMicroelectronics
4 */
5
6 #include <assert.h>
7 #include <compiler.h>
8 #include <drivers/regulator.h>
9 #include <drivers/stm32mp1_pwr.h>
10 #include <drivers/stm32mp1_syscfg.h>
11 #include <drivers/stm32mp13_regulator_iod.h>
12 #include <initcall.h>
13 #include <io.h>
14 #include <kernel/boot.h>
15 #include <kernel/dt.h>
16 #include <kernel/dt_driver.h>
17 #include <kernel/panic.h>
18 #include <kernel/pm.h>
19 #include <libfdt.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stm32_util.h>
23 #include <trace.h>
24
25 #define TIMEOUT_US_10MS U(10000)
26
27 #define IO_VOLTAGE_THRESHOLD_UV 2700000
28
29 /*
30 * struct iod_regul - IO domain regulator instance
31 *
32 * @enable_reg: PWR register offset for the IO domain
33 * @enable_mask: Domain enable register bit mask in PWR register
34 * @ready_mask: Domain ready bit mask in PWR register
35 * @valid_mask: Domain valid bit mask in PWR register
36 * @hslv_id: ID of the related HSLV domain
37 * @io_comp_id: ID of the related IO compensation domain
38 * @suspend_state: True if regulator is enabled before suspend, false otherwise
39 * @suspend_level_uv: Voltage level before suspend, in microvolts
40 */
41 struct iod_regul {
42 uint32_t enable_reg;
43 uint32_t enable_mask;
44 uint32_t ready_mask;
45 uint32_t valid_mask;
46 enum stm32mp13_hslv_id hslv_id;
47 enum stm32mp13_vddsd_comp_id io_comp_id;
48 bool suspend_state;
49 int suspend_level_uv;
50 };
51
52 static struct iod_regul iod_regulator_priv[IOD_REGU_COUNT] = {
53 [IOD_SDMMC1] = {
54 .enable_reg = PWR_CR3_OFF,
55 .enable_mask = PWR_CR3_VDDSD1EN,
56 .ready_mask = PWR_CR3_VDDSD1RDY,
57 .valid_mask = PWR_CR3_VDDSD1VALID,
58 .hslv_id = SYSCFG_HSLV_IDX_SDMMC1,
59 .io_comp_id = SYSCFG_IO_COMP_IDX_SD1,
60 },
61 [IOD_SDMMC2] = {
62 .enable_reg = PWR_CR3_OFF,
63 .enable_mask = PWR_CR3_VDDSD2EN,
64 .ready_mask = PWR_CR3_VDDSD2RDY,
65 .valid_mask = PWR_CR3_VDDSD2VALID,
66 .hslv_id = SYSCFG_HSLV_IDX_SDMMC2,
67 .io_comp_id = SYSCFG_IO_COMP_IDX_SD2,
68 },
69 };
70
71 static struct regulator *iod_regulator[IOD_REGU_COUNT];
72
stm32mp1_get_iod_regulator(enum iod_regulator_id index)73 struct regulator *stm32mp1_get_iod_regulator(enum iod_regulator_id index)
74 {
75 assert(index >= IOD_SDMMC1 && index < IOD_REGU_COUNT);
76
77 return iod_regulator[index];
78 }
79
iod_set_state(struct regulator * regu,bool enable)80 static TEE_Result iod_set_state(struct regulator *regu, bool enable)
81 {
82 struct iod_regul *iod = regu->priv;
83 uintptr_t pwr_reg = stm32_pwr_base() + iod->enable_reg;
84
85 FMSG("%s: set state %u", regulator_name(regu), enable);
86
87 if (enable) {
88 uint32_t value = 0;
89
90 io_setbits32(pwr_reg, iod->enable_mask);
91
92 if (IO_READ32_POLL_TIMEOUT(pwr_reg, value,
93 value & iod->ready_mask,
94 0, TIMEOUT_US_10MS))
95 return TEE_ERROR_GENERIC;
96
97 io_setbits32(pwr_reg, iod->valid_mask);
98 io_clrbits32(pwr_reg, iod->enable_mask);
99
100 stm32mp_set_vddsd_comp_state(iod->io_comp_id, true);
101 } else {
102 stm32mp_set_vddsd_comp_state(iod->io_comp_id, false);
103
104 io_clrbits32(pwr_reg, iod->enable_mask | iod->valid_mask);
105 }
106
107 return TEE_SUCCESS;
108 }
109
iod_get_state(struct regulator * regu,bool * enabled)110 static TEE_Result iod_get_state(struct regulator *regu, bool *enabled)
111 {
112 struct iod_regul *iod = regu->priv;
113 uintptr_t pwr_reg = stm32_pwr_base() + iod->enable_reg;
114
115 *enabled = io_read32(pwr_reg) & (iod->enable_mask | iod->valid_mask);
116
117 return TEE_SUCCESS;
118 }
119
iod_get_voltage(struct regulator * regu,int * level_uv)120 static TEE_Result iod_get_voltage(struct regulator *regu, int *level_uv)
121 {
122 *level_uv = regulator_get_voltage(regu->supply);
123
124 return TEE_SUCCESS;
125 }
126
iod_set_voltage(struct regulator * regu,int level_uv)127 static TEE_Result iod_set_voltage(struct regulator *regu, int level_uv)
128 {
129 struct iod_regul *iod = regu->priv;
130 TEE_Result res = TEE_ERROR_GENERIC;
131 bool iod_enabled = false;
132
133 FMSG("%s: set voltage level to %duV", regulator_name(regu), level_uv);
134
135 res = iod_get_state(regu, &iod_enabled);
136 if (res)
137 return res;
138
139 /* Isolate IOs and disable IOs compensation when changing voltage */
140 if (iod_enabled) {
141 res = iod_set_state(regu, false);
142 if (res)
143 return res;
144 }
145
146 /*
147 * Set IO to low speed.
148 * Setting high voltage with IOs in high speed mode may damage the IOs.
149 */
150 stm32mp_set_hslv_state(iod->hslv_id, false);
151
152 /* Forward set voltage request to the power supply */
153 res = regulator_set_voltage(regu->supply, level_uv);
154 if (res) {
155 EMSG("regulator %s set voltage failed: %#"PRIx32,
156 regulator_name(regu), res);
157
158 /* Ensure IO domain consistency for current voltage level */
159 level_uv = regulator_get_voltage(regu->supply);
160 }
161
162 if (level_uv <= IO_VOLTAGE_THRESHOLD_UV)
163 stm32mp_set_hslv_state(iod->hslv_id, true);
164
165 if (iod_enabled) {
166 TEE_Result res2 = TEE_ERROR_GENERIC;
167
168 res2 = iod_set_state(regu, true);
169 if (res2)
170 return res2;
171 }
172
173 return res;
174 }
175
iod_list_voltages(struct regulator * regu,struct regulator_voltages_desc ** desc,const int ** levels)176 static TEE_Result iod_list_voltages(struct regulator *regu,
177 struct regulator_voltages_desc **desc,
178 const int **levels)
179 {
180 /* Return supply voltage list */
181 return regulator_supported_voltages(regu->supply, desc, levels);
182 }
183
184 /*
185 * To protect the IOs, we disable High Speed Low Voltage mode before
186 * entering suspend state and restore the configuration when resuming.
187 */
iod_pm(enum pm_op op,unsigned int pm_hint __unused,const struct pm_callback_handle * hdl)188 static TEE_Result iod_pm(enum pm_op op, unsigned int pm_hint __unused,
189 const struct pm_callback_handle *hdl)
190 {
191 struct regulator *regu = hdl->handle;
192 struct iod_regul *iod = regu->priv;
193 TEE_Result res = TEE_ERROR_GENERIC;
194
195 assert(op == PM_OP_SUSPEND || op == PM_OP_RESUME);
196
197 if (op == PM_OP_SUSPEND) {
198 FMSG("%s: suspend", regulator_name(regu));
199
200 res = iod_get_state(regu, &iod->suspend_state);
201 if (res)
202 return res;
203
204 res = iod_get_voltage(regu, &iod->suspend_level_uv);
205 if (res)
206 return res;
207
208 stm32mp_set_hslv_state(iod->hslv_id, false);
209 } else {
210 FMSG("%s: resume", regulator_name(regu));
211
212 res = iod_set_voltage(regu, iod->suspend_level_uv);
213 if (res)
214 return res;
215
216 res = iod_set_state(regu, iod->suspend_state);
217 if (res)
218 return res;
219 }
220
221 return TEE_SUCCESS;
222 }
223
iod_supplied_init(struct regulator * regu,const void * fdt __unused,int node __unused)224 static TEE_Result iod_supplied_init(struct regulator *regu,
225 const void *fdt __unused, int node __unused)
226 {
227 struct iod_regul *iod = regu->priv;
228 int index = iod - iod_regulator_priv;
229
230 assert(index >= 0 && index < IOD_REGU_COUNT);
231
232 if (regulator_get_voltage(regu) < IO_VOLTAGE_THRESHOLD_UV)
233 stm32mp_set_hslv_state(iod->hslv_id, true);
234
235 /* Save regulator reference */
236 iod_regulator[index] = regu;
237
238 register_pm_driver_cb(iod_pm, regu, "iod-regulator");
239
240 FMSG("IOD regulator %s intiialized", regulator_name(regu));
241
242 return TEE_SUCCESS;
243 }
244
245 static const struct regulator_ops iod_ops = {
246 .set_state = iod_set_state,
247 .get_state = iod_get_state,
248 .set_voltage = iod_set_voltage,
249 .get_voltage = iod_get_voltage,
250 .supported_voltages = iod_list_voltages,
251 .supplied_init = iod_supplied_init,
252 };
253
254 #define DEFINE_REG(_id, _name, _supply_name) { \
255 .name = (_name), \
256 .ops = &iod_ops, \
257 .priv = iod_regulator_priv + (_id), \
258 .supply_name = (_supply_name), \
259 }
260
261 static struct regu_dt_desc iod_regul_desc[IOD_REGU_COUNT] = {
262 [IOD_SDMMC1] = DEFINE_REG(IOD_SDMMC1, "sdmmc1_io", "vddsd1"),
263 [IOD_SDMMC2] = DEFINE_REG(IOD_SDMMC2, "sdmmc2_io", "vddsd2"),
264 };
265
iod_regulator_probe(const void * fdt,int node,const void * compat_data __unused)266 static TEE_Result iod_regulator_probe(const void *fdt, int node,
267 const void *compat_data __unused)
268 {
269 const char *node_name = NULL;
270 size_t i = 0;
271
272 node_name = fdt_get_name(fdt, node, NULL);
273
274 FMSG("iod probe node '%s'", node_name);
275
276 /* Look up matching regulator name defined in SoC DTSI file */
277 for (i = 0; i < IOD_REGU_COUNT; i++)
278 if (!strcmp(iod_regul_desc[i].name, node_name))
279 break;
280
281 if (i == IOD_REGU_COUNT) {
282 EMSG("Unexpected IO domain node name '%s'", node_name);
283 return TEE_ERROR_GENERIC;
284 }
285
286 return regulator_dt_register(fdt, node, node, iod_regul_desc + i);
287 }
288
289 static const struct dt_device_match iod_regulator_match_table[] = {
290 { .compatible = "st,stm32mp13-iod" },
291 { }
292 };
293
294 DEFINE_DT_DRIVER(stm32mp13_regulator_iod_dt_driver) = {
295 .name = "stm32mp13-iod-regulator",
296 .match_table = iod_regulator_match_table,
297 .probe = iod_regulator_probe,
298 };
299