xref: /optee_os/core/drivers/regulator/stm32mp13_regulator_iod.c (revision 8e56b667209ee89a72fbdf873e48d2b45adb22c1)
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