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