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