xref: /rk3399_ARM-atf/drivers/ti/pd/ti_device_psc.c (revision a28114d66a6d43db4accef5fd5d6dab6c059e584)
1 /*
2  * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * Device to PSC Module Mapping
9  *
10  * This module bridges devices and PSC LPSC modules, providing state queries,
11  * reset control, and context loss tracking for device-to-PSC module associations.
12  */
13 
14 #include <assert.h>
15 #include <errno.h>
16 
17 #include <common/debug.h>
18 #include <ti_device.h>
19 #include <ti_device_pm.h>
20 #include <ti_psc.h>
21 
22 /* Sentinel value indicating no LPSC module association */
23 #define PSC_LPSC_NONE		55U
24 
25 /**
26  * ti_soc_device_get_state_internal() - Get the PSC state for a single SoC device domain.
27  * @dev: SoC device data identifying the PSC index and LPSC module.
28  *
29  * Return: The LPSC module state, or 0 if PSC or module is not found.
30  */
ti_soc_device_get_state_internal(const struct ti_soc_device_data * dev)31 static uint32_t ti_soc_device_get_state_internal(const struct ti_soc_device_data *dev)
32 {
33 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
34 	struct ti_lpsc_module *module;
35 
36 	if (psc_dev == NULL) {
37 		return 0U;
38 	}
39 
40 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
41 	if (module == NULL) {
42 		return 0U;
43 	}
44 
45 	return ti_lpsc_module_get_state(psc_dev, module);
46 }
47 
ti_soc_device_get_state(struct ti_device * dev)48 uint32_t ti_soc_device_get_state(struct ti_device *dev)
49 {
50 	const struct ti_soc_device_data *domains;
51 	const struct ti_dev_data *data;
52 	uint32_t ret = 2U;
53 	uint32_t i;
54 
55 	assert(dev != NULL);
56 
57 	data = ti_get_dev_data(dev);
58 
59 	if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
60 		domains = soc_psc_multiple_domains[data->soc.mod];
61 		for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
62 			uint32_t this_ret;
63 
64 			this_ret = ti_soc_device_get_state_internal(&domains[i]);
65 			if (i == 0U) {
66 				ret = this_ret;
67 			} else if (ret != this_ret) {
68 				/* Mixed state of our domains, label as transition */
69 				ret = 2U;
70 			} else {
71 				/* Do Nothing */
72 			}
73 		}
74 	} else {
75 		ret = ti_soc_device_get_state_internal(&data->soc);
76 	}
77 
78 	return ret;
79 }
80 
81 /**
82  * ti_soc_device_set_reset_iso_internal() - Set reset isolation for a single SoC device domain.
83  * @dev: SoC device data identifying the PSC index and LPSC module.
84  * @enable: True to enable reset isolation, false to disable.
85  */
ti_soc_device_set_reset_iso_internal(const struct ti_soc_device_data * dev,bool enable)86 static void ti_soc_device_set_reset_iso_internal(const struct ti_soc_device_data *dev, bool enable)
87 {
88 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
89 	struct ti_lpsc_module *module;
90 
91 	if (psc_dev == NULL) {
92 		return;
93 	}
94 
95 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
96 	if (module == NULL) {
97 		return;
98 	}
99 
100 	ti_lpsc_module_set_reset_iso(psc_dev, module, enable);
101 }
102 
ti_soc_device_set_reset_iso(struct ti_device * dev,bool enable)103 void ti_soc_device_set_reset_iso(struct ti_device *dev, bool enable)
104 {
105 	const struct ti_dev_data *data;
106 
107 	assert(dev != NULL);
108 
109 	data = ti_get_dev_data(dev);
110 
111 	if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
112 		/* Reset ISO not supported for devices with multiple domains */
113 	} else {
114 		ti_soc_device_set_reset_iso_internal(&data->soc, enable);
115 	}
116 }
117 
118 /**
119  * ti_soc_device_get_context_loss_count_internal() - Get context loss count for a device domain.
120  * @dev: SoC device data identifying the PSC index and LPSC module.
121  *
122  * Return: The context loss count for the LPSC module, or 0 if not found.
123  */
ti_soc_device_get_context_loss_count_internal(const struct ti_soc_device_data * dev)124 static uint32_t ti_soc_device_get_context_loss_count_internal(const struct ti_soc_device_data *dev)
125 {
126 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
127 	struct ti_lpsc_module *module;
128 
129 	if (psc_dev == NULL) {
130 		return 0U;
131 	}
132 
133 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
134 	if (module == NULL) {
135 		return 0U;
136 	}
137 
138 	return module->loss_count;
139 }
140 
ti_soc_device_get_context_loss_count(struct ti_device * dev)141 uint32_t ti_soc_device_get_context_loss_count(struct ti_device *dev)
142 {
143 	const struct ti_soc_device_data *domains;
144 	const struct ti_dev_data *data;
145 	uint32_t ret = 0U;
146 	uint32_t i;
147 
148 	assert(dev != NULL);
149 
150 	data = ti_get_dev_data(dev);
151 
152 	if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
153 		domains = soc_psc_multiple_domains[data->soc.mod];
154 		for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
155 			ret += ti_soc_device_get_context_loss_count_internal(&domains[i]);
156 		}
157 	} else {
158 		ret = ti_soc_device_get_context_loss_count_internal(&data->soc);
159 	}
160 
161 	return ret;
162 }
163 
164 /**
165  * ti_soc_device_enable_internal() - Enable the PSC LPSC module for a single SoC device domain.
166  * @dev: SoC device data identifying the PSC index and LPSC module.
167  */
ti_soc_device_enable_internal(const struct ti_soc_device_data * dev)168 static void ti_soc_device_enable_internal(const struct ti_soc_device_data *dev)
169 {
170 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
171 	struct ti_lpsc_module *module;
172 
173 	if (psc_dev == NULL) {
174 		return;
175 	}
176 
177 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
178 	if (module == NULL) {
179 		return;
180 	}
181 
182 	ti_lpsc_module_get(psc_dev, module);
183 }
184 
ti_soc_device_enable(struct ti_device * dev)185 void ti_soc_device_enable(struct ti_device *dev)
186 {
187 	const struct ti_soc_device_data *domains;
188 	const struct ti_dev_data *data;
189 	uint32_t i;
190 
191 	assert(dev != NULL);
192 
193 	data = ti_get_dev_data(dev);
194 
195 	VERBOSE("DEVICE_ON: dev_id=%u\n", ti_device_id(dev));
196 
197 	if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
198 		domains = soc_psc_multiple_domains[data->soc.mod];
199 		for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
200 			ti_soc_device_enable_internal(&domains[i]);
201 		}
202 	} else {
203 		ti_soc_device_enable_internal(&data->soc);
204 	}
205 }
206 
207 /**
208  * ti_soc_device_disable_internal() - Disable the PSC LPSC module for a single SoC device domain.
209  * @dev: SoC device data identifying the PSC index and LPSC module.
210  */
ti_soc_device_disable_internal(const struct ti_soc_device_data * dev)211 static void ti_soc_device_disable_internal(const struct ti_soc_device_data *dev)
212 {
213 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
214 	struct ti_lpsc_module *module;
215 
216 	if (psc_dev == NULL) {
217 		return;
218 	}
219 
220 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
221 	if (module == NULL) {
222 		return;
223 	}
224 
225 	ti_lpsc_module_put(psc_dev, module);
226 }
227 
228 /**
229  * ti_soc_device_disable_internal_flags_iterate() - Clear all PSC initialization flags.
230  * @psc_dev: The PSC device whose flags are to be cleared.
231  * @module: Entry-point LPSC module (flags cleared here first, then entire PSC reset).
232  *
233  * Clears initialization flags for every power domain and LPSC module in the
234  * PSC referenced by psc_dev. Despite accepting a specific module as the entry
235  * point, the implementation resets the entire PSC state intentionally: all
236  * LPSCs must be disabled before a power domain can power off. Recurses into
237  * any dependency PSC.
238  */
ti_soc_device_disable_internal_flags_iterate(struct ti_device * psc_dev,struct ti_lpsc_module * module)239 static void ti_soc_device_disable_internal_flags_iterate(struct ti_device *psc_dev,
240 							 struct ti_lpsc_module *module)
241 {
242 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(psc_dev));
243 	const struct ti_lpsc_module_data *data;
244 	const struct ti_psc_drv_data *depends_psc;
245 	struct ti_device *depends_dev;
246 	struct ti_psc_pd *pd;
247 	struct ti_lpsc_module *temp;
248 	uint32_t idx;
249 	struct ti_lpsc_module *module_p = module;
250 
251 	if (module_p != NULL) {
252 		module_p->use_count = 0U;
253 		module_p->ret_count = 0U;
254 		module_p->pwr_up_enabled = 0U;
255 		module_p->pwr_up_ret = 0U;
256 		module_p->sw_state = 0U;
257 		module_p->loss_count = 0U;
258 		module_p->mrst_active = 0U;
259 		module_p->sw_mrst_ret = false;
260 	}
261 
262 	if (psc == NULL) {
263 		return;
264 	}
265 
266 	for (idx = 0U; idx < psc->pd_count; idx++) {
267 		pd = &psc->powerdomains[idx];
268 		pd->use_count = 0U;
269 		pd->pwr_up_enabled = false;
270 	}
271 	for (idx = 0U; idx < psc->module_count; idx++) {
272 		temp = &psc->modules[idx];
273 		temp->use_count = 0U;
274 		temp->ret_count = 0U;
275 		temp->pwr_up_enabled = 0U;
276 		temp->pwr_up_ret = 0U;
277 		temp->sw_state = 0U;
278 		temp->sw_mrst_ret = false;
279 		temp->loss_count = 0U;
280 		temp->mrst_active = 0U;
281 	}
282 
283 	psc->data->pds_enabled = 0U;
284 	idx = ti_lpsc_module_idx(psc_dev, module_p);
285 	data = &psc->mod_data[idx];
286 
287 	if ((data->flags & TI_LPSC_DEPENDS) != 0U) {
288 		depends_dev = ti_psc_lookup((ti_psc_idx_t) data->depends_psc_idx);
289 		if (depends_dev != NULL) {
290 			depends_psc = ti_to_psc_drv_data(ti_get_drv_data(depends_dev));
291 			if ((depends_psc != NULL) && (module_p != NULL)) {
292 				module_p = &depends_psc->modules[(ti_lpsc_idx_t) data->depends];
293 				ti_soc_device_disable_internal_flags_iterate(depends_dev, module_p);
294 			}
295 		}
296 	}
297 }
298 
299 /**
300  * ti_soc_device_disable_internal_flags() - Clear PSC initialization flags for a device.
301  * @dev: SoC device data identifying the PSC and LPSC module.
302  *
303  * Clears initialization flags for the PSC module associated with the given device.
304  */
ti_soc_device_disable_internal_flags(const struct ti_soc_device_data * dev)305 static void ti_soc_device_disable_internal_flags(const struct ti_soc_device_data *dev)
306 {
307 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
308 	struct ti_lpsc_module *module;
309 
310 	if (psc_dev == NULL) {
311 		return;
312 	}
313 
314 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
315 	ti_soc_device_disable_internal_flags_iterate(psc_dev, module);
316 }
317 
ti_soc_device_disable(struct ti_device * dev,bool domain_reset)318 void ti_soc_device_disable(struct ti_device *dev, bool domain_reset)
319 {
320 	const struct ti_soc_device_data *domains;
321 	const struct ti_dev_data *data;
322 	uint32_t i;
323 
324 	assert(dev != NULL);
325 
326 	data = ti_get_dev_data(dev);
327 
328 	VERBOSE("DEVICE_OFF: dev_id=%u\n", ti_device_id(dev));
329 
330 	if (domain_reset == false) {
331 		if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
332 			domains = soc_psc_multiple_domains[data->soc.mod];
333 			for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
334 				ti_soc_device_disable_internal(&domains[i]);
335 			}
336 		} else {
337 			ti_soc_device_disable_internal(&data->soc);
338 		}
339 	}
340 }
341 
ti_soc_device_clear_flags(struct ti_device * dev)342 void ti_soc_device_clear_flags(struct ti_device *dev)
343 {
344 	const struct ti_soc_device_data *domains;
345 	const struct ti_dev_data *data;
346 	uint32_t i;
347 
348 	assert(dev != NULL);
349 
350 	data = ti_get_dev_data(dev);
351 
352 	VERBOSE("CLEAR_FLAGS: dev_id=%u\n", ti_device_id(dev));
353 
354 	if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
355 		domains = soc_psc_multiple_domains[data->soc.mod];
356 		for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
357 			ti_soc_device_disable_internal_flags(&domains[i]);
358 		}
359 	} else {
360 		ti_soc_device_disable_internal_flags(&data->soc);
361 	}
362 }
363 
ti_soc_device_ret_enable_internal(const struct ti_soc_device_data * dev)364 static void ti_soc_device_ret_enable_internal(const struct ti_soc_device_data *dev)
365 {
366 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
367 	struct ti_psc_pd *pd;
368 	struct ti_lpsc_module *module;
369 
370 	if (psc_dev == NULL) {
371 		return;
372 	}
373 
374 	pd = ti_psc_lookup_pd(psc_dev, (ti_pd_idx_t) dev->pd);
375 	if (pd != NULL) {
376 		ti_psc_pd_get(psc_dev, pd);
377 	}
378 
379 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
380 	if (module != NULL) {
381 		ti_lpsc_module_ret_get(psc_dev, module);
382 	}
383 }
384 
ti_soc_device_ret_enable(struct ti_device * dev)385 void ti_soc_device_ret_enable(struct ti_device *dev)
386 {
387 	const struct ti_soc_device_data *domains;
388 	const struct ti_dev_data *data;
389 	uint32_t i;
390 
391 	assert(dev != NULL);
392 
393 	data = ti_get_dev_data(dev);
394 
395 	if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
396 		domains = soc_psc_multiple_domains[data->soc.mod];
397 		for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
398 			ti_soc_device_ret_enable_internal(&domains[i]);
399 		}
400 	} else {
401 		ti_soc_device_ret_enable_internal(&data->soc);
402 	}
403 }
404 
ti_soc_device_ret_disable_internal(const struct ti_soc_device_data * dev)405 static void ti_soc_device_ret_disable_internal(const struct ti_soc_device_data *dev)
406 {
407 	struct ti_device *psc_dev = ti_psc_lookup((ti_psc_idx_t) dev->psc_idx);
408 	struct ti_lpsc_module *module;
409 	struct ti_psc_pd *pd;
410 
411 	if (psc_dev == NULL) {
412 		return;
413 	}
414 
415 	module = ti_psc_lookup_lpsc(psc_dev, dev->mod);
416 	if (module != NULL) {
417 		ti_lpsc_module_ret_put(psc_dev, module);
418 	}
419 
420 	pd = ti_psc_lookup_pd(psc_dev, (ti_pd_idx_t) dev->pd);
421 	if (pd != NULL) {
422 		ti_psc_pd_put(psc_dev, pd);
423 	}
424 }
425 
ti_soc_device_ret_disable(struct ti_device * dev)426 void ti_soc_device_ret_disable(struct ti_device *dev)
427 {
428 	const struct ti_soc_device_data *domains;
429 	const struct ti_dev_data *data;
430 	uint32_t i;
431 
432 	assert(dev != NULL);
433 
434 	data = ti_get_dev_data(dev);
435 
436 	if (data->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
437 		domains = soc_psc_multiple_domains[data->soc.mod];
438 		for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
439 			ti_soc_device_ret_disable_internal(&domains[i]);
440 		}
441 	} else {
442 		ti_soc_device_ret_disable_internal(&data->soc);
443 	}
444 }
445 
ti_soc_device_init_complete(void)446 void ti_soc_device_init_complete(void)
447 {
448 	ti_psc_drop_pwr_up_ref();
449 }
450 
ti_soc_device_verify_mapping(const struct ti_psc_drv_data * psc,uint32_t dev_id,const struct ti_soc_device_data * dev)451 static int32_t ti_soc_device_verify_mapping(const struct ti_psc_drv_data *psc,
452 					    uint32_t dev_id, const struct ti_soc_device_data *dev)
453 {
454 	const struct ti_lpsc_module_data *mdata;
455 	uint32_t i;
456 
457 	/*
458 	 * Make sure the redundant const data stored in the PSC data is
459 	 * correct. This redundant data would ideally be checked or even
460 	 * generated at compile time.
461 	 */
462 	if (dev->mod != PSC_LPSC_NONE) {
463 		mdata = &psc->mod_data[dev->mod];
464 
465 		if ((mdata->flags & TI_LPSC_DEVICES_LIST) != 0U) {
466 			for (i = 0U; mdata->lpsc_dev.dev_list[i] != dev_id; i++) {
467 				if (mdata->lpsc_dev.dev_list[i] == TI_DEV_ID_NONE) {
468 					VERBOSE("ACTION FAIL: INVALID_PSC_DATA\n");
469 					return -EINVAL;
470 				}
471 			}
472 		} else {
473 			for (i = 0U; mdata->lpsc_dev.dev_array[i] != dev_id; i++) {
474 				if ((i >= (ARRAY_SIZE(mdata->lpsc_dev.dev_array) - 1UL)) ||
475 				    (mdata->lpsc_dev.dev_array[i] == TI_DEV_ID_NONE)) {
476 					VERBOSE("ACTION FAIL: INVALID_PSC_DATA\n");
477 					return -EINVAL;
478 				}
479 			}
480 		}
481 	}
482 
483 	return 0;
484 }
485 
ti_soc_device_init_internal(struct ti_device * dev)486 static int32_t ti_soc_device_init_internal(struct ti_device *dev)
487 {
488 	const struct ti_soc_device_data *domains;
489 	const struct ti_dev_data *devdata;
490 	const struct ti_drv_data *drvdata;
491 	struct ti_device *psc_dev = NULL;
492 	const struct ti_psc_drv_data *psc = NULL;
493 	uint32_t dev_id;
494 	int32_t ret;
495 	uint32_t i;
496 
497 	dev_id = ti_device_id(dev);
498 	devdata = ti_get_dev_data(dev);
499 
500 	/* Check if this PSC manages its own power domain */
501 	if ((devdata->flags & TI_DEVD_FLAG_DRV_DATA) != 0U) {
502 		drvdata = ti_to_drv_data(devdata);
503 		if (drvdata->drv == &psc_drv) {
504 			psc = ti_to_psc_drv_data(drvdata);
505 			if (psc->psc_idx == devdata->soc.psc_idx) {
506 				psc_dev = dev;
507 			} else {
508 				psc = NULL;
509 			}
510 		}
511 	}
512 
513 	if (psc_dev != NULL) {
514 		/* We are our own PSC */
515 		return ti_soc_device_verify_mapping(psc, dev_id, &devdata->soc);
516 	}
517 
518 	if (devdata->soc.psc_idx == TI_PSC_DEV_MULTIPLE) {
519 		/* Find all the PSCs this device needs */
520 		domains = soc_psc_multiple_domains[devdata->soc.mod];
521 		for (i = 0U; domains[i].psc_idx != TI_PSC_DEV_NONE; i++) {
522 			psc_dev = ti_psc_lookup((ti_psc_idx_t) domains[i].psc_idx);
523 			if (psc_dev == NULL) {
524 				return -EAGAIN;
525 			}
526 
527 			psc = ti_to_psc_drv_data(ti_get_drv_data(psc_dev));
528 			ret = ti_soc_device_verify_mapping(psc, dev_id, &domains[i]);
529 			if (ret != 0) {
530 				return ret;
531 			}
532 		}
533 
534 		return 0;
535 	}
536 
537 	/* We just need the one PSC */
538 	psc_dev = ti_psc_lookup((ti_psc_idx_t) devdata->soc.psc_idx);
539 	if (psc_dev == NULL) {
540 		/*
541 		 * Don't try to bring this dev up before calling init
542 		 * on the device's PSC.
543 		 */
544 		return -EAGAIN;
545 	}
546 
547 	psc = ti_to_psc_drv_data(ti_get_drv_data(psc_dev));
548 	return ti_soc_device_verify_mapping(psc, dev_id, &devdata->soc);
549 }
550 
551 /* Defer all other device initialization until PSC initializes */
ti_soc_device_init(struct ti_device * dev)552 int32_t ti_soc_device_init(struct ti_device *dev)
553 {
554 	const struct ti_dev_data *devdata;
555 
556 	assert(dev != NULL);
557 
558 	devdata = ti_get_dev_data(dev);
559 
560 	if (devdata->soc.psc_idx != TI_PSC_DEV_NONE) {
561 		return ti_soc_device_init_internal(dev);
562 	}
563 
564 	return 0;
565 }
566