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 Initialization and Management
9 *
10 * This module provides core device initialization, deferred initialization
11 * support, and device lifecycle management for the device power management subsystem.
12 */
13
14 #include <assert.h>
15 #include <errno.h>
16 #include <stddef.h>
17
18 #include <common/debug.h>
19 #include <ti_clk.h>
20 #include <ti_device.h>
21 #include <ti_device_clk.h>
22 #include <ti_device_pm.h>
23
24 /* True if deferred (read-write) initialization has been initiated. */
25 static bool devices_rw;
26
ti_pm_devgroup_is_enabled(devgrp_t groups)27 bool ti_pm_devgroup_is_enabled(devgrp_t groups)
28 {
29 return true;
30 }
31
32 /**
33 * device_init() - Initialize a device
34 * @dev: The device to init.
35 *
36 * This performs the necessary device initialization step, including syncing
37 * the flags on the device with the real hardware state and calling the clock
38 * init function for each clock.
39 *
40 * Return: 0 on success, <0 on failure.
41 */
device_init(struct ti_device * dev)42 static int32_t device_init(struct ti_device *dev)
43 {
44 const struct ti_dev_data *data;
45 const struct ti_drv *drvp = NULL;
46 uint16_t i;
47 int32_t ret;
48
49 assert(dev != NULL);
50
51 data = ti_get_dev_data(dev);
52 if (data == NULL) {
53 return 0;
54 }
55
56 if (((data->flags & TI_DEVD_FLAG_DRV_DATA) != 0U) &&
57 ((data->flags & TI_DEVD_FLAG_DO_INIT) != 0U)) {
58 drvp = ti_to_drv_data(data)->drv;
59 }
60
61 if ((drvp != NULL) && (drvp->pre_init != NULL)) {
62 ret = drvp->pre_init(dev);
63 if (ret != 0) {
64 return ret;
65 }
66 }
67
68 if (devices_rw == false) {
69 /* Defer remainder of init */
70 return 0;
71 }
72
73 ret = ti_soc_device_init(dev);
74 if (ret != 0) {
75 return ret;
76 }
77
78 for (i = 0U; i < data->n_clocks; i++) {
79 ti_device_clk_init(dev, i);
80 }
81
82 /* Calling these multiple times for a deferred device has no effect */
83 if (ti_device_get_state(dev) != 0U) {
84 ti_device_set_state(dev, TI_DEV_POWER_ON_ENABLED_HOST_IDX, true);
85 ti_device_set_retention(dev, true);
86 }
87
88 if ((drvp != NULL) && (drvp->post_init != NULL)) {
89 ret = drvp->post_init(dev);
90 if (ret != 0) {
91 return ret;
92 }
93 }
94
95 return 0;
96 }
97
ti_devices_init(void)98 int32_t ti_devices_init(void)
99 {
100 bool done;
101 bool progress;
102 bool contents;
103 ti_dev_idx_t idx;
104
105 contents = false;
106 do {
107 struct ti_device *dev;
108
109 done = true;
110 progress = false;
111
112 for (idx = 0U; idx < soc_device_count; idx++) {
113 devgrp_t devgrp;
114 int32_t ret;
115
116 dev = &soc_devices[idx];
117 if (dev->initialized != 0U) {
118 continue;
119 }
120
121 if (soc_device_data_arr[idx] == NULL) {
122 continue;
123 }
124
125 /* Translate compressed internal representation to bitfield */
126 devgrp = (devgrp_t) BIT(soc_device_data_arr[idx]->pm_devgrp - 1U);
127
128 if (ti_pm_devgroup_is_enabled(devgrp) == false) {
129 continue;
130 }
131
132 contents = true;
133
134 ret = device_init(dev);
135 if (ret == -EAGAIN) {
136 done = false;
137 continue;
138 }
139
140 if (ret < 0) {
141 VERBOSE("ACTION FAIL: DEV_INIT dev_id=%d error=%d\n",
142 idx, -ret);
143 }
144
145 progress = true;
146 dev->initialized = 1U;
147 }
148 } while (!done && progress);
149
150 if (devices_rw == true) {
151 /* Only necessary after deferred initialization */
152 ti_clk_drop_pwr_up_en();
153 }
154
155 if ((progress == false) && (contents == true)) {
156 /* We processed at least one device but didn't make progress */
157 return -EAGAIN;
158 }
159
160 return 0;
161 }
162
ti_devices_init_rw(void)163 int32_t ti_devices_init_rw(void)
164 {
165 if (devices_rw == false) {
166 uint32_t i;
167
168 /*
169 * Force reinitialization of all devices to get deferred
170 * initialization.
171 */
172 for (i = 0U; i < soc_device_count; i++) {
173 struct ti_device *dev = &soc_devices[i];
174
175 dev->initialized = 0U;
176 }
177
178 devices_rw = true;
179
180 /* Perform deferred initialization */
181 return ti_devices_init();
182 }
183
184 return 0;
185 }
186